mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
164 lines
7.1 KiB
Bash
164 lines
7.1 KiB
Bash
# P12 android stage - device check helpers. Sourced, never run. Needs STAMP (p12w1-<sha8>).
|
|
# Every script that sources this re-runs itself under the shared device lock (flock -o, like
|
|
# window-2's lib.sh), so nothing it leaves running keeps the phone locked.
|
|
SERIAL=2f7cbe2e
|
|
PKG=top.mobilegl.plugin.p7w1.trace
|
|
TOKEN=p7w1b-lan-token-20260922 # >= 16 bytes
|
|
LISTEN=tcp://127.0.0.1:40613 # loopback on the phone, reached through adb forward
|
|
ENDPOINT=tcp://127.0.0.1:40613
|
|
: "${STAMP:?set STAMP=p12w1-<sha8>}"
|
|
BUILD_OUT=$HOME/w7/logs/p7w7/$STAMP
|
|
HOST=$BUILD_OUT/host
|
|
BUILD_TREE=$(. "$BUILD_OUT/build.env"; echo "$BUILD_TREE")
|
|
FIX=$BUILD_TREE/tools/trace_replay/fixtures
|
|
DEV=$HOME/w7/logs/p12/device
|
|
LOCK=$HOME/w7/locks/$SERIAL.lock
|
|
|
|
if [ "${P12_LOCK_HELD:-}" != 1 ]; then
|
|
export P12_LOCK_HELD=1
|
|
exec flock -o -w 3600 "$LOCK" bash "$0" "$@"
|
|
fi
|
|
|
|
A() { adb -s "$SERIAL" "$@"; }
|
|
Ash() { adb -s "$SERIAL" shell "$@" | tr -d '\r'; }
|
|
log() { printf '[%s] %s\n' "$(date +%T)" "$*"; }
|
|
devtime() { Ash "date +'%m-%d %H:%M:%S.000'"; }
|
|
wake() { Ash input keyevent KEYCODE_WAKEUP; Ash wm dismiss-keyguard > /dev/null 2>&1 || true; }
|
|
tds() { python3 "$BUILD_TREE/tools/trace_replay/tcp_device_server.py" "$@" --serial "$SERIAL" --package "$PKG" \
|
|
--listen "$LISTEN" --token "$TOKEN"; }
|
|
force_stop() { Ash am force-stop "$PKG"; }
|
|
pid_of() { Ash "pidof $1" | awk '{print $1}'; }
|
|
ps_mobilegl() { Ash "ps -A -o PID,PPID,NAME,ARGS" | grep -E "mobilegl|MobileGL" | grep -v grep; }
|
|
logcat_since() { A logcat -d -v threadtime -T "$1"; } # <devtime>
|
|
# mglines <logcat file>: only this package's own tags (MobileGL native lines, the Activity, the service).
|
|
mglines() { grep -E " [VDIWEF] (MobileGL|MobileGLDisplay|MobileGLServer) *:" "$1" | cut -c1-300; }
|
|
|
|
# wait_logcat <devtime> <extended-regex> <seconds>: 0 once logcat since <devtime> matches.
|
|
wait_logcat() {
|
|
local since=$1 pattern=$2 limit=$3 n=0
|
|
while [ $n -lt $((limit * 2)) ]; do
|
|
if logcat_since "$since" 2>/dev/null | grep -Eq -- "$pattern"; then return 0; fi
|
|
sleep 0.5; n=$((n + 1))
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# case_args <case>: archive trace golden target width height crop_x crop_y crop_w crop_h
|
|
case_args() {
|
|
python3 - "$BUILD_TREE/tools/trace_replay/trace_cases.json" "$1" <<'EOF'
|
|
import json, sys
|
|
m = json.load(open(sys.argv[1])); d = m["defaults"]
|
|
c = next(c for c in m["cases"] if c["name"] == sys.argv[2])
|
|
g = lambda k: c.get(k, d.get(k))
|
|
print(g("trace_archive"), g("trace_file"), g("golden"), g("target_call"), g("width"), g("height"),
|
|
g("crop_x"), g("crop_y"), g("crop_width"), g("crop_height"), g("ssim_threshold"))
|
|
EOF
|
|
}
|
|
|
|
# replay <dir> <case> <backend> <window|pbuffer> [K=V ...]: one host retrace against ENDPOINT, the
|
|
# run_trace_case.cmake invocation plus the surface flag. Writes <dir>/{replay.log,rc,t0,t1,output/}.
|
|
replay() {
|
|
local dir=$1 case=$2 backend=$3 surface=$4; shift 4
|
|
local archive trace golden target w h cx cy cw ch ssim
|
|
read -r archive trace golden target w h cx cy cw ch ssim < <(case_args "$case")
|
|
rm -rf "$dir/input" "$dir/output"; mkdir -p "$dir/input" "$dir/output"
|
|
tar xzf "$FIX/$archive" -C "$dir/input"
|
|
local flag=--pbuffer-surface; [ "$surface" = window ] && flag=--window-surface
|
|
date +%s.%N > "$dir/t0"
|
|
env -u DISPLAY -u WAYLAND_DISPLAY -u MOBILEGL_IPC_SURFACE \
|
|
MOBILEGL_TRANSPORT=spawn MOBILEGL_IPC_CONTROL="$ENDPOINT" MOBILEGL_IPC_DATA=stream \
|
|
MOBILEGL_IPC_TOKEN="$TOKEN" MOBILEGL_IPC_REQUIRE_SAME_BUILD=1 MOBILEGL_IPC_LOG_FORWARD=1 \
|
|
MOBILEGL_LOG_FILE_PATH="$dir/output/mobilegl.log" "$@" \
|
|
timeout 900 "$HOST/mobilegl_trace_replay" --trace "$dir/input/$trace" --golden "$FIX/$golden" \
|
|
--diff "$dir/output/$case-diff.png" --output "$dir/output" --backend "$backend" \
|
|
--mobilegl-library "$HOST/libMobileGL.so" --target-call "$target" --width "$w" --height "$h" \
|
|
--ssim-threshold "$ssim" --crop-x "$cx" --crop-y "$cy" --crop-width "$cw" --crop-height "$ch" \
|
|
"$flag" > "$dir/replay.log" 2>&1
|
|
local rc=$?
|
|
date +%s.%N > "$dir/t1"
|
|
echo "$rc" > "$dir/rc"
|
|
rm -rf "$dir/input"
|
|
return $rc
|
|
}
|
|
|
|
# shots <dir> <pid>: adb screencaps every ~1 s while <pid> lives -> <dir>/shots/NN.png + shots.tsv
|
|
shots() {
|
|
local dir=$1 pid=$2 n=0
|
|
mkdir -p "$dir/shots"
|
|
while kill -0 "$pid" 2> /dev/null; do
|
|
local t0 t1 f
|
|
f=$(printf '%s/shots/%02d.png' "$dir" "$n")
|
|
t0=$(date +%s.%N)
|
|
A exec-out screencap -p > "$f" 2> /dev/null
|
|
t1=$(date +%s.%N)
|
|
printf '%s\t%s\t%s\n' "$n" "$t0" "$t1" >> "$dir/shots.tsv"
|
|
n=$((n + 1))
|
|
sleep 0.7
|
|
done
|
|
}
|
|
|
|
# replay_with_shots <dir> <case> <backend> <surface> [K=V ...]
|
|
replay_with_shots() {
|
|
local dir=$1
|
|
mkdir -p "$dir"; : > "$dir/shots.tsv"
|
|
replay "$@" &
|
|
local pid=$!
|
|
shots "$dir" "$pid" &
|
|
local shooter=$!
|
|
wait "$pid"; local rc=$?
|
|
wait "$shooter" 2> /dev/null
|
|
return $rc
|
|
}
|
|
|
|
# shot_report <dir>: per screencap, whether it was taken DURING the replay and how much of the
|
|
# screen is non-black; the best during-replay shot is copied (and a 540p copy made) as evidence.
|
|
shot_report() {
|
|
python3 - "$1" <<'EOF'
|
|
import sys, pathlib
|
|
from PIL import Image
|
|
d = pathlib.Path(sys.argv[1])
|
|
t0 = float((d / "t0").read_text()); t1 = float((d / "t1").read_text())
|
|
best = None
|
|
rows = []
|
|
for line in (d / "shots.tsv").read_text().splitlines():
|
|
n, a, b = line.split("\t"); a = float(a); b = float(b)
|
|
f = d / "shots" / f"{int(n):02d}.png"
|
|
try:
|
|
im = Image.open(f).convert("L")
|
|
except Exception as e:
|
|
rows.append(f"{n} unreadable {e}"); continue
|
|
small = im.resize((im.width // 4, im.height // 4))
|
|
px = list(small.getdata())
|
|
lit = sum(1 for p in px if p > 24) / len(px)
|
|
mean = sum(px) / len(px)
|
|
during = a >= t0 and b <= t1
|
|
rows.append(f"{n} t=+{a - t0:6.2f}s..+{b - t0:6.2f}s during={during} nonblack={lit:.3f} mean={mean:.1f}")
|
|
if during and (best is None or lit > best[1]):
|
|
best = (f, lit, mean, a - t0)
|
|
print(f"replay ran {t1 - t0:.2f}s; {len(rows)} screencaps")
|
|
print("\n".join(rows))
|
|
if best:
|
|
f, lit, mean, at = best
|
|
ev = d / "evidence-during-replay.png"
|
|
ev.write_bytes(f.read_bytes())
|
|
im = Image.open(f); h = 540; w = max(1, im.width * h // im.height)
|
|
im.resize((w, h)).save(d / "evidence-during-replay-540p.png")
|
|
print(f"BEST during-replay screencap: {f.name} at +{at:.2f}s nonblack={lit:.3f} mean={mean:.1f} -> {ev}")
|
|
else:
|
|
print("NO screencap was taken during the replay")
|
|
EOF
|
|
}
|
|
|
|
# result_summary <dir>: the runner's own verdict (result.json) and the arm proofs from the logs.
|
|
result_summary() {
|
|
local dir=$1
|
|
echo "rc=$(cat "$dir/rc" 2>/dev/null)"
|
|
python3 - "$dir/output/result.json" <<'EOF' 2>/dev/null || echo "result.json: missing"
|
|
import json, sys
|
|
r = json.load(open(sys.argv[1]))
|
|
print("result.json:", {k: r.get(k) for k in ("passed", "statusCode", "ssim", "message", "matchedGoldenPath")})
|
|
EOF
|
|
grep -hE "surface=(window|pbuffer)|control=tcp data=stream server=|owner=server|Refuse ServerOwned|NoServerDisplay|SurfaceModeMismatch|ServerWindowLost|device lost|DEVICE_LOST|Welcome" \
|
|
"$dir"/output/mobilegl*.log 2>/dev/null | cut -c1-300 | sort | uniq -c | sort -rn | head -20
|
|
}
|