Repository navigation
build: AGP 9.3 with R8 optimized resource shrinking, and lower on-device scoring memory - #16
Merged
Merged
Conversation
AGP 9 makes R8's optimized resource shrinking the default, which Play Console asks for. 9.3.3 is the newest AGP inside Kotlin 2.4.20's tested range (AGP up to 9.3.1, Gradle up to 9.7.0; both picks are patch releases). - :engine and :shared use com.android.kotlin.multiplatform.library, since AGP 9 rejects com.android.library next to the Kotlin Multiplatform plugin. The opt-in Android target (glosso.android), onnxMain and the hand-wired hierarchy are unchanged. - :androidApp uses AGP's built-in Kotlin (no kotlin-android plugin; the JVM target follows compileOptions) and androidResources.localeFilters. - shared/src/androidUnitTest is now androidHostTest (:shared:testAndroidHostTest). - The three Compose device tests of shared components no longer compiled in :androidApp (they use internal :shared API) and move to shared/src/androidDeviceTest (:shared:connectedAndroidDeviceTest). - Gradle 9.7 deprecations fixed: no delegated `by getting/creating/registering`, and the licensing tasks no longer read Task.project at execution time. - Licensing locks and catalogue refreshed (kotlin-stdlib-common now resolves). Claude-Session: https://claude.ai/code/session_01FcVpZoyr8VdRLp1QecX1Ng
kotlinx.serialization and Credential Manager ship their own consumer rules; ours duplicated them (and kept the whole androidx.credentials.playservices package). The Coil rules named Coil 2 classes that no longer exist, and the blanket -dontwarn lines hid nothing: R8 reports no missing class without them. The native-method rule is already in proguard-android-optimize.txt. Only the ONNX Runtime keep remains, because its JNI layer looks classes, fields and constructors up by name. Release stack traces keep line numbers and now carry R8's mapping id as the source file. playstore release APK: 30431 -> 26075 referenced methods, dex 5.10 -> 4.60 MB, 277 -> 13 res/ files. Claude-Session: https://claude.ai/code/session_01FcVpZoyr8VdRLp1QecX1Ng
…ackground The ONNX session now runs without the CPU memory arena and allocates the weights outside it, so the activations of a take are freed when it ends instead of staying reserved for the life of the session. Allocation only: the recognition output is bit-identical (same transcription, confidences and timings on the parity fixture; engine bench unchanged). The app also releases the loaded model on TRIM_MEMORY_BACKGROUND and reloads it on the next take. A take holds the load lock while it runs, so a release can never close the session under it. Emulator (arm64, dumpsys meminfo native heap): 416 -> 378 MB after scoring, 447 -> 394 MB after a second model is closed, 394 -> 36 MB once trimmed. Claude-Session: https://claude.ai/code/session_01FcVpZoyr8VdRLp1QecX1Ng
IgnacioLD
added a commit
that referenced
this pull request
Nov 10, 2026
…Android The C shim now disables the CPU memory arena and sets session.use_device_allocator_for_initializers=1, as the JVM/Android recognizer does since #16. Over the 77-clip parity run the footprint after scoring drops from 666 MB to 468 MB (peak 706 -> 592 MB); the iOS logits are bit-identical with and without the options. Claude-Session: https://claude.ai/code/session_01FcVpZoyr8VdRLp1QecX1Ng
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.
Play Console (2.5.4, Android vitals) warns that the R8 setup may use more memory because optimized resource shrinking is off, and says to move to AGP 9. Google starts enforcing these memory and code optimization thresholds in February 2027. This PR upgrades the build, removes keep rules that are no longer needed, and lowers the memory that on-device scoring holds. There are three commits, one per concern.
1. AGP 8.9.1 -> 9.3.3, Gradle 8.11.1 -> 9.7.1
deploy/Dockerfilealready builds the server with. Both picks are patch releases of tested versions. The wrapper jar matches the official sha256.:engineand:sharednow usecom.android.kotlin.multiplatform.library, because AGP 9 rejectscom.android.librarynext to the KMP plugin. These stay as they were: the opt-in Android target (-Pglosso.android),onnxMain,kotlin.mpp.applyDefaultHierarchyTemplate=falseand JVM target 17.:androidApp: uses AGP's built-in Kotlin, so thekotlin-androidplugin is gone and the JVM target followscompileOptions.resourceConfigurationsis replaced byandroidResources.localeFilters. Both flavors, the licensing gate per flavor and the release-Pinputs are unchanged.shared/src/androidUnitTestis nowandroidHostTest, so the task is:shared:testAndroidHostTest.BottomActionBarTest,GlossoArtworkTestandPlayerPointerTeststopped compiling in:androidApponce the UI moved to:shared: they useinternalAPI, and one still imported Coil 2. That brokeconnectedAndroidTestandtools/score-parity/run-parity-test.shon main. They now live inshared/src/androidDeviceTest(:shared:connectedAndroidDeviceTest).by getting/creating/registeringinengine,sharedandandroidApp, andTask.projectread at execution time by the licensing tasks.licenses.jsonare regenerated withtools/licensing/collect.py.kotlin-stdlib-common:2.4.20now resolves.:shared:testAndroidHostTest.2. R8
isMinifyEnabledandisShrinkResourceswere already on for release.proguard-rules.pro:-keep class androidx.credentials.playservices.** { *; }, because the AAR ships a narrower rule;-dontwarn, because R8 reports no missing class without them;-renamesourcefileattribute, so R8 9 writes its mapping id as the source file.ai.onnxruntime.**. The JNI layer looks up classes, fields and constructors by name, and the AAR ships rules only for its telemetry classes.res/files / resources.arscMethods were counted with
apkanalyzer dex references. Most of the APK is the ONNX Runtime.sofor 4 ABIs (about 135 MB), so the total size barely moves.3. On-device scoring memory
setCPUArenaAllocator(false)andsession.use_device_allocator_for_initializers=1. These change only where tensors are allocated, not the math.OnDeviceScorerreleases the model onTRIM_MEMORY_BACKGROUNDand reloads it on the next take. A take holds the load lock while it runs, so the session cannot be closed under it.score-parity/fixtures/good.wavwas1f3c5e77...before and after.tools/engine-bench/run.shoutput is identical line for line between main and this branch.Memory on emulator-5558 (arm64, 1080x2340 at 480 dpi), debug build. A scratch instrumented probe (not committed) walks through the phases while
adb shell dumpsys meminfo me.shirobyte42.glossois sampled every 0.5 s. Values are MB at the end of each phase:onTrimMemory(TRIM_MEMORY_BACKGROUND)Scoring latency for the fixture was unchanged within noise (321/291/268 ms before, 337/310/265 ms after).
Verification (rebased on main d70a496)
./gradlew :engine:jvmTest: 463 passedLC_ALL=en_US.UTF-8 ./gradlew :server:test: 347 passed:androidApp:testFdroidDebugUnitTest/testPlaystoreDebugUnitTest: 296 / 295 passed:shared:testAndroidHostTest: 146 passed. The same test files ran astestDebugUnitTestbefore the move: 142 on the old base, plus the tests that came with feat(app): let the learner point the app at a self-hosted server #15.:androidApp:lintFdroidDebugandlintPlaystoreDebugreport 0 errors. Warnings went from 73 to 11 per flavor. The one new warning isOldTargetApi: the newer lint knows API 37, and raisingtargetSdkis a separate product change.:engine:compileKotlinIosSimulatorArm64and:shared:compileKotlinIosSimulatorArm64pass../gradlew :server:installDist -Pglosso.android=false -Pglosso.ios=falsepasses without the Android SDK in the environment. Docker is not available on this machine, sodocker buildwas not run. The Dockerfile already uses Gradle 9.7.1.assemblePlaystoreRelease,assembleFdroidReleaseandbundlePlaystoreReleasepass.testBuildType = "release", debug signing, and keep rules for the test harness only.ScoreParityTestpassed on the R8-minified playstore release on emulator-5558: good.wav scored 100 / PERFECT with delta 0, and silence, noise and low were not evaluable. ONNX Runtime loads and scores under the new rules.OfflineReferenceParityTestskipped becausethirty.wavis not staged anywhere.tools/score-parity/run-parity-test.sh --serial emulator-5558passed.:shared:connectedAndroidDeviceTestran 6 tests and all passed.GLOSSO_MODEL=<abs>/wav2vec2_phoneme_int8_dyn_pertensor.onnx tools/engine-bench/run.shgives native >= 98 for 30/45 and REFSCORE 22/28 (>= 98), identical on main and this branch. The bench's own 0.9 rate gate already fails on main; this PR does not change that.gitleaks dir . --redactreports only the 2 known false positives.Notes
:engine'scommonTesthas no Android host test. Turning one on fails to compile, becauseParityPlatformhas no Androidactual. The oldandroidUnitTestvariant never compiled either.https://claude.ai/code/session_01FcVpZoyr8VdRLp1QecX1Ng