Skip to content

[Bug] Unity App freezes for several seconds to minutes when an exception occurs with Crashlytics running #563

Closed
@Noshire

Description

@Noshire

[REQUIRED] Please fill in the following fields:

  • Unity editor version: 2021.3.1f1
  • Firebase Unity SDK version: 10.2.0
  • Source you installed the SDK: .unitypackage
  • Problematic Firebase Component: Crashlytics
  • Other Firebase Components in use: Analytics
  • Additional SDKs you are using: None
  • Platform you are using the Unity editor on: Windows
  • Platform you are targeting: iOS, Android
  • Scripting Runtime: IL2CPP
  • Pre-built SDK from the website

[REQUIRED] Please describe the issue here:

Crashlytics increases the time a Unity app freezes when handling an uncaught exception by several orders of magnitude.
We are struggling with this in a production app where users often quit the app because they assume it's stuck forever.

We managed to reproduce it in isolation (crashlytics-issue-repro project), and have used this isolated case to set up 3 test cases:

  • Synchronous, 50 Method Callstack: A void method that calls itself 50 times recursively and then throws an Exception
  • Asynchronous, 50 Method Callstack: An async Task method that calls itself 50 times recursively using await and then throws an Exception
  • Synchronous, 50 Background Threads: A void method that starts 50 worker threads that idle for 1 second and immediately throws an Exception (to find out whether uploading all thread info to Crashlytics could also cause overhead)

We've ran them with Crashlytics not initialized yet ("Crashlytics OFF"), then initialized Crashlytics and ran them again ("Crashlytics ON"). Test results running on a Huawei Y6 2018 / ATU-L21 with Android 8.0.0:

Crashlytics OFF Crashlytics ON
Synchronous, 50 Method Callstack 00:00.015 00:05.131
Asynchronous, 50 Method Callstack 00:03.607 28:29.103
Synchronous, 50 Background Threads 00:00.109 00:05.205

Exceptions that didn't cause any perceivable stutter without Crashlytics suddenly cause a >5s freeze when Crashlytics is enabled. The most troublesome was the asynchronous callstack, though, which already incurs a 3.6s freeze without Crashlytics, but suddenly jumps to nearly half an hour of freeze with Crashlytics enabled.

Steps to reproduce:

  1. Open the crashlytics-issue-repro project in Unity 2021.3.1f1
  2. Import your own google-services.json
  3. Ensure scripting backend is set to IL2CPP
  4. Build and run on any Android phone. The issue is much more visible on slightly older phones. I've used a Huawei Y6 2018 / ATU-L21.
  5. After the app starts, press the "Freeze for 3 Seconds" button as a calibration test. This simply invokes Thread.Sleep(3000), so the resulting text should show a freeze of around 3 seconds.
  6. Press the three "Throw" buttons in sequence. "Throw (Simple Stack)" and "Throw (Many Threads)" should be very fast, while "Throw (Async Stack)" could lead to a short freeze.
  7. Press the "Initialize Firebase" button. Crashlytics is now running.
  8. Press the three "Throw" buttons in sequence. "Throw (Simple Stack)" and "Throw (Many Threads)" should now take several seconds (depending on device), while "Throw (Async Stack)" should lead to a very long freeze (almost 30 minutes on the Huawei device).

Downloadable Repro Project: https://github.com/Noshire/crashlytics-issue-repro

Code Snippets

All code can be found in the linked repository. This snippet, for example, demonstrates how we fabricate the async callstack that throws an exception deep down, which leads to a 28 minute freeze with Crashlytics enabled:

        /// <summary>
        ///     Fabricates a deep async callchain and then throws
        /// </summary>
        public async Task ThrowAsync()
        {
            await EnlargeAsyncStacktraceAndFinallyThrow(50);
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        private static async Task EnlargeAsyncStacktraceAndFinallyThrow(int count)
        {
            if (count > 0)
                // ReSharper disable once TailRecursiveCall
                await EnlargeAsyncStacktraceAndFinallyThrow(count - 1);
            else
                throw new Exception("This is a test exception.");
        }

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions