Slides and Source Code for etka12 Version 2 of YLAD released

Windows Phone: Background Agents Pitfalls (4 of n)

Published on Wednesday, May 2, 2012 5:00:00 AM UTC in Programming

It's been a while since the last part of my series on background agent pitfalls, where I talked about data exchange between your app and the agent, and what potential errors and edge cases you may run into with that. There are a few more topics I wanted to create awareness for, so today I'll continue with...

Part 4: Exceptions, exceptions, exceptions

A lot of things can go wrong when you work with agents, and one of the places that are particularly interesting is at the very beginning - when you try to schedule your task. There are a hand full of conditions that may prevent you from doing this, and knowing about them to e.g. add proper error handling is vital. In this part I'll show and explain to you the individual error cases, and talk about how to work around them, if that's possible at all.

Scheduling tasks

We haven't even talked about the part where you schedule your tasks yet, simply because it seems so trivial. It barely requires more than a handful of code, for example something like this:

// create and add a new periodic task

var task = new PeriodicTask(agentName);

task.Description = description;

ScheduledActionService.Add(task);

The problem with this code is that it can fail in a variety of ways, and you should be very aware of them because they're not only of theoretical nature. Let's see what can go wrong.

Duplicate tasks

This is one of the more trivial situations: a task with the same name is already registered with the system. Naturally, you should try to name your task in a way that makes it highly unlikely that it will collide with the task of a different application. Don't just use "BackgroundTask" or something other generic like that; more specific names like "[ApplicationName]Agent" or even some random name will work much better.

Of course there's also the trivial case that you simply try to schedule your own task multiple times, which will fail in the same way. To prevent that, you can always check if there's already a task with a given name:

var task = ScheduledActionService.Find(agentName);

if (task != null)

{

  // ...

}

If you still try to register a task name that's already present in the system, an InvalidOperationException will be thrown when you invoke the Add method of the ScheduledActionService class.

Disabled background tasks

Windows Phone allows the user to disable background tasks for certain applications explicitly in the settings area. They can choose to do that to save device resources or simply because they don't want a particular application to perform anything in the background.

image

When you invoke the Add method of the ScheduledActionService class, an InvalidOperationException will be thrown in that case too. You do have the chance to handle that particular case by checking for the corresponding exception message. Although this doesn't sound like the best idea to do (an error number, a special exception type or something similar seems a lot preferable), it's indeed what the Background Agents Best Practices recommend to do. The text to test for is:

"BNS Error: The action is disabled".

Sample code for this would look like:

try

{

  ScheduledActionService.Add(task);

}

catch (InvalidOperationException exception)

{

  if (exception.Message.Contains("BNS Error: The action is disabled"))

  {

    // ...

  }

}

You can then (kindly) ask the user to turn background agents back on, and tell them that the functionality they're trying to use or access requires this feature to work.

Maximum number of agents exceeded

That's a tough one. Phones only have a very limited number of slots available for background agents. The Background Agents Overview document mentions a number as low as 6, although it seems to vary depending on the particular device. Another detail is that the user is warned about the number of background agents if the system thinks that it will result in a battery consumption too bad. No matter what number of agents is actually allowed, the thing to learn from this is that you need to be prepared for the case that there are no more slots available. In this case, once again an InvalidOperationException will be thrown. And again you have the possibility to detect that case by checking for a particular error message:

try

{

  ScheduledActionService.Add(task);

}

catch (InvalidOperationException exception)

{

  if (exception.Message.Contains("BNS Error: The maximum number of ScheduledActions of this type have already been added."))

  {

    // ...

  }

}

Please note that you do not need to display this particular error to the user, because a system dialog will be shown automatically.

Scheduler service not ready

This is an edge case, but there's still a chance you will run into it, especially when you follow some pattern I'll talk about in the next part. After the user has booted their phone, it takes a minute or so until the service responsible for the background agents has been started (for performance reasons this is delayed a certain amount of time). In this case, a SchedulerServiceException is thrown:

try

{

  ScheduledActionService.Add(task);

}

catch (SchedulerServiceException)

{

  // ...

}

You can hint the user to the fact that they should simply retry in a minute or so, if adding the task is vital.

256 MB devices

The recent update to version 7.1.1. of the SDK added support for 256 MB devices. These devices do not support background agents at all. If you try to add a task anyway, you'll receive another InvalidOperationException. Unfortunately, the error message is the same as when the maximum number of agents has exceeded (which, technically, is true...):

BNS Error: The maximum number of ScheduledActions of this type have already been added.

So it's not possible to determine this special case simply by checking for an error message. The best practice however is different anyway. What you should do is actively detect 256 MB devices in the first place, and disable any features that rely on APIs that are not available on these devices, for example background agents. Microsoft provides a nice example for this here. In particular, you can add code like:

try

{

  // check the working set limit 

  var result = (Int64)DeviceExtendedProperties.GetValue("ApplicationWorkingSetLimit");

  if (result < 94371840L)

  {

    _isLowMemDevice = true;

  }

  else

  {

    _isLowMemDevice = false;

  }

}

catch (ArgumentOutOfRangeException)

{

  // OS does not support this call => indicates a 512 MB device

  _isLowMemDevice = false;

}

You can then use this value to e.g. disable UI access to features that require background agents.

Please note the remarks on the device identity capability described in the above link, to opt-out of that detection process during Marketplace submission if you want, and your app allows that.

Conclusion

Adding a background agent can go wrong for a lot of reasons. In some rare cases your app can work around the problem itself, but most of the time you depend on the user to help you fix the problem, or limitations of the device and/or current settings prevent you from using background agents at all. Embrace this, and plan ahead for the times you cannot use the feature by adding proper error handling.

Tags: Background Agents · Windows Phone · Windows Phone 7