Skip to content

Android main-thread deadlock in OneSignal.initialize() via InAppMessages.lifecycleInit() -> waitForInit() runBlocking #1167

Description

@Anakeyz

BODY:

Description

On Android, OneSignal.initialize(appId) can permanently deadlock the main/UI thread. The app never recovers — the SDK's own ANR watchdog (OtelAnrDetector) detects and reports it as "OneSignal-related", but the main thread stays blocked (observed past 50s+ before we killed the process).

Environment

  • onesignal_flutter: 5.5.4
  • Native Android SDK (bundled): com.onesignal:OneSignal:5.8.1
  • Android 15 (API 35), physical device
  • Flutter (stable channel)

Stack trace (from device log during the hang)

W/MIUIScout App: Enter APP_SCOUT_HANG state
W/MIUIScout App: Event:APP_SCOUT_HANG Thread:main backtrace:
    at jdk.internal.misc.Unsafe.park(Native Method)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:276)
    at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:98)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:69)
    at kotlinx.coroutines.BuildersKt.runBlocking(...)
    at com.onesignal.internal.OneSignalImp.waitForInit(OneSignalImp.kt:447)
    at com.onesignal.internal.OneSignalImp.waitForInit$default(OneSignalImp.kt:446)
    at com.onesignal.internal.OneSignalImp.waitAndReturn(OneSignalImp.kt:531)
    at com.onesignal.internal.OneSignalImp.getServiceWithFeatureGate(OneSignalImp.kt:537)
    at com.onesignal.internal.OneSignalImp.getInAppMessages(OneSignalImp.kt:131)
    at com.onesignal.OneSignal.getInAppMessages(OneSignal.kt:78)
    at com.onesignal.flutter.OneSignalInAppMessages.lifecycleInit(OneSignalInAppMessages.java:100)
    at com.onesignal.flutter.OneSignalInAppMessages.onMethodCall(OneSignalInAppMessages.java:52)
    at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:267)
    at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:286)
    ...
    at android.os.Looper.loop(Looper.java:337)
    at android.app.ActivityThread.main(ActivityThread.java:9682)

Followed by the SDK's own watchdog:

W/OneSignal: [OneSignal-ANR-Watchdog] OtelAnrDetector: ⚠️ ANR detected! Main thread unresponsive for 5931ms
I/OneSignal: [OneSignal-ANR-Watchdog] OtelAnrDetector: OneSignal-related ANR detected, reporting...
D/OneSignal: [OneSignal-ANR-Watchdog] OtelAnrDetector: ANR still ongoing (16032ms), but already reported recently (10101ms ago)

This repeats indefinitely — the main thread never recovers.

Root cause (as far as we can trace)

OneSignal.initialize() in the Dart plugin (onesignal_flutter 5.5.4) does:

static Future<void> initialize(String appId) async {
  await _channel.invokeMethod('OneSignal#initialize', {'appId': appId});
  await Future.wait([
    InAppMessages.lifecycleInit(),
    User.lifecycleInit(),
    User.pushSubscription.lifecycleInit(),
    Notifications.lifecycleInit(),
  ]);
}

InAppMessages.lifecycleInit() calls into native getInAppMessages(), which internally calls getServiceWithFeatureGate() -> waitForInit(), which does a kotlinx.coroutines.runBlocking wait on the calling thread. Since this call arrives via the Flutter MethodChannel handler, it executes on the Android main/UI thread. If the SDK's own internal async init hasn't fully completed by the time this runs, and that init itself needs the main thread's Looper to signal completion, this becomes a genuine self-deadlock rather than just a slow/blocking wait.

Reproduction

  1. Fresh/cold install of an app calling await OneSignal.initialize(appId) early in app startup (e.g. right after WidgetsBinding first frame).
  2. On a "cold" OneSignal SDK state (e.g. after a full reinstall rather than an incremental update), the internal init appears to take long enough for the race to manifest as a full deadlock rather than a brief hang.
  3. Main thread never recovers; app is stuck on whatever UI was showing (in our case, a splash screen).

Expected behavior

OneSignal.initialize() should never be able to deadlock the calling thread, even during a cold/slow internal init.

Additional notes

  • We deliberately tested downgrading to a much older version of an unrelated native dependency in our app (which forced a fresh app reinstall on the test device) and that is what surfaced this as a full deadlock rather than an intermittent slow path — suggesting this is a race that's more likely to manifest on a cold SDK-state install.
  • We previously pinned onesignal_flutter to 5.5.4 specifically because 5.6.3 broke iOS pod install for us, so we haven't been able to test whether this is fixed in later native SDK versions (5.6.3 bundles native 5.9.5).

Happy to provide a minimal repro project if useful.

Second confirmation (separate run, prod entrypoint, same device)

Reproduced again on a completely fresh install (lib/main.dart, prod flavor) with the identical stack trace:

D/OneSignal: [main] Calling deprecated initWithContextSuspend(context: ...MainActivity@..., appId: 4c4758cb-...)
D/OneSignal: [main] initWithContext: SDK already initialized or in progress
...
W/MIUIScout App: Event:APP_SCOUT_HANG Thread:main backtrace:
    at kotlinx.coroutines.BuildersKt.runBlocking(...)
    at com.onesignal.internal.OneSignalImp.waitForInit(OneSignalImp.kt:447)
    at com.onesignal.internal.OneSignalImp.getServiceWithFeatureGate(OneSignalImp.kt:537)
    at com.onesignal.internal.OneSignalImp.getInAppMessages(OneSignalImp.kt:131)
    at com.onesignal.OneSignal.getInAppMessages(OneSignal.kt:78)
    at com.onesignal.flutter.OneSignalInAppMessages.lifecycleInit(OneSignalInAppMessages.java:100)
    ...
W/OneSignal: [OneSignal-ANR-Watchdog] OtelAnrDetector: ⚠️ ANR detected! Main thread unresponsive for 5321ms
D/OneSignal: [OneSignal-ANR-Watchdog] OtelAnrDetector: ANR still ongoing (17533ms), but already reported recently (12212ms ago)

Notably, right before the hang, the SDK logs "Calling deprecated initWithContextSuspend" followed by "initWithContext: SDK already initialized or in progress" — logged from a single await OneSignal.initialize(appId) call in our Dart code (no native-side init call exists anywhere in our app; confirmed no manual init in MainActivity/Application/manifest). This suggests the internal bootstrap path itself re-enters or races against its own in-progress init state, which may be related to why waitForInit() then blocks forever.

This reproduces consistently (2/2 fresh installs so far) across both our dev and prod Flutter entrypoints on the same physical Android 15 device.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions