64431d57570f794bd9aa093ba2a5c51b07c95a35
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
52cf2fc85a |
feat: record the FGS video on the real device, and fix what the take exposed
The declaration's video exists now: store-assets/fgs-demo/foreground-service-demo.mp4, recorded on
the test device (Android 12 / MIUI, 2a2ae895) with INSTALL=0 WARMUP=0, and then checked frame by
frame rather than assumed - the intro at 0 s, the scan starting ("Comparing file signatures...
91/102", 8 s), the shade held open for ~6 s with the live notification ("Finding duplicate photos
/ Looking for visually similar photos... / CANCEL", 13-18 s) while the scan kept running behind
it, and the finished results at the end. Hosting it and pasting the link into the declaration is
what remains.
The script grew two flags, both because an earlier attempt got it wrong:
- WARMUP=0 skips the warm-up and keeps the *cold* scan on camera. A warm scan of this library
takes 5.4 s - less than the notification shade takes to open - so the first phone take filmed an
empty shade, convincingly. The warm-up only ever existed for the emulator's FGS deadline
problem, which a real device does not have.
- INSTALL=0 records with the build already on the device, because MIUI does not allow adb
installs: the command hangs on two on-device prompts (Google Play Protect, then MIUI's own
Installieren) and auto-cancels as INSTALL_FAILED_USER_RESTRICTED if they go unanswered.
Also found by running this against a phone instead of an AVD:
- the trigger is chosen by mode - the intro's "Start scan" when the warm-up is skipped, the
results screen's top-bar "Scan" when it is not - and the lookup result is checked rather than
assumed,
- pacing is a variable now, tightened in the WARMUP=0 path, because the phone's cold scan is only
~20 s and the shade has to be open while it runs,
- the library check counts the demo folder rather than the whole device library: on a phone the
rest of the library is the owner's own photos and is supposed to be there,
- the warm-up became a function and does not run at all under WARMUP=0, and a stray reference to
its `attempt` variable (fatal under `set -u`) is gone.
Step 5 of the checklist now carries the recorded recipe, both flags with the reasons, and two
device facts that were invisible until a phone was attached: MIUI fails every synthetic tap with
INJECT_EVENTS until USB debugging is enabled, and toggling that resets the USB connection onto a
new /dev/bus/usb node. The emulator verdict is compressed to what it is - the platform kills the
app on every scan start there (am_crash ForegroundServiceDidNotStartInTimeException, no am_kill),
with QEMU's -icount clock dilation noted as the one thing that ever worked, and only once.
|
||
|
|
ddc7fb44b0 |
docs: record the QEMU clock-dilation lead for the FGS video
Chasing the video on the emulator found one lever that actually attacks the failure, and it is worth writing down even though it did not hold: emulator -avd phone ... -qemu -icount shift=1,sleep=off Without -icount the guest clock is tied to the host's wall clock, so Android's five-second startForegroundService() deadline means five real seconds however slowly TCG executes - which is what kills the app here every time. With -icount the guest clock advances per executed instruction, and it measured 2.30x slow (30.9 s host to 13.4 s guest uptime). On that boot a scan start succeeded: the app's notification appeared five seconds after the tap and there was no am_crash, the only success recorded on this machine. It then stopped reproducing - later attempts produced neither a notification nor a crash. Two possibilities, and the second is an app-side diagnosability gap: either the tap never reached the app, or ScanService.start() swallowed a ForegroundServiceStartNotAllowedException, which it does silently (it catches IllegalStateException and does nothing with it, so logcat shows nothing at all). Notes say so, and point at SETTLE_SECONDS / WARM_SECONDS for scaling the waits, because a dilated guest is slower at everything - uiautomator dumps included. The script also retries a tap (up to three times, re-reading the coordinates) before falling back to a cold restart, since on a slow emulator the window can still be settling while the accessibility tree already lists the button - and a restart costs another cold start. The recommendation stands: record the take on the phone. |
||
|
|
179bc2cc33 |
fix: prove the FGS video's scan start by notification, not by the service record
The script could report "scan started" on runs where the app was being killed, which sent me
chasing a "mid-scan death" that never happened. The mistake was the signal: dumpsys activity
services lists a service *record* from the moment startForegroundService() is called, so it says
nothing about whether startForeground() was reached - and that gap is exactly what the platform's
deadline measures. logcat's events buffer shows what really happened on every attempt:
am_crash: [..., android.app.ForegroundServiceDidNotStartInTimeException,
Context.startForegroundService() did not then call
Service.startForeground(): .../ScanService]
am_proc_died: [...]
No am_kill, no low-memory record: not memory pressure, and not a crash in the app's own code. The
script now waits for the app's notification, which only exists once startForeground() has been
called, and prints that am_crash line when the service never starts, so a failure is never
mistaken for a success again.
Also in the script:
- let the emulator settle before the run (first-boot work competes for the same CPU) and give the
process time to load its classes before asking it to start a service inside the budget, both
overridable as SETTLE_SECONDS and WARM_SECONDS,
- give up with a non-zero exit and an explicit "record this on a real device" message rather than
carrying on to record a video whose scan never started,
- read the events buffer rather than the main one when reporting the reason.
Verdict for the docs, corrected: this capture cannot be done on a KVM-less emulator, and the
previous "second failure mode" was this one misread. The last crash landed on a process that had
been alive and idle for over a minute, so no amount of warming fixes it - while on the phone the
same build scans 5,363 photos in 20 s with the notification up the whole time. The take belongs on
the phone; the script is the checklist for what it has to show.
|
||
|
|
1ce2f2e1f4 |
feat: record the foreground-service video Play's declaration asks for
The App content > Foreground service permissions form does not just want the justification that
was already written down. Per declared type it asks for four things, one of which is "a link to
a video demonstrating each foreground service feature. The video should demonstrate the steps
the user needs to take in your app in order to trigger the feature."
tools/record-fgs-demo.sh records exactly that journey on a device or emulator: the app on its
intro, the user tapping Start scan, Home, the ongoing notification visible in the shade while
the scan keeps running, and back into the app for the results. It loads the generated demo
library first so no real photo is in frame, writes a checkpoint PNG at each milestone so the
recording can be checked without decoding it, and takes the library off the device afterwards.
The output is git-ignored, like the screenshots.
Four things the script has to get right, each learned by getting it wrong first:
- bounds="[x1,y1][x2,y2]" cannot be parsed by stripping everything but digits: the "][ "
between the corners goes too, which glued y1 to x2 and produced coordinates like
"976 723061" - a tap that lands nowhere and reports no error at all.
- No single text matcher works: an exact match never finds the results card ("2 duplicate
groups"), while a substring match lets "Scan" match both "Start scan" and "Scanned in
39.7 s". Both matchers exist and each call site uses the right one.
- A finished scan leaves the app on its results screen, where the intro's button no longer
exists - tapping those stale coordinates silently does nothing.
- `set -e` plus start="$(failing command)" aborts a run with no message whatsoever, which
cost a whole debugging cycle.
Checklist step 5 now carries all four fields with paste-ready text: the description, the user
impact if the scan is deferred or interrupted (a scan is not deferrable work - the user is
waiting for a result, so there is no WorkManager/JobScheduler fallback), the use case
(Local processing: Other, the only dataSync option that describes a local, user-initiated
scan), and the video link.
Recording the take on this machine is not reliable, and the docs say so rather than pretending
otherwise, because both failures are platform-level rather than app-level:
- a cold app can miss Android's 5-second startForeground deadline and be killed, giving
ForegroundServiceDidNotStartInTimeException -> Force finishing activity, i.e. the launcher
where the scan should have started. The warm-up phase fixes it (a process that has started
the service once never misses), but the fallback path of restarting the app gives the warmth
back again, which is why the recorded scan is now triggered from the results screen's top-bar
"Scan" instead of the intro's button.
- the app also died mid-scan on the emulator, with the launcher on screen afterwards and no
exception of its own anywhere in logcat. No amount of warming fixes that one.
Neither reproduces on the real test device, where the same 22-photo library scans without
incident, so the take belongs on the phone. The script is the checklist for what it must show.
|