- 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。
283 lines
13 KiB
Bash
Executable File
283 lines
13 KiB
Bash
Executable File
#!/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 ]
|