Поделиться через


Being productive in the background – background tasks

In my previous post (Being productive in the background), I explained the Windows 8 background model and how your app can be productive even when it’s not on screen in a power efficient manner. In today’s post, I will talk about background tasks and how your app can run code in the background even when it is suspended. I will describe two common scenarios with example code that show you how to run your own app code in the background; downloading POP email every 15 minutes with a lock screen capable app and how any app can do work in the background when the device is on AC power.

Introduction

Background task triggers are designed for varied scenarios and applications, and so have different requirements and resource management constraints. Some background task triggers are designed for apps that always need to stay up to date (e.g. email, VOIP) while others are designed for more opportunistic scenarios (e.g. running a maintenance task on AC or when certain system conditions change). The apps that always need to stay up to date need to be on the lock screen, this is limited to 7 apps; more on this later in the post. In contrast, if you want to do opportunistic work, any app can use the maintenance trigger which runs on AC or certain system triggers. To use these triggers the app doesn’t need to be on the lock screen. Apps on the lock screen have more relaxed resource management constraints because they need to run more frequently (that’s why we limit the number and put the user in control!). I will talk about these details later.

You don’t have to use background tasks if you simply want to keep your app fresh with content. You can always use live tiles or scheduled notifications as we explained in the post Create a great tile experience. With this introduction, let’s dive into the code!

Doing work in the background when the device is on AC power

As we’ve seen in my previous post, sometimes your app needs its own code to provide functionality in the background. For example, let’s say you want to add all the photos in the Pictures Library to your app database or process them in some way (e.g. generate thumbnails). You can do this when your app is running in the foreground and interacting with the user, or you can use background tasks with a maintenance trigger which runs in the background only when the device is on AC power. The maintenance trigger is available to everyone and your app doesn’t need to be on the lock screen. The advantage of using a maintenance trigger background task is that it is guaranteed to not interfere with the user’s activity and, runs only on AC power. So you don’t need to worry about excessive battery usage.

This code example shows the maintenance background task calls ProcessPictures class to process the files when the task runs. The task runs every 8 hours to look for new files to process. The background task also registers for a cancel handler because maintenance background tasks are cancelled when the device transitions to battery power. In the cancel handler, the processing of files is cancelled. If you don’t return from the cancel handler within 5 seconds, Windows will terminate the app. Note these code examples assume knowledge of the background task and the trigger classes. For more info about these classes, see the Windows.ApplicationModel.Background namespace documentation on Dev Center.

C#
 public sealed class MaintenanceBackgroundTask: IBackgroundTask
{
    private ProcessPictures processPic; 
 
    public MaintenanceBackgroundTask()
    {
        // Code to process the pictures 
processPic = new ProcessPictures(); 
    }

    //Main Run method which is activated every 8 hours
   async void IBackgroundTask.Run(IBackgroundTaskInstance taskInstance)
    {
        taskInstance.Canceled += taskInstance_Canceled;

// Because these methods are async, you must use a deferral 
        // to wait for all of them to complete
        BackgroundTaskDeferral deferral = taskInstance.GetDeferral(); 
        List<StorageFile> list = new List<StorageFile>();
        int count = await processPic.EnumerateFiles(list);
        bool retval = await processPic.ProcessFiles(list); 
        
        deferral.Complete(); 
    }

    // Cancel handler, called whenever the task is canceled
    void taskInstance_Canceled(IBackgroundTaskInstance sender, 
            BackgroundTaskCancellationReason reason)
    {
        // Device is now on DC power, cancel processing of files 
        processPic.Cancel = true; 
    }
}

 

JavaScript
 // This JS lives within maintenanceBackgroundTask.js
var processPic = new processPictures();
var count = 0;
var retval = false;

function onCanceled(cancelSender, cancelReason) {
    // Device is now on DC power, cancel processing of files
    processPic.cancel = true;
}
backgroundTaskInstance.addEventListener("canceled", onCanceled);

var list = [];
processPic.enumerateFiles(list).then(function (value) {
    count = value;
    processPic.processFiles(list).then(function (value) {
        retval = value;
// Call close() to indicate the task is complete when 
// all async methods have completed
        close();
    });
});

                  

This code example shows how to register the maintenance background task from the main app. This background task launches every 8 hours to process any pictures in the Pictures Documents Library. If you don’t need to do this work anymore, you can unregister the background task using the Unregister method of the IBackgroundTaskRegistration class.

C#
 //Registering the maintenance trigger background task       
private bool RegisterMaintenanceBackgroundTask()
        {
            BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
            builder.Name = "Maintenance background task"; 
            builder.TaskEntryPoint = "MaintenanceTask.MaintenaceBackgroundTask";
            // Run every 8 hours if the device is on AC power 
            IBackgroundTrigger trigger = new MaintenanceTrigger(480, false);
            builder.SetTrigger(trigger); 
            IBackgroundTaskRegistration task = builder.Register(); 

            return true;
        }

 

JavaScript
 function registerMaintenanceBackgroundTask() 
{
    var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
    builder.name = "Maintenance background task";
    builder.taskEntryPoint = "js\\maintenanceBackgroundTask.js";
    //Run every 8 hours if the device is on AC power
    var trigger = new Windows.ApplicationModel.Background.MaintenanceTrigger(480, false);
    builder.setTrigger(trigger);
    var task = builder.register();

    return true;
}

You must declare Background tasks in your app manifest. Start by opening your app’s manifest in Visual Studio and from the Declarations tab add the Background Tasks declarations from the drop down menu. Choose the appropriate task type and specify your Entry point (class name of the background task) or Start page if you are using a JavaScript background task.

Background task manifest declarations 
Figure 1 - Background task manifest declarations

You can view the contents of the manifest by right clicking it and selecting View Code. Be aware that the maintenance task can run only in the system-provided host (backgroundTaskHost.exe or wwahost.exe for JavaScript) and therefore you can’t specify any Executable attribute. The task type of Maintenance trigger is systemEvent as you can see in the manifest snippet here.

 <Extension Category="windows.backgroundTasks" EntryPoint="MaintenanceTask.MaintenaceBackgroundTask">
         <BackgroundTasks>
           <Task Type="systemEvent" />
         </BackgroundTasks>
       </Extension>

In JavaScript EntryPoint is replaced by a StartPage attribute.

 <Extension Category="windows.backgroundTasks" StartPage="js\maintenaceBackgroundTask.js">

For more info on using background tasks, see the whitepaper Introduction to background tasks and the Dev Center for API usage.

Download POP mail every 15 minutes

In this example, we need the app to run predictably and frequently in the background. You can get this by placing your app on the lock screen.

Because an app uses background tasks to always stay up-to-date even when the user isn’t using their Windows 8 device, the way a user controls what apps can use these background tasks is by granting them permission to appear on the lock screen. This is a natural fit because the lock screen is designed to provide users info about their apps without the need for them to unlock their Windows 8 device. This relationship is a two-way street: your app can use these types of background tasks only if it is on the lock screen and, likewise, your app can appear on the lock screen only if it requests to use these types of background tasks.

background2_img2

Figure 2 - Lock screen personalization UI and lock screen capable apps

Because a relatively small number of apps can be placed on the lock screen, it is important for your app to provide a good lock screen experience. If it doesn’t, users will likely remove it to make room for something else. Examples of apps that fit this mold are communication apps; e.g. a mail app that shows a count of unread email messages, a calendar app that shows upcoming appointments in the detailed status slot, or a messaging app that shows how many messages a user has missed. More information about the lock screen, including more details on what makes an app a good candidate for appearing on it, is available on Dev Center.

Using time trigger to download mail every 15 minutes

This example code shows how to register a time trigger background task that runs every 15 minutes if the Internet is available using the BackgroundTaskBuilder class. If the Internet is not available then your background task doesn’t run. Instead, it waits for the Internet to be available and then automatically runs. This is another useful feature of background tasks that prevents unnecessary work from happening and preserving device battery life. Without the condition, app code would have to run and then detect that there is no network connectivity and then error out because it couldn’t download the mail. The mail will be downloaded regardless of whether the app is in the foreground or not. It will also download if the device is in Connected Standby.

C#
 private bool RegisterTimeTriggerBackgroundTask()
        {
            BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
            builder.Name = "Pop mail background task";
            builder.TaskEntryPoint = "MailClient.PopMailBackgroundTask";
            // Run every 15 minutes if the device has internet connectivity
            IBackgroundTrigger trigger = new TimeTrigger(15, false);
            builder.SetTrigger(trigger);
            IBackgroundCondition condition = 
                new SystemCondition(SystemConditionType.InternetAvailable);
            builder.AddCondition(condition); 
            IBackgroundTaskRegistration task = builder.Register();

            return true;
        }
JavaScript
 function registerTimeTriggerBackgroundTask() 
   {
       var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
       builder.name = "Pop mail background task";
       builder.taskEntryPoint = "js\\popMailBackgroundTask.js";
       //Run every 15 minutes if the device has internet connectivity
       var trigger = new Windows.ApplicationModel.Background.TimeTrigger(15, false);
       builder.setTrigger(trigger);
       var condition = new Windows.ApplicationModel.Background.SystemCondition(                             
Windows.ApplicationModel.Background.SystemConditionType.internetAvailable);
       builder.addCondition(condition);
       var task = builder.register();

       return true;
   }

The time trigger is available only to apps on the lock screen, as described previously. To programmatically request placement on the lock screen, you have to use the BackgroundExecutionManager class. If the user doesn’t put your app on the lock screen then your background tasks won’t run. If so, you may have to fall back to using a background task which doesn’t require lock screen or perform the work when the user uses your app. So that users don’t get asked over and over, the system prompts the user once. If they say no and want to add it later, they can do so manually.

C#
 public async Task<bool> ObtainLockScreenAccess()
        {
            BackgroundAccessStatus status = await BackgroundExecutionManager.RequestAccessAsync();
            
            if (status == BackgroundAccessStatus.Denied || status == BackgroundAccessStatus.Unspecified)
            {
                return false; 
            }

            return true; 
        }

 

JavaScript
 function obtainLockScreenAccess()
   {
       Windows.ApplicationModel.Background.BackgroundExecutionManager.requestAccessAsync().then(function (status) {
           if (status === Windows.ApplicationModel.Background.BackgroundAccessStatus.denied || 
               status === Windows.ApplicationModel.Background.BackgroundAccessStatus.unspecified){
               return false;
           }
           return true;
       });
   }

This code example shows the main background task that downloads email every 15 minutes. It doesn’t go into detail describing how to update the tile and badges of your app as that was previously covered in the blog post Creating a great tile experience.

C#
 void IBackgroundTask.Run(IBackgroundTaskInstance taskInstance)
        {
            int count = popmailClient.GetNewMails(); 
            // Update badge on lock screen with the mail count 
            popmailClient.UpdateLockScreenBadgeWithNewMailCount(count);

            IList<string> mailheaders = popmailClient.GetNewMailHeaders(); 
            // Update app tile with the subjects of the email 
            popmailClient.UpdateTileWithSubjects(mailheaders); 
        }

 

JavaScript
 //This JS lives within popMailBackgroundTask.js
    var count = popmailClient.getNewMails();
    // Update badge on lock screen with the mail count
    popmailClient.updateLockScreenBadgeWithNewmailCount(count);

    var mailheaders = popmailClient.getnewMailHeaders();
    // Update app tile with the subjects of the email
    popmailClient.updatetileWithSubjects(mailheaders);
    close();

To add your app to the lock screen , it needs to specify the lock screen notifications type available in the Application UI tab of the manifest.

Background task manifest declarations

Figure 3 - Background task manifest declarations

This is a code snippet of the manifest (generated by the wizard) of an app that needs to be on the lock screen and displays badges and toasts on the lock screen. The time trigger task can run only in the system provided host (backgroundTaskHost.exe or wwahost.exe for JavaScript) and therefore you can’t specify any Executable attribute. The task type is timer as you can see from the manifest.

 <LockScreen Notification="badgeAndTileText" BadgeLogo="Images\badgelogo.png" />
      <DefaultTile ShowName="allLogos" WideLogo="Images\tile-sdk.png" ShortName="LockScreen CS" />
      <SplashScreen Image="Images\splash-sdk.png" BackgroundColor="#FFFFFF" />
    </VisualElements>
    <Extensions>
      <Extension Category="windows.backgroundTasks" EntryPoint="MailClient.PopMailBackgroundTask">
        <BackgroundTasks>
          <Task Type="timer" />
        </BackgroundTasks>
      </Extension>

In JavaScript EntryPoint is replaced by a StartPage attribute.

 <Extension Category="windows.backgroundTasks" StartPage="js\popMailBackgroundTask.js"

 

Advanced scenarios

You can build more advanced VOIP, instant messaging or push email apps using other background task triggers such as Control Channel or Push Notification. Their usage is beyond the scope of this post and more info about them is provided in the Background networking whitepaper.

Resource management for background tasks

As already mentioned, background tasks were designed with power efficiency in mind and hence have CPU and network resource usage constraints applied to them. This prevents an app in the background from depleting the device’s battery without the user being aware. If an app is active and the user is interacting with it in the foreground, then no CPU or network resource constraints are applied to the app’s background tasks.

CPU resource constraints

Each app on the lock screen receives 2 seconds of CPU time every 15 minutes, which can be used by all of the background tasks of the app. At the end of 15 minutes, each app on the lock screen receives another 2 seconds of CPU time for use by its background tasks. Any unused CPU time in the 15-minute interval is lost and the app can’t accumulate it. Each app not on the lock screen receives 1 second of CPU time every 2 hours. If the app uses all of its available CPU time, its background tasks are suspended until the app’s CPU quota is replenished at the next generation for CPU quota updates.

CPU usage time refers to the actual amount of CPU used by the app and not the wall clock time of the background task. For example, if the background task is waiting in its code for the remote server to respond, and it is not actually using CPU, and this wait time is not counted against the CPU quota.

CPU resource constraints on background tasks

 

CPU resource quota

Refresh period

Lock screen capable app

2 CPU seconds

15 minutes

Non-lock screen capable app

1 CPU second

2 hours

Network resource constraints

Network usage can represent a significant drain on a device battery, and so it is also constrained during background task execution. But if a device is running on AC power then background tasks are not network-constrained. CPU usage for a background task is always resource constrained even if the device is running on AC power.

This table characterizes network data throughput, for a resource constrained WiFi network, assuming minimal interference.

 

Global pool

Even with the assigned quota for each app, sometimes these fixed resource constraints may not be enough. For those situations, there is a shared global pool from which applications can request CPU and network resources.

Details about background tasks, the global pool, its resource management constraints, and best practices are available in the Introduction to background tasks whitepaper. It also includes a sample project with source.

Summary

So the answer to the question, “can my app perform work when it is not on screen”, is a resounding yes. The background model in Windows 8 allows your app to accomplish key end-user scenarios, like file downloads, playing audio, updating e-mail in the background or performing maintenance tasks when the device is on AC power. And because the platform closely monitors these activities, your background work will have minimal impact on the foreground app’s responsiveness or the battery life of your device.

For more detailed technical info on the background model in Windows 8 go to the Dev Center and check out the various whitepapers. If you have any questions feel free to post them here in the comments and we’ll try to respond as best we can.

-- Hari Pulapaka, Program Manager, Windows.

Thanks to Jake Sabulsky, Johnny Bregar, Kyle Beck and Suhail Khalid for their contributions and many others for their valuable feedback including Alexander Corradini, Arun Kishan, Ben Srour, Ian LeGrow, Jamie Schwartz, and John Sheehan.

Resources

Link

Type

Highlights

Introduction to background tasks

Whitepaper

Introduces background tasks

Background Model API namespace

Docs

Background model API namespace

Background tasks sample project

Sample project

Demonstrates usage of background tasks

Lock screen overview

Conceptual documentation

Explains the lock screen and its best practices

Background networking

Whitepaper

Shows how to develop advanced apps like VOIP, instant messaging using background tasks.

Creating a great tile experience

Blog post

Shows how to create a great tile experience

Comments

  • Anonymous
    May 24, 2012
    The comment has been removed

  • Anonymous
    May 25, 2012
    I have been asking non-stop questions about background tasks, so perfect timing although I wish you published this 2 days ago :-) Quick question... I have an app that need to update its tile every 15 minutes...  So I use a TimerTrigger... the problem is that this requires the lock screen permission - why?  I don't want to be on the lock screen, I just want to update my tile... Thanks.

  • Anonymous
    May 25, 2012
    I have been asking non-stop questions about background tasks, so perfect timing although I wish you published this 2 days ago :-) Quick question... I have an app that need to update its tile every 15 minutes...  So I use a TimerTrigger... the problem is that this requires the lock screen permission - why?  I don't want to be on the lock screen, I just want to update my tile... Thanks.

  • Anonymous
    May 25, 2012
    Hello Emad, you don't need to use time trigger to update your tile. The "Creating a great tile experience" post linked above has more info.  

  • Anonymous
    May 26, 2012
    The comment has been removed

  • Anonymous
    May 26, 2012
    @Gareth, take a look at the background networking whitepaper linked above. They allow you to have long lived socket connections.

  • Anonymous
    May 26, 2012
    What about long-running CPU intentsive tasks (with all the CPU given)? I.e video conversion running for an hour? Are users allowed to switch to another app?

  • Anonymous
    May 29, 2012
    The comment has been removed

  • Anonymous
    May 30, 2012
    The comment has been removed

  • Anonymous
    May 31, 2012
    The comment has been removed

  • Anonymous
    May 31, 2012
    >> But is background video encoding a common tablet scenario? It could be. I plan on using my tablet as my desktop: just plug in keyboard, mouse, 2nd monitor and connect to wall power. Why can't my tablet process large amounts of data overnight when it is hooked up to wall power and nobody is using it?

  • Anonymous
    May 31, 2012
    The comment has been removed

  • Anonymous
    June 10, 2012
    So would it be possible to use a time trigger for an Alarm clock app? Could someone use the time trigger to wake the machine from sleep? (Assuming the user allows the program onto the lock screen, of course).

  • Anonymous
    June 11, 2012
    The comment has been removed

  • Anonymous
    June 12, 2012
    Hello @Hari, As mentioned above the data limit is 180/30MB per day for lock screen/non-lock screen apps. Can a task consume all of its data limit e.g. 30 MB in one time?

  • Anonymous
    June 13, 2012
    Hello Gaurav, your app receives resource quota every 15 minutes and you can use all the resource quota that your app receives at the start of the 15 minute cycle. More info about this behavior is provided in the background tasks whitepaper linked above.