A Watchdog Termination on iOS occurs when the OS kills an app for violating rules regarding time or resource usage. A few examples where this could occur include:
- An app using too much memory
- An app using too much CPU, leading to the device overheating
- An app doing synchronous networking on the main thread
- An app’s main thread being hung
- An app exceeding limits on background tasks
A Watchdog Termination always has the exception code
0x8badf00d in the system log, so you might think it would be easy for mobile developers to find and debug these types of problems. But they are in fact some of the most difficult bugs to solve.
In this post, we will go over two things:
- Why Watchdog Terminations are difficult to debug
- A common way mobile developers trigger Watchdog Terminations during background tasks and what they can do to prevent them
Why Watchdog Terminations are Difficult to Debug
Although Watchdog Terminations all have the same exception code, it’s not always easy for mobile developers to find these issues in their crash reporter. One reason is that the termination may not show up in the crash report, and this happens fairly often.
Another reason is that the crash report itself might not be easy to decipher. This stems from Watchdog Terminations happening at the “edges” of the app. They don’t result from the app running a single line of code and then immediately throwing an exception.
Far from it in fact. To trigger a Watchdog Termination from a background task, you have to background your app and wait 30 seconds. And the termination is the last thing your app will process. This means the crash point is at least 30 seconds removed from the initiation point of the background task. In a decently complex app, there could be thousands of function calls between the start of a background task and where the app crashes.
Now, in development, a mobile developer could identify a Watchdog Termination by inspecting system logs. But in production, a user would see it as an app launching into the home screen instead of the last screen they were on, or having an app playing background audio abruptly stopping. Those issues as described by users could stem from any number of root causes.
In practice, this results in developers lacking visibility into when and where they are actually occurring.
A Common Type of Watchdog Termination
A common way that mobile apps experience Watchdog Terminations is through background tasks. Some examples of background tasks include:
- App cleanup - when moving from foreground to background, an app runs for a short amount of time to properly clean up before shutdown. Examples include finishing a photo or video upload in a social app, or an SDK sending session analytics data.
- Scheduled background task - an app runs while in the background to update data for when the user foregrounds it later. Examples include running finite length tasks like updating the location in a navigation app or pulling new content for a news app.
- Continual background activity - an app purposefully runs while in the background. Examples include playing or recording audio.
Developers must be careful when adding background functionality because Apple prioritizes the user experience above all else.
How Developers Inadvertently Trigger Watchdog Terminations
One problem developers have is knowing the exact resource and time limits of background tasks. Apple changes these limits often, and in addition, their values adjust dynamically based on device state (e.g. low power mode, high-heat mode).
The following values should thus be viewed more like guidelines:
- An app has 3 minutes to complete any tasks when it moves from the foreground to the background.
- An app has 30 seconds when it resumes in the background.
- An app can’t use 80% of CPU for a given # of seconds (can be measured in wall clock time and CPU time).
Very importantly, there are only two ways to end a background task:
- When your app has finished doing whatever it set out to do.
- When the system calls the task’s expiry handler (a callback to allow you to clean up and end the background task gracefully).
In either case, the developer must explicitly call
A major source of Watchdog Terminations is failing to end a background task. Just because your app finishes the work in the background task doesn’t mean you don’t have to explicitly end the task. A background task runs until you end it.
Another common cause of Watchdog Terminations is failing to respond when the system calls your expiry handler. The resource limits mentioned above are only guidelines. Some developers assume there is no risk of a Watchdog Termination because their cleanup task should never take more than 30 seconds.
But what if the system can only give them 5 seconds because the next app the user foregrounded is very memory intensive? Or what if the user suddenly loses network connectivity and final data upload causes a freeze?
It's important to protect your app against unpredictable situations in mobile. By always responding when the system calls your expiry handler, you might not be able to complete every cleanup task, but you'll prevent watchdog terminations that cause poor user experiences.
Summing It All Up
Watchdog Terminations occur when the OS kills an app for violating time and resource limits. There are several ways these can happen, and a common one in mobile apps is when performing background tasks.
The best way to avoid Watchdog Terminations from background tasks are the following:
- Limit the amount of background tasks your app makes.
- Always set an
- Always put code in your expiry handlers to cleanly shut down work when the watchdog notifies you.
Who We Are
Embrace is an observability and data platform for mobile. We are a one-stop shop for your mobile app’s performance and error debugging needs. If you’d like to learn more about Embrace, you can check out our website or visit our docs! Feel free to ask us a question or get right down to it and see the product in action with a live demo.
- UI Application background tasks: https://developer.apple.com/forums/thread/85066
- UI Application background tasks: https://geek-is-stupid.github.io/2018-10-15-0x8badf00d-ate-bad-food/
- Apple documentation on beginBackgroundTask: https://developer.apple.com/documentation/uikit/uiapplication/1623031-beginbackgroundtask
- Apple documentation on endBackgroundTask: https://developer.apple.com/documentation/uikit/uiapplication/1622970-endbackgroundtask