#!/bin/bash # verify_apps.sh — R3 Pro II 应用加载器真机全链路验证编排 # # 用法: # ./verify_apps.sh stab 稳定性检查(60s 单实例无 recovery_all) # ./verify_apps.sh nav QOBUZ 触摸注入导航流媒体页->Qobuz(应用列表页) # ./verify_apps.sh shot fb0 截图存 device_test/.png(+ascii) # ./verify_apps.sh tap goodix 触摸注入(坐标按设备 abs 缩放) # ./verify_apps.sh scen 布置 TF 卡场景 n (0..5, 见下) # ./verify_apps.sh exitapp 让 hello 退出(注入任意键) # ./verify_apps.sh wdtap 点击看门狗虚拟返回键(20,20) # ./verify_apps.sh loop 重复 n 次 列表->启动->返回键退出 # ./verify_apps.sh devinfo 输入设备 abs 范围等调试信息 # # 场景: # scen 0 正常: MeowAPPs/hello/(hello + app.json 有效) # scen 1 无卡: umount sd_0 (测试后必须 scen 0 恢复) # scen 2 无 MeowAPPs 目录 # scen 3 MeowAPPs 空目录 # scen 4 坏 app.json(缺 exec 字段, 应跳过) # scen 5 exec 不存在(点击应提示无法启动) set -u DEV="" KEY="$HOME/Project/R3ProII/ssh_keys/" SSH="ssh -i $KEY -o StrictHostKeyChecking=accept-new -o ConnectTimeout=8" ROOT=~/Project/R3ProII TAP=$ROOT/patch_v2/uinput_tap/uinput_tap SD=/usr/data/mnt/sd_0 s() { timeout 40 $SSH root@$DEV "$1"; } devinfo() { echo "== input devices ==" s 'for d in /sys/class/input/event*/device; do [ -f $d/name ] && echo "event$(basename $(dirname $d)|cut -c6-) $(cat $d/name)"; done 2>/dev/null' s 'cat /proc/bus/input/devices | grep -A6 -E "goodix|Name=" | head -50' } # 触摸注入: 自动按 goodix abs 范围把屏幕坐标(480x720)换算成设备坐标 tap() { local sx=$1 sy=$2 # 从 /proc/bus/input/devices 解析 goodix 的 ABS_MT_POSITION_X/Y(优先) 或 ABS_X/Y 的 max local devinfo=$(s 'cat /proc/bus/input/devices') local maxx maxy maxx=$(echo "$devinfo" | awk '/Name="goodix/{f=1} f&&/ABS_MT_POSITION_X|ABS_X/{for(i=1;i<=NF;i++){gsub(/,/,"",$i); if($i ~ /^[0-9]+$/ && $i+0>m) m=$i+0}} END{print m}') maxy=$(echo "$devinfo" | awk '/Name="goodix/{f=1} f&&/ABS_MT_POSITION_Y|ABS_Y/{for(i=1;i<=NF;i++){gsub(/,/,"",$i); if($i ~ /^[0-9]+$/ && $i+0>m) m=$i+0}} END{print m}') [ -z "$maxx" ] || [ "$maxx" = "0" ] && maxx=767 [ -z "$maxy" ] || [ "$maxy" = "0" ] && maxy=1279 local dx=$(( sx * maxx / 480 )) local dy=$(( sy * maxy / 720 )) echo "tap screen($sx,$sy) -> dev($dx,$dy) max($maxx,$maxy)" s "/data/uinput_tap inject $dx $dy /dev/input/event1" } stab() { echo "== 60s 稳定性检查 ==" sleep 60 s 'echo "instances=$(ps | grep hiby_player | grep -v grep | grep -v sh | wc -l)"; ps | grep hiby_player | grep -v grep | grep -v sh; ls /data/recovery_all 2>/dev/null && echo FLAG || echo no_flag' } shot() { local name=${1:-shot} s 'dd if=/dev/fb0 of=/data/x.raw bs=691200 count=1 2>/dev/null' timeout 30 $SSH root@$DEV "cat /data/x.raw" > $ROOT/device_test/$name.raw python3 $ROOT/device_test/fb2png.py $ROOT/device_test/$name.raw $ROOT/device_test/$name.png >/dev/null 2>&1 # 判定色深并生成 ascii local sz=$(stat -c%s $ROOT/device_test/$name.raw) if [ "$sz" = "691200" ]; then python3 $ROOT/device_test/ascii_fb.py $ROOT/device_test/$name.raw 96 40 > $ROOT/device_test/$name.txt else echo "unexpected raw size $sz" fi echo "saved $ROOT/device_test/$name.png (raw $sz)" } nav() { # nav: 假设当前在流媒体页; 注入 Qobuz 入口点击 tap 355 95 sleep 2 } exitapp() { # 注入一个任意键事件让 hello 退出 (VOLUMEUP 键事件直接写 event1) s "/data/uinput_tap key 115" 2>/dev/null || \ s "printf '\x01\x00\x00\x00\x00\x00\x00\x00\x73\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > /dev/input/event1" 2>/dev/null || \ echo "key inject failed, fallback: send SIGTERM via watchdog tap" } wdtap() { tap 20 20 sleep 2 } scen() { local n=${1:-0} case $n in 0) s "mkdir -p $SD/MeowAPPs/hello; cp -f /data/hello.bin $SD/MeowAPPs/hello/hello; cp -f /data/hello_app.json $SD/MeowAPPs/hello/app.json; chmod 755 $SD/MeowAPPs/hello/hello; ls $SD/MeowAPPs/hello/; echo SCEN0_OK" ;; 1) s "umount $SD 2>/dev/null || umount /usr/data/mnt/sd_0 2>/dev/null; grep sd_0 /proc/mounts || echo SCEN1_NOCARD_OK" ;; 2) s "mv $SD/MeowAPPs $SD/MeowAPPs.bak 2>/dev/null; ls $SD/ 2>/dev/null; echo SCEN2_NODIR_OK" ;; 3) s "mkdir -p $SD/MeowAPPs; ls -la $SD/MeowAPPs/; echo SCEN3_EMPTY_OK" ;; 4) s "mkdir -p $SD/MeowAPPs/hello $SD/MeowAPPs/bad; cp -f /data/hello.bin $SD/MeowAPPs/hello/hello; cp -f /data/hello_app.json $SD/MeowAPPs/hello/app.json; chmod 755 $SD/MeowAPPs/hello/hello; echo '{\"name\":\"Bad App\"}' > $SD/MeowAPPs/bad/app.json; cat $SD/MeowAPPs/bad/app.json; echo SCEN4_BADJSON_OK" ;; 5) s "mkdir -p $SD/MeowAPPs/hello $SD/MeowAPPs/nonexec; cp -f /data/hello.bin $SD/MeowAPPs/hello/hello; cp -f /data/hello_app.json $SD/MeowAPPs/hello/app.json; chmod 755 $SD/MeowAPPs/hello/hello; echo '{\"name\":\"Ghost App\",\"exec\":\"/usr/data/mnt/sd_0/MeowAPPs/nonexec/nope\"}' > $SD/MeowAPPs/nonexec/app.json; cat $SD/MeowAPPs/nonexec/app.json; echo SCEN5_NOEXEC_OK" ;; *) echo "usage: scen 0..5"; return 1 ;; esac } loop() { local n=${1:-3} for i in $(seq 1 $n); do echo "== loop $i ==" nav shot loop_${i}_list tap 240 112 # 第 0 行 (hello) sleep 3 shot loop_${i}_app wdtap # 看门狗返回键 sleep 2 shot loop_${i}_back done } case "${1:-}" in stab) stab ;; nav) nav ;; shot) shot "${2:-shot}" ;; tap) tap "${2:-0}" "${3:-0}" ;; scen) scen "${2:-0}" ;; exitapp) exitapp ;; wdtap) wdtap ;; loop) loop "${2:-3}" ;; devinfo) devinfo ;; *) echo "usage: $0 stab|nav|shot [name]|tap x y|scen 0..5|exitapp|wdtap|loop [n]|devinfo"; exit 1 ;; esac