Sometimes a “crash” can be something entirely different from what you think it is. This makes it quite hard for (3rd party) crash reporting tools to report them. Let’s travel down the rabbit hole of “crashes” without losing our minds, and report them all!
Talking about apps that “crash”.
To an iOS developer, the phrase “my app is crashing” usually means something like this:
“I am using the app which then suddenly disappears, and am taken to the home screen. This is annoying, I had almost finished writing a really long blog post and hadn’t saved it yet. Now all product of my labor is lost; all because the app developer had a bug in their code. ”.
Turns out, one of the interesting side-effects of working on crash reporting tools for (mobile) app developers[1][2] is that you get to talk a lot about crashing applications, get to see a lot of stack traces[3], and get a lot of opportunities to figure out what the heck people want to say. By “people” I mean our own product managers, developers, and designers, as well as customers who get in touch through our various communication channels. I may even communicate with one of our customers’ customers directly. Customers that I encounter during my workday are a very diverse group of people. They can be anyone from a C-level executive of a company, a software engineer, a designer or a Product Manager of any level of seniority, or an end user. To them, the phrase “my app is crashing” can have quite a few different meanings. So what does it mean to “crash”? Let’s start with a few fun cases and move on to more technical “crashes” later on.
What does the dictionary say?
According to the dictionary[4], the verb “crash” means
“to cause (a computer system, component, or program) to crash”
or
“of a computer system, component, or program: to suffer a sudden major failure usually with attendant loss of data”
These are pretty good explanations of what it means for an (iOS) application to “crash”. They may lack some detail, but then they are from an entry in a dictionary, and not from a comprehensive guide on the meaning of the word “crash” for the iOS platform.[5]
Hard to use apps
This category of “crashes” is not strictly about “crashes”. Nonetheless, it comes up somewhat regularly. It boils down to the fact that an iOS application is harder to use than it should be. As a result, the user is under the impression that the app is not working correctly and has contacted the customer support.
Imagine the following example that happened to me during my commute to work a few months ago:
You are using a simple notes app on your iPhone. It enables you to write notes and save them (similar to iOS’ stock “Notes” app). Its main UI is a UINavigationController
with a UITableViewController
at the root that allows scrolling through a list of your notes’ titles. It supports adding notes, deleting notes, and, on selecting an item in the list, editing a note. Adding or editing an existing note pushes a UIViewController
on the stack and shows a large UITextField
to edit your note. Now, imagine you just worked on an interesting blog post for an hour or so (while you were commuting), and want to navigate back to your list of notes by swiping back to the previous scene instead of hitting the “Save” button at the top right of the UINavigationBar
. The application presents a UIAlertController
. You hit the “Ok” option. Unfortunately, you did not understand what the alert said and you lose your blog post.
What happened here? The app worked as intended, and even showed an alert, yet failed to communicate the destructive nature of my action. For example, labeling the button “Discard” instead of “Ok” could have prevented this mistake. While data was definitely lost, this case cannot be considered a “crash”, yet, people might refer to it as one.
How would you collect information similar to the example outlined above? Crash reporting tools cannot help you for this category; this case is – strictly speaking – not a “crash”. That said, iOS 11 and later come with a built-in screen recorder.[6] Make it easy for your QA testers and customers to get in touch and submit their feedback with screenshots or videos.[10]
It’s a bug in your app but not a “crash”
Following apps that fail to meet their user’s expectation, let’s talk about non-fatal bugs. A bug can of course lead to an application crash, but don’t necessarily has to; let me explain.
Back in 2015, a QA tester reported a bug in an app that I was developing for a customer. They described that they would watch a video (it was an app to stream videos), and the video player (which used the AVFoundation
framework) would suddenly “crash”. I was confused. How could the video player “crash”, but not the app itself? What actually happened was that there was an issue with their internet connection. The video player was supposed to show a message and let the user know about the problem. Unfortunately, the UILabel
for the message was hidden by another view in the pretty complex view hierarchy on the screen. I would never have thought about this as a “crash”, but what happened actually matches one of the definitions of “crash” (“[…] to suffer a sudden […] failure …”).
Like our previous category of “crashes”, it cannot be reported by crash reporting tools. It can be found during testing using automated UI tests[11] or (manual) QA testing. For the later, use a tool to allow for easy reporting of issues as mentioned in the previous paragraph.[10]
The iOS watchdog process
Moving on, we’re encountering our first “crash” category that actually exits the app: app terminations by the iOS watchdog. Although it has been around since the dawn of iOS, not all developers are familiar with it.
iOS’ watchdog process generates a “watchdog timeout” when an app takes too long to launch, terminate, or respond to system events. Note that this is not an application crash, but an app “kill” by iOS itself. App “kills” cannot be reported by 3rd-party crash reporting solutions even though there is an underlying exception. From Apple’s Tech Note 2151[7]:
The exception code 0x8badf00d indicates that an application has been terminated by iOS because a watchdog timeout occurred. The application took too long to launch, terminate, or respond to system events. One common cause of this is doing synchronous networking on the main thread. Whatever operation is on Thread 0 needs to be moved to a background thread, or processed differently, so that it does not block the main thread.
While seeing 0x8badf00d
in your stack traces in iTunes Connect[8] is typically a good indicator that there is a bug in your app, it can also be expected behavior, e.g. iOS will stop CPU intensive processes if the iDevice is running hot to prevent overheating.[9]
What are your options for this? First, during development, make sure to do some basic performance testing and app launch testing.
To check for CPU intensive operations on the main thread, utilize the “Main Thread Checker”.[12] Some crash reporting tools also have heuristics to detect cases where an app has been killed by the watchdog process.[13]
Detecting low memory situations
A very common case for app terminations is app terminations as part of the regular iOS application lifecycle.[15] Once iOS runs low on memory, its applicationDidReceiveMemoryWarning:
[16] and UIApplicationDidReceiveMemoryWarningNotification
[17] callbacks will message the app ahead of the termination to let it free up memory before it will eventually terminate the app to free resources. Make sure to utilize these methods to save any data before iOS will, as a last resort, send the applicationWillTerminate:
[18] message and ultimately terminate your application.
As with the previous categories of “crashes” (app terminations by the watchdog process), iOS will not allow for any 3rd-party crash reporting here so they need to rely on heuristics again. For example, they will listen for the applicationWillTerminate:
callback and perform some basic “termination reporting” at the next launch. Use a 3rd-party crash reporting solution that support heuristics like this but be mindful as they usually report false-positives, too.
Application kills
The watchdog process and low memory situations are not the only causes for an app’s termination. The next category in our list of “crash” causes are application “kills”. A very common cause for them is when a user decides to “force close” the application.[14] From Apples’ “App Programming Guide for iOS”:
In addition to the system terminating your app, the user can terminate your app explicitly using the multitasking UI. User-initiated termination has the same effect as terminating a suspended app. The app’s process is killed and no notification is sent to the app.
This kind of app “kills” is even more problematic to 3rd party crash reporting tools than the previous terminations, as their heuristics mostly rely on them receiving messages from iOS, i.e. the applicationWillTerminate
callback. Some 3rd party tools again use heuristics to detect app kills by the users, which are – as mentioned before – a mixed bag as they usually cause false-positives. You need to decide for yourself if you are ok with false-positives, especially if your app supports long-running background operations.
Also note that app “kills” are considered the same as the regular “kills” of suspended iOS apps. For this case, make sure you are familiar with iOS’ application lifecycle and persist your data before the app is suspended.
Exiting the app
Now that we have discussed application termination and “kills”, let’s move to the next category of “crashes”. While a deliberate exit of the applications process is technically not a “crash”, they can definitely be perceived as one. To exit an iOS app, you can call exit(0)
or [[NSThread mainThread] exit]
. While I don’t think that this is a common thing to do for the average app, there might be valid use-cases. App Center’s in-app update feature is one of them.
I have reviewed code in “ordinary” apps in the past where some error condition would exit the app:
if(error) {
// this is bad and should never happen.
exit(0);
}
Long story short: just don’t! This is a legit way to end a process, there is nothing for crash reporters to report: no crash, no crash report. 😉
Again using a crash reporting solution that supports detecting unintentional app terminations is a last resort with the aforementioned likeliness of false-positives if you want to detect application exits.
Heureka! It’s a crash!
This is brings us to the final category of “crashes”. Their description is quite simple. A “true crash” is neither a hard to use application, a non-fatal bug, an app termination, an app “kill” nor a deliberate exit of the app by its developer. A crash is when an app suffers a major failure that is fatal to the app (the user is taken to the home screen end the lifecycle of the app was ended abruptly).
Yet, all categories that were discussed fit the definition in the dictionary:
“of a computer system, component, or program: to suffer a sudden major failure usually with attendant loss of data”
So when is a “crash” a “crash”?
Some of the categories above blur the lines quite a bit. Technically, none of them are crashes. Ultimately, it doesn’t matter because your goal as an app developer is to help your users achieve a task and make them happy.
Make sure to make a crash-free experience a top priority from the start, no matter what kind of crash it is, and don’t rely on your crash reporting tool to alert you to them. And, in case someone complains about a “crash”, make sure you ask the right questions to make sure you understand what kind of “crash” they are talking about.
3 Wikipedia entry for ‘stack trace’
4 Entry for the word ‘crash’ at Merriam-Webster.com
5 Thinking about it, some of my family members sometimes refer to their internet connection not working as “my internet has crashed”, which is actually correct if we follow the definition in the dictionary.
7 Apple Tech Note 2151: Understanding and Analyzing Application Crash Reports
9 WWDC 2018 Session ‘Understanding Crashes and Crash Logs
10 HockeyApp has a basic feedback functionality while other tools support more sophisticated workflows.
11 Apple’s documentation on User Interface Testing
13 HockeySDK-iOS API to detect whether an app has not terminated cleanly
14 How to force close an iOS app
16 Documentation for applicationDidReceiveMemoryWarning:
17 Documentation for UIApplicationDidReceiveMemoryWarningNotification