Files
LibreMediaConverter/docs/api-37-emulator-crash.md
T
JMR-devandClaude Opus 5 4e6fe6b75a Drop API 37 from the E2E matrix and write down why
The android-37.0 emulator image crash-loops surfaceflinger inside its own
gralloc mapper: RegionSamplingThread calls GraphicBuffer::lock, which reaches
GoldfishMapper::readFromHost, which asserts that the host has not negotiated
ReadColorBufferDma. It has, so surfaceflinger aborts, restarts, and aborts
again. Nothing this app does can survive that, and it reproduces on a GitHub
runner under swiftshader_indirect and on a workstation under -gpu host alike.

There is no ATD image at android-37.0 to fall back to, and -feature -GLDMA is
accepted by the emulator but does not prevent the assertion.

Correcting the previous commit, which is already pushed so its message stands:
ram-size was not the cause of that failure. Setting it did move the job from
failing at install to failing during the test run, which is how the real
crash became visible, but at 2560M the guest had 1.5 GB free when it died.
The setting is kept because the emulator's own floor varies by API level --
2048M at 33, 2560M at 34 to 36 -- and pinning it makes the matrix uniform.

Also corrected: a comment claiming this could not be reproduced locally. It
can, and the local crash was the same one all along.

Dropped the dmesg probe. adb shell is not root, so klogctl is denied and it
only ever printed a permission error -- which a later reader would reasonably
misread as "no OOM kills".

docs/api-37-emulator-crash.md carries the evidence, the ruled-out fixes, the
reproduction, and how to file it upstream, so re-adding the row later starts
from what is already known rather than from scratch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 21:35:04 -05:00

8.9 KiB

API 37 is not tested in CI: a crash in Google's android-37.0 emulator image

Status: open upstream, worked around by removing API 37 from the E2E matrix Last verified: 2026-08-21, against emulator 37.1.11.0 and system image revision 6

minSdk is 33 and targetSdk is 37, and the E2E matrix in status_check.yml runs API 33 through 36. API 37 is deliberately absent. This is why.

Summary

The android-37.0 emulator system image crashes surfaceflinger in a loop. The app under test never gets a working framework, so every instrumented test fails regardless of what the app does. The bug is in the emulator image, not in this project.

The crash is an assertion inside the emulator's own gralloc implementation:

Executable:    /system/bin/surfaceflinger
signal 6 (SIGABRT), code -1 (SI_QUEUE), tid: RegionSampling
Abort message: 'Assertion failed: !rcEnc->featureInfo()->hasReadColorBufferDma'

  #03  mapper.ranchu.so   GoldfishMapper::readFromHost(cb_handle_t const&) const
  #04  mapper.ranchu.so   GoldfishMapper::GoldfishMapper()::'lambda'(...)::__invoke
  #05  libui.so           android::Gralloc5Mapper::lock(...)
  #06  libui.so           android::GraphicBufferMapper::lock(...)
  #07  libui.so           android::GraphicBuffer::lockAsync(...)
  #08  libui.so           android::GraphicBuffer::lock(...)
  #09  surfaceflinger     android::RegionSamplingThread::threadMain()

RegionSamplingThread is SystemUI's navigation-bar luma sampling. It calls GraphicBuffer::lock, which routes into GoldfishMapper::readFromHost, which asserts that the host has not negotiated the ReadColorBufferDma capability. On this image the host has, so the assertion fails and surfaceflinger aborts. It restarts and aborts again.

Impact

The failure surfaces in two different ways depending on how far the job gets, which is why it took several rounds to identify:

Guest RAM Where it dies What CI reports
1536 MB during APK install Unknown failure: cmd: Can't find service: package
2560 MB during the test run There were failing tests — all of them

At 2560 MB the install succeeds and the tests actually execute, then fail wholesale. The first failure in the report is misleading:

kotlin.UninitializedPropertyAccessException: lateinit property output has not
    been initialized
    at Media3EngineTest.tearDown(Media3EngineTest.kt:53)

java.lang.IllegalStateException: WorkManager is not initialized properly.
    You have explicitly disabled WorkManagerInitializer in your manifest, ...

Neither is a real defect in this project. tearDown throws because setUp never got far enough to assign output, and WorkManager's InitializationProvider never runs because content-provider installation fails on a framework whose surfaceflinger is crash-looping. The same tests pass at API 33, 34, 35, and 36 in the same CI run, and the first surfaceflinger abort is timestamped before the test results are reported.

That last point is inference rather than proof: the definitive check would be running the suite against a healthy API 37 device, which does not exist yet. If a fixed image ships and these tests still fail, treat the WorkManager error as a real finding.

Environment

Reproduced identically in two unrelated environments, so it is not specific to a host GPU, driver, or CI runner.

GitHub Actions Local workstation
Host ubuntu-latest, no GPU Fedora, Intel Iris Xe (TGL GT2)
Emulator 37.1.11.0 (build 15917651) 37.1.11.0 (build 15917651)
GPU mode swiftshader_indirect host
Result boots, aborts during tests aborts before boot completes

System image: system-images;android-37.0;google_apis;x86_64, Pkg.Revision=6, AndroidVersion.ApiLevel=37.0, AndroidVersion.ExtensionLevel=22

Build fingerprint: google/sdk_gphone64_x86_64/emu64xa:17/CE2A.260420.019/15611780:userdebug/dev-keys
Kernel Release:    6.12.58-android16-6-gccafb60de224-ab14828483

What was ruled out, and how

Each of these was tested rather than reasoned about, because the first three attempts at this bug were plausible fixes that turned out to address earlier, unrelated failures.

Guest memory. The emulator raises an undersized guest to a minimum on its own, but only for API levels it recognises, and it does not recognise "37.0". API 33 bumps to 2048 MB and 34/35/36 to 2560 MB, while API 37 logged no bump at all and ran at the pixel_6 default of 1536 MB. Setting ram-size: 2560M explicitly fixed that asymmetry and did change the outcome — the job got past install and into the test run — but it is not the underlying bug. At the moment of failure the guest reported MemTotal 2527392 kB with MemAvailable 1507104 kB: 1.5 GB free, and no OOM kills.

GPU mode. Both swiftshader_indirect and host crash, with the same assertion and the same frames. The crash is in the gralloc mapper, below the renderer.

Disabling the DMA feature. GLDMA is the host feature that most plausibly backs the guest's hasReadColorBufferDma. Launching with -feature -GLDMA was accepted by the emulator — the log confirms Feature 'GLDMA' (51) is overridden to 'disabled' — and surfaceflinger still aborted 13 times and the device never finished booting. Whatever sets that guest capability, it is not this flag.

An ATD image. google_atd / aosp_atd images are built for automated testing and ship without the SystemUI package set, which is what drives RegionSamplingThread in the first place. That would likely sidestep the bug class entirely, but no ATD image exists for android-37.0 — only google_apis, google_apis_playstore, the ps16k 16 KB-page variants, and Wear OS. Check again when revisiting; if an ATD image appears, try it before anything else here.

Reproducing it

Locally, with -gpu host so the emulator itself does not segfault on Intel graphics:

sdkmanager --install "system-images;android-37.0;google_apis;x86_64"
echo no | avdmanager create avd -n api37_repro \
    -k "system-images;android-37.0;google_apis;x86_64" -d pixel_6 --force

$ANDROID_HOME/emulator/emulator -avd api37_repro \
    -no-window -gpu host -noaudio -no-boot-anim -camera-back none -no-snapshot &

# Boot never completes. Count the aborts:
adb logcat -d -b crash | grep -c hasReadColorBufferDma

sys.boot_completed never reaches 1, pgrep -f system_server stays empty, and keystore2's watchdog logs await_boot_completed ... Overdue indefinitely.

To see the CI-side form instead, restore the API 37 row in the E2E matrix of status_check.yml (api-level: "37.0" — a bare 37 fails earlier still, during SDK setup, because there is no platforms;android-37).

Filing this upstream

Not yet filed. To file it:

  1. Go to https://issuetracker.google.com/ and sign in with a Google account.
  2. Choose Report an issue, then pick the component for the Android emulator — search the component picker for "Emulator"; it sits under the Android Studio component tree. If the picker is unclear, Android Studio's Help → Submit Feedback opens the same tracker with the component preselected, and the emulator's own Extended controls → Help → File a bug does likewise.
  3. Title it for the mechanism, not the symptom, so it is searchable — for example: surfaceflinger aborts in GoldfishMapper::readFromHost (hasReadColorBufferDma) on android-37.0 google_apis x86_64.
  4. Paste the assertion and backtrace from the top of this document, the environment table, and the reproduction steps above. State explicitly that it reproduces on two unrelated hosts under both GPU modes — that is the detail that stops it being closed as a local graphics problem.
  5. List what was ruled out. Bugs that arrive with -feature -GLDMA already eliminated tend not to bounce back asking for it.
  6. Attach:

Record the issue number here once filed.

When to revisit

Re-add the API 37 row when any of these happens:

  • a new android-37.0 system image revision ships (this was revision 6)
  • an ATD image appears for API 37
  • the upstream issue is marked fixed

Until then the coverage gap is narrow but real. targetSdk is 37, so the app is still compiled and unit-tested against it, and the API-dependent behaviour this matrix exists to exercise — the foreground service type, which is absent below 34, dataSync at 34, and mediaProcessing from 35 — is fully covered at 35 and 36. What is not covered is any behaviour Android 17 changes relative to 36. Verify that on a physical device before release.