From 0edfb98b1b8f614acddb03b62fb7ea080a08c9af Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Tue, 27 Jul 2021 16:39:46 -0700 Subject: [PATCH 01/15] Initial restart API branch --- .../AppLifecycle/Restart/restartApi.markdown | 492 ++++++++++++++++++ 1 file changed, 492 insertions(+) create mode 100644 specs/AppLifecycle/Restart/restartApi.markdown diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown new file mode 100644 index 0000000000..38923d8379 --- /dev/null +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -0,0 +1,492 @@ +# Reunion Restart API Spec + +## Contents + +[1. Overview](#overview) +- [Reunion Restart API components](#reunion-restart-api-components) + +[2. API](#api) + +- [Existing API Summary](#existing-api-summary) + +- [All Existing Scenarios](#all-existing-scenarios) + +- [Existing API Details](#existing-api-details) + +- [New API Details](#new-api-details) + +- [API Sample Code](#api-sample-code) + +[3. Telemetry](##restartApi\telemetry) + +[4. Resources](#resources) + +## Contacts + +### Program Managers + +Hamza Usmani (mousma)\ +Andrew Whitechapel (andreww) + +### Developers +Scott Darnell (scodar) + +### Data +TBD + +## Overview + +We are creating a new AppLifecycle component that provides a core set of +functionality related to app activation and lifecycle. The 3 key goals +of this component are: + +- it is undocked from the OS; that is, it will release out-of-band + from the OS; + +- it provides a centralized place for core app lifecycle functionality + that *all* apps can easily consume, whether traditional unpackaged + Win32, Winforms, WPF, packaged (Centennial) Win32, or UWP. + +- it will be made available as open-source. + +This spec addresses the **Restart APIs** in the component. The main +goals of this specific API are the following: + +Addressing the gaps that exist today: at a high-level, Win32 apps can +register with the OS to restart in update/hang/reboot scenarios but +cannot restart immediately on-command with specific arguments/state. UWP +apps can restart on-command with command-line restart arguments but +cannot register with the OS Restart Manager for update/hang/reboot +scenarios. These are the gaps we need to address. + +### Reunion Restart API components + +1. Expose a new function: **RegisterForRestart**, which allows any app + to register itself for restart if it was running when a system + update occurs or if an app hangs/crashes unexpectedly. + + a. This is an existing Win32 API (RegisterApplicationRestart) which + we want UWP parity with + +2. Expose a new function: **RequestRestartNow** function to enable any + app to terminate and restart itself on command, and to provide an + arbitrary command-line string for the restarted instance. + + a. Mirror the functionality of an existing WinRT API + (RequestRestartAsync) which we want to work with Win32, UWP + applications + WinUI + +## API + +### Existing API Summary + +1. **Restart-me-now**. UWP CoreApplication exposes the + [RequestRestartAsync](https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.core.coreapplication.requestrestartasync?view=winrt-18362) + method, which allows an app to terminate and restart itself, and to + provide an arbitrary command-line string for the restarted instance. + +2. **Restart-me-after-termination**. The Win32 API + [RegisterApplicationRestart](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registerapplicationrestart) + enables an app to register itself to be restarted after termination, + and to provide an arbitrary command-line string for the restarted + instance. The reasons for termination include app crash or hang, app + update, or system update. There's also a matching + [UnregisterApplicationRestart](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-unregisterapplicationrestart) + API. + +There are 2 related Win32 APIs that focus on recovery prior to restart: + +1. **Let-me-do-something-before-termination**. An app can call + [RegisterApplicationRecoveryCallback](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registerapplicationrecoverycallback) + to register a callback for the system to call before terminating the + app. If an application encounters an unhandled exception or becomes + unresponsive, Windows Error Reporting (WER) calls the specified + recovery callback, where the app can save state information. The + system pings the app every n seconds to make sure that it hasn't + hung in its callback. The app can specify the ping interval when it + registers the callback. In its recovery callback, the app can call + RegisterApplicationRestart a second time, to update the + command-line. + +2. **Recovery-in-progress**. While the app is doing work in its + recovery callback, the app must periodically call + [ApplicationRecoveryInProgress](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-applicationrecoveryinprogress) + -- if it doesn't call within the registered ping interval, WER will + terminate the process. + + + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
App TypeApplicable Restart MechanismGap
Win32 (unpackaged)
    +
  • RegisterApplicationRestart for OS + app update/restart/crash scenarios 

  • +
    +
  • Apps can register with the OS to restart in specific app/OS states, but cannot restart on-command in a healthy state 

  • +
Win32/Centennial (packaged)
    +
  • RegisterApplicationRestart for OS + app update/restart/crash scenarios 

  • +
    +
  • Apps can register with the OS to restart in specific app/OS states, but cannot restart on-command in a healthy state 

  • +
UWP
    +
  • +

    RequestRestartAsync for restarting on demand in a healthy state 

    +
  • +
+
    +
  • Automatically registered to restart in restart scenario by Explorer/shell using RestartUwpApp 

  • +
    +
  • +

    Apps can restart on-command asynchronously when healthy/active but do not have the ability to ensure restart in app crash/hang scenarios 

    +
  • +
+
    +
  •  

  • +
WinUI (UWP)
    +
  • +

    RequestRestartAsync for restarting on demand in a healthy state 

    +
  • +
+
    +
  • Automatically registered to restart in restart scenario by Explorer/shell using RestartUwpApp 

  • +
    +
  • +

    Apps can restart on-command asynchronously when healthy/active but do not have the ability to ensure restart in app crash/hang scenarios 

    +
  • +
+
    +
  •  

  • +
WinUI (Centennial)
    +
  • RegisterApplicationRestart for OS + app update/restart/crash scenarios 

  • +
    +
  • Apps can register with the OS to restart in specific app/OS states, but cannot restart on-command in a healthy state 

  • +
+ +## Existing API Details + + ++++ + + + + + + + + + + + + + + + + +
Existing API for Win32 AppsDetails

HRESULT RegisterApplicationRestart(

+

PCWSTR pwzCommandline,

+

DWORD dwFlags);

The pwzCommandline parameter is passed into the new instance as its command-line arguments string. The dwFlags can be 0 or one or more of the (flags) values:

+
    +
  • +

    1: RESTART_NO_CRASH - Do not restart the process if it terminates due to an unhandled exception.

    +
  • +
  • +

    2: RESTART_NO_HANG - Do not restart the process if it terminates due to the application not responding.

    +
  • +
  • +

    4: RESTART_NO_PATCH - Do not restart the process if it terminates due to the installation of an OS update.

    +
  • +
  • +

    8: RESTART_NO_REBOOT - Do not restart the process if the computer is restarted as the result of an OS update.

    +
  • +
HRESULT UnregisterApplicationRestart();Unregisters the app for restart, where the app had previously called RegisterApplicationRestart.
+ + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Existing API for UWP AppsDetails
public static IAsyncOperation<AppRestartFailureReason> RequestRestartAsync(
+string launchArguments);

Static function in CoreApplication. Requests immediate termination and restart.

+
    +
  • +

    The launchArguments string is passed into the new instance as the Arguments property on LaunchActivatedEventArgs.

    +
  • +
  • +

    Also sets LaunchActivatedEventArgs.PreviousExecutionState to Terminated.

    +
  • +
public enum AppRestartFailureReason
    +
  • +

    0: RestartPending - a restart is already in progress.

    +
  • +
  • +

    1: NotInForeground - an app must be visible and in the foreground when it calls the restart API.

    +
  • +
  • +

    2: InvalidUser - could not restart for the specified user.

    +
  • +
  • +

    3: Other - unspecified failure.

    +
  • +
void RestartUwpApp(const wchar_t* const appUserModelId)Internal-only function in shell/explorer added as of 20H1 allowing UWP apps to be restarted in a minimized state
public enum AppRestartFailureReason

Enum which will be used in the new API detailed below to indicate the reason for a failed restart now.

+
    +
  • +

    0: RestartPending - a restart is already in progress.

    +
  • +
  • +

    1: NotInForeground - an app must be visible and in the foreground when it calls the restart API.

    +
  • +
  • +

    2: InvalidUser - could not restart for the specified user.

    +
  • +
  • +

    3: Other - unspecified failure.

    +
  • +
class LaunchActivatedEventArg

Relevant Properties:

+
    +
  • Arguments: gets the arguments that are passed to the app during its launch activation.

  • +
  • Kind: Gets the reason that this app is being activated. This is of type enum ActivationKind

  • +
+

PreviousExecutionState: Gets the execution state of the app before this activation.

+ +### New API Details + +#### RegisterForRestart + + +++++ + + + + + + + + + + + + + + + + + + + + + + + + +
New API DescriptionPriority
static bool RegisterForRestart(string restartArguments, RestartContext context)

Equivalent to the Win32 RegisterApplicationRestart function.

+

restartArguments is the same as the pwzCommandline parameter in the Win32 RegisterApplicationRestart. It is a string of command-line arguments which will be passed as restart arguments.

+

restartArguments become the restarted/new instance’s LaunchActivatedEventArgs.

P3
[Flags] enum RestartContext

The values passed for RestartContext indicate which cases

+

the app should be restarted.
+
+
The possible cases are the same as dwFlag values listed above in Win32’s RegisterApplicationRestart:

+
    +
  • -1: ALL

  • +
  • 1: CRASH

  • +
  • 2: HANG

  • +
  • 4: PATCH

  • +
  • 8: REBOOT

  • +
+

[Flags] enum RestartContext { All = -1, Crash = 1, Hang = 2, Patch = 4, Reboot = 8 }

P3
static bool UnregisterForRestart()Equivalent to the Win32 UnregisterApplicationRestart function.P3
+ +#### RequestRestartNow + + +++++ + + + + + + + + + + + + + + +
New API DescriptionPriority
static AppRestartFailureReason RequestRestartNow(string restartArguments)

Equivalent to CoreApplication.RequestRestartAsync, except that it is not async. +

    +
  • The app must be visible and foreground when it calls this API.
  • +
  • If the restart fails, but the user subsequently launches the app manually, the app will launch normally and no restart arguments will be passed.
  • +
  • If the app has any in-process background tasks running when it calls this API, those tasks will be cancelled in the normal way. Out-of-process background tasks will not be affected.
  • +
+ The restarted instance will be activated with Windows.ApplicationModel.Activation.LaunchActivatedEventArgs.

+
    +
  • When the app is restarted, LaunchActivatedEventArgs.PreviousExecutionState will have the value Terminated so that the app can distinguish between a resume and a restart.
  • +
+

Returns a failure reason for why the restart didn’t successfully complete.

P1
+ +### API Sample Code + +#### RegisterForRestart Sample + + public class App { + +         // App was just launched +         protected override void OnLaunched(LaunchActivatedEventArgs args) +         { +             // If the application was terminated for example and has now been restarted +             if (args != NULL) +             { +                 if (args.PreviousExecutionState == ApplicationExecutionState.Terminated) +                 { +                     Telemetry::WriteLine("Restart activated: " + args.Arguments); +                 } +             } +         } + +         // We want to register the app for restart if termination happens only after crash +         protected bool restartOnUpdate(){ +             bool result = AppLifecycle::RegisterForRestart("args for new instance", RestartContext::Crash); +             Telemetry::WriteLine("RegisterForRestart: Restart Context: " + RestartContext::Crash.ToString()  + + ". Result: " + result ? "success" : "fail"); + +             // Do normal app behavior +         } + +         // We want to unregister for post-crash restarts +         protected bool removeRestartOnUpdate(){ +             bool result = AppLifecycle::UnregisterForRestart(); +             Telemetry::WriteLine("UnregisterForRestart: Result: " + result ? "success" : "fail"); +         } + } + +### RequestRestartNow Sample + + public class App { +        // Let's assume this method is run when an app updates assets. +        // The new assets have downloaded and installed, and now the app has to restart immediately +        protected void updateInstallComplete(){ +            // code here that checks the app update has installed + +            WCHAR buffer\[1024\];  +            AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); + +            switch (result){ +                 case AppRestartFailureReason::RestartPending: +                     Telemetry::WriteLine("Restart request successful."); +                     break; +                 case AppRestartFailureReason::NotInForeground: +                     wcscpy_s(buffer, L"App must be in the foreground to request restart."); +                     break; +                 case AppRestartFailureReason::InvalidUser: +                     wcscpy_s(buffer, L"Cannot restart for this user."); +                     break; +                 case AppRestartFailureReason::Other: +                     wcscpy_s(buffer, L"Unknown failure."); +                     break; +            } +        }                + }   + +## Telemetry + +This section explores the telemetry needs for the Restart feature in +four dimensions – Usage, Reliability, Performance and Failure +Investigation. The telemetry will include the metadata that are needed +not only for measuring quality but also for helping with investigations +of failures. Following is the event which can be used to capture +telemetry information: + +Event Name: **AppRestart** + +| Metadata | Description | Data type | +|-------------------------|---------------------------------------------------------------------------------------------------|-----------| +| RestartContext | Reason for an App to register for restart and then attempt to restart | Enum | +| AppRestartFailureReason | Reason an app restart failed. This will be collected when an app requests a restart now but fails | Enum | +| AppName | Name of the app which restarted | String | +| AppType | UWP App or Centennial App or Win32 app | String | + +## Resources + +| Resource | Description | +|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------| +| [API Design Process](http://osgwiki.com/wiki/API_Design) | API design process overview with FAQs and links to useful resources. | +| [API Design Representatives](http://osgwiki.com/wiki/API_Design_Representatives) | API design representatives and their areas of expertise. | +| [API Design Guidelines](http://osgwiki.com/wiki/WinRT_API_Design_Guidelines) | API design guidelines for various frameworks. | +| [Sample Requirements](https://osgwiki.com/wiki/API_Design#Sample_Requirements) | Requirements for the samples above including when samples in specific languages are required. | +| [Interface Definition Guidelines](https://microsoft.sharepoint.com/teams/osg_core_dep/devtools/Shared%20Documents/API%20Design/Educational%20Content/Interface%20Definition%20Guidelines.docx) | Guidelines for providing interface definitions. | +| [Code Analysis Guidelines](https://osgwiki.com/wiki/API_Design#Design_Analysis_Guidelines) | Guidelines for running code analysis tools. | +| [RtCop Bug Template](http://aka.ms/rtcopbug) | The bug template to use when filing RtCop bugs. | From f255310e7ed83e2842e309a089de46915178c035 Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Tue, 27 Jul 2021 16:54:13 -0700 Subject: [PATCH 02/15] Formatting to code blocks --- .../AppLifecycle/Restart/restartApi.markdown | 122 +++++++++--------- 1 file changed, 60 insertions(+), 62 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index 38923d8379..25a10b00f2 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -163,9 +163,6 @@ There are 2 related Win32 APIs that focus on recovery prior to restart:

Apps can restart on-command asynchronously when healthy/active but do not have the ability to ensure restart in app crash/hang scenarios 

- WinUI (UWP) @@ -182,9 +179,7 @@ There are 2 related Win32 APIs that focus on recovery prior to restart:

Apps can restart on-command asynchronously when healthy/active but do not have the ability to ensure restart in app crash/hang scenarios 

- + WinUI (Centennial) @@ -401,65 +396,68 @@ string launchArguments); ### API Sample Code #### RegisterForRestart Sample - - public class App { - -         // App was just launched -         protected override void OnLaunched(LaunchActivatedEventArgs args) -         { -             // If the application was terminated for example and has now been restarted -             if (args != NULL) -             { -                 if (args.PreviousExecutionState == ApplicationExecutionState.Terminated) -                 { -                     Telemetry::WriteLine("Restart activated: " + args.Arguments); -                 } -             } -         } - -         // We want to register the app for restart if termination happens only after crash -         protected bool restartOnUpdate(){ -             bool result = AppLifecycle::RegisterForRestart("args for new instance", RestartContext::Crash); -             Telemetry::WriteLine("RegisterForRestart: Restart Context: " + RestartContext::Crash.ToString()  - + ". Result: " + result ? "success" : "fail"); - -             // Do normal app behavior -         } - -         // We want to unregister for post-crash restarts -         protected bool removeRestartOnUpdate(){ -             bool result = AppLifecycle::UnregisterForRestart(); -             Telemetry::WriteLine("UnregisterForRestart: Result: " + result ? "success" : "fail"); -         } - } +```c# +public class App { + +        // App was just launched +        protected override void OnLaunched(LaunchActivatedEventArgs args) +        { +            // If the application was terminated for example and has now been restarted +            if (args != NULL) +            { +                if (args.PreviousExecutionState == ApplicationExecutionState.Terminated) +                { +                    Telemetry::WriteLine("Restart activated: " + args.Arguments); +                } +            } +        } + +        // We want to register the app for restart if termination happens only after crash +        protected bool restartOnUpdate(){ +            bool result = AppLifecycle::RegisterForRestart("args for new instance", RestartContext::Crash); +            Telemetry::WriteLine("RegisterForRestart: Restart Context: " + RestartContext::Crash.ToString()  + + ". Result: " + result ? "success" : "fail"); + +            // Do normal app behavior +        } + +        // We want to unregister for post-crash restarts +        protected bool removeRestartOnUpdate(){ +            bool result = AppLifecycle::UnregisterForRestart(); +            Telemetry::WriteLine("UnregisterForRestart: Result: " + result ? "success" : "fail"); +        } +} +``` ### RequestRestartNow Sample - public class App { -        // Let's assume this method is run when an app updates assets. -        // The new assets have downloaded and installed, and now the app has to restart immediately -        protected void updateInstallComplete(){ -            // code here that checks the app update has installed - -            WCHAR buffer\[1024\];  -            AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); - -            switch (result){ -                 case AppRestartFailureReason::RestartPending: -                     Telemetry::WriteLine("Restart request successful."); -                     break; -                 case AppRestartFailureReason::NotInForeground: -                     wcscpy_s(buffer, L"App must be in the foreground to request restart."); -                     break; -                 case AppRestartFailureReason::InvalidUser: -                     wcscpy_s(buffer, L"Cannot restart for this user."); -                     break; -                 case AppRestartFailureReason::Other: -                     wcscpy_s(buffer, L"Unknown failure."); -                     break; -            } -        }                - }   +```c# +public class App { +       // Let's assume this method is run when an app updates assets. +       // The new assets have downloaded and installed, and now the app has to restart immediately +       protected void updateInstallComplete(){ +           // code here that checks the app update has installed + +           WCHAR buffer\[1024\];  +           AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); + +           switch (result){ +                case AppRestartFailureReason::RestartPending: +                    Telemetry::WriteLine("Restart request successful."); +                    break; +                case AppRestartFailureReason::NotInForeground: +                    wcscpy_s(buffer, L"App must be in the foreground to request restart."); +                    break; +                case AppRestartFailureReason::InvalidUser: +                    wcscpy_s(buffer, L"Cannot restart for this user."); +                    break; +                case AppRestartFailureReason::Other: +                    wcscpy_s(buffer, L"Unknown failure."); +                    break; +           } +       }                +} +``` ## Telemetry From 42b93383cc29903926cc43cf3774fe99a9c24358 Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Tue, 27 Jul 2021 16:55:47 -0700 Subject: [PATCH 03/15] Updates to heading --- specs/AppLifecycle/Restart/restartApi.markdown | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index 25a10b00f2..12aecf489c 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -21,19 +21,6 @@ [4. Resources](#resources) -## Contacts - -### Program Managers - -Hamza Usmani (mousma)\ -Andrew Whitechapel (andreww) - -### Developers -Scott Darnell (scodar) - -### Data -TBD - ## Overview We are creating a new AppLifecycle component that provides a core set of From c4fbdb0f43e014bc6ebb1dc0395e133fbd2cecec Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Tue, 27 Jul 2021 16:58:13 -0700 Subject: [PATCH 04/15] Removed preamble --- specs/AppLifecycle/Restart/restartApi.markdown | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index 12aecf489c..55acbcd41a 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -23,20 +23,7 @@ ## Overview -We are creating a new AppLifecycle component that provides a core set of -functionality related to app activation and lifecycle. The 3 key goals -of this component are: - -- it is undocked from the OS; that is, it will release out-of-band - from the OS; - -- it provides a centralized place for core app lifecycle functionality - that *all* apps can easily consume, whether traditional unpackaged - Win32, Winforms, WPF, packaged (Centennial) Win32, or UWP. - -- it will be made available as open-source. - -This spec addresses the **Restart APIs** in the component. The main +This spec addresses the **Restart APIs** in the AppLifecycle component. The main goals of this specific API are the following: Addressing the gaps that exist today: at a high-level, Win32 apps can From b1c5fe2883a8f1145c0750c36506e6f01e4c1ec8 Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Tue, 27 Jul 2021 17:05:20 -0700 Subject: [PATCH 05/15] Updates to overview --- specs/AppLifecycle/Restart/restartApi.markdown | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index 55acbcd41a..bbeef774d8 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -35,20 +35,14 @@ scenarios. These are the gaps we need to address. ### Reunion Restart API components -1. Expose a new function: **RegisterForRestart**, which allows any app +1. Expose a new function: **RegisterForRestart**, which allows any app (win32/packaged win32, UWP, WinUI apps) to register itself for restart if it was running when a system update occurs or if an app hangs/crashes unexpectedly. - a. This is an existing Win32 API (RegisterApplicationRestart) which - we want UWP parity with - 2. Expose a new function: **RequestRestartNow** function to enable any - app to terminate and restart itself on command, and to provide an + app (win32/packaged win32, UWP, WinUI apps) to terminate and restart itself on command, and to provide an arbitrary command-line string for the restarted instance. - a. Mirror the functionality of an existing WinRT API - (RequestRestartAsync) which we want to work with Win32, UWP - applications + WinUI ## API From 57ca83e8dee9cd05d3aadad65d70fba823239dd0 Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Tue, 27 Jul 2021 17:07:46 -0700 Subject: [PATCH 06/15] Removing resources content --- specs/AppLifecycle/Restart/restartApi.markdown | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index bbeef774d8..024cc15c08 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -444,15 +444,3 @@ Event Name: **AppRestart** | AppRestartFailureReason | Reason an app restart failed. This will be collected when an app requests a restart now but fails | Enum | | AppName | Name of the app which restarted | String | | AppType | UWP App or Centennial App or Win32 app | String | - -## Resources - -| Resource | Description | -|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------| -| [API Design Process](http://osgwiki.com/wiki/API_Design) | API design process overview with FAQs and links to useful resources. | -| [API Design Representatives](http://osgwiki.com/wiki/API_Design_Representatives) | API design representatives and their areas of expertise. | -| [API Design Guidelines](http://osgwiki.com/wiki/WinRT_API_Design_Guidelines) | API design guidelines for various frameworks. | -| [Sample Requirements](https://osgwiki.com/wiki/API_Design#Sample_Requirements) | Requirements for the samples above including when samples in specific languages are required. | -| [Interface Definition Guidelines](https://microsoft.sharepoint.com/teams/osg_core_dep/devtools/Shared%20Documents/API%20Design/Educational%20Content/Interface%20Definition%20Guidelines.docx) | Guidelines for providing interface definitions. | -| [Code Analysis Guidelines](https://osgwiki.com/wiki/API_Design#Design_Analysis_Guidelines) | Guidelines for running code analysis tools. | -| [RtCop Bug Template](http://aka.ms/rtcopbug) | The bug template to use when filing RtCop bugs. | From dc9d7f8b8f49a6319dde257171b275c6cb87b153 Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Fri, 12 Nov 2021 17:34:52 -0800 Subject: [PATCH 07/15] Updating restart spec with latest changes --- .../AppLifecycle/Restart/restartApi.markdown | 93 +------------------ 1 file changed, 2 insertions(+), 91 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index 024cc15c08..7b71776484 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -28,18 +28,11 @@ goals of this specific API are the following: Addressing the gaps that exist today: at a high-level, Win32 apps can register with the OS to restart in update/hang/reboot scenarios but -cannot restart immediately on-command with specific arguments/state. UWP -apps can restart on-command with command-line restart arguments but -cannot register with the OS Restart Manager for update/hang/reboot -scenarios. These are the gaps we need to address. +cannot restart immediately on-command with specific arguments/state. This applies to packaged (Centennial) and unpackaged apps. These are the gaps we need to address. ### Reunion Restart API components -1. Expose a new function: **RegisterForRestart**, which allows any app (win32/packaged win32, UWP, WinUI apps) - to register itself for restart if it was running when a system - update occurs or if an app hangs/crashes unexpectedly. - -2. Expose a new function: **RequestRestartNow** function to enable any +1. Expose a new function: **RequestRestartNow** function to enable any app (win32/packaged win32, UWP, WinUI apps) to terminate and restart itself on command, and to provide an arbitrary command-line string for the restarted instance. @@ -280,53 +273,6 @@ string launchArguments); ### New API Details -#### RegisterForRestart - - ----- - - - - - - - - - - - - - - - - - - - - - - - - -
New API DescriptionPriority
static bool RegisterForRestart(string restartArguments, RestartContext context)

Equivalent to the Win32 RegisterApplicationRestart function.

-

restartArguments is the same as the pwzCommandline parameter in the Win32 RegisterApplicationRestart. It is a string of command-line arguments which will be passed as restart arguments.

-

restartArguments become the restarted/new instance’s LaunchActivatedEventArgs.

P3
[Flags] enum RestartContext

The values passed for RestartContext indicate which cases

-

the app should be restarted.
-
-
The possible cases are the same as dwFlag values listed above in Win32’s RegisterApplicationRestart:

-
    -
  • -1: ALL

  • -
  • 1: CRASH

  • -
  • 2: HANG

  • -
  • 4: PATCH

  • -
  • 8: REBOOT

  • -
-

[Flags] enum RestartContext { All = -1, Crash = 1, Hang = 2, Patch = 4, Reboot = 8 }

P3
static bool UnregisterForRestart()Equivalent to the Win32 UnregisterApplicationRestart function.P3
- #### RequestRestartNow @@ -363,40 +309,6 @@ string launchArguments); ### API Sample Code -#### RegisterForRestart Sample -```c# -public class App { - -        // App was just launched -        protected override void OnLaunched(LaunchActivatedEventArgs args) -        { -            // If the application was terminated for example and has now been restarted -            if (args != NULL) -            { -                if (args.PreviousExecutionState == ApplicationExecutionState.Terminated) -                { -                    Telemetry::WriteLine("Restart activated: " + args.Arguments); -                } -            } -        } - -        // We want to register the app for restart if termination happens only after crash -        protected bool restartOnUpdate(){ -            bool result = AppLifecycle::RegisterForRestart("args for new instance", RestartContext::Crash); -            Telemetry::WriteLine("RegisterForRestart: Restart Context: " + RestartContext::Crash.ToString()  - + ". Result: " + result ? "success" : "fail"); - -            // Do normal app behavior -        } - -        // We want to unregister for post-crash restarts -        protected bool removeRestartOnUpdate(){ -            bool result = AppLifecycle::UnregisterForRestart(); -            Telemetry::WriteLine("UnregisterForRestart: Result: " + result ? "success" : "fail"); -        } -} -``` - ### RequestRestartNow Sample ```c# @@ -440,7 +352,6 @@ Event Name: **AppRestart** | Metadata | Description | Data type | |-------------------------|---------------------------------------------------------------------------------------------------|-----------| -| RestartContext | Reason for an App to register for restart and then attempt to restart | Enum | | AppRestartFailureReason | Reason an app restart failed. This will be collected when an app requests a restart now but fails | Enum | | AppName | Name of the app which restarted | String | | AppType | UWP App or Centennial App or Win32 app | String | From 724201cab41a2f43aa39ee42a81ffbf25286d19e Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Mon, 15 Nov 2021 15:04:33 -0800 Subject: [PATCH 08/15] Fixed summary --- specs/AppLifecycle/Restart/restartApi.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index 7b71776484..0fe25987cf 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -32,8 +32,8 @@ cannot restart immediately on-command with specific arguments/state. This applie ### Reunion Restart API components -1. Expose a new function: **RequestRestartNow** function to enable any - app (win32/packaged win32, UWP, WinUI apps) to terminate and restart itself on command, and to provide an +1. Expose a new function: **RequestRestartNow** function to enable any packaged or unpackaged Win32 + app to terminate and restart itself on command, and to provide an arbitrary command-line string for the restarted instance. From ebc5d9c9ab1e372d3f1ee08b75fcfa37824e7493 Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Fri, 19 Nov 2021 13:58:21 -0800 Subject: [PATCH 09/15] Updates to API details, mechanism and sample --- .../AppLifecycle/Restart/restartApi.markdown | 264 ++++++------------ 1 file changed, 78 insertions(+), 186 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index 0fe25987cf..2943e77b88 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -1,47 +1,36 @@ -# Reunion Restart API Spec +# Restart API -## Contents +# Contents -[1. Overview](#overview) -- [Reunion Restart API components](#reunion-restart-api-components) +- [Restart API](#restart-api) +- [Contents](#contents) +- [Background](#background) + - [Description](#description) +- [API](#api) + - [Existing API Summary](#existing-api-summary) + - [Existing API Details](#existing-api-details) + - [New API Details](#new-api-details) + - [RequestRestartNow](#requestrestartnow) + - [Examples and Scenarios](#examples-and-scenarios) +- [Telemetry](#telemetry) -[2. API](#api) +# Background -- [Existing API Summary](#existing-api-summary) +This spec addresses the **Restart APIs** in the AppLifecycle component. At a high-level, Win32 apps can +register with the OS to restart in update/hang/reboot scenarios but cannot restart immediately on-command +with specific arguments/state. This applies to packaged (Centennial) and unpackaged apps. This API will address +these gaps and provide the ability for any Win32 app to restart immediately. -- [All Existing Scenarios](#all-existing-scenarios) +## Description -- [Existing API Details](#existing-api-details) +The goal of this feature is the new function: **RequestRestartNow**, which will enable any packaged or unpackaged Win32 +app to terminate and restart itself on command, and to provide an arbitrary command-line string for the restarted instance. -- [New API Details](#new-api-details) +# API -- [API Sample Code](#api-sample-code) +## Existing API Summary -[3. Telemetry](##restartApi\telemetry) - -[4. Resources](#resources) - -## Overview - -This spec addresses the **Restart APIs** in the AppLifecycle component. The main -goals of this specific API are the following: - -Addressing the gaps that exist today: at a high-level, Win32 apps can -register with the OS to restart in update/hang/reboot scenarios but -cannot restart immediately on-command with specific arguments/state. This applies to packaged (Centennial) and unpackaged apps. These are the gaps we need to address. - -### Reunion Restart API components - -1. Expose a new function: **RequestRestartNow** function to enable any packaged or unpackaged Win32 - app to terminate and restart itself on command, and to provide an - arbitrary command-line string for the restarted instance. - - -## API - -### Existing API Summary - -1. **Restart-me-now**. UWP CoreApplication exposes the +1. **Restart-me-now**. CoreApplication exposes the [RequestRestartAsync](https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.core.coreapplication.requestrestartasync?view=winrt-18362) method, which allows an app to terminate and restart itself, and to provide an arbitrary command-line string for the restarted instance. @@ -72,87 +61,12 @@ There are 2 related Win32 APIs that focus on recovery prior to restart: 2. **Recovery-in-progress**. While the app is doing work in its recovery callback, the app must periodically call [ApplicationRecoveryInProgress](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-applicationrecoveryinprogress) - -- if it doesn't call within the registered ping interval, WER will + \-- if it doesn't call within the registered ping interval, WER will terminate the process. - -
----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
App TypeApplicable Restart MechanismGap
Win32 (unpackaged)
    -
  • RegisterApplicationRestart for OS + app update/restart/crash scenarios 

  • -
    -
  • Apps can register with the OS to restart in specific app/OS states, but cannot restart on-command in a healthy state 

  • -
Win32/Centennial (packaged)
    -
  • RegisterApplicationRestart for OS + app update/restart/crash scenarios 

  • -
    -
  • Apps can register with the OS to restart in specific app/OS states, but cannot restart on-command in a healthy state 

  • -
UWP
    -
  • -

    RequestRestartAsync for restarting on demand in a healthy state 

    -
  • -
-
    -
  • Automatically registered to restart in restart scenario by Explorer/shell using RestartUwpApp 

  • -
    -
  • -

    Apps can restart on-command asynchronously when healthy/active but do not have the ability to ensure restart in app crash/hang scenarios 

    -
  • -
-
WinUI (UWP)
    -
  • -

    RequestRestartAsync for restarting on demand in a healthy state 

    -
  • -
-
    -
  • Automatically registered to restart in restart scenario by Explorer/shell using RestartUwpApp 

  • -
    -
  • -

    Apps can restart on-command asynchronously when healthy/active but do not have the ability to ensure restart in app crash/hang scenarios 

    -
  • -
-
WinUI (Centennial)
    -
  • RegisterApplicationRestart for OS + app update/restart/crash scenarios 

  • -
    -
  • Apps can register with the OS to restart in specific app/OS states, but cannot restart on-command in a healthy state 

  • -
+| App Type | Applicable Restart Mechanism | Gap | +| ------------------------------------------------------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| Win32 (unpackaged), Win32/Centennial (packaged), WinUI (Centennial) | RegisterApplicationRestart for OS + app update/restart/crash scenarios | Apps can register with the OS to restart in specific app/OS states, but cannot restart on-command in a healthy state | ## Existing API Details @@ -163,15 +77,13 @@ There are 2 related Win32 APIs that focus on recovery prior to restart: -Existing API for Win32 Apps +Existing API Details -

HRESULT RegisterApplicationRestart(

-

PCWSTR pwzCommandline,

-

DWORD dwFlags);

+

HRESULT RegisterApplicationRestart(PCWSTR pwzCommandline, DWORD dwFlags);

The pwzCommandline parameter is passed into the new instance as its command-line arguments string. The dwFlags can be 0 or one or more of the (flags) values:

  • @@ -192,21 +104,6 @@ There are 2 related Win32 APIs that focus on recovery prior to restart: HRESULT UnregisterApplicationRestart(); Unregisters the app for restart, where the app had previously called RegisterApplicationRestart. - - - - ---- - - - - - - - @@ -238,28 +135,6 @@ string launchArguments); - - - - - - - -
    Existing API for UWP AppsDetails
    public static IAsyncOperation<AppRestartFailureReason> RequestRestartAsync(
    string launchArguments);
    void RestartUwpApp(const wchar_t* const appUserModelId)Internal-only function in shell/explorer added as of 20H1 allowing UWP apps to be restarted in a minimized state
    public enum AppRestartFailureReason

    Enum which will be used in the new API detailed below to indicate the reason for a failed restart now.

    -
      -
    • -

      0: RestartPending - a restart is already in progress.

      -
    • -
    • -

      1: NotInForeground - an app must be visible and in the foreground when it calls the restart API.

      -
    • -
    • -

      2: InvalidUser - could not restart for the specified user.

      -
    • -
    • -

      3: Other - unspecified failure.

      -
    • -
    class LaunchActivatedEventArg

    Relevant Properties:

      @@ -271,9 +146,9 @@ string launchArguments);
    -### New API Details +## New API Details -#### RequestRestartNow +### RequestRestartNow @@ -285,15 +160,13 @@ string launchArguments); - - +
    • When the app is restarted, LaunchActivatedEventArgs.PreviousExecutionState will have the value Terminated so that the app can distinguish between a resume and a restart.
    -

    Returns a failure reason for why the restart didn’t successfully complete.

    - +

    Returns a failure reason for why the restart didn’t successfully complete (AppRestartFailureReason). +

      +
    • This API does not require for the app to be in foreground, and so AppRestartFailureReason::NotInForeground will never be returned
    • +
    +

    New API  DescriptionPriority
    static AppRestartFailureReason RequestRestartNow(string restartArguments)static AppRestartFailureReason RequestRestartNow(string restartArguments)

    Equivalent to CoreApplication.RequestRestartAsync, except that it is not async.

      -
    • The app must be visible and foreground when it calls this API.
    • If the restart fails, but the user subsequently launches the app manually, the app will launch normally and no restart arguments will be passed.
    • If the app has any in-process background tasks running when it calls this API, those tasks will be cancelled in the normal way. Out-of-process background tasks will not be affected.
    @@ -301,45 +174,64 @@ string launchArguments);
    P1
    -### API Sample Code +When an application calls RequestRestartNow, the mechanism for restart will be as follows: +1. Application calls RequestRestartNow API. +2. The API will CreateProcess with the Agent (a helper EXE in the framework package containing the API) and will then wait for an an acknowledgment (ACK) from the Agent. +3. The Agent will get the executable path of the application and signal an ACK to the API. The Agent will then wait for termination of the application. +4. The API will terminate the application. +5. The Agent will CreateProcess with the application (restarted). -### RequestRestartNow Sample +## Examples and Scenarios ```c# public class App {        // Let's assume this method is run when an app updates assets. -       // The new assets have downloaded and installed, and now the app has to restart immediately +       // The new assets have downloaded and installed, and now the app has to request a restart immediately        protected void updateInstallComplete(){ -           // code here that checks the app update has installed - -           WCHAR buffer\[1024\];  -           AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); - -           switch (result){ -                case AppRestartFailureReason::RestartPending: -                    Telemetry::WriteLine("Restart request successful."); -                    break; -                case AppRestartFailureReason::NotInForeground: -                    wcscpy_s(buffer, L"App must be in the foreground to request restart."); -                    break; -                case AppRestartFailureReason::InvalidUser: -                    wcscpy_s(buffer, L"Cannot restart for this user."); -                    break; -                case AppRestartFailureReason::Other: -                    wcscpy_s(buffer, L"Unknown failure."); -                    break; +           // Checking if the assets have updated successfully and there are no pending updates + if (!CheckForUpdate()){ +            AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); +            switch (result){ +                 case AppRestartFailureReason::RestartPending: + // An example of how to handle this case is updating a progress bar to the user + // indicating immediate restart + UpdateProgressBar(); +                     break; +                 case AppRestartFailureReason::Other: +                     // In this case, a dialog box will appear informing of an error requesting restart + ShowErrorMessage(); +                     break; +            } + } +       }  + + // In this scenario, assume the app encounters an error during initialization. + // The app displays an error dialogue, and after the user clicks OK on the dialog the app must restart immediately. + // This scenario simply displays logging for these use cases + protected void handleInitializationError(){ +  AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); +        switch (result){ +         case AppRestartFailureReason::RestartPending: +             Telemetry::WriteLine("Restart request successful."); +             break; +            case AppRestartFailureReason::Other: +                Telemetry::WriteLine("Failure restarting."); +                break;            } -       }                + } } ``` -## Telemetry +# Telemetry This section explores the telemetry needs for the Restart feature in four dimensions – Usage, Reliability, Performance and Failure @@ -351,7 +243,7 @@ telemetry information: Event Name: **AppRestart** | Metadata | Description | Data type | -|-------------------------|---------------------------------------------------------------------------------------------------|-----------| +| ----------------------- | ------------------------------------------------------------------------------------------------- | --------- | | AppRestartFailureReason | Reason an app restart failed. This will be collected when an app requests a restart now but fails | Enum | | AppName | Name of the app which restarted | String | | AppType | UWP App or Centennial App or Win32 app | String | From 1efb599d3d147c23635954fd2fcaf5c27eed449d Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Fri, 19 Nov 2021 14:01:53 -0800 Subject: [PATCH 10/15] run markdown prettifier --- specs/AppLifecycle/Restart/restartApi.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index 2943e77b88..f95f409386 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -226,7 +226,7 @@ public class App {             case AppRestartFailureReason::Other:                 Telemetry::WriteLine("Failure restarting.");                 break; -           } +     } } } ``` From f49996b7a454487f1d391ef0a1fd2d6042e5efdb Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Fri, 19 Nov 2021 14:25:24 -0800 Subject: [PATCH 11/15] Updating mechanism --- specs/AppLifecycle/Restart/restartApi.markdown | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index f95f409386..89eb3c4e6b 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -186,9 +186,7 @@ string launchArguments); When an application calls RequestRestartNow, the mechanism for restart will be as follows: 1. Application calls RequestRestartNow API. 2. The API will CreateProcess with the Agent (a helper EXE in the framework package containing the API) and will then wait for an an acknowledgment (ACK) from the Agent. -3. The Agent will get the executable path of the application and signal an ACK to the API. The Agent will then wait for termination of the application. -4. The API will terminate the application. -5. The Agent will CreateProcess with the application (restarted). +3. The Agent will get the executable path of the application and signal an ACK to the API. The Agent will then then terminate the application and then CreateProcess with the application (restarted). ## Examples and Scenarios From e6baf128d7091902c23e2d784b848f8c6ee1b98d Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Fri, 19 Nov 2021 15:00:01 -0800 Subject: [PATCH 12/15] Updating formatting for consistency --- .../AppLifecycle/Restart/restartApi.markdown | 75 ++++++++++--------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index 89eb3c4e6b..9753d71d40 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -18,13 +18,13 @@ This spec addresses the **Restart APIs** in the AppLifecycle component. At a high-level, Win32 apps can register with the OS to restart in update/hang/reboot scenarios but cannot restart immediately on-command -with specific arguments/state. This applies to packaged (Centennial) and unpackaged apps. This API will address +with specific arguments/state. This applies to packaged (Desktop Bridge/Centennial) and unpackaged apps. This API will address these gaps and provide the ability for any Win32 app to restart immediately. ## Description The goal of this feature is the new function: **RequestRestartNow**, which will enable any packaged or unpackaged Win32 -app to terminate and restart itself on command, and to provide an arbitrary command-line string for the restarted instance. +app (including Console, WinMain, Windows Forms, WPF and WinUI) to terminate and restart itself on command, and to provide an arbitrary command-line string for the restarted instance. # API @@ -176,7 +176,8 @@ string launchArguments);

Returns a failure reason for why the restart didn’t successfully complete (AppRestartFailureReason).

    -
  • This API does not require for the app to be in foreground, and so AppRestartFailureReason::NotInForeground will never be returned
  • +
  • This API leverages an existing Enum (AppRestartFailureReason), but not all return values are relevant.
  • +
  • This API does not require for the app to be in foreground, and so AppRestartFailureReason::NotInForeground will never be returned

@@ -191,40 +192,46 @@ When an application calls RequestRestartNow, the mechanism for restart will be a ## Examples and Scenarios ```c# -public class App { -       // Let's assume this method is run when an app updates assets. -       // The new assets have downloaded and installed, and now the app has to request a restart immediately -       protected void updateInstallComplete(){ -           // Checking if the assets have updated successfully and there are no pending updates - if (!CheckForUpdate()){ -            AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); -            switch (result){ -                 case AppRestartFailureReason::RestartPending: - // An example of how to handle this case is updating a progress bar to the user - // indicating immediate restart - UpdateProgressBar(); -                     break; -                 case AppRestartFailureReason::Other: -                     // In this case, a dialog box will appear informing of an error requesting restart - ShowErrorMessage(); -                     break; -            } - } -       }  +public class App +{ + // Let's assume this method is run when an app updates assets. + // The new assets have downloaded and installed, and now the app has to request a restart immediately + protected void UpdateInstallComplete() + { + // Checking if the assets have updated successfully and there are no pending updates + if (!CheckForUpdate()) + { + AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); + switch (result) + { + case AppRestartFailureReason::RestartPending: + // An example of how to handle this case is updating a progress bar to the user + // indicating immediate restart + UpdateProgressBar(); + break; + case AppRestartFailureReason::Other: + // In this case, a dialog box will appear informing of an error requesting restart + ShowErrorMessage(); + break; + } + } + }  // In this scenario, assume the app encounters an error during initialization. - // The app displays an error dialogue, and after the user clicks OK on the dialog the app must restart immediately. + // The app displays an error dialog, and after the user clicks OK on the dialog the app must restart immediately. // This scenario simply displays logging for these use cases - protected void handleInitializationError(){ -  AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); -        switch (result){ -         case AppRestartFailureReason::RestartPending: -             Telemetry::WriteLine("Restart request successful."); -             break; -            case AppRestartFailureReason::Other: -                Telemetry::WriteLine("Failure restarting."); -                break; -     } + protected void HandleInitializationError() + { + AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); + switch (result) + { + case AppRestartFailureReason::RestartPending: + Telemetry::WriteLine("Restart request successful."); + break; + case AppRestartFailureReason::Other: + Telemetry::WriteLine("Failure restarting."); + break; + } } } ``` From c7c31991d80601c06ee52e8ec7c5e3929cfe7d28 Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Tue, 30 Nov 2021 00:12:53 -0800 Subject: [PATCH 13/15] Updates to return value description --- .../AppLifecycle/Restart/restartApi.markdown | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index 9753d71d40..dfbfd12ac1 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -174,10 +174,13 @@ string launchArguments);
  • When the app is restarted, LaunchActivatedEventArgs.PreviousExecutionState will have the value Terminated so that the app can distinguish between a resume and a restart.
-

Returns a failure reason for why the restart didn’t successfully complete (AppRestartFailureReason). +

If the request to restart is successful, the application will be restarted immediately. The user does not have to do anything else/handle a return value in any way. + +If the request fails due to a nonfatal reason, a failure reason is returned for why the restart didn’t successfully complete. This method leverages an existing enum (AppRestartFailureReason) which has the following relevant return fields.

    -
  • This API leverages an existing Enum (AppRestartFailureReason), but not all return values are relevant.
  • -
  • This API does not require for the app to be in foreground, and so AppRestartFailureReason::NotInForeground will never be returned
  • +
  • InvalidUser: Could not restart for the specified user.
  • +
  • RestartPending: A restart is already in progress.
  • +
  • Other: Unspecified failure.

@@ -205,9 +208,8 @@ public class App switch (result) { case AppRestartFailureReason::RestartPending: - // An example of how to handle this case is updating a progress bar to the user - // indicating immediate restart - UpdateProgressBar(); + // In this case the restart could not be completed because another restart is pending and we can try to restart again after a period of time + RetryRestartAfterXSeconds(); break; case AppRestartFailureReason::Other: // In this case, a dialog box will appear informing of an error requesting restart @@ -226,7 +228,10 @@ public class App switch (result) { case AppRestartFailureReason::RestartPending: - Telemetry::WriteLine("Restart request successful."); + Telemetry::WriteLine("Another restart is currently pending."); + break; + case AppRestartFailureReason::InvalidUser: + Telemetry::WriteLine("Current user is not signed in or not a valid user."); break; case AppRestartFailureReason::Other: Telemetry::WriteLine("Failure restarting."); From 49d6f8193b9188207da6c27ff189e6288d6e869b Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Mon, 17 Jan 2022 20:23:47 -0800 Subject: [PATCH 14/15] Updates to spec after latest review --- .../AppLifecycle/Restart/restartApi.markdown | 361 ++++++++++-------- 1 file changed, 196 insertions(+), 165 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index dfbfd12ac1..3d8dfe3e96 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -5,30 +5,35 @@ - [Restart API](#restart-api) - [Contents](#contents) - [Background](#background) - - [Description](#description) + - [Purpose](#purpose) - [API](#api) - - [Existing API Summary](#existing-api-summary) + - [Existing API](#existing-api) + - [Summary](#summary) - [Existing API Details](#existing-api-details) + - [Existing API](#existing-api-1) - [New API Details](#new-api-details) - - [RequestRestartNow](#requestrestartnow) - - [Examples and Scenarios](#examples-and-scenarios) -- [Telemetry](#telemetry) + - [New API](#new-api) + - [Description](#description) + - [Mechanism](#mechanism) + - [Examples](#examples) # Background -This spec addresses the **Restart APIs** in the AppLifecycle component. At a high-level, Win32 apps can -register with the OS to restart in update/hang/reboot scenarios but cannot restart immediately on-command -with specific arguments/state. This applies to packaged (Desktop Bridge/Centennial) and unpackaged apps. This API will address +This spec addresses the **Restart APIs** in the AppInstance component. At a high-level, Win32 apps can +register with the OS to restart in update/hang/reboot scenarios but cannot initiate an explicit restart +with specific arguments/state. This applies to packaged (Desktop Bridge) and unpackaged apps. This API will address these gaps and provide the ability for any Win32 app to restart immediately. -## Description +## Purpose -The goal of this feature is the new function: **RequestRestartNow**, which will enable any packaged or unpackaged Win32 -app (including Console, WinMain, Windows Forms, WPF and WinUI) to terminate and restart itself on command, and to provide an arbitrary command-line string for the restarted instance. +The goal of this feature is the new function: **Restart**, which will enable any packaged or unpackaged Win32 +app (including Console, WinMain, Windows Forms, WPFI) to terminate and restart itself on command, and to provide an arbitrary command-line string for the restarted instance. + +This behavior (restarting an app immediately) is not currently available to Win32 applications. This new method will fill the gap for Win32 applications and align with CoreApplication's existing ``CoreApplication.RequestRestartAsync``. # API -## Existing API Summary +## Existing API 1. **Restart-me-now**. CoreApplication exposes the [RequestRestartAsync](https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.core.coreapplication.requestrestartasync?view=winrt-18362) @@ -64,135 +69,177 @@ There are 2 related Win32 APIs that focus on recovery prior to restart: \-- if it doesn't call within the registered ping interval, WER will terminate the process. -| App Type | Applicable Restart Mechanism | Gap | -| ------------------------------------------------------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -| Win32 (unpackaged), Win32/Centennial (packaged), WinUI (Centennial) | RegisterApplicationRestart for OS + app update/restart/crash scenarios | Apps can register with the OS to restart in specific app/OS states, but cannot restart on-command in a healthy state | +### Summary + +For Win32 apps (packaged or unpackaged): +- Applicable restart mechanism: **RegisterApplicationRestart** for OS + app update/restart/crash scenarios +- Gap: Apps can register with the OS to restart in specific app/OS states, but cannot initiate a restart from a healthy state + ## Existing API Details - ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Existing APIDetails

HRESULT RegisterApplicationRestart(PCWSTR pwzCommandline, DWORD dwFlags);

The pwzCommandline parameter is passed into the new instance as its command-line arguments string. The dwFlags can be 0 or one or more of the (flags) values:

-
    -
  • -

    1: RESTART_NO_CRASH - Do not restart the process if it terminates due to an unhandled exception.

    -
  • -
  • -

    2: RESTART_NO_HANG - Do not restart the process if it terminates due to the application not responding.

    -
  • -
  • -

    4: RESTART_NO_PATCH - Do not restart the process if it terminates due to the installation of an OS update.

    -
  • -
  • -

    8: RESTART_NO_REBOOT - Do not restart the process if the computer is restarted as the result of an OS update.

    -
  • -
HRESULT UnregisterApplicationRestart();Unregisters the app for restart, where the app had previously called RegisterApplicationRestart.
public static IAsyncOperation<AppRestartFailureReason> RequestRestartAsync(
-string launchArguments);

Static function in CoreApplication. Requests immediate termination and restart.

-
    -
  • -

    The launchArguments string is passed into the new instance as the Arguments property on LaunchActivatedEventArgs.

    -
  • -
  • -

    Also sets LaunchActivatedEventArgs.PreviousExecutionState to Terminated.

    -
  • -
public enum AppRestartFailureReason
    -
  • -

    0: RestartPending - a restart is already in progress.

    -
  • -
  • -

    1: NotInForeground - an app must be visible and in the foreground when it calls the restart API.

    -
  • -
  • -

    2: InvalidUser - could not restart for the specified user.

    -
  • -
  • -

    3: Other - unspecified failure.

    -
  • -
class LaunchActivatedEventArg

Relevant Properties:

-
    -
  • Arguments: gets the arguments that are passed to the app during its launch activation.

  • -
  • Kind: Gets the reason that this app is being activated. This is of type enum ActivationKind

  • -
-

PreviousExecutionState: Gets the execution state of the app before this activation.

+### Existing API + +```cpp +HRESULT RegisterApplicationRestart(PCWSTR pwzCommandline, DWORD dwFlags) +``` +Registers an app for restart. More details on the [MSDN page](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registerapplicationrestart). + +```cpp +HRESULT UnregisterApplicationRestart() +``` +Unregisters the app for restart, where the app had previously called RegisterApplicationRestart. More details on the [MSDN page](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-unregisterapplicationrestart). + +```cpp +public static IAsyncOperation RequestRestartAsync( +string launchArguments) +``` +Static function in CoreApplication. Requests immediate termination and restart. More details on the [MSDN page](https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.core.coreapplication.requestrestartasync?view=winrt-22000). + +```cpp +public enum AppRestartFailureReason +``` +An existing enum with the following values: +- 0: RestartPending - a restart is already in progress. +- 1: NotInForeground - an app must be visible and in the foreground when it calls the restart API. +- 2: InvalidUser - could not restart for the specified user. +- 3: Other - unspecified failure. + +```cpp +class LaunchActivatedEventArg +``` + +Relevant Properties: +- Arguments: gets the arguments that are passed to the app during its launch activation. +- Kind: Gets the reason that this app is being activated. This is of type enum ActivationKind +- PreviousExecutionState: Gets the execution state of the app before this activation. ## New API Details -### RequestRestartNow - - ----- - - - - - - - - - - - - -
New API Description
static AppRestartFailureReason RequestRestartNow(string restartArguments)

Equivalent to CoreApplication.RequestRestartAsync, except that it is not async. -

    -
  • If the restart fails, but the user subsequently launches the app manually, the app will launch normally and no restart arguments will be passed.
  • -
  • If the app has any in-process background tasks running when it calls this API, those tasks will be cancelled in the normal way. Out-of-process background tasks will not be affected.
  • -
- The restarted instance will be activated with Windows.ApplicationModel.Activation.LaunchActivatedEventArgs.

-
    -
  • When the app is restarted, LaunchActivatedEventArgs.PreviousExecutionState will have the value Terminated so that the app can distinguish between a resume and a restart.
  • -
-

If the request to restart is successful, the application will be restarted immediately. The user does not have to do anything else/handle a return value in any way. +### New API + +```c# +static AppRestartFailureReason Restart(String arguments) +``` + +```c# +namespace Microsoft.Windows.AppLifecycle +{ + enum ExtendedActivationKind + { + Launch = 0, + Search, + ShareTarget, + File, + Protocol, + FileOpenPicker, + FileSavePicker, + CachedFileUpdater, + ContactPicker, + Device, + PrintTaskSettings, + CameraSettings, + RestrictedLaunch, + AppointmentsProvider, + Contact, + LockScreenCall, + VoiceCommand, + LockScreen, + PickerReturned = 1000, + WalletAction, + PickFileContinuation, + PickSaveFileContinuation, + PickFolderContinuation, + WebAuthenticationBrokerContinuation, + WebAccountProvider, + ComponentUI, + ProtocolForResults = 1009, + ToastNotification, + Print3DWorkflow, + DialReceiver, + DevicePairing, + UserDataAccountsProvider, + FilePickerExperience, + LockScreenComponent, + ContactPanel, + PrintWorkflowForegroundTask, + GameUIProvider, + StartupTask, + CommandLineLaunch, + BarcodeScannerProvider, + PrintSupportJobUI, + PrintSupportSettingsUI, + PhoneCallActivation, + VpnForeground, + // NOTE: Values below 5000 are designated for the platform. The above list is kept in sync with + // Windows.ApplicationModel.Activation.ActivationKind. + + Push = 5000, + }; + + runtimeclass AppActivationArguments + { + ExtendedActivationKind Kind { get; }; + IInspectable Data{ get; }; + }; + + runtimeclass AppInstance + { + static AppInstance GetCurrent(); + static Windows.Foundation.Collections.IVector GetInstances(); + static AppInstance FindOrRegisterForKey(String key); + static Windows.ApplicationModel.Core.AppRestartFailureReason Restart(String arguments); + + void UnregisterKey(); + Windows.Foundation.IAsyncAction RedirectActivationToAsync(Microsoft.Windows.AppLifecycle.AppActivationArguments args); + Microsoft.Windows.AppLifecycle.AppActivationArguments GetActivatedEventArgs(); + event Windows.Foundation.EventHandler Activated; + + String Key{ get; }; + Boolean IsCurrent{ get; }; + UInt32 ProcessId{ get; }; + } + + static runtimeclass ActivationRegistrationManager + { + static void RegisterForFileTypeActivation(String[] supportedFileTypes, String logo, + String displayName, String[] supportedVerbs, String exePath); + static void RegisterForProtocolActivation(String scheme, String logo, String displayName, + String exePath); + static void RegisterForStartupActivation(String taskId, String exePath); + + static void UnregisterForFileTypeActivation(String[] fileTypes, String exePath); + static void UnregisterForProtocolActivation(String scheme, String exePath); + static void UnregisterForStartupActivation(String taskId); + }; +} +``` + +### Description + +Equivalent to CoreApplication.RequestRestartAsync, except that it is *not* async. +- If the restart fails, but the user subsequently launches the app manually, the app will launch normally and no restart arguments will be passed. +- If the app has any in-process background tasks running when it calls this API, those tasks will be cancelled in the normal way. Out-of-process background tasks will not be affected. + +The restarted instance will be activated with Windows.ApplicationModel.Activation.LaunchActivatedEventArgs. +- When the app is restarted, LaunchActivatedEventArgs.PreviousExecutionState will have the value Terminated so that the app can distinguish between a resume and a restart. +- The elevation state of the app is also maintained in the new restarted process. + +If the request to restart is successful, the application will be restarted immediately with no return value. The user does not have to do anything else/handle a return value in any way. If the request fails due to a nonfatal reason, a failure reason is returned for why the restart didn’t successfully complete. This method leverages an existing enum (AppRestartFailureReason) which has the following relevant return fields. -

    -
  • InvalidUser: Could not restart for the specified user.
  • -
  • RestartPending: A restart is already in progress.
  • -
  • Other: Unspecified failure.
  • -
-

- -When an application calls RequestRestartNow, the mechanism for restart will be as follows: -1. Application calls RequestRestartNow API. -2. The API will CreateProcess with the Agent (a helper EXE in the framework package containing the API) and will then wait for an an acknowledgment (ACK) from the Agent. -3. The Agent will get the executable path of the application and signal an ACK to the API. The Agent will then then terminate the application and then CreateProcess with the application (restarted). - -## Examples and Scenarios +- InvalidUser: Could not restart for the specified user. +- RestartPending: A restart is already in progress. +- Other: Unspecified failure. + +### Mechanism + +When an application calls Restart, the mechanism for restart will be as follows: +1. Application calls Restart API. +2. The API calls CreateProcess to launch the agent (a helper EXE in the framework package containing the API) +3. The Agent will get the executable path of the application. The Agent will then then terminate the application and then call CreateProcess with the application (restarted). + +### Examples ```c# public class App @@ -204,16 +251,16 @@ public class App // Checking if the assets have updated successfully and there are no pending updates if (!CheckForUpdate()) { - AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); - switch (result) + AppRestartFailureReason reason = AppInstance.Restart("/RestartCalled"); + switch (reason) { - case AppRestartFailureReason::RestartPending: - // In this case the restart could not be completed because another restart is pending and we can try to restart again after a period of time + case AppRestartFailureReason.RestartPending: + // In this case the restart could not be completed because another restart is pending and we can try to restart again after a period of time. RetryRestartAfterXSeconds(); break; - case AppRestartFailureReason::Other: + case AppRestartFailureReason.Other: // In this case, a dialog box will appear informing of an error requesting restart - ShowErrorMessage(); + ShowErrorMessage("Something went wrong. Restart was not successful"); break; } } @@ -223,37 +270,21 @@ public class App // The app displays an error dialog, and after the user clicks OK on the dialog the app must restart immediately. // This scenario simply displays logging for these use cases protected void HandleInitializationError() - { - AppRestartFailureReason result = AppLifecycle::RequestRestartNow("args for new instance"); - switch (result) + { + // Restart in safe mode to avoid whatever made initialization fail + AppRestartFailureReason reason = AppInstance.Restart("/safemode"); + switch (reason) { - case AppRestartFailureReason::RestartPending: - Telemetry::WriteLine("Another restart is currently pending."); + case AppRestartFailureReason.RestartPending: + Telemetry.WriteLine("Another restart is currently pending."); break; - case AppRestartFailureReason::InvalidUser: - Telemetry::WriteLine("Current user is not signed in or not a valid user."); + case AppRestartFailureReason.InvalidUser: + Telemetry.WriteLine("Current user is not signed in or not a valid user."); break; - case AppRestartFailureReason::Other: - Telemetry::WriteLine("Failure restarting."); + case AppRestartFailureReason.Other: + Telemetry.WriteLine("Failure restarting."); break; } } } ``` - -# Telemetry - -This section explores the telemetry needs for the Restart feature in -four dimensions – Usage, Reliability, Performance and Failure -Investigation. The telemetry will include the metadata that are needed -not only for measuring quality but also for helping with investigations -of failures. Following is the event which can be used to capture -telemetry information: - -Event Name: **AppRestart** - -| Metadata | Description | Data type | -| ----------------------- | ------------------------------------------------------------------------------------------------- | --------- | -| AppRestartFailureReason | Reason an app restart failed. This will be collected when an app requests a restart now but fails | Enum | -| AppName | Name of the app which restarted | String | -| AppType | UWP App or Centennial App or Win32 app | String | From a0b8f0b03eb51965fbab8e50ba4d7c45ecb94ef7 Mon Sep 17 00:00:00 2001 From: Hamza Usmani Date: Wed, 19 Jan 2022 02:05:44 -0500 Subject: [PATCH 15/15] Prettified to match md guidelines, fixed nits --- .../AppLifecycle/Restart/restartApi.markdown | 110 +++++++++++------- 1 file changed, 68 insertions(+), 42 deletions(-) diff --git a/specs/AppLifecycle/Restart/restartApi.markdown b/specs/AppLifecycle/Restart/restartApi.markdown index 3d8dfe3e96..cc1d37e623 100644 --- a/specs/AppLifecycle/Restart/restartApi.markdown +++ b/specs/AppLifecycle/Restart/restartApi.markdown @@ -19,17 +19,21 @@ # Background -This spec addresses the **Restart APIs** in the AppInstance component. At a high-level, Win32 apps can -register with the OS to restart in update/hang/reboot scenarios but cannot initiate an explicit restart -with specific arguments/state. This applies to packaged (Desktop Bridge) and unpackaged apps. This API will address -these gaps and provide the ability for any Win32 app to restart immediately. +This spec addresses the **Restart APIs** in the AppInstance component. At a high-level, Win32 apps +can register with the OS to restart in update/hang/reboot scenarios but cannot initiate an explicit +restart with specific arguments/state. This applies to packaged (Desktop Bridge) and unpackaged +apps. This API will address these gaps and provide the ability for any Win32 app to restart +immediately. ## Purpose -The goal of this feature is the new function: **Restart**, which will enable any packaged or unpackaged Win32 -app (including Console, WinMain, Windows Forms, WPFI) to terminate and restart itself on command, and to provide an arbitrary command-line string for the restarted instance. +The goal of this feature is the new function: **Restart**, which will enable any packaged or +unpackaged Win32 app (including Console, WinMain, Windows Forms, WPFI) to terminate and restart +itself on command, and to provide an arbitrary command-line string for the restarted instance. -This behavior (restarting an app immediately) is not currently available to Win32 applications. This new method will fill the gap for Win32 applications and align with CoreApplication's existing ``CoreApplication.RequestRestartAsync``. +This behavior (restarting an app immediately) is not currently available to Win32 applications. This +new method will fill the gap for Win32 applications and align with CoreApplication's existing +``CoreApplication.RequestRestartAsync``. # API @@ -37,15 +41,14 @@ This behavior (restarting an app immediately) is not currently available to Win3 1. **Restart-me-now**. CoreApplication exposes the [RequestRestartAsync](https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.core.coreapplication.requestrestartasync?view=winrt-18362) - method, which allows an app to terminate and restart itself, and to - provide an arbitrary command-line string for the restarted instance. + method, which allows an app to terminate and restart itself, and to provide an arbitrary + command-line string for the restarted instance. 2. **Restart-me-after-termination**. The Win32 API [RegisterApplicationRestart](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registerapplicationrestart) - enables an app to register itself to be restarted after termination, - and to provide an arbitrary command-line string for the restarted - instance. The reasons for termination include app crash or hang, app - update, or system update. There's also a matching + enables an app to register itself to be restarted after termination, and to provide an arbitrary + command-line string for the restarted instance. The reasons for termination include app crash or + hang, app update, or system update. There's also a matching [UnregisterApplicationRestart](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-unregisterapplicationrestart) API. @@ -53,27 +56,26 @@ There are 2 related Win32 APIs that focus on recovery prior to restart: 1. **Let-me-do-something-before-termination**. An app can call [RegisterApplicationRecoveryCallback](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registerapplicationrecoverycallback) - to register a callback for the system to call before terminating the - app. If an application encounters an unhandled exception or becomes - unresponsive, Windows Error Reporting (WER) calls the specified - recovery callback, where the app can save state information. The - system pings the app every n seconds to make sure that it hasn't - hung in its callback. The app can specify the ping interval when it - registers the callback. In its recovery callback, the app can call - RegisterApplicationRestart a second time, to update the - command-line. - -2. **Recovery-in-progress**. While the app is doing work in its - recovery callback, the app must periodically call + to register a callback for the system to call before terminating the app. If an application + encounters an unhandled exception or becomes unresponsive, Windows Error Reporting (WER) calls + the specified recovery callback, where the app can save state information. The system pings the + app every n seconds to make sure that it hasn't hung in its callback. The app can specify the + ping interval when it registers the callback. In its recovery callback, the app can call + RegisterApplicationRestart a second time, to update the command-line. + +2. **Recovery-in-progress**. While the app is doing work in its recovery callback, the app must + periodically call [ApplicationRecoveryInProgress](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-applicationrecoveryinprogress) - \-- if it doesn't call within the registered ping interval, WER will - terminate the process. + \-- if it doesn't call within the registered ping interval, WER will terminate the process. ### Summary For Win32 apps (packaged or unpackaged): -- Applicable restart mechanism: **RegisterApplicationRestart** for OS + app update/restart/crash scenarios -- Gap: Apps can register with the OS to restart in specific app/OS states, but cannot initiate a restart from a healthy state + +- Applicable restart mechanism: **RegisterApplicationRestart** for OS + app update/restart/crash + scenarios +- Gap: Apps can register with the OS to restart in specific app/OS states, but cannot initiate a + restart from a healthy state ## Existing API Details @@ -83,23 +85,29 @@ For Win32 apps (packaged or unpackaged): ```cpp HRESULT RegisterApplicationRestart(PCWSTR pwzCommandline, DWORD dwFlags) ``` -Registers an app for restart. More details on the [MSDN page](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registerapplicationrestart). +Registers an app for restart. More details on the [MSDN +page](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registerapplicationrestart). ```cpp HRESULT UnregisterApplicationRestart() ``` -Unregisters the app for restart, where the app had previously called RegisterApplicationRestart. More details on the [MSDN page](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-unregisterapplicationrestart). +Unregisters the app for restart, where the app had previously called RegisterApplicationRestart. +More details on the [MSDN +page](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-unregisterapplicationrestart). ```cpp public static IAsyncOperation RequestRestartAsync( string launchArguments) ``` -Static function in CoreApplication. Requests immediate termination and restart. More details on the [MSDN page](https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.core.coreapplication.requestrestartasync?view=winrt-22000). +Static function in CoreApplication. Requests immediate termination and restart. More details on the +[MSDN +page](https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.core.coreapplication.requestrestartasync?view=winrt-22000). ```cpp public enum AppRestartFailureReason ``` An existing enum with the following values: + - 0: RestartPending - a restart is already in progress. - 1: NotInForeground - an app must be visible and in the foreground when it calls the restart API. - 2: InvalidUser - could not restart for the specified user. @@ -110,6 +118,7 @@ class LaunchActivatedEventArg ``` Relevant Properties: + - Arguments: gets the arguments that are passed to the app during its launch activation. - Kind: Gets the reason that this app is being activated. This is of type enum ActivationKind - PreviousExecutionState: Gets the execution state of the app before this activation. @@ -188,6 +197,8 @@ namespace Microsoft.Windows.AppLifecycle static AppInstance GetCurrent(); static Windows.Foundation.Collections.IVector GetInstances(); static AppInstance FindOrRegisterForKey(String key); + + // This is the new method exposed by this feature static Windows.ApplicationModel.Core.AppRestartFailureReason Restart(String arguments); void UnregisterKey(); @@ -214,20 +225,31 @@ namespace Microsoft.Windows.AppLifecycle }; } ``` +There is no relevant RtCop output for this feature. ### Description Equivalent to CoreApplication.RequestRestartAsync, except that it is *not* async. -- If the restart fails, but the user subsequently launches the app manually, the app will launch normally and no restart arguments will be passed. -- If the app has any in-process background tasks running when it calls this API, those tasks will be cancelled in the normal way. Out-of-process background tasks will not be affected. -The restarted instance will be activated with Windows.ApplicationModel.Activation.LaunchActivatedEventArgs. -- When the app is restarted, LaunchActivatedEventArgs.PreviousExecutionState will have the value Terminated so that the app can distinguish between a resume and a restart. +- If the restart fails, but the user subsequently launches the app manually, the app will launch + normally and no restart arguments will be passed. +- If the app has any in-process background tasks running when it calls this API, those tasks will be + cancelled in the normal way. Out-of-process background tasks will not be affected. + +The restarted instance will be activated with +Windows.ApplicationModel.Activation.LaunchActivatedEventArgs. + +- When the app is restarted, LaunchActivatedEventArgs.PreviousExecutionState will have the value + Terminated so that the app can distinguish between a resume and a restart. - The elevation state of the app is also maintained in the new restarted process. -If the request to restart is successful, the application will be restarted immediately with no return value. The user does not have to do anything else/handle a return value in any way. +If the request to restart is successful, the application will be restarted immediately with no +return value. The user does not have to do anything else/handle a return value in any way. + +If the request fails due to a nonfatal reason, a failure reason is returned for why the restart +didn’t successfully complete. This method leverages an existing enum (AppRestartFailureReason) which +has the following relevant return fields. -If the request fails due to a nonfatal reason, a failure reason is returned for why the restart didn’t successfully complete. This method leverages an existing enum (AppRestartFailureReason) which has the following relevant return fields. - InvalidUser: Could not restart for the specified user. - RestartPending: A restart is already in progress. - Other: Unspecified failure. @@ -235,9 +257,12 @@ If the request fails due to a nonfatal reason, a failure reason is returned for ### Mechanism When an application calls Restart, the mechanism for restart will be as follows: + 1. Application calls Restart API. -2. The API calls CreateProcess to launch the agent (a helper EXE in the framework package containing the API) -3. The Agent will get the executable path of the application. The Agent will then then terminate the application and then call CreateProcess with the application (restarted). +2. The API calls CreateProcess to launch the agent (a helper EXE in the framework package containing + the API) +3. The Agent will get the executable path of the application. The Agent will then then terminate the + application and then call CreateProcess with the application (restarted). ### Examples @@ -255,7 +280,8 @@ public class App switch (reason) { case AppRestartFailureReason.RestartPending: - // In this case the restart could not be completed because another restart is pending and we can try to restart again after a period of time. + // In this case the restart could not be completed because another restart is + // pending and we can try to restart again after a period of time. RetryRestartAfterXSeconds(); break; case AppRestartFailureReason.Other: @@ -267,7 +293,7 @@ public class App }  // In this scenario, assume the app encounters an error during initialization. - // The app displays an error dialog, and after the user clicks OK on the dialog the app must restart immediately. + // The app displays an error dialog, and after the user clicks OK on the dialog the app must restart. // This scenario simply displays logging for these use cases protected void HandleInitializationError() {