[Unity] Crashes and ANRs in Android Devices 101.

A Call for Help.

I have been working hard to improve my game, “Old Farm Restoration Business.”(buy its source from SellMyApp). One of my main goals has been to collect and fix issues like crashes and ANRs by trying out Google’s latest Game Activity feature.

I kindly ask you to download it and play through the first 5 levels. It allows the Android System to collect crash and ANR events while you play. This data will be sent to the Play Console Report System, providing me with valuable insights and feedback to enhance and perfect the game. I will use this report to add a section about Game Activity feature later.

Thank you for your collaboration and support in providing valuable data to make this blog better.

What is Crash and ANR?

Glossary

Crash term is obvious. If you are opening or using an app and it quit unexpectedly, that count a crash. Android has 2 types of crash:

  • Foreground Crash: You are actively interacting with the application, and it quit because of an unhandled exception (Java, Kotlin) or an unhandled signal (C++).
  • Background Crash: You did nothing with this application and a crash pop-up appeared, telling you to restart it. It is often caused by your background services such as broadcast receivers or content providers. Recently, I experienced many crashes from a broadcast receiver for Android Notification due to recent changes in FLAG_IMMUTABLE after the release of Android 12.

ANR stands for “App Not Respond”. It means the application can’t process user input or drawing the screen in the given time. A system dialog will show up which allows users to force kill the application.

You should take a look at this article from Google to get a better understanding of Crash and ANRs in Android.

Crashes and ANRs in Unity Android

A Unity game is a very complicated application with two parts:

  • Unity Runtime (C++): Rendering, Gameplay Logic, Audio, Physics Calculator. Crash cause by it always have the unhandled signal flag (SIGSEGV). I have zero ANR in the Unity Runtime in my life.
  • Unity Main Activity (Java): Communicate with Android System for resources, player input and pass them to the runtime. Crash cause by it represented by Throwable class. ANR cause by it represented by (90% Input Dispatch Timeout, 10% other).

Take a quick look at your Android Vitals and you could pinpoint which part of the game has the bigger problem.

Why we should care about Crashes and ANRs.

Google enforces bad behavior rules for ANRs and crash rates. Applications that exceed this threshold will receive a warning on store listing pages and have their ASO scores reduced. This makes it more difficult to retain existing users and attract new ones. By the way, users generally prefer a good application over a bad one. Here are my charts, which show the ANRs, crashes, and their current thresholds.

Where should we begin?

There is no “Holy Grail” for every game, as each one presents its own unique challenges and issues. Throughout my career, I have diligently collected and thoroughly documented the myriad of common mistakes that lead to frequent crashes and ANRs (Application Not Responding) in my game. It is my sincere hope that this compilation shall serve as an invaluable starting point for you, enabling you to elevate the quality and performance of your game to unparalleled heights.

Pinpoint the problem.

First, we have to locate the source of the crashes and ANRs. There are many tools and techniques that support this process.

  • Android Logcat is a tool to view your device logs in real time. It’s used in development and pre-release phases to detect early problems before you distribute your game to users.
  • Android Pre-launch Report helps to identify issues proactively before your app reaches users. It will run on 4 different devices with Android version 10, 11, 12, and 13 with a full test of stability, compatibility, performance, accessibility, security, and privacy. Each test device has a bunch of screenshots and a gameplay testing video too, which is very helpful for manual investigation before launching your game. I have encountered a black screen issue in one of my games on the Android 12 platform. This problem manifests itself when I utilize a specific feature while observing the testing video. I must commend the diligence of Google report in bringing this matter to light.
  • Firebase Test Lab is the premium version of Android Pre-launch Report, which offers an extensive range of cutting-edge features and advanced capabilities. By investing a minimal fee, you gain the unparalleled ability to handpick the exact devices and configurations that align perfectly with your unique testing requirements, enabling you to create a meticulously tailored testing scenario that guarantees optimal results.
  • The Android Vitals Dashboard provides valuable log information relating to the various aspects of quality, such as Crashes and ANRs. It proves to be extremely beneficial in the post-launch phase for collecting and inspecting real production scenarios. To obtain the complete stack trace, it is recommended that you upload the symbolication file along with your “*.abb”. The symbolication file is essential for thorough analysis and troubleshooting. You can read these articles for more details.
  • Firebase Crashlytics is an exceptional tool that efficiently collects and processes crashes and ANRs (same as Android Vitals). It does this in real-time, providing a remarkably user-friendly UX. With its exceptional analysis engine, Crashlytics pre-processes your log information, categorizing it into diverse groups based on their priority. This advanced functionality ensures that you can seamlessly manage and address any potential issues that may arise.

These incredible tools encompass and address each of the three vital stages in your development cycle: development, pre-launch, and post-launch. When properly implemented, they possess the remarkable capacity to wholly or partially resolve a significant portion – ranging from 30 to an astounding 75 percent – of crashes and ANRs. By diligently scrutinizing and tracing the issue stack, a more profound understanding of the root causes can be achieved, leading to effective resolutions.

Common mistakes.

High workload while Application Switching from and to background.

You should always be vigilant and actively search for any code segments within the OnApplicationPause() function that need to be addressed and removed. This function is triggered whenever your app enters or exits the background stack, which can occur when users interact with your app by clicking its icon, switching between different apps, or even when they watch an advertisement. It’s important to note that complex tasks like data retrieval and storage, object destruction, and server connectivity can accumulate and intermingle with other activities performed by native plugins. This accumulation has the potential to place an excessive burden on the main thread of your application, ultimately resulting in ANRs (Application Not Responding). To prevent such scenarios, it is crucial to carefully manage and streamline your code within the OnApplicationPause() function.

If your game has already implemented In-App Purchases (IAP) or Reward Video Ads, it is advisable to optimize your reward function by converting it into a coroutine and introducing a delay of one frame before actually granting any rewards. This particular function is triggered immediately after your game activity transitions from the background to the foreground. It is worth mentioning that this function can be seen as the underlying cause of numerous ANRs (Application Not Responding) and crashes, which are closely associated with memory Input/Output (IO) and the overloading of the main thread. Personally, in my initial gaming experience, I encountered a multitude of errors such as SIGSEGV_11 and main thread timeouts, which were directly attributable to the implementation of Admob Video Reward function.

High memory usage.

Player has a limited amount of memory. In low-end devices, lacking memory (RAM, cache…) makes the main thread spend more time waiting for loading resources from slow-speed hardware. If your game uses more than the memory threshold, it could cause crashes and ANRs during heavy load, such as opening the game and application switching. Expanding the text: The player’s memory capacity is inherently limited. This constraint becomes particularly apparent in low-end devices, where insufficient memory (including RAM and cache) forces the main thread to expend additional time idling while waiting for resources to load from the sluggish hardware. If your game surpasses the designated memory threshold, the consequence may manifest in the form of crashes and ANRs (Application Not Responding) during periods of intense usage, such as launching the game or switching between applications.

You should strive to minimize the memory footprint of your project by implementing various techniques. One effective approach is to utilize Sprite Atlas, which consolidates multiple sprites into a single texture, reducing memory usage. Additionally, ensuring proper Audio Clip settings can play a significant role in optimizing memory consumption. Another crucial aspect to consider is optimizing your 3D assets. By employing efficient modeling techniques, utilizing LOD (Level of Detail) systems, and employing appropriate compression algorithms, you can minimize the memory requirements of your 3D assets while maintaining visual fidelity.

Moreover, exercising caution when it comes to saving and loading your game data is crucial. Keeping your data structure simple and concise is advantageous. If your data becomes too large, consider shifting to more compact formats such as Message Pack or Protobuf. These formats offer efficient encoding and decoding processes, reducing the workload and overall size of your save files.

By implementing these strategies, you can effectively reduce the memory footprint of your project, leading to improved performance and a more seamless user experience.

Use Unity Engine Tech Stream (alpha version of Unity LTS).

When making your game, remember to use Unity LTS, which stands for Long Term Service. These versions are reliable and have very few bugs, making them stable choices for your projects. They also come with 2 years of support, so you’ll have assistance and updates throughout your development. Unity LTS offers several benefits. Firstly, they undergo rigorous testing and optimization, ensuring stability and a strong foundation for your projects. This means your game will run smoothly without major technical issues. Additionally, LTS releases continuously improve and fix bugs, further enhancing their reliability. Another advantage of Unity LTS is the extensive support from the community and developers. Since many people use these versions, you can find resources, tutorials, and expert advice to help you overcome any challenges you may face during development. This support network allows you to focus on creating and delivering high-quality games.

When it comes to developing a simple game, I highly recommend sticking with the ancient but reliable Unity 2018 LTS. Despite its age, this version proves to be very lightweight and performs exceptionally well on various devices. However, it’s important to note that Unity 2018 LTS does lack some of the newer features, and achieving desired results may require a significant amount of knowledge and expertise. In contrast, the more recent versions of Unity LTS come with an abundance of features. While these additions may seem appealing, it’s worth considering whether they will be beneficial to your specific project. In many cases, these additional features can lead to unnecessary bloat and potential performance issues. To mitigate this, I suggest utilizing Unity’s package manager to selectively remove any excess functionalities that are not essential to your game.

By carefully evaluating your project’s requirements and making informed decisions regarding version selection and feature usage, you can ensure a streamlined and efficient development process.

Over-use of 3rd party plugin, SDK.

Remove any unused third-party plugins from your application. It is recommended to minimize the number of plugins as they can impose additional stress on the main thread. The impact they have on application switching is not fully predictable.

Let me share a story from the past: There was a time when my boss desired to experiment with various bidding strategies without the need to rebuild the entire game. Consequently, we were instructed to incorporate all the ad mediation capabilities of IronSource, regardless of the fact that only a few were actually utilized by the game. Unfortunately, this approach led to a significant decline in the performance of the game due to the excessive workload imposed by each mediation process on the limited resources of the main thread.

It is crucial to find the right balance between functionality and resource efficiency in order to ensure optimal performance of your application.

Useful Articles.

Official Document explains Crashes, ANRs and how they affect your application from Google.

Iron Source guide to reduce ANRs in your game.

ARM guide to Unity Mobile Optimization

Sprite Atlas Work Flow from Unity.

Symbolic Crashes and ANRs for Unity Games.

Game Activity Entry Point

Summary

Alrighty folks, we’ve reached the grand finale of my awesome blog! I really hope it has given y’all a solid head start in sprucing up the quality and performance of your super cool game. Hit me up if you’ve got any burning questions, I’m here to help!

If you think this tutorial is helpful and would like to express your gratitude towards me. Your gratitude drives me forward and inspires me to keep delivering valuable content.

Buy Me A Coffee

or via PayPal:

https://www.paypal.com/paypalme/kampertee

Leave a comment