Repository navigation
Dismiss system ANR dialogs during the emulator screenshot capture - #137
Merged
Merged
Conversation
On a fraction of captures the first emulator attempt shows a "Pixel Launcher isn't responding" dialog. It takes input focus, so uiautomator dumps only the dialog and every wait times out behind it for the rest of the attempt: about 8.5 minutes of dead waiting before the retry boots a fresh emulator and succeeds. Two layers, both in the shared capture script: - On CI, set Settings.Global hide_error_dialogs=1 once the framework is up, so an ANR makes the system kill the stuck process instead of asking. The key, its live observer and that behaviour are in AOSP 14 through main. - ui_dump taps Wait on any "isn't responding" dialog it sees, logs one line naming the app, and reports the dump as stale so the caller dumps again. It stops after five presses, so a dialog that Wait cannot clear ends in the usual wait failures instead of a flood of log lines. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0129RzhbEE2cboMcYyZMuxqX
Contributor
ScreenshotsCaptured from the demo build at af5a180. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
On a fraction of screenshot captures the first emulator attempt is dead on arrival: a system "Pixel Launcher isn't responding" dialog takes input focus,
uiautomator dumpreturns only that dialog, and every wait incapture-screenshots.shtimes out behind it. The attempt spends about 8.5 minutes waiting, fails with all six screenshots missing, and only the retry (a fresh emulator) succeeds. This PR makes the script clear the dialog instead of waiting behind it. Only.github/scripts/capture-screenshots.shchanges (+36/-2).Related to #125: a stop-gap while the emulator pipeline exists; it does not change that proposal.
Root cause and evidence
Every case has the same signature:
... pull did not lead to 'AA:BB:CC:DD:EE:01' (attempt 3),! scan results never appeared,state at scan-missing: ... text="Pixel Launcher isn't responding" ... text="Close app" text="Wait",! simulated car not listed,! dark cars list not reachable, sixmissing required screenshot, and a first attempt of about 10 minutes. The samestate at ...line repeats atcar-not-listed,dark-carsandfinal, so uiautomator never sees anything but the dialog.Hit rates (first attempt, verified from the step timings; the dialog itself confirmed in the logs where noted):
main, so neither fixed it). Dialog confirmed in all four logs.Why it is slow: the waits count loop iterations, not seconds. Each iteration is a uiautomator dump + pull +
sleep 1, about 3 s on these emulators, so a "20 s" wait takes about 62 s, and the failing path chains several of them.What raises the dialog is not proven. In all 9 failing attempts the runner's own post-boot
input keyevent 82took 7-10.5 s (6.6 s or less in 9 of 10 clean attempts), which suggests Pixel Launcher is still starting and the unlock key times out, so the dialog is probably already up when this script starts. The failed attempt's logcat is not available: the retry step runsrm -rf screenshots, which deletesscreenshots/debug/.Change
adb shell settings put global hide_error_dialogs 1, plus a one-line read-back in the log (hide_error_dialogs=1). Gated onCIbecause the setting persists on the AVD, so local runs (tools/demo-emulator.sh --capture) leave it alone.ui_dumptaps Wait when the dump contains an "isn't responding" dialog, using the button's bounds from the dump, logs one line naming the app (... dismissing "Pixel Launcher isn't responding" dialog), and returns failure so the caller re-dumps. It stops after five presses, so a dialog that Wait cannot clear ends in the usual wait failures instead of a flood of log lines.What I checked in AOSP for
hide_error_dialogs(sources from theaosp-mirror/platform_frameworks_basemirror):core/java/android/provider/Settings.java:Settings.Global.HIDE_ERROR_DIALOGS = "hide_error_dialogs", documented as "If nonzero, all system error dialogs will be hidden. For example, the crash and ANR dialogs will not be shown, and the system will just proceed as if they had been accepted by the user." (@hide,@TestApi.)ActivityTaskManagerService: aSettingObserverwatches that URI and callsupdateShouldShowDialogsLocked(...)on change, so a runtimesettings puttakes effect without a reboot;canShowErrorDialogs()returnsmShowDialogs && ....AppErrors.handleShowAnrUi: the dialog is shown onlyif (canShowErrorDialogs() || showBackground); otherwise "Just kill the app if there is no dialog to be shown" (doKill = true).android-14.0.0_r1(API 34),android14-qpr2-release,android14-qpr3-release,android15-release,android16-releaseandmain. The workflows pinapi-level: 34,google_apis,x86_64(job log:system-images;android-34;google_apis;x86_64).Hiding the dialog has one cost: the system kills the unresponsive process instead of pausing it. That applies to the app under test too; it has never ANR'd in any log I read, and the fallback alone would have pressed Wait. If you prefer the fallback only, drop the
if [ -n "${CI:-}" ]block. In the logged failures the dialog was already up at the first dump, so the fallback does the work and prevention only covers dialogs raised later.Expected saving
A hit costs about 10 minutes for the dead first attempt plus about 4 for the retry (about 14 in total) against about 4.5 for a clean capture, so about 9-10 minutes per hit on main previews and PR runs. At the rates above that is roughly 1 main preview in 3 and 1 PR run in 7. It also removes the case where both attempts hit the dialog and the run fails (the Demo smoke failure).
Not changed (possible follow-ups)
rm -rf screenshotsin the four retry steps (android.ymlx2,demo-smoke.yml,pr-screenshots.yml). Moving them aside needs edits in three workflows, so it is out of scope here; it is also why the trigger above is unproven.Type
Testing
Verified locally:
bash -nandshellcheck0.10.0 (-S style) are clean on the whole script (it was clean before).adbdrives the whole script end to end (a small state machine for the cars list, car view and Settings; the dialog is modelled on the structure in the CI dumps: six empty containers, the title, "Close app", "Wait"). Sleeps are stubbed out because the waits count iterations.! scan results never appeared,state at scan-missing: ... "Pixel Launcher isn't responding" ... "Wait",! simulated car not listed,! dark cars list not reachable, 6xmissing required screenshot(the CI signature reproduced)... dismissing "Pixel Launcher isn't responding" dialog, no screenshot shows the dialogCIsethide_error_dialogs=1read backCIunset (local), with and without dialoghide_error_dialogsuntouched; dialog still dismissedNot verified:
Nothing ran on a real emulator: there is no Android SDK or emulator here (
dl.google.comis blocked). Thehide_error_dialogseffect is verified from AOSP source only, and the real dialog's Wait bounds and the tap on API 34 are untested.This PR's own
PR screenshotsrun will most likely not hit the dialog (5 of 36 PR runs did), so a green run proves little; the fixtures above are the proof. The capture log will showhide_error_dialogs=1, confirming the prevention step ran, and a... dismissing ... dialogline if the dialog does appear../gradlew :core:test(not applicable: CI script only)./gradlew :app:testDebugUnitTest(not applicable)./gradlew :app:lintDebug(not applicable)Real car (not applicable)
Checklist
expected.txtregenerated, not hand-edited (not applicable)SPDX-License-Identifier: AGPL-3.0-only(no new files)🤖 Generated with Claude Code
https://claude.ai/code/session_0129RzhbEE2cboMcYyZMuxqX
Generated by Claude Code