diff --git a/docs/PLAY_RELEASE_CHECKLIST.md b/docs/PLAY_RELEASE_CHECKLIST.md index acffc89..b20579a 100644 --- a/docs/PLAY_RELEASE_CHECKLIST.md +++ b/docs/PLAY_RELEASE_CHECKLIST.md @@ -308,12 +308,20 @@ action except the items marked **[code]**. `startForeground()` inside Android's budget — while on the phone this app scans a 5,363-photo library in 20 s with the notification up throughout. - An earlier version of this note claimed a second, unexplained mid-scan death. That was - this same failure misread: the script's old "is a scan running?" check matched the - service *record*, which exists from the moment `startForegroundService()` is called, so - it reported success on runs that were already dying. `tools/record-fgs-demo.sh` now waits - for the app's notification instead, which is the only honest proof the service started, - and reports the `am_crash` line when it never does. + One emulator-side lever is worth knowing, because it is the only thing that ever got this + app's foreground service started on this machine: QEMU's virtual instruction counter + dilates the **guest** clock, so Android's deadline is measured against time that passes + more slowly than the host's. Booting with `-qemu -icount shift=1,sleep=off` made the guest + clock run **2.30× slow** (measured: 30.9 s of host time to 13.4 s of guest uptime), and on + that boot a scan start *worked* — the app's notification appeared five seconds after the + tap, with no `am_crash`, the only success recorded here. It then stopped working: later + attempts produced neither a notification nor a crash, which means the tap never reached + the app, or `ScanService.start()` silently swallowed a + `ForegroundServiceStartNotAllowedException` (it catches `IllegalStateException` and does + nothing with it, so that path leaves no trace in logcat at all — a diagnosability gap + worth a log line if this is ever chased further). So treat `-icount` as a lead to retry + with patience rather than a recipe to rely on, and use `SETTLE_SECONDS` / `WARM_SECONDS` + to scale this script's waits for a dilated clock. The declaration is **per type**: if a new foreground-service type is ever added to the manifest, it has to be declared here too. diff --git a/tools/record-fgs-demo.sh b/tools/record-fgs-demo.sh index c7bb72a..2bc193d 100755 --- a/tools/record-fgs-demo.sh +++ b/tools/record-fgs-demo.sh @@ -29,6 +29,15 @@ # # It also writes a checkpoint PNG at each milestone, so the recording can be checked without # decoding the video. `ffprobe` is used for the duration when it is installed. +# +# On a host with no KVM the one lever that ever got the service started here was QEMU's clock +# dilation, which makes Android's deadline be measured in slower time than the host's: +# +# emulator -avd ... -qemu -icount shift=1,sleep=off # guest clock ran 2.30x slow +# +# That worked once and then not again, so treat it as a lead rather than a recipe: scale the two +# timing knobs up for a dilated clock (the guest is slower at everything, dumps included) and expect +# to iterate. docs/PLAY_RELEASE_CHECKLIST.md step 5 has the long version of this note. set -euo pipefail here="$(cd "$(dirname "$0")" && pwd)" @@ -209,9 +218,23 @@ while [ "$attempt" -lt 4 ]; do started=no # dumpsys only while the service starts: every `uiautomator dump` spawns a JVM on the device and # competes for exactly the CPU that the five-second deadline is measured against. - for _ in $(seq 1 12); do - if fgs_started; then started=yes; break; fi - sleep 3 + for tap_try in 1 2 3; do + for _ in $(seq 1 12); do + if fgs_started; then started=yes; break; fi + sleep 3 + done + if [ "$started" = yes ]; then break; fi + printf ' tap %s did not start the service' "$tap_try" + # On a slowed emulator the window can still be settling even though the accessibility tree + # already lists the button, so the tap goes nowhere. Tapping again is far cheaper than the + # cold restart the outer loop would otherwise resort to. + if start="$(wait_for 'Start scan' 60)"; then + printf ' - tapping again\n' + "${adb[@]}" shell input tap $start + else + printf ' - the intro is gone, so restarting instead\n' + break + fi done if [ "$started" = yes ]; then printf ' attempt %s: the service started (notification posted)\n' "$attempt"