Ship a baseline profile, generated on the emulator because the phone cannot collect one

The profile is real: 13193 lines in app/src/main/baseline-prof.txt, 584 of them the app's own classes, bundled into the release APK as assets/dexopt/baseline.prof. It is produced by a new :baselineprofile test module that walks the first journey - roots screen, one volume opened - under the androidx.baselineprofile plugin, and :app now depends on androidx.profileinstaller so the bundled profile is applied at install time.

Two device facts decided how it was made. Collection requires API 33+ (BaselineProfileRule refuses Android 12 outright), so it ran on the API 35 AVD that was already in ~/.android/avd; that emulator is software-rendered and needs androidx.benchmark.suppressErrors=EMULATOR for any macrobenchmark. And the release build needed profileable android:shell=true, which is why app/src/release/AndroidManifest.xml exists and says why: the same APK is both the thing measured and the thing shipped, so the profile's class names are the ones in the shipped dex.

The effect is not measured, and PERFORMANCE.md says so: 7404 ms median without the profile against 9005 ms with it, run to run, because a TCG emulator varies by more than a profile can buy. What remains is one run on a physical API 33+ phone, with the two compile commands documented. The emulator did settle the other open question - FrameTimingMetric there reports frameDurationCpuMs and frameOverrunMs, the metrics this phone cannot produce at all.

:baselineprofile is compiled by tools/verify.sh --release like :benchmark, so it cannot rot between device runs.
This commit is contained in:
2026-10-17 17:06:08 +02:00
parent 0a3ff88247
commit 4846454645
12 changed files with 13377 additions and 6 deletions
+32
View File
@@ -242,3 +242,35 @@ kept true by automation; the three above need a device and a decision about whic
either side of it. `docs/COMPETITIVE_ANALYSIS.md` had already written "a thumbnail that is bigger and
slower is strictly worse than one that is smaller and instant" — which is a hypothesis until it is a
number.
## The baseline profile
`app/src/main/baseline-prof.txt` is generated, committed and bundled — the release APK now contains
`assets/dexopt/baseline.prof`. It is produced by `:baselineprofile`, a test module that walks the first
journey (roots screen, one volume opened) on a device:
```bash
./gradlew :app:generateReleaseBaselineProfile # needs a device with API 33+
```
Collection **requires API 33 or a rooted device**: `BaselineProfileRule` refuses this phone (Android 12)
with `Baseline Profile collection requires API 33+, or a rooted device`. It was generated on the `phone35`
AVD (API 35, software-rendered) instead, which also needs `androidx.benchmark.suppressErrors=EMULATOR`
for any macrobenchmark.
**Its effect is not measured here, and that is stated rather than glossed over.** The phone cannot collect
a profile, and the emulator is too noisy to resolve the delta: the same APK measured 7 404 ms median
without the profile and 9 005 ms with it, run to run, because a software-rendered emulator varies by more
than the profile could ever buy. What the profile needs to be justified is one measurement on a physical
API 33+ device, with and without:
```bash
adb shell cmd package compile --reset de.softwareapp_hb.filemanager # no profile
adb shell cmd package compile -m speed-profile -f de.softwareapp_hb.filemanager # profile applied
```
The emulator did answer one open question, though: on that path `FrameTimingMetric` **does** report what
the phone cannot — `frameDurationCpuMs` and `frameOverrunMs` are both present (P50 233 ms and 341 ms for
opening the folder, which is software rendering and not a number anyone should quote). The metric exists
as soon as the device supports frame timelines, so a physical API 33+ phone gives both the profile
delta and the jank figures the interaction benchmarks have been missing.