Adapt LibreMail's emulator instrumentation for the E2E matrix
The E2E legs could fail with almost nothing to show for it. The previous handler
was a single line of semicolons printing meminfo and 60 lines of crash logcat,
and it only ran when gradle RETURNED non-zero -- a hang left nothing at all, and
`adb logcat -d` at the end only holds whatever survived in the ring buffer, which
a chatty run evicts.
The two failure shapes want different evidence, so they are handled separately:
FAILED -- gradle returned non-zero. The test reports already say which test and
why, so this captures the surrounding state: guest memory and
storage, whether the app even installed, native crashes, and the
runner's own kvm/memory/disk.
WEDGED -- gradle never returned and the wrapper timeout killed it. There are no
reports, so the evidence has to come off the live device: which test
was in flight per the TestRunner logcat, whether the binder services
are published, and SIGQUIT thread dumps of both processes. That last
one is the point -- ART writes full stacks to logcat and /data/anr,
which is what separates a deadlocked test from a stuck MediaCodec
from a device that stopped answering. dumpsys media.player is in
there because both engines transcode through MediaCodec, so a hung
conversion shows up in it.
Logcat is now streamed to a file from the start of the step and uploaded whichever
way the leg goes, since the leg worth reading is usually the one that went red once
and green on re-run -- by which time the emulator is gone.
It is a script rather than inline YAML because it has to be. The action splits its
`script` input on newlines and runs each line as its own `sh -c`, so functions and
`if` blocks cannot survive there; that constraint is what produced the one-line
handler in the first place. One line calls the script now.
The wrapper timeout is 1200s against measured ~5-minute healthy legs, so it cannot
trip on a slow-but-working run, and sits far enough under the 60-minute cap to
leave room for the capture. It wraps only the foreground gradle client, never the
emulator the action owns, so it cannot hang the leg itself.
Not adopted from LibreMail: the hand-provisioned AVD boot, its SDK-integrity
installer and its focus gate. Those answer failures this repo has not had, and
replacing a boot path that works to fix problems we do not have is how a working
matrix breaks. Every emulator setting here -- ram-size, disk-size, the ABI filter,
swiftshader -- is untouched, along with the reasoning already written next to it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -261,20 +261,12 @@ jobs:
|
||||
# dominate the APK, so shipping arm64 to an x86_64 emulator doubles the
|
||||
# install for code that can never run: 114 MB against 80 MB.
|
||||
#
|
||||
# The probe lines survive from diagnosing the API 37 crash and are kept
|
||||
# because a red instrumented run is otherwise near-impossible to read from a
|
||||
# log alone. The first reports what the guest actually got, so a wrong
|
||||
# emulator configuration is visible on a green run too; the crash dump runs
|
||||
# only on failure, so a green run is unchanged.
|
||||
#
|
||||
# Each line here is a separate `sh -c` -- the action splits the script on
|
||||
# newlines -- so the failure handler has to stay on one line. The action does
|
||||
# not pass ignoreReturnCode, so a non-zero line fails the job outright: the
|
||||
# probe ends in `|| true` because a grep that matches nothing exits 1, and a
|
||||
# diagnostic must never be the thing that turns a run red.
|
||||
script: |
|
||||
adb shell cat /proc/meminfo | grep -E 'MemTotal|MemAvailable|SwapTotal' || true
|
||||
./gradlew :app:connectedDebugAndroidTest -PabiFilters=x86_64 || { echo "=== guest memory at failure ==="; adb shell cat /proc/meminfo | grep -E 'MemTotal|MemAvailable|SwapTotal'; echo "=== native crashes ==="; adb logcat -d -b crash | tail -60; exit 1; }
|
||||
# Diagnostics live in .github/scripts/e2e-run.sh, not here. This action splits
|
||||
# `script` on newlines and runs each line as its own `sh -c`, so a handler written
|
||||
# inline has to fit on ONE line -- which is how the previous version ended up as an
|
||||
# unreadable chain of semicolons. One line invokes the script; the script can use
|
||||
# functions, and captures a hang as well as a failure. See its header.
|
||||
script: bash .github/scripts/e2e-run.sh ${{ matrix.label }}
|
||||
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: always()
|
||||
@@ -283,3 +275,25 @@ jobs:
|
||||
path: |
|
||||
app/build/reports/androidTests/
|
||||
app/build/outputs/androidTest-results/
|
||||
if-no-files-found: warn
|
||||
|
||||
# The streamed logcat and the failure dump. Uploaded always, because a leg that goes red
|
||||
# once and green on re-run is exactly the one worth reading afterwards, and by then the
|
||||
# emulator is long gone.
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: always()
|
||||
with:
|
||||
name: e2e-diagnostics-api${{ matrix.label }}
|
||||
path: |
|
||||
${{ runner.temp }}/logcat-api${{ matrix.label }}.txt
|
||||
${{ runner.temp }}/diagnostics-api${{ matrix.label }}.txt
|
||||
if-no-files-found: warn
|
||||
|
||||
# Only exists when the wrapper timeout tripped, so `ignore` keeps healthy runs quiet
|
||||
# instead of warning on every green leg.
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: always()
|
||||
with:
|
||||
name: e2e-wedge-api${{ matrix.label }}
|
||||
path: ${{ runner.temp }}/wedge-diagnostics-api${{ matrix.label }}.txt
|
||||
if-no-files-found: ignore
|
||||
|
||||
Reference in New Issue
Block a user