[Fix] (ci): split APK retrace AVD lifecycle

- expose AVD create, launch, retrace, diagnostics, and stop as separate workflow steps

- add bounded waits for emulator adb connection, boot, and trace replay execution

- collect emulator diagnostics for APK retrace artifacts
This commit is contained in:
2026-06-20 14:27:11 +08:00
parent 317b3602c3
commit a49a463acf
2 changed files with 208 additions and 96 deletions
+39 -5
View File
@@ -96,6 +96,9 @@ jobs:
name: retrace (${{ matrix.backend.name }}, ${{ matrix.case.name }}) name: retrace (${{ matrix.backend.name }}, ${{ matrix.case.name }})
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build needs: build
timeout-minutes: 75
env:
AVD_NAME: mobilegl-${{ matrix.backend.id }}
strategy: strategy:
fail-fast: false fail-fast: false
max-parallel: 4 max-parallel: 4
@@ -376,6 +379,8 @@ jobs:
run: | run: |
echo "date_today=$(date +'%Y-%m-%d')" >> "$GITHUB_ENV" echo "date_today=$(date +'%Y-%m-%d')" >> "$GITHUB_ENV"
echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_ENV" echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_ENV"
echo "EMULATOR_LOG=${RUNNER_TEMP}/mobilegl-emulator.log" >> "$GITHUB_ENV"
echo "EMULATOR_PID_FILE=${RUNNER_TEMP}/mobilegl-emulator.pid" >> "$GITHUB_ENV"
- name: Setup Android SDK - name: Setup Android SDK
uses: android-actions/setup-android@v3 uses: android-actions/setup-android@v3
@@ -393,17 +398,28 @@ jobs:
sudo udevadm control --reload-rules sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm sudo udevadm trigger --name-match=kvm
- name: Retrace and validate - name: Create AVD
run: | run: |
apk_file="$(find android-retrace-apks -name '${{ matrix.backend.apk }}' -print -quit)" sh android-plugin/run-avd-ci.sh create \
sh android-plugin/run-avd-ci.sh \
--api-level 35 \ --api-level 35 \
--target google_apis \ --target google_apis \
--arch x86_64 \ --arch x86_64 \
--profile pixel_6 \ --profile pixel_6 \
--avd-name "${AVD_NAME}"
- name: Launch Emulator
run: |
sh android-plugin/run-avd-ci.sh start \
--avd-name "${AVD_NAME}" \
--gpu "${{ matrix.backend.gpu }}" \ --gpu "${{ matrix.backend.gpu }}" \
--avd-name "mobilegl-${{ matrix.backend.id }}" \ --emulator-log "${EMULATOR_LOG}" \
-- sh android-plugin/trace-replay-ci.sh \ --pid-file "${EMULATOR_PID_FILE}" \
--boot-timeout 300
- name: Retrace and validate
run: |
apk_file="$(find android-retrace-apks -name '${{ matrix.backend.apk }}' -print -quit)"
timeout "$(( ${{ matrix.case.timeout_seconds }} + 300 ))" sh android-plugin/trace-replay-ci.sh \
--apk-file "${apk_file}" \ --apk-file "${apk_file}" \
--package "${{ matrix.backend.package }}" \ --package "${{ matrix.backend.package }}" \
--backend "${{ matrix.backend.name }}" \ --backend "${{ matrix.backend.name }}" \
@@ -424,6 +440,24 @@ jobs:
--fuzz-percent "${{ matrix.case.fuzz_percent }}" \ --fuzz-percent "${{ matrix.case.fuzz_percent }}" \
--timeout-seconds "${{ matrix.case.timeout_seconds }}" --timeout-seconds "${{ matrix.case.timeout_seconds }}"
- name: Collect emulator diagnostics
if: always()
run: |
mkdir -p android-retrace-result/diagnostics
adb devices -l > android-retrace-result/diagnostics/adb-devices.txt || true
timeout 30 adb logcat -d -t 1000 > android-retrace-result/diagnostics/logcat.txt || true
if [ -f "${EMULATOR_LOG}" ]; then
cp "${EMULATOR_LOG}" android-retrace-result/diagnostics/emulator.log
fi
- name: Stop Emulator
if: always()
run: |
sh android-plugin/run-avd-ci.sh stop \
--avd-name "${AVD_NAME}" \
--emulator-log "${EMULATOR_LOG}" \
--pid-file "${EMULATOR_PID_FILE}"
- name: Upload Android retrace result - name: Upload Android retrace result
if: always() if: always()
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
+125 -47
View File
@@ -4,14 +4,24 @@ set -eu
usage() { usage() {
cat <<'EOF' cat <<'EOF'
Usage: Usage:
sh android-plugin/run-avd-ci.sh \ sh android-plugin/run-avd-ci.sh create \
--api-level N \ --api-level N \
--target TARGET \ --target TARGET \
--arch ARCH \ --arch ARCH \
--profile PROFILE \ --profile PROFILE \
--gpu GPU \ --avd-name NAME
sh android-plugin/run-avd-ci.sh start \
--avd-name NAME \ --avd-name NAME \
-- COMMAND [ARGS ...] --gpu GPU \
--emulator-log FILE \
--pid-file FILE \
--boot-timeout SECONDS
sh android-plugin/run-avd-ci.sh stop \
--avd-name NAME \
--emulator-log FILE \
--pid-file FILE
EOF EOF
} }
@@ -36,44 +46,73 @@ require_value() {
fi fi
} }
api_level="" print_diagnostics() {
target="" emulator_log="$1"
arch="" adb devices -l >&2 || true
profile="" if [ -f "${emulator_log}" ]; then
gpu="" echo "----- emulator log -----" >&2
avd_name="" cat "${emulator_log}" >&2 || true
echo "----- end emulator log -----" >&2
fi
}
while [ "$#" -gt 0 ]; do create_avd() {
api_level=""
target=""
arch=""
profile=""
avd_name=""
while [ "$#" -gt 0 ]; do
case "$1" in case "$1" in
--api-level) api_level="$(next_arg "$@")"; shift 2 ;; --api-level) api_level="$(next_arg "$@")"; shift 2 ;;
--target) target="$(next_arg "$@")"; shift 2 ;; --target) target="$(next_arg "$@")"; shift 2 ;;
--arch) arch="$(next_arg "$@")"; shift 2 ;; --arch) arch="$(next_arg "$@")"; shift 2 ;;
--profile) profile="$(next_arg "$@")"; shift 2 ;; --profile) profile="$(next_arg "$@")"; shift 2 ;;
--gpu) gpu="$(next_arg "$@")"; shift 2 ;;
--avd-name) avd_name="$(next_arg "$@")"; shift 2 ;; --avd-name) avd_name="$(next_arg "$@")"; shift 2 ;;
--) shift; break ;;
-h|--help) usage; exit 0 ;; -h|--help) usage; exit 0 ;;
*) die "unknown argument: $1" ;; *) die "unknown create argument: $1" ;;
esac esac
done done
require_value "${api_level}" "--api-level" require_value "${api_level}" "--api-level"
require_value "${target}" "--target" require_value "${target}" "--target"
require_value "${arch}" "--arch" require_value "${arch}" "--arch"
require_value "${profile}" "--profile" require_value "${profile}" "--profile"
require_value "${gpu}" "--gpu" require_value "${avd_name}" "--avd-name"
require_value "${avd_name}" "--avd-name"
if [ "$#" -eq 0 ]; then system_image="system-images;android-${api_level};${target};${arch}"
die "missing command" sdkmanager "platform-tools" "emulator" "platforms;android-${api_level}" "${system_image}"
fi echo no | avdmanager create avd --force --name "${avd_name}" --package "${system_image}" --device "${profile}"
}
system_image="system-images;android-${api_level};${target};${arch}" start_avd() {
sdkmanager "platform-tools" "emulator" "platforms;android-${api_level}" "${system_image}" avd_name=""
echo no | avdmanager create avd --force --name "${avd_name}" --package "${system_image}" --device "${profile}" gpu=""
emulator_log=""
pid_file=""
boot_timeout=""
emulator_log="${RUNNER_TEMP:-.}/${avd_name}-emulator.log" while [ "$#" -gt 0 ]; do
emulator -avd "${avd_name}" \ case "$1" in
--avd-name) avd_name="$(next_arg "$@")"; shift 2 ;;
--gpu) gpu="$(next_arg "$@")"; shift 2 ;;
--emulator-log) emulator_log="$(next_arg "$@")"; shift 2 ;;
--pid-file) pid_file="$(next_arg "$@")"; shift 2 ;;
--boot-timeout) boot_timeout="$(next_arg "$@")"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) die "unknown start argument: $1" ;;
esac
done
require_value "${avd_name}" "--avd-name"
require_value "${gpu}" "--gpu"
require_value "${emulator_log}" "--emulator-log"
require_value "${pid_file}" "--pid-file"
require_value "${boot_timeout}" "--boot-timeout"
mkdir -p "$(dirname "${emulator_log}")" "$(dirname "${pid_file}")"
emulator -avd "${avd_name}" \
-no-window \ -no-window \
-gpu "${gpu}" \ -gpu "${gpu}" \
-no-snapshot \ -no-snapshot \
@@ -82,34 +121,73 @@ emulator -avd "${avd_name}" \
-camera-back none \ -camera-back none \
-camera-front none \ -camera-front none \
> "${emulator_log}" 2>&1 & > "${emulator_log}" 2>&1 &
emulator_pid="$!" emulator_pid="$!"
echo "${emulator_pid}" > "${pid_file}"
cleanup() { if ! timeout "${boot_timeout}" adb wait-for-device; then
if kill -0 "${emulator_pid}" 2>/dev/null; then print_diagnostics "${emulator_log}"
adb -s emulator-5554 emu kill >/dev/null 2>&1 || kill "${emulator_pid}" >/dev/null 2>&1 || true die "emulator did not connect to adb within ${boot_timeout}s"
fi fi
}
trap cleanup EXIT INT TERM
adb wait-for-device booted=""
for _ in $(seq 1 "${boot_timeout}"); do
booted=""
for _ in $(seq 1 300); do
booted="$(adb shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)" booted="$(adb shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)"
if [ "${booted}" = "1" ]; then if [ "${booted}" = "1" ]; then
break break
fi fi
sleep 1 sleep 1
done done
if [ "${booted}" != "1" ]; then if [ "${booted}" != "1" ]; then
cat "${emulator_log}" >&2 || true print_diagnostics "${emulator_log}"
die "emulator did not boot" die "emulator did not boot within ${boot_timeout}s"
fi
adb shell settings put global window_animation_scale 0
adb shell settings put global transition_animation_scale 0
adb shell settings put global animator_duration_scale 0
adb shell input keyevent 82 || true
}
stop_avd() {
avd_name=""
emulator_log=""
pid_file=""
while [ "$#" -gt 0 ]; do
case "$1" in
--avd-name) avd_name="$(next_arg "$@")"; shift 2 ;;
--emulator-log) emulator_log="$(next_arg "$@")"; shift 2 ;;
--pid-file) pid_file="$(next_arg "$@")"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) die "unknown stop argument: $1" ;;
esac
done
require_value "${avd_name}" "--avd-name"
require_value "${emulator_log}" "--emulator-log"
require_value "${pid_file}" "--pid-file"
adb emu kill >/dev/null 2>&1 || true
if [ -f "${pid_file}" ]; then
emulator_pid="$(cat "${pid_file}")"
if [ -n "${emulator_pid}" ] && kill -0 "${emulator_pid}" 2>/dev/null; then
kill "${emulator_pid}" >/dev/null 2>&1 || true
fi
fi
}
if [ "$#" -eq 0 ]; then
die "missing command"
fi fi
adb shell settings put global window_animation_scale 0 command="$1"
adb shell settings put global transition_animation_scale 0 shift
adb shell settings put global animator_duration_scale 0
adb shell input keyevent 82 || true
"$@" case "${command}" in
create) create_avd "$@" ;;
start) start_avd "$@" ;;
stop) stop_avd "$@" ;;
-h|--help) usage; exit 0 ;;
*) die "unknown command: ${command}" ;;
esac