Files
MeowOS-For-R3P2/patch_v2/meow_powermgr/test_powermgr.sh
T
AskaEth 5663acfbb9 feat(powermgr): 期3 policy 生效 + 标定工具 + 模型单键 setter + events 说明
- policy:IPC 0xD2/0xD3 GET/SET(SET 动作级鉴权=root+系统身份,SO_PEERCRED→pid→exe→classify,同 svc_power)
  + CLI `meow_power policy show|set`。策略项 profile 四档(performance/balanced/powersave/ultra)
  + 低电阈值(power.low_pct/critical_pct 读 settings.conf) + 亮度上限(power.brightness_cap)
  + 息屏上限(power.screen_timeout_cap)。**默认全关**(profile=balanced 无操作=现状, cap=0 不生效,
  只能用户手动开)。生效方式: powermgr 不直接写系统——只写 settings.conf power.* 键(原子),
  launcher/sysui 期4 消费; 本服务绝不 poke 背光/息屏/wlan0/bt。低电/极低阈值改从 settings.conf
  读, 事件检测即时生效。
- calibrate:`meow_power calibrate start <场景>|stop|list`——守护内 2s 节拍采样 电流(mp2731
  current_now)+亮度+CPU+wifi/bt 状态+电量%变化,写 TF MeowOS/logs/power_calib_<epoch>.csv
  (无卡降级 /tmp,逐行 fflush),用户实验中 start/stop 两命令即可。
- model:`meow_power model set <key> <mw>` 读改写单键+原子写(tmp+rename),守护每拍重载 conf。
- events:App 前后台切换——launcher MSG_ACT_FOCUS 为单向 app→launcher 上报,powermgr 侧无导出点
  可接,诚实标注「期4 接 launcher」扩展,本期不编造该事件(延续期2 口径)。
- 验证:宿主+qemu 全量 76/76 PASS(期1/2 全过+新增 policy/calibrate/model-set 用例),mipsel
  静态交叉 0 warning,二进制 151516B(<200KB 阈值)。md5 1ef2f8afc07acc7aa09dee9f7149aba8。
2026-09-02 16:25:51 +08:00

283 lines
13 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# test_powermgr.sh — meow_powermgr 宿主桩测试(假 sysfs/procfs 节点,MEOW_*_DIR env 覆盖)。
# 用法:./test_powermgr.sh [host二进制路径](默认 ./meow_powermgr_host;可传 mipsel 二进制 + QEMU 前缀)
# QEMU="qemu-mipsel" ./test_powermgr.sh ./meow_powermgr # qemu 验证
set -u
cd "$(dirname "$0")"
BIN="${1:-./meow_powermgr_host}"
Q="${QEMU:-}"
T=$(mktemp -d /tmp/pmtest.XXXXXX)
trap 'kill $DPID 2>/dev/null; rm -rf "$T"' EXIT
PASS=0; FAIL=0
ck() { # ck <名> <期望子串> <实际>
if echo "$3" | grep -qF "$2"; then PASS=$((PASS+1)); echo "PASS $1";
else FAIL=$((FAIL+1)); echo "FAIL $1: 期望含 [$2] 实际=[$3]"; fi
}
# ---- 搭假节点 ----
PS="$T/ps"; BL="$T/bl"; NET="$T/net"; RF="$T/rfkill"; BT="$T/bt"
mkdir -p "$PS/battery" "$PS/mp2731-charger" "$PS/fusb302-typec-source" "$PS/ac" \
"$BL" "$NET/wlan0" "$RF/rfkill0" "$BT/hci0"
echo 94 > "$PS/battery/capacity"
echo Discharging > "$PS/battery/status"
echo 4275000 > "$PS/battery/voltage_now"
echo Good > "$PS/battery/health"
echo Li-ion > "$PS/battery/technology"
echo Discharging > "$PS/mp2731-charger/status" # 权威链
echo 300 > "$PS/mp2731-charger/temp"
echo 0 > "$PS/fusb302-typec-source/online"
echo 0 > "$PS/ac/online"
echo 101 > "$BL/max_brightness" # R3 Pro II 实测量程 0-101
echo 50 > "$BL/actual_brightness" # 中档(49%)
echo 50 > "$BL/brightness"
echo up > "$NET/wlan0/operstate"
echo 1 > "$NET/wlan0/carrier" # 已关联(carrier 0=未关联)
echo bluetooth > "$RF/rfkill0/type"
echo 1 > "$RF/rfkill0/soft" # BT 被 soft 块 → off
cat > "$T/netdev" <<'EOF'
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
wlan0: 1000000 1000 0 0 0 0 0 0 2000000 1000 0 0 0 0 0 0
EOF
echo "cpu 100 0 100 800 0 0 0 0 0 0" > "$T/proc_stat"
echo meow > "$T/boot_mode"
mkdir -p "$T/logs" # 标定 CSV 落点(MEOW_LOG_DIR)
cat > "$T/settings.conf" <<'SEOF'
# meow-settings 1 (测试桩:policy power.* 键落点)
SEOF
ENVS="MEOW_PS_DIR=$PS MEOW_BL_DIR=$BL MEOW_NET_DIR=$NET MEOW_RFKILL_DIR=$RF MEOW_BT_DIR=$BT
MEOW_NETDEV=$T/netdev MEOW_PROC_STAT=$T/proc_stat MEOW_BOOT_MODE=$T/boot_mode
MEOW_PM_MODEL=$T/model.conf MEOW_SETTINGS_FILE=$T/settings.conf MEOW_LOG_DIR=$T/logs
MEOW_AUDIO_SOCK=$T/no_audio.sock MEOW_PM_SOCK=$T/pm.sock
MEOW_PM_NO_HCICONFIG=1 MEOW_PM_AUTH_TEST=1"
ln -sf "$(readlink -f "$BIN")" "$T/meow_power" # argv[0] 双形态
# ---- T1: 守护直读(无守护 → 降级直读) ----
OUT=$(env $ENVS $Q "$T/meow_power" status 2>/dev/null)
ck T1a "state=Discharging cap=94%" "$OUT"
echo "$OUT" | grep -q "mv=4275" && { PASS=$((PASS+1)); echo "PASS T1b mv"; } || { FAIL=$((FAIL+1)); echo "FAIL T1b: $OUT"; }
ck T1c "health=Good" "$OUT"
ck T1d "charger_temp=30.0C" "$OUT"
ck T1e "rate=null" "$OUT"
ck T1f "src=direct" "$OUT"
# ---- T2: 起守护,IPC 路径 ----
env $ENVS MEOW_PM_SAMPLE_SEC=1 MEOW_PM_MIN_SPAN_SEC=2 $Q "$BIN" --sock "$T/pm.sock" >"$T/daemon.log" 2>&1 &
DPID=$!
for i in $(seq 1 30); do [ -S "$T/pm.sock" ] && break; sleep 0.2; done
[ -S "$T/pm.sock" ] || { echo "FAIL T0: daemon socket 未出现"; cat "$T/daemon.log"; exit 1; }
PASS=$((PASS+1)); echo "PASS T0 daemon up"
OUT=$(env $ENVS $Q "$T/meow_power" status 2>/dev/null)
ck T2a "src=daemon" "$OUT"
ck T2b "cap=94%" "$OUT"
ck T2c "mode=meow" "$OUT"
# ---- T3: 容量差分速率(94→93,span≥2s)→ rate/est_left=derived ----
echo 93 > "$PS/battery/capacity"
sleep 4
OUT=$(env $ENVS $Q "$T/meow_power" status 2>/dev/null)
ck T3a "conf=derived" "$OUT"
ck T3b "est_left=" "$OUT"
echo "$OUT" | grep -q "rate=-" && { PASS=$((PASS+1)); echo "PASS T3c 放电速率为负"; } || { FAIL=$((FAIL+1)); echo "FAIL T3c: $OUT"; }
# ---- T4: estimate(模型合成;中档背光+面板+wifi idle+bt off+audio unknown) ----
OUT=$(env $ENVS $Q "$T/meow_power" estimate 2>/dev/null)
ck T4a "confidence=estimated" "$OUT"
ck T4b "待真机标定" "$OUT"
ck T4c "backlight=450" "$OUT" # 49% → 中档 450
ck T4d "panel=80" "$OUT"
ck T4e "bt=0(off)" "$OUT" # rfkill soft=1 → off
ck T4f "audio=0(unknown)" "$OUT" # 无 audiod → unknown 0mW
# est_mw = 300(base)+450+80+200(wifi idle)+0+0+cpu(0,静态proc_stat)=1030
ck T4g "est_mw=1030" "$OUT"
# ---- T5: wifi 传输档(netdev 增量 >4096/拍 → tx=600) ----
sed -i 's/wlan0: 1000000/wlan0: 1999999/; s/ 2000000 / 2999999 /' "$T/netdev"
sleep 3
OUT=$(env $ENVS $Q "$T/meow_power" estimate 2>/dev/null)
ck T5a "wifi=600(tx)" "$OUT"
# ---- T5b: wifi 未关联(carrier=0)→ unassoc 档 ----
echo 0 > "$NET/wlan0/carrier"
sleep 2
OUT=$(env $ENVS $Q "$T/meow_power" estimate 2>/dev/null)
ck T5b "wifi=80(unassoc)" "$OUT"
echo 1 > "$NET/wlan0/carrier"
# ---- T5c: BT up(rfkill 未软块 + hci0 存在;host 无 hciconfig → 回退 up) ----
echo 0 > "$RF/rfkill0/soft"
sleep 2
OUT=$(env $ENVS $Q "$T/meow_power" estimate 2>/dev/null)
ck T5c "bt=60(up)" "$OUT"
echo 1 > "$RF/rfkill0/soft"
# ---- T6: 息屏(actual_brightness=0)→ 背光/面板归零 ----
echo 0 > "$BL/actual_brightness"
OUT=$(env $ENVS $Q "$T/meow_power" estimate 2>/dev/null)
ck T6a "backlight=0" "$OUT"
ck T6b "panel=0" "$OUT"
echo 50 > "$BL/actual_brightness"
# ---- T7: 模型 conf 覆盖 ----
printf '# test\nbaseline_mw=999\nwifi_idle_mw=111\n' > "$T/model.conf"
OUT=$(env $ENVS $Q "$T/meow_power" model 2>/dev/null)
ck T7a "baseline_mw=999" "$OUT"
ck T7b "wifi_idle_mw=111" "$OUT"
ck T7c "bl_high_mw=900" "$OUT" # 未覆盖键留默认
rm -f "$T/model.conf"
# ---- T8: HibyOS 只读降级(不施估算;电池仍可读) ----
echo hiby > "$T/boot_mode"
sleep 2 # 等守护下一拍热切换
OUT=$(env $ENVS $Q "$T/meow_power" estimate 2>/dev/null)
ck T8a "HibyOS 只读模式" "$OUT"
OUT=$(env $ENVS $Q "$T/meow_power" status 2>/dev/null)
ck T8b "cap=93%" "$OUT" # 只读模式电池采样不受影响
ck T8c "mode=readonly" "$OUT"
echo meow > "$T/boot_mode"
sleep 2
OUT=$(env $ENVS $Q "$T/meow_power" estimate 2>/dev/null)
ck T8d "est_mw=" "$OUT" # 热切换回全功能
# ---- T9: 期 2 CLI — history(守护采样环)/policy(期3桩) ----
sleep 1 # 再采几拍,history 有样本
OUT=$(env $ENVS $Q "$T/meow_power" history 2>&1)
ck T9a "history:" "$OUT"
ck T9b "采样点" "$OUT"
ck T9c "est_mW" "$OUT"
echo "$OUT" | grep -q "守护不可达" && { FAIL=$((FAIL+1)); echo "FAIL T9d 应走守护"; } || { PASS=$((PASS+1)); echo "PASS T9d via-daemon"; }
# ---- T9e: 期 3 policy show(默认全关:profile=balanced / cap=0 / enact=off)----
OUT=$(env $ENVS $Q "$T/meow_power" policy show 2>&1)
ck T9e "profile=balanced low_pct=15 critical_pct=5" "$OUT"
ck T9e2 "brightness_cap=0 screen_timeout_cap=0 enact=off" "$OUT"
ck T9e3 "默认全关" "$OUT"
# ---- T9f: 期 3 policy set profile powersave(写入 settings.conf;enact=on)----
OUT=$(env $ENVS $Q "$T/meow_power" policy set profile powersave 2>&1)
ck T9f "policy set profile=powersave" "$OUT"
OUT=$(env $ENVS $Q "$T/meow_power" policy show 2>&1)
ck T9f2 "profile=powersave" "$OUT"
ck T9f3 "enact=on" "$OUT"
grep -q "power.profile=powersave" "$T/settings.conf" && { PASS=$((PASS+1)); echo "PASS T9f4 settings 键"; } || { FAIL=$((FAIL+1)); echo "FAIL T9f4: $(cat "$T/settings.conf")"; }
# ---- T9g: 期 3 低电阈值读 settings.conf(power.low_pct=20 生效于事件判定)----
env $ENVS $Q "$T/meow_power" policy set low-pct 20 >/dev/null 2>&1
echo 19 > "$PS/battery/capacity" # 从 93 跳到 19 < 20 → 低电事件(阈值 20%)
sleep 4 # 等守护节拍采样
OUT=$(env $ENVS $Q "$T/meow_power" policy show 2>&1)
ck T9g "low_pct=20" "$OUT"
OUT=$(env $ENVS $Q "$T/meow_power" events 2>&1)
ck T9g2 "阈值 20%" "$OUT"
echo 93 > "$PS/battery/capacity" # 恢复
env $ENVS $Q "$T/meow_power" policy set low-pct 15 >/dev/null 2>&1
env $ENVS $Q "$T/meow_power" policy set profile balanced >/dev/null 2>&1
# ---- T9h: 期 3 policy set bri-cap(0-101 越界拒绝)----
OUT=$(env $ENVS $Q "$T/meow_power" policy set bri-cap 88 2>&1)
ck T9h "policy set bri-cap=88" "$OUT"
OUT=$(env $ENVS $Q "$T/meow_power" policy set bri-cap 255 2>&1)
ck T9h2 "0-101" "$OUT"
env $ENVS $Q "$T/meow_power" policy set bri-cap 0 >/dev/null 2>&1
# ---- T9i: 期 3 标定工具 calibrate start/stop/list 出 CSV ----
OUT=$(env $ENVS $Q "$T/meow_power" calibrate start 纯亮屏 2>&1)
ck T9i "calibrate 已启动" "$OUT"
ck T9i2 "power_calib_" "$OUT"
sleep 5 # 等 2s×2 拍
OUT=$(env $ENVS $Q "$T/meow_power" calibrate stop 2>&1)
ck T9i3 "calibrate 已停止" "$OUT"
ck T9i4 "rows=" "$OUT"
CSV=$(ls "$T/logs"/power_calib_*.csv 2>/dev/null | head -1)
if [ -n "$CSV" ]; then PASS=$((PASS+1)); echo "PASS T9i5 csv exists ($CSV)"; else FAIL=$((FAIL+1)); echo "FAIL T9i5 CSV 未生成"; fi
[ -n "$CSV" ] && grep -q "ts,cap_pct,vol_mv,current_ua,charge_mw,brightness_pct,cpu_util_pct,wifi_state,bt_state" "$CSV" && { PASS=$((PASS+1)); echo "PASS T9i6 csv header"; } || { FAIL=$((FAIL+1)); echo "FAIL T9i6 csv header"; }
[ -n "$CSV" ] && grep -q "scene=纯亮屏" "$CSV" && { PASS=$((PASS+1)); echo "PASS T9i7 csv scene"; } || { FAIL=$((FAIL+1)); echo "FAIL T9i7 csv scene"; }
OUT=$(env $ENVS $Q "$T/meow_power" calibrate list 2>&1)
ck T9i8 "power_calib_" "$OUT"
# ---- T9j: 期 3 模型单键 setter model set <key> <mw>(守护每拍重载生效)----
OUT=$(env $ENVS $Q "$T/meow_power" model set baseline_mw 999 2>&1)
ck T9j "model set baseline_mw=999" "$OUT"
OUT=$(env $ENVS $Q "$T/meow_power" model 2>/dev/null)
ck T9j2 "baseline_mw=999" "$OUT"
sleep 2 # 等守护重载 model
OUT=$(env $ENVS $Q "$T/meow_power" estimate 2>/dev/null)
ck T9j3 "baseline=999" "$OUT" # 守护侧 estimate 用新系数
OUT=$(env $ENVS $Q "$T/meow_power" model set bad_key 5 2>&1)
ck T9j4 "未知键" "$OUT"
env $ENVS $Q "$T/meow_power" model set baseline_mw 300 >/dev/null 2>&1
# ---- T10: meow_powermgr 名直调子命令也走 CLI ----
OUT=$(env $ENVS $Q "$BIN" model 2>/dev/null)
ck T10a "nominal_mah=1600" "$OUT"
# ---- T13: mp2731 current_now 充电功率实测接入(期 2 项 5)----
echo Charging > "$PS/mp2731-charger/status"
echo 1500000 > "$PS/mp2731-charger/current_now"
echo 4200000 > "$PS/mp2731-charger/constant_charge_voltage"
sleep 2
OUT=$(env $ENVS $Q "$T/meow_power" estimate 2>/dev/null)
ck T13a "charge=+6300mW" "$OUT" # 4.2V×1.5A=6.3W
ck T13b "confidence=measured" "$OUT" # 充电功率升 measured
OUT=$(env $ENVS $Q "$T/meow_power" status 2>/dev/null)
ck T13c "state=Charging" "$OUT" # 权威链 mp2731=Charging
echo Discharging > "$PS/mp2731-charger/status"
echo 0 > "$PS/mp2731-charger/current_now"
sleep 2
OUT=$(env $ENVS $Q "$T/meow_power" estimate 2>/dev/null)
ck T13d "charge=null" "$OUT" # 放电 → 无实测轨
# ---- T14: 电源事件流(充电器插拔 + 息屏,App 前后台诚实标注不支持)----
OUT=$(env $ENVS $Q "$T/meow_power" events 2>&1)
ck T14a "events:" "$OUT"
ck T14b "charger" "$OUT" # 插/拔充电器事件 tag
echo 0 > "$BL/actual_brightness" # 息屏 → screen 事件
sleep 2
OUT=$(env $ENVS $Q "$T/meow_power" events 2>&1)
ck T14c "screen" "$OUT"
ck T14d "息屏" "$OUT"
echo 50 > "$BL/actual_brightness" # 恢复亮屏(供后测)
# ---- T15: top 功耗分解实时排序(一次输出)----
OUT=$(env $ENVS MEOW_PM_TOP_ONCE=1 $Q "$T/meow_power" top 2>/dev/null)
ck T15a "功耗分解" "$OUT"
ck T15b "screen" "$OUT"
ck T15c "baseline" "$OUT"
echo "$OUT" | grep -q "cpu" && { PASS=$((PASS+1)); echo "PASS T15d cpu行"; } || { FAIL=$((FAIL+1)); echo "FAIL T15d"; }
# ---- T16: 模型系数路径(新定案 /data/meow/powermgr/power_model.conf)----
ENVS_NM=$(echo "$ENVS" | tr ' ' '\n' | grep -v '^MEOW_PM_MODEL=' | tr '\n' ' ')
OUT=$(env $ENVS_NM $Q "$T/meow_power" model 2>/dev/null)
ck T16a "powermgr/power_model.conf" "$OUT"
# ---- T11: 守护停 → CLI 自动降级直读不崩 ----
kill $DPID 2>/dev/null; wait $DPID 2>/dev/null; DPID=""
sleep 1
OUT=$(env $ENVS $Q "$T/meow_power" status 2>/dev/null)
ck T11a "src=direct" "$OUT"
ck T11b "cap=93%" "$OUT"
# ---- T12: audiod 在场时音频链分量(真 audiod 二进制当桩:无 HELLO 直接 QUERY 协议) ----
AUDIOD_BIN=../meow_audiod/meow_audiod_host
[ -n "$Q" ] && AUDIOD_BIN=../meow_audiod/meow_audiod
if [ -x "$AUDIOD_BIN" ]; then
env MEOW_AUDIO_FORCE=1 MEOW_AUDIO_SOCK="$T/audio.sock" MEOW_AUDIO_OUT="$T/a.wav" \
MEOW_AUDIO_SINK=null $Q "$AUDIOD_BIN" --sock "$T/audio.sock" >"$T/audiod.log" 2>&1 &
APID=$!
for i in $(seq 1 30); do [ -S "$T/audio.sock" ] && break; sleep 0.2; done
env $ENVS MEOW_AUDIO_SOCK="$T/audio.sock" MEOW_PM_SAMPLE_SEC=1 MEOW_PM_MIN_SPAN_SEC=2 \
MEOW_PM_SOCK="$T/pm2.sock" $Q "$BIN" --sock "$T/pm2.sock" >"$T/daemon2.log" 2>&1 &
DPID=$!
for i in $(seq 1 30); do [ -S "$T/pm2.sock" ] && break; sleep 0.2; done
OUT=$(env $ENVS MEOW_AUDIO_SOCK="$T/audio.sock" MEOW_PM_SOCK="$T/pm2.sock" $Q "$T/meow_power" estimate 2>/dev/null)
ck T12a "audio=50(idle)" "$OUT" # audiod 在场无流 → 静态档 50
kill $DPID $APID 2>/dev/null; wait 2>/dev/null; DPID=""
else
echo "SKIP T12 (无 audiod 二进制 $AUDIOD_BIN)"
fi
echo "=============================="
echo "PASS=$PASS FAIL=$FAIL"
[ $FAIL -eq 0 ]