Make Android data sync foreground work policy-compliant#11
Merged
Promises merged 1 commit intoMay 15, 2026
Merged
Conversation
Remove the boot-completed dataSync foreground service startup path and route immediate library syncs through WorkManager. Keep the download service as the only dataSync foreground service, make it non-sticky, declare the runtime service type, and pause work on Android 15 foreground-service timeout. Add library sorting by audiobook length across UI and Rust storage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This change updates LibriSync's Android background transfer behavior for current foreground-service policy requirements and adds library sorting by audiobook length.
What changed
BootReceiverand itsRECEIVE_BOOT_COMPLETEDregistration so the app no longer starts adataSyncforeground service from boot or package replacement broadcasts.BackgroundTaskServicefrom the Android manifests and Expo config plugin as a registereddataSyncforeground service.DownloadServiceas the only app-owneddataSyncforeground service path for explicit download/conversion work.DownloadServicenon-sticky so Android does not restart it later without an explicit user action intent.FOREGROUND_SERVICE_TYPE_DATA_SYNCwhen starting the download foreground service.Service.onTimeout()handling so Android 15+ dataSync timeouts pause active downloads and stop the service cleanly.Lengthas a library sort option in the React Native UI, JNI mapping, Rust storage query layer, and Rust test coverage.Why
Android 15 blocks several foreground service types from being started from
BOOT_COMPLETED, includingdataSync. If a boot receiver starts such a service, Android throwsForegroundServiceStartNotAllowedException.Android 15 also introduces a time budget for
dataSyncforeground services while the app is in the background. Once that budget is exhausted, the system callsService.onTimeout(), and the service must stop itself promptly.Android 16 further tightens background job behavior, so long-running or restart-oriented background work should use system-managed scheduling where possible. In this codebase, periodic sync work fits WorkManager, while direct audiobook downloads remain an explicit user-visible transfer path.
Relevant Android documentation:
User impact
Validation
npm run typecheck./gradlew :expo-rust-bridge:compileDebugKotlin :app:processDebugMainManifest./gradlew :expo-rust-bridge:processDebugManifest :app:processDebugManifest --rerun-taskscargo test storage::queries::tests::test_list_books_with_filters_sorts_by_lengthgit diff --checknpm run build:rust:androidnpx expo run:android./gradlew :app:assembleReleaseLength.After regenerating the merged debug manifests, the old app-owned
BootReceiverandexpo.modules.rustbridge.tasks.BackgroundTaskServiceare no longer present. The remainingBOOT_COMPLETEDentry is fromandroidx.work, which is expected for WorkManager rescheduling.