From 7166ac47c58a4a8acccebb07ae9395773ad9958e Mon Sep 17 00:00:00 2001 From: Lena Date: Sat, 1 Aug 2026 00:00:00 +0000 Subject: test-rig: exercise release paths --- test-rig/record.sh | 178 ----------------------------------------------------- 1 file changed, 178 deletions(-) delete mode 100755 test-rig/record.sh (limited to 'test-rig/record.sh') diff --git a/test-rig/record.sh b/test-rig/record.sh deleted file mode 100755 index 82e31dc..0000000 --- a/test-rig/record.sh +++ /dev/null @@ -1,178 +0,0 @@ -#!/bin/sh -# Boot the emulator + Mirror, then capture frames via `screencap` and -# inject taps/keys through the app. Frames are PNGs in $TMPDIR/frames; -# the host side stitches them into /work/output.mp4 with ffmpeg. -# -# Why not `screenrecord`? On the AOSP x86_64 system image with a -# software GPU, screenrecord composes the system layer but misses -# SurfaceView's hardware layer - the mirror's decoded surface ends -# up as a black rectangle in the recording. screencap goes through -# a different capture path that does include the SurfaceView, as -# the pixhash check in ./test e2e already verifies. -# -# Source == target: every injected tap/key fires both locally and -# over the wire - visible in the nested mirror, which is the demo. - -set -eu - -ROOT=/work -# Debug applicationId (note the .debug suffix). Activity classes live in -# the invalid.lena.scrcpy namespace, which carries no suffix. -PKG=invalid.lena.scrcpy.debug -AVD=scrcpy-test -SERIAL=emulator-5554 -APK=$ROOT/app/build/outputs/apk/debug/app-debug.apk -TMPDIR=$ROOT/.tools/e2e -FRAMES=$TMPDIR/frames -OUT=$ROOT/output.mp4 -FPS=8 -mkdir -p "$TMPDIR" "$FRAMES" -rm -f "$FRAMES"/*.png 2>/dev/null || true - -log() { printf 'record: %s\n' "$*" >&2; } - -# ---- 0. server jar ---- -[ -f "$ROOT/app/src/main/assets/scrcpy-server.jar" ] || "$ROOT/scripts/update-server" - -# ---- 1. build APK ---- -log 'gradle :app:assembleDebug' -"$ROOT/gradlew" --no-daemon -q :app:assembleDebug - -# ---- 2. AVD + boot ---- -if ! avdmanager list avd | grep -q "Name: $AVD$"; then - log "creating avd $AVD" - echo no | avdmanager create avd -n "$AVD" -k 'system-images;android-35;default;x86_64' -d pixel >/dev/null -fi -AVD_DIR="$ANDROID_AVD_HOME/$AVD.avd" -rm -f "$AVD_DIR"/multiinstance.lock "$AVD_DIR"/hardware-qemu.ini.lock \ - "$AVD_DIR"/snapshot.lock.lock "$AVD_DIR"/read-snapshot.txt 2>/dev/null || true -rm -rf "$HOME/.android/avd/running" 2>/dev/null || true - -if ! pgrep -f "emulator.*-avd $AVD" >/dev/null; then - log 'booting emulator' - emulator -avd "$AVD" -no-window -no-audio -no-snapshot -gpu swiftshader_indirect \ - -no-boot-anim -accel on >"$TMPDIR/emulator.log" 2>&1 & -fi -adb -s "$SERIAL" wait-for-device -until [ "$(adb -s "$SERIAL" shell getprop sys.boot_completed | tr -d '\r')" = 1 ]; do - sleep 2 -done - -# ---- 3. root + install ---- -log 'adb root' -adb -s "$SERIAL" root -adb -s "$SERIAL" wait-for-device -log "install $APK" -adb -s "$SERIAL" install -r "$APK" >/dev/null - -# ---- 4. bootstrap adb_keys via the app's own keypair ---- -adb -s "$SERIAL" shell am start -W -n "$PKG/invalid.lena.scrcpy.Main" >/dev/null -sleep 1 -adb -s "$SERIAL" shell "run-as $PKG cat files/adbkey" > "$TMPDIR/adbkey.der" -[ -s "$TMPDIR/adbkey.der" ] || { log 'adbkey was empty'; exit 1; } -java "$ROOT/test-rig/Keygen.java" "$TMPDIR/adbkey.der" > "$TMPDIR/adb_keys.line" -adb -s "$SERIAL" push "$TMPDIR/adb_keys.line" /sdcard/adb_keys.line >/dev/null -adb -s "$SERIAL" shell "cat /sdcard/adb_keys.line >> /data/misc/adb/adb_keys \ - && chown system:shell /data/misc/adb/adb_keys \ - && chmod 640 /data/misc/adb/adb_keys \ - && rm /sdcard/adb_keys.line" - -# Dismiss the "Viewing full screen" system toast that pops up the -# first time an activity goes immersive - otherwise it covers the top -# strip of the mirror in our captures. -adb -s "$SERIAL" shell settings put global policy_control \ - 'immersive.full=*' >/dev/null 2>&1 || true - -# ---- 5. launch Mirror ---- -log 'launching Mirror against 127.0.0.1:5555' -adb -s "$SERIAL" logcat -c -adb -s "$SERIAL" shell am start -n "$PKG/invalid.lena.scrcpy.Mirror" \ - --es host 127.0.0.1 --ei port 5555 >/dev/null - -# ---- 6. wait for first frame ---- -deadline=$(( $(date +%s) + ${E2E_DEADLINE:-120} )) -while [ "$(date +%s)" -lt "$deadline" ]; do - if adb -s "$SERIAL" logcat -d -s scrcpy-android | tail -500 | grep -q 'video frame n=1'; then - ok=1; break - fi - sleep 1 -done -if [ "${ok:-}" != 1 ]; then - log 'timed out waiting for first frame; full app log:' - adb -s "$SERIAL" logcat -d -s scrcpy-android > "$TMPDIR/logcat.record.scrcpy" 2>&1 || true - tail -60 "$TMPDIR/logcat.record.scrcpy" >&2 || true - exit 1 -fi -log 'first frame ok - settling 5 s for the immersive toast to fade' -# The first immersive activity on a fresh AVD draws a top-of-screen -# "Viewing full screen" toast that fades after ~4 s. We deliberately -# do NOT try to dismiss it by injecting touch - anything at y ~= 0 -# pulls the notification shade, anything near the bottom hits the nav -# bar, and either ends Mirror's foreground status. Wait it out instead. -sleep 5 - -# ---- 7. screencap loop in background while we inject events ---- -# Mirror's overlay TextViews (target / frame counts / last event) -# live in the regular view hierarchy, so screencap captures them -# fine - the actual decoded video underneath stays black to capture -# but the overlay is the in-test proof. -log "capturing frames @ ${FPS} fps via screencap" -touch "$TMPDIR/recording" -( - i=0 - while [ -f "$TMPDIR/recording" ]; do - n=$(printf '%05d' "$i") - adb -s "$SERIAL" exec-out screencap -p > "$FRAMES/f_$n.png" 2>/dev/null || true - i=$((i + 1)) - done -) & -CAP_PID=$! -sleep 1 - -log 'taps' -adb -s "$SERIAL" shell input tap 540 960 -sleep 0.6 -adb -s "$SERIAL" shell input tap 270 480 -sleep 0.6 -adb -s "$SERIAL" shell input tap 810 1440 -sleep 0.6 - -log 'swipe' -adb -s "$SERIAL" shell input swipe 200 1000 880 1000 250 -sleep 0.6 - -log 'dpad keys' -for k in KEYCODE_DPAD_RIGHT KEYCODE_DPAD_LEFT KEYCODE_DPAD_DOWN KEYCODE_DPAD_UP; do - adb -s "$SERIAL" shell input keyevent "$k" - sleep 0.3 -done - -log 'alphanumerics' -for k in KEYCODE_S KEYCODE_C KEYCODE_R KEYCODE_C KEYCODE_P KEYCODE_Y; do - adb -s "$SERIAL" shell input keyevent "$k" - sleep 0.25 -done - -sleep 1 -adb -s "$SERIAL" shell input tap 540 960 -sleep 2 - -# ---- 8. stop capture, stitch ---- -rm -f "$TMPDIR/recording" -wait "$CAP_PID" 2>/dev/null || true - -count=$(ls "$FRAMES"/*.png 2>/dev/null | wc -l) -log "captured $count frames" -[ "$count" -gt 0 ] || { log 'no frames captured'; exit 1; } - -log "stitching $FRAMES/*.png -> $OUT" -ffmpeg -y -framerate "$FPS" -pattern_type glob -i "$FRAMES/f_*.png" \ - -c:v libx264 -pix_fmt yuv420p -movflags +faststart "$OUT" \ - >/dev/null 2>&1 - -# ---- 9. cleanup ---- -adb -s "$SERIAL" logcat -d -s scrcpy-android > "$TMPDIR/logcat.record.scrcpy" 2>&1 || true -log "app log: $TMPDIR/logcat.record.scrcpy" -adb -s "$SERIAL" emu kill || true -log "wrote $(wc -c <"$OUT") bytes to $OUT" -log 'done' -- cgit v1.2.3