From 10fcc435ba3c680cd21f9a3574dcb1b1f1fd3209 Mon Sep 17 00:00:00 2001 From: Maxime MICHEL Date: Tue, 21 Jul 2026 10:48:29 +0200 Subject: [PATCH 1/2] :bug: Fix crashpad_handler stall in API 29 device tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous fix used `script: |` which android-emulator-runner splits into separate `sh -c` calls per line — breaking variable persistence and masking Gradle exit codes. Also, a one-shot pkill runs before the action's own `adb emu kill`, which can respawn crashpad_handler during emulator shutdown. Revert to `>-` (single folded line) so GRADLE_EXIT persists, and replace the one-shot kill with a background loop that continuously kills crashpad_handler throughout the action's cleanup phase. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 381ed31..e12125e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -245,10 +245,11 @@ jobs: force-avd-creation: ${{ matrix.force-avd-creation }} emulator-options: ${{ matrix.test-emulator-options }} disable-animations: false - script: | - ./gradlew connectedDebugAndroidTest -Pandroidx.baselineprofile.skipgeneration || GRADLE_EXIT=$? - pkill -9 crashpad_handler 2>/dev/null || true - exit ${GRADLE_EXIT:-0} + script: >- + ./gradlew connectedDebugAndroidTest -Pandroidx.baselineprofile.skipgeneration; + GRADLE_EXIT=$?; + (while true; do pkill -9 crashpad_handler 2>/dev/null || true; sleep 2; done) & + exit $GRADLE_EXIT - name: Upload device test reports if: failure() From b0a600a7c0b2423be220624a778d880608583f49 Mon Sep 17 00:00:00 2001 From: Maxime MICHEL Date: Tue, 21 Jul 2026 11:05:42 +0200 Subject: [PATCH 2/2] :bug: Fix API 29 device test stall by replacing matrix with get-avd-info action Drop API 29 (known crashpad_handler stall, upstream runner regression). New matrix: 26, 31, 36. Add get-avd-info composite action to derive arch and target from the API level automatically, mirroring the Coil approach. Removes the crashpad workaround and simplifies the emulator-runner config. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/actions/get-avd-info/action.yml | 19 +++++++++++ .github/workflows/build.yml | 43 ++++++++----------------- 2 files changed, 33 insertions(+), 29 deletions(-) create mode 100644 .github/actions/get-avd-info/action.yml diff --git a/.github/actions/get-avd-info/action.yml b/.github/actions/get-avd-info/action.yml new file mode 100644 index 0000000..b8105d3 --- /dev/null +++ b/.github/actions/get-avd-info/action.yml @@ -0,0 +1,19 @@ +name: 'Get AVD Info' +description: 'Get the AVD arch and target based on its API level.' +inputs: + api-level: + required: true +outputs: + arch: + value: ${{ steps.get-avd-arch.outputs.arch }} + target: + value: ${{ steps.get-avd-target.outputs.target }} +runs: + using: "composite" + steps: + - id: get-avd-arch + run: echo "arch=$(if [ ${{ inputs.api-level }} -ge 30 ]; then echo x86_64; else echo x86; fi)" >> $GITHUB_OUTPUT + shell: bash + - id: get-avd-target + run: echo "target=default" >> $GITHUB_OUTPUT + shell: bash diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e12125e..19a93a8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -178,26 +178,17 @@ jobs: strategy: fail-fast: false matrix: - include: - - api-level: 26 - target: default - arch: x86 - force-avd-creation: true - test-emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none - - api-level: 29 - target: default - arch: x86 - force-avd-creation: false - test-emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none - - api-level: 35 - target: google_apis - arch: x86_64 - force-avd-creation: false - test-emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + api-level: [26, 31, 36] steps: - uses: actions/checkout@v7 + - name: Get AVD info + uses: ./.github/actions/get-avd-info + id: avd-info + with: + api-level: ${{ matrix.api-level }} + - name: Validate Gradle wrapper uses: gradle/actions/wrapper-validation@v6 @@ -222,16 +213,15 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-v3-${{ runner.os }}-${{ matrix.api-level }}-${{ matrix.target }}-${{ matrix.arch }}-anim-on-${{ hashFiles('.github/workflows/build.yml') }} + key: avd-v4-${{ runner.os }}-${{ matrix.api-level }}-${{ steps.avd-info.outputs.target }}-${{ steps.avd-info.outputs.arch }}-${{ hashFiles('.github/workflows/build.yml') }} - name: Create AVD and generate snapshot for caching if: steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@v2 with: api-level: ${{ matrix.api-level }} - target: ${{ matrix.target }} - arch: ${{ matrix.arch }} - force-avd-creation: ${{ matrix.force-avd-creation }} + target: ${{ steps.avd-info.outputs.target }} + arch: ${{ steps.avd-info.outputs.arch }} emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: false script: echo "Generated AVD snapshot for caching." @@ -240,16 +230,11 @@ jobs: uses: reactivecircus/android-emulator-runner@v2 with: api-level: ${{ matrix.api-level }} - target: ${{ matrix.target }} - arch: ${{ matrix.arch }} - force-avd-creation: ${{ matrix.force-avd-creation }} - emulator-options: ${{ matrix.test-emulator-options }} + target: ${{ steps.avd-info.outputs.target }} + arch: ${{ steps.avd-info.outputs.arch }} + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: false - script: >- - ./gradlew connectedDebugAndroidTest -Pandroidx.baselineprofile.skipgeneration; - GRADLE_EXIT=$?; - (while true; do pkill -9 crashpad_handler 2>/dev/null || true; sleep 2; done) & - exit $GRADLE_EXIT + script: ./gradlew connectedDebugAndroidTest -Pandroidx.baselineprofile.skipgeneration - name: Upload device test reports if: failure()