Yet another iOS mulititasking explanation post

There’s been a lot of confusion about just how multitasking works in the iPhone’s latest iOS 4.0, and just what the limitations on background processes are. Most of the articles I’ve seen attempting to clarify it have concentrated on the addition of the new suspend state and how apps being background vs suspended vs terminated relates to the task list interface. That helps with the end-user confusion, but to me has just made it even more confusing from the developer’s perspective — I want to know what my app will be able to do in this brave new multitasking world, and what its limitations are going to be.

I’ve gone ahead and actually looked at the documentation (RTFM); here’s some notes… (Impatient readers may wish to skip to the summary at the end!)

Application state lifecycle

First, let’s go ahead and put those “background” and “suspend” states into perspective…

Not running

On screen? no
Running? no
In memory? no
Resources none

In the beginning, there was nothing… Before your application is started, it just doesn’t exist in the system yet.

An app that’s not running has no way to execute code, but popup notifications may be shown on its behalf by a registered server application or from earlier scheduling.

When your app gets launched, your code gets loaded into memory and you transition into:
Active state

On screen? yes
Running? yes
In memory? yes
Resources as you like

Your app is large and in charge! Your code and data are in memory, code is being executed, and you’ve got free control over the user interface, audio, network, etc.

There’s also an inactive state when the system takes over the UI and event loops for stuff like showing the incoming phone call dialog; your app is temporarily paused from the UI, but all your resources stay intact and you’ll get them back soon.

When it comes time to switch apps (through the home menu, task list, or programatically), your app loses control of the screen and enters the…
Background state

On screen? no
Running? yes
In memory? yes
Resources restricted*

Your code is still running, but you’ve got no access to the screen, and various resources start getting cut off. Usually this is a temporary state giving an application a chance to save data, close out unneeded resources, and generally tidy up before being suspended completely.

There are some special exceptions which can allow an app to run in background state for prolonged time, which is where the really interesting stuff comes in. We’ll get to that soon!

When we’re done with background state, the OS can put your app to bed; now it’s in…
Suspend state

On screen? no
Running? no
In memory? yes
Resources mostly freed

This is the biggest change in iOS 4: after your post-switchaway cleanup, the app remains in memory so it can be continued at a moment’s notice.

Previously, after your app did a little cleanup on the way out it would be terminated and all its memory and network resources freed. Instead, the app is now simply stopped at this point, but with the explicit warning that it may or may not ever be continued.

If the app is reactivated from suspend mode, anything you kept in memory is still there — you have a lot less work to do to reestablish your application’s running state than when relaunching the process.

But you may die before you wake, in which case you’re back to…

Not running state.

If the system needs more memory to assign to another application, or gets shut down, your suspended app will be terminated without being woken to inform it.

You need to be prepared for termination before entering suspend state… but really, you’re already writing code that assumes it could crash at any time and saves state at intervals and key points so it won’t lose user data, right? Um, right?

Background mode limitations

So just what are the limits of what you can do while running in background state? The docs mix together a lot of strict limits along with recommendations for being a good citizen; I’ve tried to split them out here:

YOU CANNOT (technical restrictions on what you can do):

  • Can’t make OpenGL calls; they will terminate your app.
  • Can’t accept new connections on a listening socket.
  • Can’t use shared system resources like the Address Book (it sounds like they might sorta work if still open, but you could get terminated if there’s a conflict.)
  • Can’t use external accessories — you must register for and handle disconnection events.

YOU SHOULD (recommendations for behaving well):

  • Should be prepared for loss of connectivity — open network connections could be torn down at any time.
  • Should save your state, since your app could be terminated due to memory pressure.
    (You should be saving state during regular operation anyway to protect against application or system crashes, power failures, etc. Programs that assume orderly shutdown are asking for trouble!)
  • Should avoid updating your windows and views; it’ll work but since your UI is hidden it’s a waste of time & battery.
  • Should normalize your UI state — cancel modal alerts, hide temporarily shown passwords, etc.
  • Should “do minimal work” while in background.

Reaching the user when not on screen

iPhone OS 2 introduced networked push notifications, where — through the magic of the internet — your app’s web services can trigger a notification dialog on the phone, even if your application is no longer running. iOS 4 extends this to local background tasks; if your app is in the background state, it can pop up a notification immediately without needing to go out to the network.

You can also schedule a future notification at any time (up to 128 scheduled per app), which will trigger even if your app has been terminated — obviously handy for alarms, calendars, and timer apps.

Notifications are limited in that they alert the user, not the app. If you were suspended or not running when the notification came, you won’t be woken unless the user pushes the button that opens your app.

When in background…

Any app can start up background task threads, which will block the background->suspended state transition.

This is primarily intended for orderly shutdown tasks, like completing that photo uploading to Twitbook or syncing mailbox state to a server after reading a bunch of messages. The system actually gives you a time limit, and will terminate your app if you don’t declare your tasks complete when the time limit’s up! Once you’re done, you’re forced to suspend… absent other triggers, your app is going to stay that way until the user switches back to it or it’s terminated.

You can also register to receive an event for “significant location updates“, which will wake or even relaunch your application when the cell network has noticed that you’ve moved a non-trivial distance. This avoids running down the battery with the GPS if you want updates but don’t really need to be watching it continuously.

Special backgrounding modes

An app can declare itself to have certain types of backgrounding characteristics, which can allow some additional behaviors in background state. Since these are pre-declared in the code-signed app bundle, you need to be aware of what affect they’ll have on your app’s runtime behavior, and will have to run the App Store approval gauntlet with an extra bulls-eye on your forehead. ;)

Background audio mode

Normally, the system audio frameworks cut you off when transitioning from active to background state. If your app is marked as a background audio app, you get two perks:

  • Audio in/out continues to work in background state.
  • Suspend is blocked while playing audio, so you can keep running in the background arbitrarily long.

If audio is not active, your app will still be able to suspend — so a music player that’s paused, or reaches the end of its playlist in the background, can free its resources.

Articles I’ve seen have had a lot of vague language seeming to indicate that apps in this mode can “only” play audio and do nothing else, which might imply that there’s some kind of wacky alternate API for bg audio — this is not true. The docs recommend avoiding unnecessary work while playing background audio to keep resource usage down, but there’s no artificial restriction beyond the general limitations on backgrounded apps.

You’ll still use the same old network interfaces, the same old audio APIs, etc; reportedly it only took an hour to port Pandora’s iPhone player to use background audio.

Background VOIP mode

The VOIP mode is really about management of long-running network clients — an actual VOIP app will probably need to also mark itself as needing background audio. Your app will still get suspended if the user switches away with no active call, but gets a few special abilities:

  • Sockets you register as VOIP control channels will stay live when your app is suspended. If data comes in, you’ll be woken up — this lets you handle an incoming call.
  • You can register a timeout to be woken at intervals, so you to send keepalive pings if needed.
  • The app is automatically launched in the background on boot, so you can connect to the server.
  • The app is automatically relaunched on non-zero exit code, so a one-off app crash won’t break the VOIP service.

Note that while this mode sounds ideal for IM/chat apps, connections to real-time update streams for social networking clients, etc, I suspect that Apple would not actually approve such apps.

Continuous location mode

Navigation apps, GPS tracers, etc may need a more direct way to monitor the GPS for location changes while backgrounded. This is similar to the background audio mode:

  • Continue to use the regular location services APIs…
  • …while you’ve got it active, suspend will be blocked and you can remain in background mode arbitrarily long.

GPS has a particularly bad reputation for running down the battery, so if you’re just looking to ping 4square or something you should probably use the “significant location updates” event registration instead.

Summary

Now that we’ve seen something about how it all works, let’s take some sample cases and ask whether they’ll actually do what we need… So what do we need?

I’m a media player (Pandora, Airfoil Speakers, etc)

  • Can I continue playing audio after switching away?
    • Yes — mark your app as requiring background audio, and it’ll stay backgrounded on switch.
  • Can I keep communicating with the network while playing audio?
    • Yes! But if you’re doing other stuff not needed for your audio and Apple notices, they may not approve your app.
  • Can I start playing audio later on after having been backgrounded, like an alarm clock?
    • No — if you’re not playing audio at switch time, you’ll still get suspended. You could schedule a local notification to alert the user and they could push a button to launch your app and then you could play the music. Ewww!
  • Can I keep a socket open to listen for other computers to connect and send me audio to play?
    • No — your listening sockets will be closed, and you’ll have been suspended anyway as above.

I’m a VOIP client (SIP clients, Skype etc)

  • Can I keep an active call going after switching away from the app?
    • Yes — mark your app as requiring background audio, and a running call will be able to keep on going.
  • Can I maintain a connection to my server to listen for incoming calls?
    • Yes — mark your app as needing VOIP mode, and set the special flag on your control channel after setting up the connection.
  • Can I be automatically launched on boot, so I can open that connection?
    • Yes — mark your app as needing VOIP mode, you’ll be automatically launched if you
  • Can I maintain a listening socket to receive direct SIP calls?
    • No — all listening sockets will be closed in the background. You need an existing connection to a server which’ll send a packet down when there’s an event.
  • Can I auto-answer calls?
    • I’m not 100% sure on this one; if the system fully foregrounds you to handle incoming events so you can show an “incoming” screen then yes, otherwise I don’t think so.

I’m an IM or social networking client (AIM, Meebo etc; StatusNet, Twitter, Facebook, etc)

  • Can I finish uploading a post in the background if the user switches apps before it’s done?
    • Yes — do it from a background task thread, and notify the system when you’re done and ready to be suspended.
  • Can I poll my server in the background to check for updates?
    • No — you’ll need to pair with a server component and use networked notifications to alert the user.
  • Can I keep a socket open to listen for real-time updates from my server?
    • No — in theory the VOIP mode would allow this, but Apple would have to approve your app’s using it for non-VOIP use.
  • Can I be woken to check status when the physical location has changed?
    • Yes — you can register for significant location updates and be woken or launched to check if you need to perform any actions.

I’m any kind of server:

  • Can I listen for clients while in the background?
    • No. Your listening sockets will be closed, and any Bonjour service stuff will be torn down.
  • Can I finish up an existing client connection after switching away?
    • In theory this ought to work, if the operation can complete in a background task thread before you’re forced to suspend.

I’m any other bit of software:

  • Can my app be woken at a specified time?
    • No. You can set a notification to display at a given time, but user interaction will be needed to wake or launch your app.

Whee!

7 thoughts on “Yet another iOS mulititasking explanation post”

  1. A few extra notes:

    – You have to specify explicitly that you want backgrounding in Info.plist for all modes except task completion;

    – There are three different location services: regular (high-precision), significant location update (low-precision, low battery use) and geofencing/region monitoring (when the phone moves within a certain area you pick — very low battery use, low precision, iPhone 4 only). In the case of the latter two, if there’s an update incoming and you got terminated, the app will be relaunched and the update delivered.

  2. >this brave new multitasking world
    >implying that multitasking didn’t exist for over 20 years now *trollface*

  3. Lots of things have existed in other forms on other platforms for 20 years; knowing that doesn’t really help you much when you want to know specific things about a specific platform’s specific interfaces and implementations. :)

  4. This is one of the clearest explanations I’ve come across. Kudos!

    Perhaps you could clarify a couple of points:

    You are given a “time limit” for background task threads. How long is this (10ms, 1s, 30s…)? Is it constant, or does it depend on e.g. processor or memory load?

    After being woken on a voip socket – assume it’s a control message, not an incoming call so the user isn’t bothered – after dealing with the message, how do you “auto-suspend” or is this automatic after some time limit. Is it the same time limit as above?

    Thanks for your help,

    Greg.

  5. Thanks ………. but then whats the use of having background apps if one cannot connect to the server.

    But this article was a detailed one liked it.

  6. Does an NSTimer stay running on background mode and if the app is suspended?

Comments are closed.