Reducing app crash rates
Updated: Dec 2, 2024
This topic outlines some established best practices for reducing app crash rates on Meta Quest platforms. The purpose of these best practices is to provide you with actionable advice on how to reduce app crash rates, ensuring a better user experience and higher engagement.
App crashes can have significant financial, reputation, and platform perception implications. Here are some reasons why reducing app crashes is crucial:
- Financial impact: App crashes can lead to lost revenue due to decreased user engagement, negative reviews, and reduced sales.
- Reputation impact: App crashes can damage your brand reputation, leading to a loss of customer trust and loyalty.
- Platform impact: App crashes can negatively impact the overall perception of the Meta Horizon platform, leading to decreased user engagement and satisfaction.
Before you start fixing app crashes, we recommend that you roll back the build that caused them. This stops your users from having a bad experience. Use the following steps to rollback a build.
- Open your browser and sign into the Developer Dashboard.
- Select your app.
- From the left-side navigation click Distribution and then select Release Channels.
- From the table click Production (Store).
- Click Change Current Build to choose one of your previous builds from the drop-down list.
- Click Submit.
Users will automatically get updated to the old version.
When working on your app to resolve, test for, or mitigate crashes we recommend the following actions:
- Test thoroughly: Test your app thoroughly before releasing it to ensure that it is stable and crash-free.
- Use crash reporting tools: Use crash reporting tools, such as crash analytics, to monitor and track crashes.
- Implement error handling: Implement error handling mechanisms to catch and handle exceptions.
- Optimize code: Optimize your code to reduce memory usage and improve performance.
App crashes are classified in the following broad categories:
- Java crashes: In simplest terms, these are the crashes originating from the Java code of the app. A few examples include:
- Null Pointer Exceptions (NPE) - Mainly happens when an app tries to access a null object reference.
- Array Index Out Of Bounds Exception - Occurs when the app tries to access an array element outside its bounds.
- Stack Overflow Error - Happens when the app exceeds the maximum allowed stack size.
- Out Of Memory Error (OOM) - OOMscrashes happen when the app runs out of memory.
- Native crashes: A native crash in Android occurs when a problem arises in the native code of an app, which is written in languages like C or C++. This type of crash is different from a Java crash, which occurs in the Java code of an app. A few classifications include:
- Memory corruption - When the app tries to access memory that it shouldn’t, or when it tries to write data to a location that’s already occupied.
- Null pointer dereferences - When the app tries to access a null (non-existent) object or variable.
- Invalid function calls - When the app calls a function with invalid arguments or in an invalid context.
- Resource leaks - When the app fails to release system resources, such as memory or file handles.
- Application Not Responding (ANR): An ANR is a type of error that occurs when an app stops responding to user input or system events. This can happen due to various reasons, such as:
- Long-running operations on the main thread - Performing time-consuming tasks, such as network requests or database queries, on the main thread can block it and cause an ANR.
- Deadlocks - When two or more threads are blocked, waiting for each other to release resources, it can lead to a deadlock and an ANR.
- Memory leaks - When an app fails to release memory, it can lead to a memory leak, which can cause the app to become unresponsive and result in an ANR.
- Native crashes - Crashes in native code may cause ANRs.
- Low Memory Kills (LMK): LMKs come into picture when the system is low on free RAM, and is somehow unable to reclaim the RAM via different methods. In such cases, the LMK Daemon (LMKD) starts terminating the processes. The order of terminations may vary by system, however it is executed in the order of process priority (for example, low priority background processes are killed first and other high priority processes are killed later).
When working to resolve app crashes of the identified types, we recommend using this high-level guidance:
- Java crashes: Handle null pointer exceptions, array index out of bounds exceptions, stack overflow errors, and out of memory errors.
- Native crashes: Handle memory corruption, null pointer dereferences, invalid function calls, and resource leaks.
- ANRs: Avoid long-running operations on the main thread, deadlocks, memory leaks, and native crashes.
- LMKs: Optimize memory usage, avoid memory leaks, and implement efficient memory management strategies.
Beyond the high-level guidance above for fixing your app crashes, here are some resolution steps that you can try to find the root cause for your app crashes and fix the problem(s):
- Read the logs (logcat stream): You use the logcat tool via adb (./adb logcat) to get more information about the crash. The logcat prints log messages (exceptions, errors, and warnings) along with other vitals of the system that can help with your root cause analysis of the crashes.
- Use 3rd party tools: The GNU debugger (gdb) and Android Studio can be used to analyze core dumps and debug both the native code and Java crashes, respectively.
- The crash analytics dashboard gives you the ability to monitor app level crashes and analyze them by applying different filters (eg. app version, OS version).
- The analytics alerts tool allows you to set up analytics alerts on most metrics including user crash rate.
The main tool we provide for diagnostics is
symbolication. It gives you the ability to view your symbolicated stack traces in the crash analytics dashboard so that you can trace the crash to a specific function in your app.