Skip to content

ci(android): un-flake the emulator integration-test job - #251

Merged
ddfreiling merged 1 commit into
Notalib:mainfrom
ddfreiling:fix/android-emulator-boot-flake
Sep 22, 2026
Merged

ddfreiling merged 1 commit into
Notalib:mainfrom
ddfreiling:fix/android-emulator-boot-flake

Conversation

@ddfreiling

Copy link
Copy Markdown
Member

Problem

The API 24 emulator job fails about one run in five, and it is not a boot failure — the emulator boots fine. reactivecircus/android-emulator-runner presses the unlock key the instant sys.boot_completed reads 1, with no hook in between:

await waitForDevice(port, emulatorBootTimeout);
await adb(port, `shell input keyevent 82`);

A restored quickboot snapshot sets that property before its services are back, so the keypress is killed (exit 137) and the step dies before our script: runs — which is also why the failed runs upload no diagnostics. Upstream issue #489 is open; the fix (#495) is unmerged, so bumping the action does not help.

Signature, identical across every affected run:

INFO | Successfully loaded snapshot 'default_boot' using 3563 ms
Emulator booted.
[command] .../adb -s emulator-5554 shell input keyevent 82
##[error]The process '.../adb' failed with exit code 137

Survey of the last 60 CI runs:

Job Failures Concluded Of those, this bug
API 24 9 42 6
API 36 1 48 0

Fix

A sleep cannot be inserted where it is needed — the action exposes only pre-emulator-launch-script (before launch) and script (after the keypress). So, two guards instead:

  • Snapshot a settled system. The AVD-snapshot step now idles (script: sleep 60) before teardown, so the cached snapshot captures a system that has finished starting rather than one mid-startup. Only runs on a cache miss.
  • Retry, narrowly. Run integration tests is continue-on-error, and retries once only when android-test-api<N>.log is absent. A missing log proves the suite never started; a real test failure always leaves its log behind and is never re-run.

Both attempts call a new shared composite action, .github/actions/run-android-integration-tests, so the two paths cannot drift. The AVD cache key now hashes that file too.

Verification

  • actionlint clean; both YAML files parse.
  • The flutter test one-liner moved byte-identical (diffed), apart from matrix. → inputs..
  • Editing these files changes the AVD cache key, so the settled snapshots regenerate on the first run of this branch.

Not verified: this has not run in CI yet. The retry logic is sound on paper; the settle sleep is well-reasoned but unproven — the failure is intermittent, so a single green run will not confirm it either. Worth watching the API 24 job over the next couple of weeks.

No CHANGELOG.md entry: CI-only, nothing a consumer upgrading the package would notice.

🤖 Generated with Claude Code

android-emulator-runner presses the unlock key the instant
`sys.boot_completed` reads 1, with no hook in between. A restored
quickboot snapshot sets that property before its services are back,
so the keypress is killed (exit 137) and the step dies before our
`script:` ever runs. Roughly one API 24 job in five over the last 60
CI runs; API 36 is unaffected. Upstream fix is open but unmerged
(ReactiveCircus/android-emulator-runner#489).

Two guards. The AVD-snapshot step now idles before teardown, so the
cached snapshot captures a settled system instead of one mid-startup.
And the test step retries once, but only when
`android-test-api<N>.log` is absent — a missing log proves the suite
never started, while a real test failure always leaves its log and
must stand.

Both attempts call a new shared composite action so the two paths
cannot drift.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ddfreiling
ddfreiling merged commit faa62c8 into Notalib:main Sep 22, 2026
23 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant