Take the picker test off the API 37 gating leg, and stop the SystemUI disable pretending #245

Merged
JMR-dev merged 8 commits from fix/api37-task-snapshot-crash into main 2026-09-06 14:01:57 +00:00
JMR-dev commented 2026-09-06 13:45:25 +00:00 (Migrated from github.com)

The gating E2E API 37 leg failed three of the last ten status_check runs, on PRs
whose diffs could not reach the E2E matrix. This is the cause and the fix, plus two
harness defects the same logcats turned up.

The leg is red because of one test, and it is red by luck

Four gating runs read logcat-first — 34006456986, 34001744574, 34001377499 and the
green 34002313300. Each carries exactly two hasReadColorBufferDma aborts before
the suite starts (both surfaceflinger, during boot and the SystemUI disable) and
exactly one during it: system_server, thread TaskSnapshotPer, always inside
SafPickerRoundTripTest.pickingAFileThroughTheSystemPickerFillsInTheFileCard's window.
Nothing else in the gating set of 57 reaches the mapper at all.

run picker test window the run's only in-suite abort leg
34006456986 02:33:04.2 → 02:34:46.9, failed 02:34:46.845 red, failed: 1
34001744574 00:55:41.4 → 00:57:23.9, failed 00:57:23.794 red, failed: 1
34001377499 00:35:53.3 → 00:36:00.6, passed 00:35:59.662 red, failed: 0
34002313300 00:58:12.7 → 00:58:19.8, passed 00:58:19.218 green

So the test kills the framework on this image whether it passes or not. That is #108,
and #190 is what it costs at scale.

docs/api-37-emulator-crash.md measured this test on 2026-08-24, recorded "passes, 4
aborts in the window", and read the pass/fail column alone. The correction is recorded
beside the original rather than replacing it.

The test now carries @FailsOnEmulatorApi37; baseline 3 → 4, gating 57 → 56. The
marker's wording widens from "does not pass on this image" to "cannot be run on this
image", because this carrier passes about half the time. The single baseline still holds
on the advisory leg — measured, api37-debug run 34008889182 reports 4/4/4, and the
order in that log is Media3, Media3, rotation, picker, so the rotation test takes the
framework down before the picker runs.

Also probed on that image and recorded: there is no shell knob for task snapshots.
Not getprop, settings, device_config or cmd window; dumpsys window shows
mSnapshotEnabled=true with nothing to set it. The marker is the available answer.

When the test itself fails, the abort is the coda

InputDispatcher: No new touched window at (539.0, 525.0) is in both reds and absent
from the green — the tap on the fixture root reaches no window and is discarded,
UiObject2.click() cannot see that, and DocumentsUI logs nothing where the green run
logs a directory load 40 ms later. All four back presses then land on an activity
WindowManager says has not added a window yet, for 63 s.

forceStopThePicker goes around input entirely, so pickTheFixture's whole-picker
retry becomes reachable. Made to bite on a local API 36 emulator, with the picker left
open and pressBack removed: passes with the call (force-stop in logcat, a second
PickActivity, the retry completes the pick), fails without it with the API 37
message verbatim. The unmutated class passes either way, which is why the mutation was
needed.

The SystemUI disable does nothing, and finding that out cost two dispatches

adb shell stop/start are root-only and adbd is not root, so every API 37 leg has printed
Must be root twice — green legs and red alike — and both waits printed their own exhaustion as
an elapsed time (system_server down after ~40 s is what a stop that did nothing looks like).

Giving it adb root made the restart real and made the leg worse. api37-debug run
34010167885: pm disable-user succeeds, the stop lands ~2 s later and kills system_server
before PackageManager flushes its delayed write of package restrictions, the state is gone on the
way back up (NOT DISABLED after the restart, three rounds), and the leg reported
expected: 0, received: 0 — Starting 0 tests.

A 15 s pause before the stop does make the state survive (bisected locally), and it still does not
help: with the package verified disabled-user before and after a clean restart,
com.android.systemui comes up 3 s after system_server regardless. CI's own logcat says the
same with no restart at all — in 34006456986 the package is verified disabled at 02:29:33 and
SystemUI pid 4275 is alive from 02:28:52 for the whole run.

So pm disable-user does not stop SystemUI starting on this image, ever. The restart is
removed from all three copies rather than repaired. What is kept is the 45-second no-new-aborts
window, which was always the load-bearing part — the boot aborts land at 02:28:18 and 02:28:43,
and the wait is what puts instrumentation at 02:32:42, after them rather than inside one. The pm disable-user call is kept because every green leg and every number quoted about this row was
measured with it applied.

Verified on api37-debug run 34011072884: tests start again, and the log now says the true thing
next to the misleading one —

  pm list packages -d: com.android.systemui is in it
  com.android.systemui pid: 1987
final state: com.android.systemui is disabled in pm (it still runs)

One caveat withdrawn, and it is good news. status_check.yml said this row runs "with SystemUI
disabled and the framework restarted under it", that no other leg or Pixel run uses that
configuration, and that anything depending on system UI must not trust it. None of that was ever
true. This row's device configuration is the same as the other four's, and a green here means what
a green at 33–36 means.

One consequence of the fourth marker

The two verification dispatches of the identical configuration reported 4/4/4 and then 4/3/3 —
the abort landing one test earlier, so the picker test never started. The baseline check would
have called that "one now passes". failed is therefore compared only on a run that finished;
expected is compared always, because Starting N tests is printed before anything can abort.
Two cases in e2e-report-shape-test.sh pin the pair, including that a clean run short by one
still deviates.

Conflicts with

#221, which edits the same CLAUDE.md paragraph. Whichever lands second rebases.

Closes #108.

Splits out #246: the disable is now honest about doing nothing, but nobody knows what would
keep SystemUI down on this image, and three knobs still carry names for a thing that does not
happen.

🤖 Generated with Claude Code

The gating `E2E API 37` leg failed three of the last ten `status_check` runs, on PRs whose diffs could not reach the E2E matrix. This is the cause and the fix, plus two harness defects the same logcats turned up. ## The leg is red because of one test, and it is red by luck Four gating runs read logcat-first — 34006456986, 34001744574, 34001377499 and the **green** 34002313300. Each carries exactly two `hasReadColorBufferDma` aborts before the suite starts (both `surfaceflinger`, during boot and the SystemUI disable) and exactly **one** during it: `system_server`, thread `TaskSnapshotPer`, always inside `SafPickerRoundTripTest.pickingAFileThroughTheSystemPickerFillsInTheFileCard`'s window. Nothing else in the gating set of 57 reaches the mapper at all. | run | picker test window | the run's only in-suite abort | leg | |---|---|---|---| | 34006456986 | 02:33:04.2 → 02:34:46.9, **failed** | 02:34:46.845 | red, `failed: 1` | | 34001744574 | 00:55:41.4 → 00:57:23.9, **failed** | 00:57:23.794 | red, `failed: 1` | | 34001377499 | 00:35:53.3 → 00:36:00.6, passed | 00:35:59.662 | red, `failed: 0` | | 34002313300 | 00:58:12.7 → 00:58:19.8, passed | 00:58:19.218 | green | So the test kills the framework on this image whether it passes or not. That is #108, and #190 is what it costs at scale. `docs/api-37-emulator-crash.md` measured this test on 2026-08-24, recorded "passes, 4 aborts in the window", and read the pass/fail column alone. The correction is recorded beside the original rather than replacing it. The test now carries `@FailsOnEmulatorApi37`; baseline 3 → 4, gating 57 → 56. The marker's wording widens from "does not pass on this image" to "cannot be **run** on this image", because this carrier passes about half the time. The single baseline still holds on the advisory leg — measured, `api37-debug` run 34008889182 reports 4/4/4, and the order in that log is Media3, Media3, rotation, picker, so the rotation test takes the framework down before the picker runs. Also probed on that image and recorded: **there is no shell knob for task snapshots**. Not `getprop`, `settings`, `device_config` or `cmd window`; `dumpsys window` shows `mSnapshotEnabled=true` with nothing to set it. The marker is the available answer. ## When the test itself fails, the abort is the coda `InputDispatcher: No new touched window at (539.0, 525.0)` is in both reds and absent from the green — the tap on the fixture root reaches no window and is discarded, `UiObject2.click()` cannot see that, and DocumentsUI logs nothing where the green run logs a directory load 40 ms later. All four back presses then land on an activity WindowManager says has not added a window yet, for 63 s. `forceStopThePicker` goes around input entirely, so `pickTheFixture`'s whole-picker retry becomes reachable. Made to bite on a local API 36 emulator, with the picker left open and `pressBack` removed: **passes** with the call (force-stop in logcat, a second `PickActivity`, the retry completes the pick), **fails** without it with the API 37 message verbatim. The unmutated class passes either way, which is why the mutation was needed. ## The SystemUI disable does nothing, and finding that out cost two dispatches `adb shell stop`/`start` are root-only and adbd is not root, so every API 37 leg has printed `Must be root` twice — green legs and red alike — and both waits printed their own exhaustion as an elapsed time (`system_server down after ~40 s` is what a stop that did nothing looks like). Giving it `adb root` made the restart real and **made the leg worse**. `api37-debug` run 34010167885: `pm disable-user` succeeds, the stop lands ~2 s later and kills `system_server` before PackageManager flushes its delayed write of package restrictions, the state is gone on the way back up (`NOT DISABLED after the restart`, three rounds), and the leg reported `expected: 0, received: 0` — `Starting 0 tests`. A 15 s pause before the stop does make the state survive (bisected locally), and it still does not help: with the package verified `disabled-user` before **and** after a clean restart, `com.android.systemui` comes up 3 s after `system_server` regardless. CI's own logcat says the same with no restart at all — in 34006456986 the package is verified disabled at 02:29:33 and SystemUI pid 4275 is alive from 02:28:52 for the whole run. **So `pm disable-user` does not stop SystemUI starting on this image, ever.** The restart is removed from all three copies rather than repaired. What is kept is the 45-second no-new-aborts window, which was always the load-bearing part — the boot aborts land at 02:28:18 and 02:28:43, and the wait is what puts instrumentation at 02:32:42, after them rather than inside one. The `pm disable-user` call is kept because every green leg and every number quoted about this row was measured with it applied. Verified on `api37-debug` run 34011072884: tests start again, and the log now says the true thing next to the misleading one — ``` pm list packages -d: com.android.systemui is in it com.android.systemui pid: 1987 final state: com.android.systemui is disabled in pm (it still runs) ``` **One caveat withdrawn, and it is good news.** `status_check.yml` said this row runs "with SystemUI disabled and the framework restarted under it", that no other leg or Pixel run uses that configuration, and that anything depending on system UI must not trust it. None of that was ever true. This row's device configuration is the same as the other four's, and a green here means what a green at 33–36 means. ## One consequence of the fourth marker The two verification dispatches of the identical configuration reported 4/4/4 and then 4/3/3 — the abort landing one test earlier, so the picker test never started. The baseline check would have called that "one now passes". `failed` is therefore compared only on a run that finished; `expected` is compared always, because `Starting N tests` is printed before anything can abort. Two cases in `e2e-report-shape-test.sh` pin the pair, including that a *clean* run short by one still deviates. ## Conflicts with #221, which edits the same CLAUDE.md paragraph. Whichever lands second rebases. Closes #108. Splits out #246: the disable is now honest about doing nothing, but nobody knows what *would* keep SystemUI down on this image, and three knobs still carry names for a thing that does not happen. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.