Skip to content

Deadlock between ReplayIntegration.close() and connectivity callbacks blocks main thread (ANR) #5518

Description

@buenaflor

Integration

sentry-android

Build System

Gradle

AGP Version

8.6.0

Proguard

Disabled

Other Error Monitoring Solution

No

Version

8.41.3

Steps to Reproduce

  1. SentryAndroid.init with Session Replay enabled (e.g. sessionSampleRate = 1.0) — ReplayIntegration registers as a connection status observer and AndroidConnectionStatusProvider
    registers a ConnectivityManager network callback.
  2. Call Sentry.close() from the main thread shortly after init (or whenever a connectivity notification is in flight — Android delivers the current network state immediately after
    callback registration, so closing soon after init hits this reliably).
  3. Race: loop init→close with replay enabled on a loaded emulator; reproduces within ~30 cycles.

Expected Result

Sentry.close() completes and the SDK shuts down cleanly.

Actual Result

Sentry.close() never returns — AB-BA deadlock between ReplayIntegration.lifecycleLock and AndroidConnectionStatusProvider.lock. When close() runs on the main thread this is a permanent
main-thread block (ANR).

  • Closing thread: ReplayIntegration.close() holds lifecycleLock (ReplayIntegration.kt:365) → removeConnectionStatusObserver() waits on the provider lock
    (AndroidConnectionStatusProvider.java:441).
  • ConnectivityThread: updateCacheAndNotifyObservers holds the provider lock while notifying observers (AndroidConnectionStatusProvider.java:274) →
    ReplayIntegration.onConnectionStatusChangedresumeInternal() waits on lifecycleLock (ReplayIntegration.kt:220).
  "main" Waiting
    at io.sentry.android.core.internal.util.AndroidConnectionStatusProvider.removeConnectionStatusObserver(AndroidConnectionStatusProvider.java:441)
    at io.sentry.android.replay.ReplayIntegration.close(ReplayIntegration.kt:370)
    at io.sentry.Scopes.close(Scopes.java:439)
    at io.sentry.Sentry.close(Sentry.java:727)

  "ConnectivityThread" Waiting
    at io.sentry.android.replay.ReplayIntegration.resumeInternal(ReplayIntegration.kt:220)
    at io.sentry.android.replay.ReplayIntegration.onConnectionStatusChanged(ReplayIntegration.kt:393)
    at io.sentry.android.core.internal.util.AndroidConnectionStatusProvider$1.updateCacheAndNotifyObservers(AndroidConnectionStatusProvider.java:277)
    at io.sentry.android.core.internal.util.AndroidConnectionStatusProvider$1.onCapabilitiesChanged(AndroidConnectionStatusProvider.java:255)

Full thread dump attached: sentry_replay_deadlock_trace.txt

Impact

  • CI (ongoing): Recurring 30-minute job timeouts in getsentry/sentry-dart integration tests e.g.
    https://github.com/getsentry/sentry-dart/actions/runs/27229728938/job/80406349339
  • Production (very rare): Any app with replay enabled that calls Sentry.close() or re-inits the SDK at runtime can
    deadlock if a connectivity change lands in the window. When close() runs on the main thread the result is a permanent ANR caused by the SDK, and the ANR trace is effectively undiagnosable for users — just two parked threads inside io.sentry.*.
  • Not affected: apps that never close/re-init Sentry; backgrounding alone is safe (stop() never takes the provider lock).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions