Worker rollout follow-ups: WM 2.11, .tmp resume, service uses worker#23
Closed
ivan-digital wants to merge 3 commits into
Closed
Worker rollout follow-ups: WM 2.11, .tmp resume, service uses worker#23ivan-digital wants to merge 3 commits into
ivan-digital wants to merge 3 commits into
Conversation
This was referenced May 10, 2026
ff89a10 to
0005370
Compare
99838e6 to
ee1ac47
Compare
added 3 commits
May 10, 2026 12:23
Picks up bug fixes since 2.9.1. The SystemForegroundService manifest override stays in the SDK manifest because 2.11 still doesn't declare foregroundServiceType in its bundled manifest.
… retries Two existing deletions were destroying the partial-download state we want to keep: 1. ensureModels() opens by walking the models dir and deleting every .tmp. The intent was to clean up after process crashes, but it also nukes the in-progress .tmp from a previous ModelDownloadWorker invocation that returned Result.retry() — meaning every WorkManager retry restarted that file from byte 0. Range resume can't help if there's nothing on disk to resume from. Replace with a comment explaining why we keep them; stale .tmp from an old MODEL_VERSION is still wiped by the version-mismatch path above. 2. downloadFile() deleted the .tmp file when its 5-attempt retry loop was exhausted before throwing. Same problem: a transient network failure that outlasts those 5 in-loop retries should still leave resumable bytes for the worker's next try. Drop the deletion. Net effect: a 1.2 GB download that hits a flaky network now keeps every byte that made it to disk — observed during emulator verification of PR #22 where a worker retry dropped ~2.5 MB of partial parakeet-encoder bytes for no good reason. Test: invert 'cleans up tmp file after all retries fail' to assert the .tmp persists after exhaustion, using DISCONNECT_DURING_RESPONSE_BODY to get a realistic mid-stream failure path.
…rker
When Gboard binds to our service for the first time on a fresh install,
resolveModelDir() used to call ensureModels() inline — blocking the
recognition request on a 1.2 GB download tied to the bind's lifecycle.
If Gboard times out (which it will, well before the download finishes),
the coroutine cancels and the bytes that made it to disk are at the
mercy of the user re-tapping the mic.
Now:
1. Fast path — ModelManager.areModelsReady(ctx, INT8) checks file
validity without touching the network. If true, return modelDir
immediately and the service starts in milliseconds.
2. Slow path — enqueue ModelDownloadWorker (idempotent via
ExistingWorkPolicy.KEEP) and await its terminal state via
getWorkInfoByIdFlow().filterNotNull().first { it.state.isFinished }.
The worker runs as a foreground service so the download keeps
progressing even when Gboard's bind times out and the user puts
the phone in their pocket. The next mic tap takes the fast path.
ModelManager: add public areModelsReady() + modelDir(). The validity
check duplicates the per-file validation that ensureModels() already
does, but exposed without the side effect of starting a download.
The protected resolveModelDir() seam stays in place; tests still
override it to bypass the worker entirely.
0005370 to
9b44fd4
Compare
ee1ac47 to
680fdf3
Compare
5 tasks
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.
Stacked on #22. Three independent improvements to the worker rollout:
1.
d1ae47dBumpandroidx.work2.9.1 → 2.11.2Picks up bug fixes since 2.9.1. The SDK manifest still has the
SystemForegroundServiceforegroundServiceTypeoverride because2.11's bundled manifest still doesn't declare one — verified by
inspecting the AAR.
2.
7643c4aPreserve .tmp files across worker retriesTwo existing deletions in
ModelManagerwere destroying partialdownload state we want to keep:
ensureModels()—dir.walk().filter{ext==tmp}.forEach{delete}.tmpfrom the previous worker invocation that returnedResult.retry()— every WorkManager retry restarted that file from byte 0.downloadFile()retry loopBoth are now removed. Stale
.tmpfrom an old MODEL_VERSION is stillwiped by the version-mismatch path. Test
cleans up tmp file after all retries failis inverted to assert preservation, usingDISCONNECT_DURING_RESPONSE_BODYto exercise a realistic mid-streamfailure.
Concrete impact: during PR #22's emulator run we observed a worker
retry drop ~2.5 MB of partial
parakeet-encoderbytes betweenrestarts. That doesn't happen anymore.
3.
99838e6SpeechRecognitionService uses the workerThe service used to call
ModelManager.ensureModels()inline fromresolveModelDir(). On a fresh install, the first Gboard mic tap wassynchronously waiting on a 1.2 GB download tied to the binder's
lifecycle.
New flow:
ModelManager.areModelsReady(ctx, INT8)(new public API; duplicates the per-file validity check fromensureModels()without the download side-effect). If true, returnModelManager.modelDir(ctx)immediately.ModelDownloadWorkerandawaitits terminal state viagetWorkInfoByIdFlow().filterNotNull().first { it.state.isFinished }. The worker runs as a foreground service so the download persists past the binder timeout and the user putting the phone in their pocket. The next mic tap takes the fast path.The protected
resolveModelDir()seam stays in place; existingSpeechRecognitionServiceTeststill overrides it.Test plan
./gradlew :sdk:testDebugUnitTest— 26/26 pass./gradlew :sdk:assembleDebug— green./gradlew :app:assembleDebug— greensettings put secure voice_recognition_service ...), tap Gboard mic on a fresh install — observe download notification appear, dismiss Gboard, wait, re-tap — should now transcribe without re-downloading.adb shell am force-stop ...) mid-download, relaunch — should resume from the last.tmpbyte (verify viaadb shell run-as ... ls -la files/models), not byte 0.Notes
mainafter Move model download to a foreground WorkManager worker #22 merges.areModelsReadyis a public-API addition. It belongs in the SDK's surface contract going forward — third-party hosts can use it to gate their own pre-load decisions.