Thursday, June 16, 2011

Generic background agents in Mango

In Mango, one of the multitasking mechanisms available is the ability to schedule custom code to run in the background at a regular time interval, even when the application is closed. The custom code that you need to run in the background is contained in a class library separate from the foreground application, and runs in a separate process.
In Visual Studio, you use the scheduled task agent template to create the agent library in the phone application solution, and you reference the agent library from the phone app. As a result, the WMAppManifest file gets updated with a new element that references the agent assembly, so the main app knows where to find the code to run.
For example, you can create an agent that will log some memory usage data for the phone to a local file in isolated storage. You add the code to carry out this task in the OnInvoke() override in the agent class, which the system invokes each time the agent gets run – and that in turn depends on how you schedule it (see below).
The agent code may look like this :
   1: protected override void OnInvoke(ScheduledTask task)
   2: {
   3:     string logFilename = "applog.txt";
   4:     var store = IsolatedStorageFile.GetUserStoreForApplication();
   5:  
   6:     using (var stream = new IsolatedStorageFileStream(
   7:         logFilename, FileMode.Append, store))
   8:     {
   9:         using (var sw = new StreamWriter(stream))
  10:         {
  11:             sw.WriteLine("Task type : " + task.GetType().ToString());
  12:             sw.WriteLine("Date time : " + DateTime.Now);
  13:             sw.WriteLine("Memory usage : " + DeviceStatus.ApplicationCurrentMemoryUsage);
  14:             sw.WriteLine("Peak mem usage : " + DeviceStatus.ApplicationPeakMemoryUsage);
  15:             sw.WriteLine("********************");
  16:         }
  17:     }
  18:  
  19:     NotifyComplete();
  20: }

Now that you’ve defined the code you want the agent to run in the background, you need to schedule the agent. You do that in the foreground phone application, your main app. For this, you create and register a scheduled task. It may be a periodic task, which the system will roughly run every 30 minutes for 15 seconds (some restrictions apply). Or a resource intensive task, which will only run in the phone is plugged in and charged and wifi is available, but will run for up to 15 minutes so, you can use it to do some serious work, like syncing large data.

Note that you may schedule both a periodic AND a resource intensive task.

You use the ScheduledActionService to register the task( s) with the system. Here’s how you do it :


   1: var task = new PeriodicTask(agentName);
   2: task.Description = "Logs memory performance for the device";
   3: ScheduledActionService.Add(task);

And/or :


   1: var riTask = new ResourceIntensiveTask(riAgentName);

Once the task is scheduled, your custom code in the agent will run on a regular basis in the background. In the main app you can check the log file in isolated storage to see the results :


   1: IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
   2:  
   3: try
   4: {
   5:     using (var isoFileStream = new IsolatedStorageFileStream(
   6:         logFileName, FileMode.Open, store))
   7:     {
   8:         using (var isoFileReader = new StreamReader(isoFileStream))
   9:         {
  10:             data = isoFileReader.ReadToEnd();
  11:             myTextBlock.Text = data; 
  12:         }
  13:     }
  14:  
  15: }
  16: catch
  17: {
  18:     MessageBox.Show("Log file not found.");
  19: }

In your app, you probably want to add mechanisms for the user deschedule and reschedule the task, and for the app to automatically reconnect to the scheduler service when resuming from closed or tombstoned state, since the service continues to run in the background.


var task = ScheduledActionService.Find(agentName);
var riTask = ScheduledActionService.Find(riAgentName);
 
if (task != null | riTask != null)
{
...

A final note : the user can view which apps have agents, and whether they’re currently scheduled, in the new Background Services section of the phone settings (‘Applications’ tab) :

image      image

To recap, generic agents let you run your own code at regular system-defined time intervals. This is Mango’s way of letting us multitask, and it’s designed to fully preserve system health when a bunch of crazy apps try to take over the background by running all sorts of resource-consuming things.

Cheers!

No comments:

Post a Comment