You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Linux_android_emu android_hardware_smoke_opengles_instrumented_tests is 2.04% flaky #193557
The post-submit test builder Linux_android_emu android_hardware_smoke_opengles_instrumented_tests had a flaky ratio 2.04% for the past (up to) 100 commits, which is above our 2.00% threshold.
This and #193207 represent a failure case which I'm not sure how to resolve. Sometimes the environment is in a bad state when the test starts. I implemented a detection and retry mechanism for this.
║ INFRASTRUCTURE FAILURE: EGL / graphics driver pipeline collapsed on emulator after 2 attempts.
However, it seems either no retries are needed, or all retries are exhausted. If the test starts in a bad state, it fails that way across all retries. Ideally there would be some way to avoid this from happening, but I don't have any ideas at the moment.
I took another look at the failures. I didn't see any pattern with regards to a particular machine, and I found two distinct emulator graphics failure modes behind this flakiness.
The first and more common failure mode (#194928, #191348, #193205) is a SurfaceFlinger display wedge where the 3 platform view tests always produce solid-black screenshots while the non-platform view tests pass. During test startup, CI launches the emulator with hw.gpu.enabled = true and hw.gpu.mode = swangle_indirect, while restoring a default_boot QuickBoot snapshot saved with hw.gpu.enabled=no and hw.gpu.mode=auto. Every CI boot logs WARNING Snapshot.cpp:365 | change of renderer detected and ERROR FrameBuffer.cpp:3642 | Failed to find ColorBuffer:0. Roughly 99% of the time, SurfaceFlinger recovers after waking from the snapshot and binds a new window surface against swangle_indirect. On roughly 1% of boots, that post-restore re-initialization fails (EmulationGl.cpp:702 | Failed to find emulated EGL config 4 and FrameBuffer.cpp:3193 | Failed to create EmulatedEglWindowSurface), leaving the thawed SurfaceFlinger process holding stale pre-snapshot EGLConfig and ColorBuffer handles. The first 6 tests still pass because the newly launched app process initializes fresh GPU state against swangle_indirect and reads pixels in-process via RenderRepaintBoundary.toImage(), whereas the 3 platform view tests take screenshots with adb screencap (or UiAutomation.takeScreenshot()), which reads from SurfaceFlinger's broken display surface.
The second failure mode (#193557) is a native host-GPU-pipe crash during app launch. Occasionally a newly launched app process fails to open its guest-to-host GPU pipe (E EGL_emulation: Failed to establish connection with the host, W libEGL: eglInitialize(...) failed (EGL_SUCCESS), and SIGSEGV in libEGL.so on OpenGLES, or E MESA: vulkan: Failed to get host connection and ErrorDeviceLost on Vulkan). When that crash happens right after the Dart VM prints its service URI, flutter drive hangs until LUCI kills the entire shard on timeout.
I tried to reproduce the QuickBoot SurfaceFlinger wedge locally first. I created an API 35 google_apis (userdebug) AVD and cold-booted it headless (emulator -avd ci_repro_api35 -no-window -no-audio -no-boot-anim), which defaults in config.ini to hw.gpu.enabled=no, hw.gpu.mode=auto, and fastboot.forceFastBoot=yes. Running adb emu kill sends a graceful shutdown over the emulator console, triggering QEMU's QuickBoot exit hook to save default_boot automatically (Saving snapshot 'default_boot'). When I tried to restore that snapshot with a different renderer (emulator -avd ci_repro_api35 -no-window -gpu host -no-snapshot-save and -gpu swangle), my local Android Emulator 36.5.11.0 binary (CI pins 35.3.11 and 35.4.9) rejected the cross-renderer snapshot outright with WARNING | Change of GLES renderer detected (or Change of Vulkan renderer detected) followed by Error -1 from the snapshot callback -> Failed to load snapshot 'default_boot' -> The emulator is starting from scratch. Reason: different renderer configured. That means newer 36.x emulator binaries treat cross-renderer QuickBoot loads as unsafe, though it also meant 36.5.11.0 cold-booted cleanly instead of entering the stale-snapshot SurfaceFlinger wedge.
While I couldn't enter the 35.x snapshot wedge locally on 36.5.11.0, I was able to reproduce the second failure mode (the native host-GPU-pipe startup crash and flutter drive hang) on that booted API 35 emulator by running adb root and chmod 0660 /dev/goldfish_pipe_dprctd /dev/goldfish_address_space so the already-running surfaceflinger kept its open file descriptors while newly launched app processes could not open the host GPU transport:
On OpenGLES, the app hit the same logcat failure sequence seen in #193557: E EGL_emulation: Failed to establish connection with the host, W libEGL: eglInitialize(...) failed (EGL_SUCCESS), and SIGSEGV in libEGL.so. That caught an important edge case in our logcat filter: excluding bare 'EGL_SUCCESS' (intended for HWUI's error = EGL_SUCCESS probe) masked libEGL's real eglInitialize(...) failed (EGL_SUCCESS) failure when libEGL_emulation returned EGL_FALSE without setting a TLS error code.
On Vulkan, the app hit the Vulkan equivalent (E MESA: vulkan: Failed to get host connection, Could not create Vulkan instance: ErrorDeviceLost, and Could not create surface from invalid Android context), crashing right after the Dart VM printed its service URI and reproducing the exact FlutterDriver VM service connection hang from CI.
Testing against that live failure mode also showed why our existing retries weren't working. _runRetryLoop ran flutter drive via runCommand, which called foundError on attempt 1 and permanently marked the shard failed even if attempt 2 had ever passed (in CI logs, attempt 2 never passed anyway because the display stayed wedged). App-level retries (ActivityScenario.recreate() and flutter drive --no-build) only restarted the app Activity without touching SurfaceFlinger. We can instead call adb shell stop -> adb shell start to respawn surfaceflinger and zygote, though we have to set sys.boot_completed to 0 beforehand because stop leaves it at 1 and our readiness poll would otherwise launch attempt 2 before userspace finishes booting back up. On native startup crashes, the hung flutter drive process never reached attempt 2 without checking adb shell pidof on stalled VM connections and sending SIGKILL (flutter_tools catches SIGTERM and exits 0).
The logcat checks had two bugs of their own. FlutterActivityTest logged its attempt marker with Log.i while logcat -d --pid=$pid *:W stripped all INFO lines so post-marker checks never armed, and both the Kotlin and Dart filters matched benign HWUI warnings like EGL_SWAP_BEHAVIOR_PRESERVED and Davey! instead of explicit fatal graphics errors.
With a background watcher on the emulator restoring /dev/goldfish_pipe_dprctd and /dev/goldfish_address_space permissions (chmod 0666) upon sys.boot_completed=0, attempt 1 detected the Vulkan crash, killed the hung flutter drive, restarted surfaceflinger and zygote64 to fresh PIDs, and passed all 9 golden tests on attempt 2 (+9) with shard exit code 0.
Although we could only test the host-pipe crash recovery locally, we have strong evidence that adb shell stop and adb shell start will also recover the QuickBoot SurfaceFlinger wedge in CI: in every wedged CI run, host QEMU's swangle_indirect renderer itself is healthy — the freshly spawned Flutter app process creates valid host GPU state and passes all 6 offscreen Impeller tests, and Android HWUI inside that app creates its own EGLSurface without config errors. Only the long-lived surfaceflinger process thawed out of the default_boot RAM snapshot held stale pre-snapshot EGLConfig (config 4) and ColorBuffer handles. Killing and respawning surfaceflinger forces a fresh eglInitialize / eglChooseConfig / EmulatedEglWindowSurface handshake against swangle_indirect just like a newly launched process, which we'll be able to confirm directly in CI logs via the new Restarting Android userspace before retry... message.
I'll land the retry and userspace-restart fixes first, and as a separate work item, I recommend we rebake the CIPD AVD snapshots with matching -gpu swangle_indirect flags so this mismatch never happens. Maybe we should also upgrade the CIPD emulator binary from 35.x to 36.x or higher to get the behavior that rejects cross-renderer snapshots.
Activity
andywolff commentedon Oct 5, 2026
This and #193207 represent a failure case which I'm not sure how to resolve. Sometimes the environment is in a bad state when the test starts. I implemented a detection and retry mechanism for this.
However, it seems either no retries are needed, or all retries are exhausted. If the test starts in a bad state, it fails that way across all retries. Ideally there would be some way to avoid this from happening, but I don't have any ideas at the moment.
gaaclarke commentedon Oct 12, 2026
moving to p1 since they are suppresed
andywolff commentedon Nov 3, 2026
I took another look at the failures. I didn't see any pattern with regards to a particular machine, and I found two distinct emulator graphics failure modes behind this flakiness.
The first and more common failure mode (
#194928,#191348,#193205) is aSurfaceFlingerdisplay wedge where the 3 platform view tests always produce solid-black screenshots while the non-platform view tests pass. During test startup, CI launches the emulator withhw.gpu.enabled = trueandhw.gpu.mode = swangle_indirect, while restoring adefault_bootQuickBoot snapshot saved withhw.gpu.enabled=noandhw.gpu.mode=auto. Every CI boot logsWARNING Snapshot.cpp:365 | change of renderer detectedandERROR FrameBuffer.cpp:3642 | Failed to find ColorBuffer:0. Roughly 99% of the time,SurfaceFlingerrecovers after waking from the snapshot and binds a new window surface againstswangle_indirect. On roughly 1% of boots, that post-restore re-initialization fails (EmulationGl.cpp:702 | Failed to find emulated EGL config 4andFrameBuffer.cpp:3193 | Failed to create EmulatedEglWindowSurface), leaving the thawedSurfaceFlingerprocess holding stale pre-snapshotEGLConfigandColorBufferhandles. The first 6 tests still pass because the newly launched app process initializes fresh GPU state againstswangle_indirectand reads pixels in-process viaRenderRepaintBoundary.toImage(), whereas the 3 platform view tests take screenshots withadb screencap(orUiAutomation.takeScreenshot()), which reads fromSurfaceFlinger's broken display surface.The second failure mode (
#193557) is a native host-GPU-pipe crash during app launch. Occasionally a newly launched app process fails to open its guest-to-host GPU pipe (E EGL_emulation: Failed to establish connection with the host,W libEGL: eglInitialize(...) failed (EGL_SUCCESS), andSIGSEGVinlibEGL.soon OpenGLES, orE MESA: vulkan: Failed to get host connectionandErrorDeviceLoston Vulkan). When that crash happens right after the Dart VM prints its service URI,flutter drivehangs until LUCI kills the entire shard on timeout.I tried to reproduce the QuickBoot
SurfaceFlingerwedge locally first. I created an API 35google_apis(userdebug) AVD and cold-booted it headless (emulator -avd ci_repro_api35 -no-window -no-audio -no-boot-anim), which defaults inconfig.initohw.gpu.enabled=no,hw.gpu.mode=auto, andfastboot.forceFastBoot=yes. Runningadb emu killsends a graceful shutdown over the emulator console, triggering QEMU's QuickBoot exit hook to savedefault_bootautomatically (Saving snapshot 'default_boot'). When I tried to restore that snapshot with a different renderer (emulator -avd ci_repro_api35 -no-window -gpu host -no-snapshot-saveand-gpu swangle), my local Android Emulator36.5.11.0binary (CI pins35.3.11and35.4.9) rejected the cross-renderer snapshot outright withWARNING | Change of GLES renderer detected(orChange of Vulkan renderer detected) followed byError -1 from the snapshot callback->Failed to load snapshot 'default_boot'->The emulator is starting from scratch. Reason: different renderer configured. That means newer36.xemulator binaries treat cross-renderer QuickBoot loads as unsafe, though it also meant36.5.11.0cold-booted cleanly instead of entering the stale-snapshotSurfaceFlingerwedge.While I couldn't enter the
35.xsnapshot wedge locally on36.5.11.0, I was able to reproduce the second failure mode (the native host-GPU-pipe startup crash andflutter drivehang) on that booted API 35 emulator by runningadb rootandchmod 0660 /dev/goldfish_pipe_dprctd /dev/goldfish_address_spaceso the already-runningsurfaceflingerkept its open file descriptors while newly launched app processes could not open the host GPU transport:#193557:E EGL_emulation: Failed to establish connection with the host,W libEGL: eglInitialize(...) failed (EGL_SUCCESS), andSIGSEGVinlibEGL.so. That caught an important edge case in our logcat filter: excluding bare'EGL_SUCCESS'(intended forHWUI'serror = EGL_SUCCESSprobe) maskedlibEGL's realeglInitialize(...) failed (EGL_SUCCESS)failure whenlibEGL_emulationreturnedEGL_FALSEwithout setting a TLS error code.E MESA: vulkan: Failed to get host connection,Could not create Vulkan instance: ErrorDeviceLost, andCould not create surface from invalid Android context), crashing right after the Dart VM printed its service URI and reproducing the exactFlutterDriverVM service connection hang from CI.Testing against that live failure mode also showed why our existing retries weren't working.
_runRetryLoopranflutter driveviarunCommand, which calledfoundErroron attempt 1 and permanently marked the shard failed even if attempt 2 had ever passed (in CI logs, attempt 2 never passed anyway because the display stayed wedged). App-level retries (ActivityScenario.recreate()andflutter drive --no-build) only restarted the appActivitywithout touchingSurfaceFlinger. We can instead calladb shell stop->adb shell startto respawnsurfaceflingerandzygote, though we have to setsys.boot_completedto0beforehand becausestopleaves it at1and our readiness poll would otherwise launch attempt 2 before userspace finishes booting back up. On native startup crashes, the hungflutter driveprocess never reached attempt 2 without checkingadb shell pidofon stalled VM connections and sendingSIGKILL(flutter_toolscatchesSIGTERMand exits0).The logcat checks had two bugs of their own.
FlutterActivityTestlogged its attempt marker withLog.iwhilelogcat -d --pid=$pid *:Wstripped allINFOlines so post-marker checks never armed, and both the Kotlin and Dart filters matched benignHWUIwarnings likeEGL_SWAP_BEHAVIOR_PRESERVEDandDavey!instead of explicit fatal graphics errors.With a background watcher on the emulator restoring
/dev/goldfish_pipe_dprctdand/dev/goldfish_address_spacepermissions (chmod 0666) uponsys.boot_completed=0, attempt 1 detected the Vulkan crash, killed the hungflutter drive, restartedsurfaceflingerandzygote64to fresh PIDs, and passed all 9 golden tests on attempt 2 (+9) with shard exit code0.Although we could only test the host-pipe crash recovery locally, we have strong evidence that
adb shell stopandadb shell startwill also recover the QuickBootSurfaceFlingerwedge in CI: in every wedged CI run, host QEMU'sswangle_indirectrenderer itself is healthy — the freshly spawned Flutter app process creates valid host GPU state and passes all 6 offscreen Impeller tests, and AndroidHWUIinside that app creates its ownEGLSurfacewithout config errors. Only the long-livedsurfaceflingerprocess thawed out of thedefault_bootRAM snapshot held stale pre-snapshotEGLConfig(config 4) andColorBufferhandles. Killing and respawningsurfaceflingerforces a fresheglInitialize/eglChooseConfig/EmulatedEglWindowSurfacehandshake againstswangle_indirectjust like a newly launched process, which we'll be able to confirm directly in CI logs via the newRestarting Android userspace before retry...message.I'll land the retry and userspace-restart fixes first, and as a separate work item, I recommend we rebake the CIPD AVD snapshots with matching
-gpu swangle_indirectflags so this mismatch never happens. Maybe we should also upgrade the CIPD emulator binary from35.xto36.xor higher to get the behavior that rejects cross-renderer snapshots.Fix android_hardware_smoke_test retry mechanisms (flutter#195708)