Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App Lifecycle #111

Closed
andreww-msft opened this issue Jul 14, 2020 · 57 comments · Fixed by #268 or #772
Closed

App Lifecycle #111

andreww-msft opened this issue Jul 14, 2020 · 57 comments · Fixed by #268 or #772
Assignees
Labels
area-Lifecycle area-UWP Support for UWP apps area-Win32 Support for Win32 packaged and non-packaged apps feature proposal
Milestone

Comments

@andreww-msft
Copy link
Contributor

andreww-msft commented Jul 14, 2020

Summary Status

Customer / job-to-be-done: App developers using WPF, WinForms, or Win32 C++ need to register for certain activation types like file associations and startup activation, need to selectively single-instance their apps, and need to use power states to selectively suspend their apps.

Problem: Non-packaged apps use a different set of APIs to achieve all of the above, and they also don't have access to power state notifications

How does our solution make things easier? All types of apps will benefit from the same single API regardless of app type, apps can now listen to power states, and WIn32 apps have a built-in easy way to single instance.

✅ Problem validation
❌ Docs
🔄 Dev spec
❌ Solution validation
❌ Implementation
❌ Samples

Summary

Provide a core set of functionality related to app activation and lifecycle. The initial release focuses on the following 4 main feature areas:

  1. Activation.
  2. Selective Multi-instancing.
  3. Restart and Recovery.
  4. Power/State Notifications.

Rationale

  • Enable all apps to register for the core activation contracts, consistently in the same way.
  • Enable all apps to use platform support for single-instancing, or selective multi-instancing.
  • Enable all apps to request immediate restart, or to opt in to recovery/restart in the event of app failure or system reboot.
  • Enable all apps to get power/battery/user/system-state change notifications so that they can be better power/battery citizens.

This aligns with Project Reunion's roadmap:

  • Enable all applications (packaged and not-packaged) to use the same mechanisms for managing app activation and lifecycle.

Scope

Capability Priority
This proposal will allow developers to use the same mechanism to register for different activation kinds regardless of app technology (classic Win32, Windows Forms, WPF, UWP or WinUI). Must
This proposal will allow developers to use the same mechanism to get rich activation event arguments regardless of app technology. Must
This proposal will allow users to activate any app by double-clicking it in file explorer, or typing in a path in a command window. Must
This proposal will allow developers to use a consistent mechanism to single-instance or multi-instance their apps, based on app-defined logic. Must
This proposal will allow developers to use a consistent mechanism to take part in app and system restart and recovery. Must
This proposal will allow developers to use a consistent mechanism to get power and system state notifications. Must
This proposal will allow apps to better tune their operations to improve power/battery usage. Must
This proposal will allow developers to take part in system resource management Could
This proposal will allow developers to take part in app suspend/resume behavior Could

Important Notes

  • This is not "yet another app framework" -- rather it is an easier way for all app types to use features in the platform consistently.
  • In some cases, we'll be providing parallels to existing APIs -- and the benefit is that converging traditional Win32 APIs with modern WinRT APIs into one component allows all app types to use the same APIs (instead of one app type using Win32 APIs, and another app type using WinRT APIs) consistently. This will also make it easier for app developers to move from one app type to another as appropriate -- they can continue to use the same AppLifecycle component regardless.
  • We will not wrap existing public APIs as this would result in a performance penalty -- rather, we will provide parallel APIs that use the same underlying primitives.
  • Whatever we build, we strive to make it as easy as possible for app developers to use. We aim not to introduce new hurdles, new development paradigms, or new architectural concepts that would cause friction. We also won't make the developer change what they're doing just because we version the Reunion component. As we add improvements/new features over time, these should "just work" seamlessly.

Rich Activation Behaviors

The activation part of the AppLifecycle component is focused on the
following 4 functional requirements:

  • Enable activation of any app (including Desktop Bridge and UWP) via CreateProcess on its path.
  • Enable all apps to register for any of the most common activation kinds.
  • Provide a GetActivatedEventArgs API that all apps can use to get any of the supported rich arguments for any of the supported activation kinds.

CreateProcess activation

In the Win32 world, it is normal to activate an app by calling CreateProcess (or ShellExecute), specifying the filesystem path to the executable file. When the user double-clicks an executable file in File Explorer, this uses that same mechanism. When the user types in an executable file name into a command window, the same thing happens. In contrast, up until now, when a UWP or Desktop Bridge app is activated, this is done via the app's Application User Model ID (AUMID). For example, when an app calls Launcher.LaunchUriAsync, it specifies the target AUMID -- or a file or protocol, which causes the platform to look up registered AUMIDs in its State Repository database, before activating
the app.

The Windows a-la-carte features introduced in 2004 include the ability to activate an app via CreateProcess on its path, as well as by the UWP AUMID lookup. The gap here is that the CreateProcess mechanism only works for Win32 apps -- as part of Reunion, we will bring this to packaged (Desktop Bridge and UWP) apps also.

With this, you will be able to CreateProcess a UWP app by specifying the path to its executable, or navigate to the filesystem location and double-click it there.

Activation kinds

UWP supports ~40 different activation kinds. Traditional Win32 apps have a much smaller set available -- the most common being file-type associations and protocol handling. In UWP both of these are formalized into specific activation contracts (ActivationKind.File and ActivationKind.Protocol) and when the app is activated in this way, the platform passes in rich FileActivatedEventArgs or ProtocolActivatedEventArgs. The same applies for command-line activation, activation at user login (startup activation), and so on.

Of the many different kinds of activation that UWP supports, 6 of the most commonly-used kinds are also supported for Desktop Bridge apps, and almost the same set is supported for Windows a-la-carte apps. We will support this core set of activation kinds for unpackaged Win32 apps also, plus command-line and restart activation. So the initial list is as follows:

  • Launch
  • File
  • Protocol
  • StartupTask
  • ToastNotification
  • ShareTarget
  • CommandLine
  • Restart

How should we ask developers to specify their registrations for the various activation kinds? For the activation kinds that are supported in Win32 -- such as file and protocol -- apps commonly write registry keys. Conversely, UWP apps write morally equivalent extension entries in their regular MSIX manifest.

Apps that write regkeys on install sometimes don't clean them up on uninstall, and this is a primary source of winrot. This is one of the main benefits of MSIX. Therefore, the proposal is to encourage app developers to specify their activation registrations in an XML manifest rather than in the registry.

An additional advantage of the manifest approach is that it also provides an easy way for the app to get identity. The proposal is that we ask an app to craft some subset of an MSIX manifest -- sufficient for the activation extension registrations, plus identity. We will not require that the app is MSIX-packaged, merely that they have a simple manifest. While this will be a subset of the full MSIX manifest, it must use the same schemas. The platform can then use the same Deployment Extension Handlers (DEHs) on deployment to register these extensions.

Activation and ActivatedEventArgs

Traditional Win32 apps expect to get their arguments passed into WinMain in the form of a string array. Windows Forms apps expect to call Environment.GetCommandLineArgs to return a string array. ulti-instanced UWP and Desktop Bridge apps can call the AppInstance.GetActivatedEventArgs API to return strongly-typed objects for each activation kind. We will provide a converged GetActivatedEventArgs which will get all args, regardless of activation kind -- including both traditional command-line activation and also the richer UWP activation objects. This will be available to all apps.

Activation broker

Two of the proposed activation kinds present particular problems: ToastNotification and ShareTarget. Both of these will likely require some additional component at runtime to act as a broker between the source and target of the activation.

The a-la-carte model has paved the way for apps of all kinds to get a system-recognized identity. This then provides several benefits when using modern features -- including the activation kinds under consideration for the undocked AppLifecycle component. We would like to use the a-la-carte model for undocked activation. However, there are a few issues:

  • The a-la-carte implementation is unfortunately very tightly coupled with the OS and the app platform, and it is infeasible to undock it in the timeframe of Reunion v1.
  • The model is only available from OS version 2004, but there is a desire for the undocked AppLifecycle functionality to be available down to OS version 1809.
  • For the same reasons that it is infeasible to undock a-la-carte, it is also infeasible to service the OS down to 1809 to include a-la-carte.
  • For ShareTarget specifically, the model uses a small MSIX broker which must be authored for each app. From 2004, ShareTarget can be achieved with just the manifest registration alone, no broker.

Identity

Both UWP and Desktop Bridge apps have an identity that is registered on the platform, and on which multiple APIs in the platform rely. Unpackaged Win32 apps do not have such an identity, and therefore cannot use any of the APIs that require identity.

In the Windows a-la-carte model, the app creates an XML manifest specifying its identity, and registers this with the system during install (or at runtime) via new PackageManager APIs.

There is an initiative in the Cobalt timeframe to enable the Store to serve up unpackaged Win32 apps in addition to UWP and Desktop Bridge apps. This is part of a general strategy of de-fragmenting the user experience of apps. Right now, there are several places where packaged apps are treated differently from unpackaged apps. A user experience example is the Apps & features page, where the options are differentiated. A more critical example is in the API surface where many WinRT APIs require the caller to have identity.

Crucially, some WinRT APIs behave differently depending on whether or not the caller has identity. Given that even unpackaged Win32 apps are already using WinRT APIs, we cannot apply identity unless the app specifically registers for identity. Instead, if an app wants to call an API, we should simply document whether or not that API requires identity, and guide the app developer to creating the appropriate manifest if they need it.

Single/Multi-Instancing

In the Win32 world, apps are multi-instance by default. That is, if the user launches Notepad 3 times in a row, they get 3 separate instances of the app. Conversely, in the UWP world, apps are single-instance by default: if the user launches Maps times in a row, the first request causes the Maps app to launch, and the second and subsequent requests cause the platform to make another activation call into the first (and only) instance.

Since Windows OS version 1803, a UWP app can opt in to multi-instancing via a manifest declaration. This feature also includes APIs to allow an app to declare itself to be multi-instanced, and yet to choose dynamically for each instance that is activated whether in fact it wants to redirect that activation to an existing instance instead. In this way, the app has the freedom to choose among several options:

  • constrain itself to a single instance
  • constrain itself to an app-defined finite set of instances
  • allow for an open-ended set of multiple instances.

Win32 apps have existing mechanisms (most commonly, named mutexes and named pipes) which they can use to achieve single-instancing in this context. There's also a Visual Basic Application Model which Windows Forms apps (whether written in Visual Basic or not) can use for single-instancing. The undocked AppLifecycle component will include a consistent, platform-supported API for selective
multi/single-instancing. This updates the UWP mechanism and enables it for use by Desktop Bridge and unpackaged Win32 apps.

The specific multi-instance redirection APIs that we will provide for all apps are all based on the existing WinRT
AppInstance class. The proposal is to expose equivalents to almost all AppInstance methods and properties from the new AppLifecycle class.

The existing APIs allow an app to intercept each activation, find any other running instances, and choose which instance to handle the new activation (either the current instance, or any other). The app doesn't control the activation event args -- these are simply directed to the chosen instance. In the Win32 world, apps have the opportunity to intercept the args, and therefore have the opportunity to modify/suppress/replace these args before forwarding them on. So, we propose to enhance the existing WinRT APIs to allow each activation to pass in additional payload to the target instance (at a lower priority, possibly deferred to a later release). This payload is in addition to the ActivatedEventArgs that the system originally passed in, and which the system will pass on to the target activated instance.

The multi-instancing part of the AppLifecycle component is focused on the following functional requirements:

  • Provide an undocked implementation of the existing AppInstance multi-instance redirection APIs so they are also usable by Desktop Bridge and unpackaged Win32 apps.
  • Enhance the multi-instance APIs to enable apps to intercept the activation args and manipulate them in any way they require: including modifying, suppressing or replacing them.
  • Provide an Activated event on AppLifecycle, specifically so that apps that are using multi/single-instancing can handle being the target of a redirection.

App Restart and Recovery

The CoreApplication WinRT class exposes the RequestRestartAsync method, which allows a UWP app to terminate and restart itself immediately, on request, and to provide an arbitrary command-line string for the restarted instance.

A related API exists in the Win32 world: RegisterApplicationRestart
and the matching UnregisterApplicationRestart API. This is intended for an app to register itself to be restarted if it was running when a system update occurs, or if it crashed or hung. This behavior is currently not available to UWP apps.

The use-cases for these 2 APIs are different, but related enough that it makes sense to offer both from the same place in the undocked
AppLifecycle.

Related to RegisterApplicationRestart, there are 2 further Win32 APIs that enable an app to save state or perform other clean-up operations prior to termination. As part of this recovery, the app can choose to update the command-line to be used when the app is restarted:

  • Let-me-save-state-before-termination. An app can call
    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.

  • Recovery-in-progress. While the app is doing work in its recovery callback, the app must periodically call
    ApplicationRecoveryInProgress
    -- if it doesn't call within the registered ping interval, WER will terminate the process.

These APIs will also be included in the Converged AppLifecycle component.

  • Undock RequestRestartAsync, to enable any app to terminate and restart itself, and to provide an arbitrary command-line string for the restarted instance.
  • For consistency with other activation scenarios, provide a new Restart ActivationKind and RestartActivatedEventArgs. This will encapsulate the app-supplied command-line payload. For old apps this is surfaced in the LaunchActivatedEventArgs. For new apps, they can use the new RestartActivatedEventArgs.
  • Alongside the RequestRestartAsync API, expose an additional RegisterApplicationRestart, which mirrors the Win32 app to allow an app to register itself to be restarted if it was running when a system update occurs. Also provide an associated UnregisterApplicationRestart.
  • AppLifecycle should include functionality equivalent to RegisterApplicationRecoveryCallback and ApplicationRecoveryInProgress.

Improved Power Usage

For UWP apps, a major factor in improving device power usage and battery life is that the platform can suspend an app if the user is not actively engaged in it. UWP apps are familiar with the suspend/resume aspects of app lifecycle. That said, the suspend/resume behavior is not without problems. Power usage and battery life is an important factor for users, and there are 2 main aspects in this spec:

  1. System state changes: notifications that the system sends to an app when interesting battery/power changes occur (eg, switching
    between AC and DC, critical power level changes, critical battery level changes, etc). In addition to power state, we'll send
    notifications for other interesting events such as user inactive, screen off, and so on -- since these can also be used by an app to
    better tune its work. All of these are simply informative notifications: the app can do whatever it likes with the information.

  2. Suspend/resume or resource throttling: for UWP apps, the platform has heuristics to determine when to suspend or resume an
    app, including whether the main window is minimized, whether certain critical background triggers are fired, and so on. The pattern here is more than a simple notification, specifically:
    a. There is a notification that suspension is imminent.
    b. There is an opportunity for the app to defer suspension for a finite period so that it can complete some arbitrary work. After
    this period, the app will be suspended.
    c. There is a notification that the app is being resumed from suspension.

Note: it will likely be difficult for many Win32 apps to adopt UWP-style suspend/resume, but more apps might want to take part in resource throttling, and all apps could listen for interesting power/system-state notifications if they wish.

The proposed features for this part of the AppLifecycle component are as follows:

  • A new undocked API that provides equivalent functionality to Windows.System.Power.PowerManager.
  • Additional events in the PowerManager type, based off events used in PowerSettingRegisterNotification.
  • A new API for suspend/resume/throttle, plus a ResourceUsageChange notification. Merging with the RegisterForReducedUsage API -- that is, an API where the app can opt in and say "you can throttle me", or "you can suspend me".
  • Apps & features "good resource citizen" badge.

Power state changes

There are several existing APIs which apps can use to detect changes in battery/power status, in order to participate in improved battery life.

These APIs cover most if not all of the battery/power state change scenarios that apps would care about -- but there's no single API that is consumable by all app types. There's also no single API that's undocked from the OS. The proposal is to incorporate a clone of the W.S.P.PowerManager API in the undocked AppLifecycle component, and augment it with additional notifications based on the Win32
PowerSettingRegisterNotification API.

Suspend/resume and throttling

In UWP-style suspend/resume behavior, the constraints of the UWP app-container allow the system to suspend the app safely. Conversely,
traditional Win32 apps can't always reliably be suspended because they might be using system-wide resources (file handles, named pipes, etc), so suspending the app would lock these resources, and the platform has no mechanism to deal with this scenario. Such apps would not opt in to UWP suspend/resume.

What does suspend/resume actually mean? When an app is suspended it remains in memory, but its threads are not scheduled to run -- this
allows the system to restore it quickly when needed.

When does an app get suspended? In the UWP world, the most obvious manifestation is when the app's main window is minimized this is usually (but not always) following by the app getting suspended. The system can use its own heuristics and policies to decide when is a good time to suspend an app, including (but not limited to) when the app has no foreground, un-obscured or un-minimized windows.

What should an app do in its suspending handler? The key reason an app wants to know when it is about to be suspended is that there's no
guarantee that the system will ever resume it, and might terminate the app at any time while it is suspended -- therefore the suspending event is the app's opportunity to save state such that it can pick up again seamlessly when it is next activated. If a suspended UWP app is holding a file open, the system can terminate the app if necessary to release the lock.

Even some UWP apps have found that the suspend/resume behavior can be difficult to work with. One mitigation that the platform offers is the option to take a SuspendingDeferral
in the Suspending event handler. The app is given a SuspendingEventArgs which includes a method to request a deferral. On top of that, beyond a simple deferral, an app can request an ExtendedExecution -- including potentially an indefinite extension (although this is rarely granted, by policy).

Given the difficulties that UWP apps experience with suspend/resume, and the added complexities of Win32 apps which perform operations outside the control or awareness of an app-container context, it is most likely that very few complex Win32 apps would be able to use UWP-style suspend/resume, and a trivially simply Win32 app is unlikely to be a significant resource-hog. However, there are likely more apps that could take part in some form of throttling -- and especially if the throttling is under app control. Exactly how this throttling might work is TBD.

Recognition for good citizens

Apps will want to opt in to lifecycle and resource management because they want to be good citizens. To further incentivize apps, we should also surface this to the user in some way. One approach would be to add a "battery-aware" or "good resource citizen" badge in the Apps & features list in Settings, similar to the badge used in the traditional TaskManager (although this badge is conferred simply whenever the app is suspended).

We could apply the badge for any app that opts in to throttling and/or suspension. Note: simply registering for power state change
notifications is not enough to qualify: the app could respond to low power/battery states by doing less work -- or it could respond by doing more work.

It has been pointed out that neither TaskManager nor the Apps & Features page in Settings are highly visible, especially to a non-technical user. Two other options present for consideration:

  • Show a notification for excessive usage -- more of a stick than a carrot.
  • Put the good-citizen badge on the app's icon in the taskbar and/or in the app's window chrome (if it has any).

Final implementation TBD.

Open Questions

  • Should we include the broker model in v1 of Reunion so that apps can target down to 1809, or do we defer support for ShareTarget
    -- and avoid the need for a broker -- until a later release when apps might be OK with targeting only down to 2004?
  • Can we provide a way for unpackaged apps to have identity without undocking the whole of Windows a-la-carte?
  • Is there any suspend/resume or resource (CPU, network) throttling behavior that would actually be useful for a traditional Win32 app to take part in, or is this just too difficult to work with?
@mdtauk
Copy link

mdtauk commented Jul 15, 2020

Would this be a good place to consider how the app behaves when an App Update is installed from the store, to prevent apps restarting in the middle of the user working on an unsaved document?

Also could this allow WinUI Desktop apps to opt-in to the UWP Permissions system?

@jesbis
Copy link
Member

jesbis commented Jul 15, 2020

Should #9 be closed in favor of this?

@ptorr-msft
Copy link
Contributor

@mdtauk permissions are mostly relevant only within the context of an AppContainer, so this proposal alone won't do anything to enable Win32 apps to have the same experience as UWP apps. We're interested in doing more here but it should be a separate issue.

@dremin
Copy link

dremin commented Jul 17, 2020

As a part of these changes, it would be great if UWP app activation no longer relied upon explorer.exe running!

@jonwis
Copy link
Member

jonwis commented Jul 17, 2020

@dremin - we're definitely aware of that! Is there a specific use case you're looking for that it'd enable for you?

@jonwis jonwis added area-UWP Support for UWP apps area-Win32 Support for Win32 packaged and non-packaged apps labels Jul 17, 2020
@dremin
Copy link

dremin commented Jul 17, 2020

@jonwis For me, that would be fantastic to allow for alternate shells (such as one I maintain) to continue to exist in the future. As more functionality moves into UWP applications, alternate shells have unfortunately become far less feasible (and running an alternate shell atop Explorer brings its own set of issues).

@riverar
Copy link
Contributor

riverar commented Jul 19, 2020

Feedback

  1. The proposal uses some internal jargon that requires definition:
  • Windows a-la-carte
  • Cobalt timeframe
  1. The proposal has spacing issues that need correction and would greatly improve readability.

Questions

  1. With regards to CreateProcess activation of modern apps, the proposal suggests "you will be able to CreateProcess a UWP app by [...navigating to the] filesystem location and double-click". With most modern apps being delivered via the Microsoft Store, this puts apps in an un-browsable location on disk. How will users double-click these app executables? What if the package manifest has multiple applications specified?

  2. With regards to activation, the proposal suggests that apps should have a "simple manifest", perhaps "a subset of the full MSIX manifest". The proposal, however, leaves the location of this manifest open-ended. Will this manifest sit side-by-side with the executable? Can it be embedded, a la fusion manifests?

Answers to open questions

Should we include the broker model in v1 of Reunion so that apps can target down to 1809, or do we defer support for ShareTarget -- and avoid the need for a broker -- until a later release when apps might be OK with targeting only down to 2004?

Target 1809. 1809 EOL is May 11, 2021. Users will not be able to min-target 2004 until ~May 10, 2022.

Can we provide a way for unpackaged apps to have identity without undocking the whole of Windows a-la-carte?

It's not clear what "undocking the whole of Windows a-la-carte" refers to. But I suggest re-using the appxmanifest approach as outlined in Activation kinds above. Beware of certain areas in Windows that perform caller identity checking as a security mechanism.

Is there any suspend/resume or resource (CPU, network) throttling behavior that would actually be useful for a traditional Win32 app to take part in, or is this just too difficult to work with?

Would be great if desktop applications could opt-into behaviors that realized connection costs/limits/metering (e.g. a la Windows.Networking.Connectivity.ConnectionCost).

@riverar
Copy link
Contributor

riverar commented Jul 19, 2020

@jonwis Sometimes I have the need to kill File Explorer via Task Manager. Or update an app that restarts the shell to update a shell extension. When I do these things, app modern apps often terminate.

@weltkante
Copy link

weltkante commented Jul 19, 2020

@riverar FYI clean shutdown of explorer is possible when its not hung, in the shutdown dialog (e.g. click the taskbar and Alt+F4) hold ctrl+alt+shift and press cancel. This is documented for shell extension authors to test their extensions without rebooting.

(for anyone else coming across this in the future: to restart it run explorer from task manager)

Never tested this before so I don't know if its consistent across versions but UWP apps seem to stay open and stop rendering when you close explorer this way, when you restart explorer they all seem to close. In general very poor behavior.

@riverar
Copy link
Contributor

riverar commented Jul 19, 2020

@weltkante TIP: Ctrl+Shift then right-clicking Taskbar also offers a Exit Explorer option.

Where is this officially documented? It doesn't work properly on Windows 10 Version 2004. My Mail app terminated. Further, starting a new File Explorer process resulted in a shell load/crash loop that I had to resolve manually.

@weltkante
Copy link

weltkante commented Jul 19, 2020

Thanks, wasn't aware.

Where is this officially documented?

That was years ago when I had to write an explorer extension, seems the docs are updated to use the method you mentioned, but they still list the other method as well, even if not recommending it. [edit] here is the version in the new doc system

I mostly just chime in when someone speaks of "killing explorer" because clean shutdown is often preferrable to killing processes. Will mention your method in the future since it seems preferable.

@riverar
Copy link
Contributor

riverar commented Jul 22, 2020

@stevewri I see the "needs-triage" tag was removed. Can you provide more details as to what that means for proposals as such? I have unanswered questions above.

@stevewri
Copy link
Contributor

stevewri commented Jul 22, 2020 via email

@lukeblevins
Copy link

@andreww-msft Reading this proposal made me think about Microsoft Edge's use of sparse MSIX to register PWAs/better integrate with Windows. (Currently behind a flag)

When you say any "app technology", are you referring to scenarios like this? In other words, is it possible for sparse MSIX packages registered by Edge to take advantage of the WinRT app lifecycle improvements?

@VagueGit
Copy link

VagueGit commented Sep 2, 2020

Would it be possible for an app to declare, as a UWP app declares capabilities, it's need to remain open until the user shuts it down? This is important for business apps. I know most of these currently are Win32/Web, but moving forward this capability should be available I think.

@ptorr-msft
Copy link
Contributor

Hi @VagueGit, can you be more specific? Apps can already use confirmAppClose to implement "Are you sure you want to exit?" style dialogs, and extendedExecution on Desktop to keep running when minimized. Is there another scenario you're thinking of?

@VagueGit
Copy link

VagueGit commented Sep 3, 2020

@ptorr-msft Currently we have to deal with UWP apps being suspended and request an extendedExecution, but this might be denied. It would be nice not to have to deal with it at all.

If the app could declare on install that it doesn't want Windows to suspend it and give the user the option to accept that, then the issue goes away. We have both UWP and Win32 versions of our business app and our customers are used to leaving the app open all day.

@ptorr-msft
Copy link
Contributor

Thanks for the extra info. I agree it's a useful feature to add (whether it's a manifest opt-in or something else that is easier to manage than "sessions").

In the meantime, as long as your users are on Desktop and not running on battery, the Extended Execution should run forever. If they are running on battery power, there is a setting they can use to still enable the app to run forever (see Run with Extended Execution)

@andreww-msft
Copy link
Contributor Author

For unpackaged applications it would seem that the intent is for the application (or installer) to be responsible for registering and unregistering. The question then is, what happens if an unpackaged application doesn't unregister - for example, if the user simply deletes the application folder, or moves it to a different location? Is there a mechanism where the cleanup (ie unregistering) can be automated?

Well, that is after all one of the benefits of MSIX packaging and deployment, and an unpackaged app misses out on those benefits. For the platform to be able to fully track unpackaged app uninstall/move/delete would require significant infrastructure that would probably parallel the MSIX infrastructure.

@andreww-msft
Copy link
Contributor Author

I beg the team to please consider my proposal (#126) (and possible future extensions) when creating the design of the manifest for this feature. My proposed changes would immensely benefit from a well-thought out manifest container. Thanks!

Yes, thanks Rafael, #126 is under consideration.

@andreww-msft
Copy link
Contributor Author

Many single instance desktop apps today just either terminate when a new instance is created or show an message box that an instance is already running. Even more, there's a difference between multiple windows in a single instance versus multiple instances. UWP has the concept of the MainView which is created by the OS however since Win32 desktop apps create their own window, it should be handled in the framework level and not the app model level to switch to the right window when a new instance is created

Different apps have different requirements here. We want to be very careful not to force all apps into one path. So instead we provide tools where each app can choose how it wants to behave - and in fact, can make this choice dynamically. This leaves control firmly in the hands of the app itself.

@DrusTheAxe
Copy link
Member

@nickrandolph For unpackaged applications it would seem that the intent is for the application (or installer) to be responsible for registering and unregistering

Yes - as they already are. If you're an MSIX package then your "installer" is Windows (and more specifically, the MSIX deployment pipeline in windows). If you're not an MSIX package then you have an install model (run foosetup.exe or foo.msi, unzip foo.zip, even XCOPY has an install model -- copy foo.exe(+friends)). You can use Project Reunion to supplement your app. Like many components and frameworks, Project Reunion has 'install' needs to 'register' appropriately with Windows (and uninstall/deregister on the flip side).

what happens if an unpackaged application doesn't unregister
Same thing that happens with any other component/framework that's installed and not uninstalled. Ideally it's inert (just using some disk space) but YMMV, depending on the framework.

for example, if the user simply deletes the application folder
If ProjectReunion is installed via MSIX framework packages then its files don't live with the application, they live where the package is managed by Windows, e.g. C:\ProgramFiles\WindowsApps\Microsoft.ProjectReunion.0.5_0.5.0.0_x86__1234567890abc, and since it's managed by Windows it's possible to cleanly remove it (worst case, via powershell -c Get-AppxPackage *reunion*|Remove-AppxPackage).

Of course that assumes the app that installed ProjectReunion is the only one using it. That's unlikely (especially over time). You wouldn't want to remove ProjectReunion if any app on the system needs it.

OTOH if an in-app deployment model is used then any registrations and the app's directory is deleted (or at least Project Reunion's files) then whatever's wired up won't be found if/when Windows tries to access it. Impacts depend on the nature of the registration and can range from nothing (inert, not used) to error dialogs ("I need to run X but can't find it"), broken functionality or other negative user experiences.

or moves it to a different location?
Any registrations needing those files would result in the same experience as if you deleted them. Unless you tell Windows "these files? they're over there now" it's the same broken experiences.

Is there a mechanism where the cleanup (ie unregistering) can be automated?
Ultimately PackageManager.RemovePackageAsync() is the key to removing an MSIX package. If it can be removed - some can't, for varying reasons. Some packages can't be uninstalled (e.g. Settings) as it would break Windows. Framework packages can't be removed if there's any package dependent on them (again, ripping out FoooFramework.msix would break Bar if BarMain.msix depends on it).

Generally MSIX packages can be uninstalled (if it wouldn't break things). Some people have asked Project Reunion to not be uninstallable, as they view it as critical infrastructure where the cons of being uninstallable (causing problems and support headaches) outweighs the value of being uninstallable. Project Reunion 0.5 is uninstallable (if no one's dependent on it). We are of course interested in developers needs and desires so the feedback is being considered (as is all input).

Good discussion but we're drifting off the App Lifecycle topic. If there's additional questions or issues we should discuss them under new Issues or Discussions more focused on the matter(s).

@nickrandolph
Copy link

@DrusTheAxe in the case on in-app deployment, I see the lack of automated cleanup to be a nasty side effect. I get that the whole point of having installers (and ideally MSIX) it to provide for cleanup but if we're providing a mechanism for apps to register (for the in-app deployment scenario), can't we provide a mechanism where cleanup can be done automatically if the app or folder is deleted, or moved. I guess this is something that the community could provide......

@DrusTheAxe
Copy link
Member

@nickrandolph can't we provide a mechanism where cleanup can be done automatically if the app or folder is deleted, or moved

Yes, I think we can. In particular I'm thinking of the LifetimeKind + LifetimeArtifact model like in MddTryCreatePackageDependency.

Ideally we'd want LifetimeKind + LifetimeArtifact parameters on the deployment APIs next to ExternalLocation, so you could specify "here's my stuff AND automagically remove me if this thing is gone". Since we're talking ideal we'd want various codepaths to check/handle this as well as a general maintenance task (i.e. garbage collection) to run every so often.

Doing something equivalent in Project Reunion is possible, at least in part. I'll need to think on it some more and talk with a few folks but, yes. This does look very promising. Thanks for the suggestion!

@soumyamahunt
Copy link

Some additional things I would like to see in new App Lifecycle management for multi-instance scenario:

  1. Ability to check if an instance is pre-launched, this would come handy when an app is trying to create new instance and instead of creating one they can redirect activation to pre-launched instance for better performance.

  2. Ability to check if there is any instance present in the external display/virtual desktop the activation initiated. One of the pain points in multi-instancing is when user switches to external display/another virtual desktop and launches app/ tries to open file with an app and being dragged to the other virtual desktop where app is already present. This would allow apps to launch a new instance instead of redirecting activation in such scenarios.

@aeloros aeloros linked a pull request Apr 27, 2021 that will close this issue
@mqudsi
Copy link

mqudsi commented Jul 3, 2021

Question: which WinUI preview release was the to include support for lifecycle management in UWP apps?

Note: a lot of the notes on changes to the lifecycle API are only present in versioned GitHub links to transient versions of MarkDown documents in the repo that are no longer available in HEAD/master. Is there a single "source of truth" document that survives that includes the changes to the APIs?

@RobMeyer
Copy link

RobMeyer commented Jul 3, 2021

Is there a single "source of truth" document that survives that includes the changes to the APIs?

I believe that would be docs.microsoft.com. Process lifetime management is a broad set of related apis and has changed/grown over time, so you’ll want to look up a specific api endpoint to see when it was introduced. For example, https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.activation.appointmentsprovideraddappointmentactivatedeventargs?view=winrt-20348 was introduced in v1.0, 10.0.10240.0

@nlogozzo
Copy link

Is the RequestRestartAsync working? I tried it in my WindowsAppSDK V0.8.1 app and it seems to not be working.

@JaiganeshKumaran
Copy link
Contributor

Is the RequestRestartAsync working? I tried it in my WindowsAppSDK V0.8.1 app and it seems to not be working.

RequestRestartAsync is only for UWP apps. In a desktop app, you can start a new instance of your app and terminate the current one.

@mqudsi
Copy link

mqudsi commented Aug 16, 2021

I have observed GetActivatedEventArgs() returning null in packaged WinMain applications under Project Reunion 0.8.x and Windows App SDK 1.0.0-experimental1.

I have a hunch that this might be because the kind of activation is one of the ~34 other types that @andreww-msft didn't explicitly mention (Launch, File, Protocol, StartupTask, ToastNotification, ShareTarget, CommandLine, Restart). Is there no way for packaged (or unpackaged) WinMain apps to handle being activated in response to such an event, even if it requires manually piecing together an instance of IActivatedEventArgs from various, disjoint sources and then invoking App.OnActivated/App.OnBackgroundActivated/etc yourself?

@Samuel12321
Copy link

Why was this issue closed @aeloros when it hasn't been fully implemented yet.

@aeloros
Copy link
Contributor

aeloros commented Aug 20, 2021

This issue was closed because it is fully implemented. If there are bugs in the code, then they should be filed as separate issues. This issue was for the initial implementation which is done.

@riverar
Copy link
Contributor

riverar commented Oct 26, 2021

@aeloros How did activation get handled? Did that "subset of the full MSIX manifest" idea pan out?

@aeloros
Copy link
Contributor

aeloros commented Oct 26, 2021

@riverar,
Could you clarify?

@riverar
Copy link
Contributor

riverar commented Oct 26, 2021

@aeloros The proposal here refers to potentially creating a "subset of the full MSIX manifest" to give unpackaged apps identity. Did that happen? Or do we need to use MSIX sparse packages? Just asking because my proposal had a dependency on the creation of this new manifest.

@aeloros
Copy link
Contributor

aeloros commented Oct 26, 2021

@aeloros The proposal here refers to potentially creating a "subset of the full MSIX manifest" to give unpackaged apps identity. Did that happen? Or do we need to use MSIX sparse packages? Just asking because my proposal had a dependency on the creation of this new manifest.

I don't think anything has been decided yet with regards to identity. It's a fairly complex problem and will take considerable thinking.

@riverar
Copy link
Contributor

riverar commented Oct 26, 2021

@aeloros Hm ok. I guess I misunderstood your "This issue was closed because it is fully implemented" then.

@andreww-msft
Copy link
Contributor Author

Folks

Although this issue is closed, I wanted to clarify a few points. This was the very first Reunion/Windows App SDK feature document to be published - at a time when we were still very much feeling our way through a whole bunch of new processes around how we would publish docs and specs. We wanted to get the doc out very early, to gather feedback - and we have indeed received a lot of feedback - so many thanks for that!

Reading through all the comments again, it's clear there's been a little confusion: it's worth calling out that the doc was to some extent aspirational - it was a set of proposals rather than a committed detailed design. The more detailed API specs for AppLifecycle features were published much later. This initial doc therefore contains some ideas that we ended up changing as we fine-tuned the designs, and some ideas that got re-shuffled in the schedule, for example, the Restart support is now targeting 1.1. Another example: we originally proposed unpackaged support for 8 activation kinds, but it turns out that Launch and CommandLine are indistinguishable for unpackaged apps, so we combined these, and we deferred ToastNotification and ShareTarget to later releases.

Going forward, I'll leave this document as is, for historical reference. The aforementioned API specs and the docs.microsoft.com documentation should be considered more accurate references. Also, for suggestions for improving or extending the AppLifecycle support, we'll file new issues. For example, I've just created a new issue 1709 for improvements to the instancing redirection APIs. Of course, we're also considering issues that other folks file, such as 126 Loosen import redirection restrictions from Rafael.

@andreww-msft andreww-msft reopened this Nov 3, 2021
@ghost ghost added the needs-triage label Nov 3, 2021
@ghost ghost removed the needs-triage label Nov 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Lifecycle area-UWP Support for UWP apps area-Win32 Support for Win32 packaged and non-packaged apps feature proposal
Projects
None yet