Skip to content

Fix crash on Android 9–11 from expedited sync workers (#78)#79

Merged
vitofico merged 1 commit into
mainfrom
fix/android9-expedited-worker-crash
Jun 2, 2026
Merged

Fix crash on Android 9–11 from expedited sync workers (#78)#79
vitofico merged 1 commit into
mainfrom
fix/android9-expedited-worker-crash

Conversation

@vitofico

@vitofico vitofico commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes #78 — a crash on Android 9 (and any Android < 12), most visibly at app startup.

Root cause

On API < 31, WorkManager backs an expedited work request with a foreground service and calls CoroutineWorker.getForegroundInfo() to obtain the notification to display. The default CoroutineWorker implementation throws IllegalStateException("Not implemented"):

java.lang.IllegalStateException: Not implemented
    at androidx.work.CoroutineWorker.getForegroundInfo$suspendImpl(CoroutineWorker.kt:100)

On API 31+ expedited work uses JobScheduler expedited jobs, so getForegroundInfo() is never called — which is why the crash only surfaced on older devices.

Two workers opt into expedited work and were missing the override:

  • LibraryMirrorPushWorker — enqueued expedited at app start (LibraryMirrorPushScheduler.enqueueOneTime(expedited = true)), the most likely culprit for crash-on-launch.
  • SyncWorker — enqueued expedited for user-initiated "Sync now".

The reporter's OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST doesn't help here: that policy only governs quota exhaustion, not the foreground-service requirement on pre-12.

Fix

Override getForegroundInfo() in both workers to return a ForegroundInfo backed by a silent, low-importance (IMPORTANCE_LOW) notification on a dedicated channel.

Resulting behavior

Version Before After
Android 8–11 (API 26–30) Crash when an expedited worker ran Brief, silent, ongoing notification while the worker runs; auto-clears on completion. No crash.
Android 12+ (API 31+) Worked (JobScheduler expedited jobs) UnchangedgetForegroundInfo() is never called, no notification.

Non-expedited triggers (ambient sync, daily periodic library push, enqueueAfterLibraryChange) never run as a foreground service, so they show no notification on any version.

No manifest changes needed: FOREGROUND_SERVICE is already merged transitively from work-runtime, and the foreground-service path only executes on API ≤ 30, so targetSdk 34's foreground-service-type / DATA_SYNC permission requirements don't apply. No POST_NOTIFICATIONS concern either (that's API 33+, where this path never runs).

Tests

Regression tests in both modules under @Config(sdk = [28]) (Android 9) asserting getForegroundInfo() returns a valid notification instead of throwing. Added work.testing as a test dependency to :data:sync.

Verified locally via scripts/dgradle :data:sync:testDebugUnitTest :data:library:testDebugUnitTest — BUILD SUCCESSFUL.

On API < 31, WorkManager backs an expedited work request with a
foreground service and calls CoroutineWorker.getForegroundInfo() to get
the notification to display. The default implementation throws
IllegalStateException("Not implemented"), which crashed the app — most
visibly at startup, where LibraryMirrorPushScheduler enqueues an
expedited library-mirror push. On API 31+ expedited work uses
JobScheduler, so getForegroundInfo() is never called and the crash
never surfaced there.

Override getForegroundInfo() in both expedited CoroutineWorkers
(SyncWorker, LibraryMirrorPushWorker) to return a ForegroundInfo backed
by a silent, low-importance notification on a dedicated channel. The
notification only appears on Android ≤ 11 while an expedited worker
runs and auto-clears on completion; behavior on Android 12+ is
unchanged (no foreground service, no notification).

No manifest changes needed: FOREGROUND_SERVICE is already merged
transitively from work-runtime, and the foreground-service path only
executes on API ≤ 30, so targetSdk 34's foreground-service-type and
DATA_SYNC permission requirements don't apply.

Adds regression tests in both modules under @config(sdk = [28])
asserting getForegroundInfo() returns a valid notification instead of
throwing.
@vitofico vitofico added the bug Something isn't working label Jun 2, 2026
@vitofico
vitofico merged commit 4128846 into main Jun 2, 2026
7 checks passed
@vitofico
vitofico deleted the fix/android9-expedited-worker-crash branch June 2, 2026 08:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash on Android 9: IllegalStateException in CoroutineWorker.getForegroundInfo (expedited sync)

1 participant