Skip to content

ANR during CrashlyticsRegistrar static initialization #7882

@ZeeshanShabbir

Description

@ZeeshanShabbir

[READ] Step 1: Are you in the right place?

Issues filed here should be about bugs in the code in this repository. If you have a general
question, need help debugging, or fall into some other category use one of these other channels:

  • For general technical questions, post a question on StackOverflow
    with the firebase tag.
  • For general Firebase discussion, use the
    firebase-talk google group.
  • For help troubleshooting your application that does not fall under one of the above categories,
    reach out to the personalized Firebase support channel.

[REQUIRED] Step 2: Describe your environment

  • Android Studio version: Android Studio Otter | 2025.2.1 Patch 1
  • Firebase Component: Firebase Crashlytics (firebase-crashlytics)
  • Component version: BOM 34.3.0

[REQUIRED] Step 3: Describe the problem

We are seeing ANRs during app cold start caused by CrashlyticsRegistrar.<clinit> eagerly initializing a kotlinx.coroutines Mutex on the main thread. When Firebase discovers components via ComponentDiscovery, it reflectively loads CrashlyticsRegistrar using Class.forName(), which triggers its static initializer. This creates a MutexImpl, which cascades into initializing the entire kotlinx.coroutines synchronization infrastructure (SemaphoreAndMutexImpl, SemaphoreSegment, SemaphoreKt, ConcurrentLinkedListNode, SystemPropsKt) all via <clinit> blocks on the main thread.
This happens before Application.onCreate() is called, inside FirebaseInitProvider.onCreate(). On budget devices (Realme, Vivo), this class loading chain exceeds the ANR timeout.
We have 10 stack traces all showing the same pattern, caught at different points in the cascade. All other threads are idle no lock contention is involved.

Affected devices: Budget Realme and Vivo phones
Android versions: Android 15 (SDK 35), Android 16 Beta (SDK 36)
Visibility: Foreground
Firebase BOM: 34.3.0
kotlinx-coroutines: 1.10.2
androidx.collection: 1.5.0

Steps to reproduce:

Cannot reproduce locally. Observed in production via Playstore reports on budget devices during cold start.
Stack traces:
All traces share this common path:

FirebaseInitProvider.onCreate()
  → FirebaseApp.initializeApp()
    → ComponentRuntime.<init>()
      → ComponentDiscovery$$ExternalSyntheticLambda0.get() [Class.forName]
        → CrashlyticsRegistrar.<clinit>
          → MutexImpl.<init>
            → SemaphoreAndMutexImpl.<init>

Below the SemaphoreAndMutexImpl.<init>, the traces are caught at different points in the class initialization cascade:
Variant 1 - ConcurrentLinkedListNode.<clinit> → AtomicReferenceFieldUpdater:

"main" tid=1 Runnable
  at java.lang.Class.getDeclaredField (Native method)
  at java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl.<init>
  at java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater
  at kotlinx.coroutines.internal.ConcurrentLinkedListNode.<clinit>
  at kotlinx.coroutines.sync.SemaphoreAndMutexImpl.<init>
  at kotlinx.coroutines.sync.MutexImpl.<init>
  at com.google.firebase.crashlytics.CrashlyticsRegistrar.<clinit>
  at java.lang.Class.classForName (Native method)
  at java.lang.Class.forName
  at com.google.firebase.components.ComponentDiscovery$$ExternalSyntheticLambda0.get
  at com.google.firebase.components.ComponentRuntime.<init>
  at com.google.firebase.FirebaseApp.<init>
  at com.google.firebase.FirebaseApp.initializeApp
  at com.google.firebase.provider.FirebaseInitProvider.onCreate

Variant 2 - Segment.<clinit>:

"main" tid=1 Runnable
  at kotlinx.coroutines.internal.Segment.<clinit>
  at kotlinx.coroutines.sync.SemaphoreAndMutexImpl.<init>
  at kotlinx.coroutines.sync.MutexImpl.<init>
  at com.google.firebase.crashlytics.CrashlyticsRegistrar.<clinit>
  ...same lower frames...

Variant 3 - SemaphoreKt.<clinit> → systemProp:

"main" tid=1 Runnable
  at kotlinx.coroutines.internal.InlineList.systemProp
  at kotlinx.coroutines.sync.SemaphoreKt.<clinit>
  at kotlinx.coroutines.sync.SemaphoreSegment.<init>
  at kotlinx.coroutines.sync.SemaphoreAndMutexImpl.<init>
  at kotlinx.coroutines.sync.MutexImpl.<init>
  at com.google.firebase.crashlytics.CrashlyticsRegistrar.<clinit>
  ...same lower frames...

Variant 4 -SystemPropsKt.<clinit> → Runtime.availableProcessors:

"main" tid=1 Runnable
  at libcore.io.ForwardingOs.sysconf
  at java.lang.Runtime.availableProcessors
  at kotlinx.coroutines.internal.SystemPropsKt__SystemPropsKt.<clinit>
  at kotlinx.coroutines.internal.InlineList.systemProp
  at kotlinx.coroutines.sync.SemaphoreKt.<clinit>
  at kotlinx.coroutines.sync.SemaphoreSegment.<init>
  at kotlinx.coroutines.sync.SemaphoreAndMutexImpl.<init>
  at kotlinx.coroutines.sync.MutexImpl.<init>
  at com.google.firebase.crashlytics.CrashlyticsRegistrar.<clinit>
  ...same lower frames...

Variant 5 - SemaphoreKt.<clinit> → findSegmentInternal:

"main" tid=1 Runnable
  at kotlinx.coroutines.internal.InlineList.findSegmentInternal
  at kotlinx.coroutines.sync.SemaphoreKt.<clinit>
  at kotlinx.coroutines.sync.SemaphoreSegment.<init>
  at kotlinx.coroutines.sync.SemaphoreAndMutexImpl.<init>
  at kotlinx.coroutines.sync.MutexImpl.<init>
  at com.google.firebase.crashlytics.CrashlyticsRegistrar.<clinit>
  ...same lower frames...

What happened? How can we make the problem occur? This could be a description, log/console output,
etc.

Relevant Code:

// No app code involved. ANR occurs before Application.onCreate()
// during ContentProvider initialization triggered by the system.
// CrashlyticsRegistrar is loaded reflectively by ComponentDiscovery
// via Class.forName(), triggering its static initializer on the main thread.
Image

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions