mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[CI] (.github/workflows, android-plugin): boot retrace emulators from a cached snapshot
- the AVD job boots the new AVD once per GPU mode and saves a snapshot into the cache - retrace jobs load their mode's snapshot, log whether it loaded, and skip SDK setup on a hit
This commit is contained in:
+54
-15
@@ -379,7 +379,7 @@ jobs:
|
||||
${{ env.ANDROID_SDK_ROOT }}/platform-tools
|
||||
${{ env.ANDROID_SDK_ROOT }}/platforms/android-35
|
||||
${{ env.ANDROID_SDK_ROOT }}/system-images/android-35/google_apis/x86_64
|
||||
key: ${{ runner.os }}-mobilegl-avd-api35-google_apis-x86_64-pixel_6-v2-${{ hashFiles('android-plugin/run-avd-ci.sh') }}
|
||||
key: ${{ runner.os }}-mobilegl-avd-api35-google_apis-x86_64-pixel_6-v3-${{ hashFiles('android-plugin/run-avd-ci.sh') }}
|
||||
|
||||
- name: Create AVD
|
||||
if: steps.android-avd-cache.outputs.cache-hit != 'true'
|
||||
@@ -391,6 +391,33 @@ jobs:
|
||||
--profile pixel_6 \
|
||||
--avd-name "${AVD_NAME}"
|
||||
|
||||
- name: Enable KVM
|
||||
if: steps.android-avd-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
# Boot the new AVD once per emulator GPU mode of the retrace matrix (the backends' `gpu` in
|
||||
# tools/trace_replay/trace_cases.py) and keep a snapshot of each booted device in the cached
|
||||
# AVD, so a retrace job loads one instead of cold-booting. A mode whose snapshot cannot be
|
||||
# saved still leaves the AVD past its first-boot setup.
|
||||
- name: Pre-boot AVD and save snapshots
|
||||
if: steps.android-avd-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
for gpu in software lavapipe; do
|
||||
log="${RUNNER_TEMP}/avd-snapshot-${gpu}.log"
|
||||
pid="${RUNNER_TEMP}/avd-snapshot-${gpu}.pid"
|
||||
if ! sh android-plugin/run-avd-ci.sh snapshot --avd-name "${AVD_NAME}" --gpu "${gpu}" \
|
||||
--name "ci-${gpu}" --emulator-log "${log}" --pid-file "${pid}" --boot-timeout 300; then
|
||||
echo "::warning::no ci-${gpu} snapshot was saved; retrace jobs in that GPU mode cold-boot"
|
||||
tail -50 "${log}" || true
|
||||
sh android-plugin/run-avd-ci.sh stop --avd-name "${AVD_NAME}" --emulator-log "${log}" --pid-file "${pid}"
|
||||
timeout 60 tail --pid="$(cat "${pid}")" -f /dev/null || true
|
||||
fi
|
||||
done
|
||||
du -sh "${ANDROID_AVD_HOME}"
|
||||
|
||||
retrace:
|
||||
name: retrace (${{ matrix.backend.name }} / ${{ matrix.transport || 'monolith' }}, ${{ matrix.case.name }})
|
||||
runs-on: ubuntu-26.04
|
||||
@@ -440,8 +467,29 @@ jobs:
|
||||
echo "EMULATOR_LOG=${RUNNER_TEMP}/mobilegl-emulator.log" >> "$GITHUB_ENV"
|
||||
echo "EMULATOR_PID_FILE=${RUNNER_TEMP}/mobilegl-emulator.pid" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Restore Android AVD cache
|
||||
id: android-avd-cache
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
${{ env.ANDROID_AVD_HOME }}
|
||||
${{ env.ANDROID_SDK_ROOT }}/emulator
|
||||
${{ env.ANDROID_SDK_ROOT }}/platform-tools
|
||||
${{ env.ANDROID_SDK_ROOT }}/platforms/android-35
|
||||
${{ env.ANDROID_SDK_ROOT }}/system-images/android-35/google_apis/x86_64
|
||||
key: ${{ runner.os }}-mobilegl-avd-api35-google_apis-x86_64-pixel_6-v3-${{ hashFiles('android-plugin/run-avd-ci.sh') }}
|
||||
|
||||
# The cache holds everything a retrace job runs (emulator, adb, image, AVD); the SDK manager
|
||||
# is only needed to create the AVD when the cache missed.
|
||||
- name: Use the cached SDK tools
|
||||
if: steps.android-avd-cache.outputs.cache-hit == 'true'
|
||||
run: |
|
||||
echo "${ANDROID_SDK_ROOT}/platform-tools" >> "$GITHUB_PATH"
|
||||
echo "${ANDROID_SDK_ROOT}/emulator" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Setup Android SDK
|
||||
id: netsetup415
|
||||
if: steps.android-avd-cache.outputs.cache-hit != 'true'
|
||||
continue-on-error: true
|
||||
timeout-minutes: 15
|
||||
uses: android-actions/setup-android@v4
|
||||
@@ -460,20 +508,9 @@ jobs:
|
||||
cmdline-tools-version: 13114758
|
||||
|
||||
- name: Accept Android SDK licenses
|
||||
if: steps.android-avd-cache.outputs.cache-hit != 'true'
|
||||
run: yes | sdkmanager --licenses >/dev/null
|
||||
|
||||
- name: Restore Android AVD cache
|
||||
id: android-avd-cache
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
${{ env.ANDROID_AVD_HOME }}
|
||||
${{ env.ANDROID_SDK_ROOT }}/emulator
|
||||
${{ env.ANDROID_SDK_ROOT }}/platform-tools
|
||||
${{ env.ANDROID_SDK_ROOT }}/platforms/android-35
|
||||
${{ env.ANDROID_SDK_ROOT }}/system-images/android-35/google_apis/x86_64
|
||||
key: ${{ runner.os }}-mobilegl-avd-api35-google_apis-x86_64-pixel_6-v2-${{ hashFiles('android-plugin/run-avd-ci.sh') }}
|
||||
|
||||
- name: Download retrace APK
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
@@ -503,7 +540,8 @@ jobs:
|
||||
--gpu "${{ matrix.backend.gpu }}" \
|
||||
--emulator-log "${EMULATOR_LOG}" \
|
||||
--pid-file "${EMULATOR_PID_FILE}" \
|
||||
--boot-timeout 300
|
||||
--boot-timeout 300 \
|
||||
--snapshot "ci-${{ matrix.backend.gpu }}"
|
||||
|
||||
- name: Retrace and validate
|
||||
env:
|
||||
@@ -610,7 +648,8 @@ jobs:
|
||||
--gpu "${{ matrix.backend.gpu }}" \
|
||||
--emulator-log "${EMULATOR_LOG}" \
|
||||
--pid-file "${EMULATOR_PID_FILE}" \
|
||||
--boot-timeout 300
|
||||
--boot-timeout 300 \
|
||||
--snapshot "ci-${{ matrix.backend.gpu }}"
|
||||
run_retrace
|
||||
elif [ "${retrace_status}" -ne 0 ]; then
|
||||
exit "${retrace_status}"
|
||||
|
||||
+147
-35
@@ -16,6 +16,15 @@ Usage:
|
||||
--gpu GPU \
|
||||
--emulator-log FILE \
|
||||
--pid-file FILE \
|
||||
--boot-timeout SECONDS \
|
||||
[--snapshot NAME]
|
||||
|
||||
sh android-plugin/run-avd-ci.sh snapshot \
|
||||
--avd-name NAME \
|
||||
--gpu GPU \
|
||||
--name SNAPSHOT \
|
||||
--emulator-log FILE \
|
||||
--pid-file FILE \
|
||||
--boot-timeout SECONDS
|
||||
|
||||
sh android-plugin/run-avd-ci.sh stop \
|
||||
@@ -118,48 +127,34 @@ create_avd() {
|
||||
echo no | "${avdmanager_bin}" create avd --force --name "${avd_name}" --package "${system_image}" --device "${profile}"
|
||||
}
|
||||
|
||||
start_avd() {
|
||||
avd_name=""
|
||||
gpu=""
|
||||
emulator_log=""
|
||||
pid_file=""
|
||||
boot_timeout=""
|
||||
# The guest property a snapshot carries: `snapshot` sets it just before saving, and it lives only
|
||||
# in guest RAM, so after `start` it reads the snapshot's name exactly when that snapshot loaded.
|
||||
snapshot_marker_prop="debug.ci.boot_snapshot"
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
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"
|
||||
|
||||
adb_bin="$(find_android_tool adb platform-tools/adb)"
|
||||
emulator_bin="$(find_android_tool emulator emulator/emulator)"
|
||||
ensure_android_avd_home
|
||||
|
||||
mkdir -p "$(dirname "${emulator_log}")" "$(dirname "${pid_file}")"
|
||||
"${emulator_bin}" -avd "${avd_name}" \
|
||||
# launch_emulator AVD GPU LOG PID_FILE SNAPSHOT_FLAG...: the flags a snapshot is saved and loaded
|
||||
# with must match, so both commands launch through here.
|
||||
launch_emulator() {
|
||||
launch_avd="$1"
|
||||
launch_gpu="$2"
|
||||
launch_log="$3"
|
||||
launch_pid_file="$4"
|
||||
shift 4
|
||||
mkdir -p "$(dirname "${launch_log}")" "$(dirname "${launch_pid_file}")"
|
||||
"${emulator_bin}" -avd "${launch_avd}" \
|
||||
-no-window \
|
||||
-gpu "${gpu}" \
|
||||
-no-snapshot \
|
||||
-gpu "${launch_gpu}" \
|
||||
"$@" \
|
||||
-noaudio \
|
||||
-no-boot-anim \
|
||||
-camera-back none \
|
||||
-camera-front none \
|
||||
> "${emulator_log}" 2>&1 &
|
||||
emulator_pid="$!"
|
||||
echo "${emulator_pid}" > "${pid_file}"
|
||||
> "${launch_log}" 2>&1 &
|
||||
echo "$!" > "${launch_pid_file}"
|
||||
}
|
||||
|
||||
wait_for_boot() {
|
||||
emulator_log="$1"
|
||||
boot_timeout="$2"
|
||||
if ! timeout "${boot_timeout}" "${adb_bin}" wait-for-device; then
|
||||
print_diagnostics "${emulator_log}"
|
||||
die "emulator did not connect to adb within ${boot_timeout}s"
|
||||
@@ -185,6 +180,122 @@ start_avd() {
|
||||
"${adb_bin}" shell input keyevent 82 || true
|
||||
}
|
||||
|
||||
start_avd() {
|
||||
avd_name=""
|
||||
gpu=""
|
||||
emulator_log=""
|
||||
pid_file=""
|
||||
boot_timeout=""
|
||||
snapshot=""
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
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 ;;
|
||||
--snapshot) snapshot="$(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"
|
||||
|
||||
adb_bin="$(find_android_tool adb platform-tools/adb)"
|
||||
emulator_bin="$(find_android_tool emulator emulator/emulator)"
|
||||
ensure_android_avd_home
|
||||
|
||||
# A snapshot only shortens the boot: the image, the AVD and the GPU mode are the same, and the
|
||||
# emulator cold-boots by itself when the snapshot does not load.
|
||||
started_at="$(date +%s)"
|
||||
if [ -n "${snapshot}" ] && [ -d "${ANDROID_AVD_HOME}/${avd_name}.avd/snapshots/${snapshot}" ]; then
|
||||
launch_emulator "${avd_name}" "${gpu}" "${emulator_log}" "${pid_file}" -snapshot "${snapshot}" -no-snapshot-save
|
||||
else
|
||||
launch_emulator "${avd_name}" "${gpu}" "${emulator_log}" "${pid_file}" -no-snapshot
|
||||
fi
|
||||
wait_for_boot "${emulator_log}" "${boot_timeout}"
|
||||
|
||||
seconds="$(( $(date +%s) - started_at ))"
|
||||
marker="$("${adb_bin}" shell getprop "${snapshot_marker_prop}" 2>/dev/null | tr -d '\r' || true)"
|
||||
if [ -n "${snapshot}" ] && [ "${marker}" = "${snapshot}" ]; then
|
||||
echo "run-avd-ci.sh: booted in ${seconds}s from snapshot ${snapshot}"
|
||||
elif [ -n "${snapshot}" ]; then
|
||||
echo "run-avd-ci.sh: booted in ${seconds}s by cold boot; snapshot ${snapshot} did not load"
|
||||
else
|
||||
echo "run-avd-ci.sh: booted in ${seconds}s by cold boot"
|
||||
fi
|
||||
}
|
||||
|
||||
# Boot the AVD cold once in GPU mode GPU and save snapshot NAME of the booted device, then shut it
|
||||
# down cleanly so the AVD can be cached. The first call also does the AVD's first-boot setup,
|
||||
# which a cold boot after a cache restore then no longer repeats.
|
||||
snapshot_avd() {
|
||||
avd_name=""
|
||||
gpu=""
|
||||
snapshot_name=""
|
||||
emulator_log=""
|
||||
pid_file=""
|
||||
boot_timeout=""
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--avd-name) avd_name="$(next_arg "$@")"; shift 2 ;;
|
||||
--gpu) gpu="$(next_arg "$@")"; shift 2 ;;
|
||||
--name) snapshot_name="$(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 snapshot argument: $1" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
require_value "${avd_name}" "--avd-name"
|
||||
require_value "${gpu}" "--gpu"
|
||||
require_value "${snapshot_name}" "--name"
|
||||
require_value "${emulator_log}" "--emulator-log"
|
||||
require_value "${pid_file}" "--pid-file"
|
||||
require_value "${boot_timeout}" "--boot-timeout"
|
||||
|
||||
adb_bin="$(find_android_tool adb platform-tools/adb)"
|
||||
emulator_bin="$(find_android_tool emulator emulator/emulator)"
|
||||
ensure_android_avd_home
|
||||
|
||||
started_at="$(date +%s)"
|
||||
launch_emulator "${avd_name}" "${gpu}" "${emulator_log}" "${pid_file}" -no-snapshot-load -no-snapshot-save
|
||||
wait_for_boot "${emulator_log}" "${boot_timeout}"
|
||||
echo "run-avd-ci.sh: ${gpu} cold boot took $(( $(date +%s) - started_at ))s"
|
||||
|
||||
"${adb_bin}" shell setprop "${snapshot_marker_prop}" "${snapshot_name}"
|
||||
saved="$("${adb_bin}" emu avd snapshot save "${snapshot_name}" 2>&1 | tr -d '\r' || true)"
|
||||
echo "run-avd-ci.sh: snapshot save ${snapshot_name}: ${saved}"
|
||||
|
||||
"${adb_bin}" emu kill >/dev/null 2>&1 || true
|
||||
emulator_pid="$(cat "${pid_file}")"
|
||||
for _ in $(seq 1 120); do
|
||||
kill -0 "${emulator_pid}" 2>/dev/null || break
|
||||
sleep 1
|
||||
done
|
||||
if kill -0 "${emulator_pid}" 2>/dev/null; then
|
||||
kill "${emulator_pid}" >/dev/null 2>&1 || true
|
||||
die "emulator did not exit after saving snapshot ${snapshot_name}"
|
||||
fi
|
||||
|
||||
snapshot_dir="${ANDROID_AVD_HOME}/${avd_name}.avd/snapshots/${snapshot_name}"
|
||||
case "${saved}" in
|
||||
*OK*) ;;
|
||||
*) rm -rf "${snapshot_dir}"; die "snapshot ${snapshot_name} was not saved: ${saved}" ;;
|
||||
esac
|
||||
[ -d "${snapshot_dir}" ] || die "snapshot ${snapshot_name} reported OK but ${snapshot_dir} does not exist"
|
||||
du -sh "${snapshot_dir}"
|
||||
}
|
||||
|
||||
stop_avd() {
|
||||
avd_name=""
|
||||
emulator_log=""
|
||||
@@ -226,6 +337,7 @@ shift
|
||||
case "${command}" in
|
||||
create) create_avd "$@" ;;
|
||||
start) start_avd "$@" ;;
|
||||
snapshot) snapshot_avd "$@" ;;
|
||||
stop) stop_avd "$@" ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) die "unknown command: ${command}" ;;
|
||||
|
||||
Reference in New Issue
Block a user