7
votes

I am using C# to develop a UWP app for Windows 10 running only on desktop computers, targeting platform version 10.0.14393.0. Due to business requirements, the app lifecycle must behave like a traditional Win32 application.

Therefore, I followed the recommendation from this article to request an ExtendedExecutionSession with ExtendedExecutionReason.Unspecified. I also configured Windows to never sleep and never hibernate.

Still, on rare occasions, Windows will revoke the extended execution session with reason SystemPolicy and then proceed to suspend the UWP app.

Two questions:

  1. How can I get more information (system logs? event logs?) regarding what led to Windows revoking the extended execution session?
  2. How can I get rid of these rare cases of suspensions so that the UWP app lifecycle behaves exactly like Win32 applications (that is, stay running until user explicitly stops it from running)?

Thanks!

5
Does the PC that you tested your app on have a battery or connected to an uninterruptible power supply?A. Milto
The PC does not have a battery and is plugged in to wall AC power outlet.hwaien

5 Answers

7
votes

ExtendedExecutionSession with ExtendedExecutionReason.Unspecified is a subject to multiple restrictions regarding resource consumption. Since your test device doesn't have a battery, then the most likely reason for your app getting suspended is its high memory use. You can try to optimize the app in terms of memory consumption and make use of Memory Management APIs as documentation suggests, but still this doesn't guarantee that your app will never get suspended.

If your app is aimed at business sector then you might consider using more powerful ExtendedExecutionForegroundSession instead of ExtendedExecutionSession. This would probably be the perfect solution for your problem. But it's a restricted capability, which means an app that utilizes it is not allowed to Windows Store - only to Windows Store for Business. You'd also need to manually declare the extendedExecutionUnconstrained capability in the manifest (see the Special and restricted capabilities section of documentation) to take advantage of the API.

Alternatively you can use hacks that prevent app from getting suspended for long periods of time:

  1. Use of App services for communicating with Win32 apps as pnp0a03 suggested.

  2. Use Background Media Playback for playing silent audio sample in the background infinitely in a loop (even if the user stops it manually or another app pauses it to play its own background audio, your app can trace it and automatically restart the playback).

3
votes

I was trying to solve this for days and days but then found this link. Very good explanation and solution to this and most importantly.. easy to understand. You need to put the code in the app.xaml.cs and also edit the package manifest file. You will also need the following directives in the app.xaml.cs

using Windows.ApplicationModel.ExtendedExecution.Foreground; using System.Threading.Tasks;

non-suspending-uwp

2
votes

I remembered that previous SO post - His question was : When I use the App service to communicate with Win32 apps, it prevents the app entering suspend state. I've succeeded to recreate the issue with the sample app that referred at the post.

I don't now that is an intended behavior or not, but it may help to resolve your situation.

UWP application not going to suspend state

0
votes

Use Visual Studio debug mode to run the app, and the app will never run into a suspended state. It is kept awakened by Visual Studio.

Ahh, this is just a joke.

I think unfortunately what you expect is a behavior that is in contradiction to the design principles of UWP.

The system reserves the right to suspend a background app after some “deferal”. If you request an extended execution session, you have to prepare for the revocation as well, being connected to wall power does not keep the app running forever.

Option 1 is resort to desktop app, though this may not be an option. If you get this requirement because users like UWP but doesn’t like the idea of “suspended” (What the... suspended??), I am afraid you cannot fulfill this requirement.

Option 2 is... is there any real task that has to be kept running even the app is switched to the background? If the task needs to run periodically, like checking inbox of a mail account, you can use some kind of timer triggered background task.

Option 3: Think about kiosk mode, there is only one app allowed to run on the device, so it cannot be possibly switched to the background and put into suspension.

0
votes

According to this article in MSDN magazine you can also use background tasks to keep the application alive. The article claims that background tasks should be preferred over the Extended Session method.

A BackgroundTask Implementation

public sealed class TimerTask : IBackgroundTask
{
  public void Run(IBackgroundTaskInstance taskInstance)
  {
    var deferral = taskInstance.GetDeferral();
    taskInstance.Canceled += TaskInstance_Canceled;
    await ShowToastAsync("Hello from Background Task");
    deferral.Complete();
  }
  private void TaskInstance_Canceled(IBackgroundTaskInstance sender,
    BackgroundTaskCancellationReason reason)
  {
    // Handle cancellation
    deferral.Complete();
  }
}

In the application manifest, the background task must also be registered. This registration tells Windows the trigger type, the entry point and the executable host of the task, as follows:

<Extensions>
  <Extension Category="windows.backgroundTasks" EntryPoint="BackgroundTasks.TimerTask">
    <BackgroundTasks>
      <Task Type="timer" />
    </BackgroundTasks>
  </Extension>

Background Task Registration

private void RegisterBackgroundTasks()
{
  BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
  builder.Name = "Background Test Class";
  builder.TaskEntryPoint = "BackgroundTaskLibrary.TestClass";
  IBackgroundTrigger trigger = new TimeTrigger(30, true);
  builder.SetTrigger(trigger);
  IBackgroundCondition condition =
    new SystemCondition(SystemConditionType.InternetAvailable);
  builder.AddCondition(condition);
  IBackgroundTaskRegistration task = builder.Register();
  task.Progress += new BackgroundTaskProgressEventHandler(task_Progress);
  task.Completed += new BackgroundTaskCompletedEventHandler(task_Completed);
}