- sdk/meow_time32: 抽出可独立链接的 o32 time32 取时/睡眠设施(不依赖 meow_ui.a, watchdog 等独立静态组件可直接链;可选 -DMEOW_TIME32_LIBC_OVERRIDES 接管 libc 入口) - watchdog: now_ms/usleep 改走 time32(修复 held 变天文数字→每次单击都弹菜单); 阈值读 power.longpress_menu_ms/forceoff_ms(缺省 3000/8000),删除 PWR_TOGGLE_MS==PWR_MENU_MS;新增 wd_power.h 纯判定 + 宿主行为矩阵测试 - launcher: App 前台电源菜单补齐 §10.5(notif 全抑制 + 帧恢复 + SIGCONT 排空 + 标记翻回前台);show_power_menu 恢复进入前背景帧(关闭后不再停留菜单画面); 重绘挪到首轮按键采样之后;activity 标记排空窗 + 会话入口清理 + manual_off 去闩锁 - lock_screen: 电源改按下边沿 + 进场 300ms 才熄屏;电源熄屏退出也恢复底层帧; launcher 在 SIGCONT 前写 /tmp/meow_app_repaint,SDK present 消费并 dirty_full - power_menu: 菜单内强关接 power.forceoff_ms(按 longpress 抵扣),日志不再谎称 8s - 重编 meow_ui.a 并重链 meow_launcherd/ncm/files/hello/reader(picbrowser 无源码) - fw_content.conf: 同步 launcherd/watchdog 新 md5;顺带修正 M35 遗留的 nyai 失效钉值 Host: test_wd_fw 66/66、test_overlay_gate 40/40、test_meow_time64/time/repaint PASS。 真机未验证(设备关机);未刷机、未写设备。
112 lines
8.3 KiB
C
112 lines
8.3 KiB
C
/* test_overlay_gate.c — §310 三连 bug 的**纯决策**宿主单测(overlay_gate.h + lock_screen.h 谓词)。
|
||
*
|
||
* 覆盖三个症状对应的关闭/恢复决策,不依赖信号/设备/文件系统:
|
||
* S1 锁屏期触摸不穿透 → overlay_drain_required():App 被 SIGSTOP 过(非保活)必须在
|
||
* unlink /tmp/meow_notif_active 前先 SIGCONT + 排窗,让 SDK 输入线程
|
||
* 排空冻结期缓冲的 evdev 事件副本;OVERLAY_DRAIN_WINDOW_MS > SDK 200ms 节流。
|
||
* S2 解锁状态栏恢复 → overlay_force_sb_resync():解锁后必须强制 g_sb_mode_last=-1 重叠加,
|
||
* 不等 app 循环 1s 慢刷(消除「解锁回 App 无状态栏」残留)。
|
||
* S3 App 死亡触发主屏重绘 → lock_overlay_app_died_exit():锁屏叠加期 App 崩溃(僵尸)必须走
|
||
* 统一退出路径(交回 waitpid 循环回收 + run_menu 重绘主屏含状态栏)。
|
||
* S1b 未冻结 App 输入被排 → overlay_keepalive_needs_grab():媒体保活 App(保持运行、SDK 输入
|
||
* 线程实时读 evdev)在锁屏期必须靠 launcher EVIOCGRAB 独占触控设备 +
|
||
* 标记让 SDK 排空——而非冻结 App 的 SIGCONT 排空(drain_required=0)。
|
||
* S1c 手动息屏触发锁屏 → overlay_wake_should_lock():超时息屏(auto_slept)与电源键手动息屏
|
||
* (watchdog blank → manual_panel_off)两类唤醒都须走 lock 语义。
|
||
* S2b 锁屏重铺盖 App 残帧 → OVERLAY_LOCK_COVER_MS:锁屏进场后重铺全屏不透明底的阈值必须
|
||
* > SDK present 抑制标记节流窗(200ms),盖住 App 抑制窗内的残帧。
|
||
* S4 锁屏页自睡(294 遗留) → overlay_lock_idle_off_sec():阈值 = min(系统 screen_off_timeout, 30s)
|
||
* (0/超30→30,尊重更短);overlay_lock_should_sleep()/overlay_lock_wake_now()
|
||
* 判定超时灭屏(锁态保持)与唤醒回锁屏。
|
||
* M40 F3/F4 → overlay_activity_drain_active():叠加/菜单返回后的排空窗内忽略
|
||
* activity 标记(防冻结期输入重放成「亮屏+锁屏」);
|
||
* overlay_lock_power_off_now():锁屏电源必须按下边沿 + 进场≥300ms。
|
||
*
|
||
* 编译运行(在 patch_v2/meow_launcherd 下,无其它依赖):
|
||
* gcc -Wall -Wextra -o test_overlay_gate test_overlay_gate.c && ./test_overlay_gate
|
||
* 全 PASS -> exit 0。
|
||
*/
|
||
#include <stdio.h>
|
||
#include "overlay_gate.h"
|
||
#include "lock_screen.h"
|
||
|
||
static int g_pass = 0, g_fail = 0;
|
||
#define CHECK(cond, msg) do { \
|
||
if (cond) { g_pass++; printf("PASS %s\n", msg); } \
|
||
else { g_fail++; printf("FAIL %s\n", msg); } \
|
||
} while (0)
|
||
|
||
int main(void)
|
||
{
|
||
/* ---- S1 输入穿透:SIGSTOP 过的 App 关闭时必须先排空再 unlink ---- */
|
||
CHECK(overlay_drain_required(0) == 1, "S1 drain required (app was SIGSTOP/frozen)");
|
||
CHECK(overlay_drain_required(1) == 0, "S1 no drain needed (media keep-alive, never stopped)");
|
||
/* 排空窗必须大于 SDK overlay_input_suppressed 的 200ms 标记节流窗,保证恢复后确实重新 stat 到
|
||
* 标记再整批丢弃缓冲事件;此处断言契约不被踩线。 */
|
||
CHECK(OVERLAY_DRAIN_WINDOW_MS > 200, "S1 drain window > SDK 200ms throttle");
|
||
|
||
/* ---- S1b 未冻结(媒体保活)App 输入被排:靠 EVIOCGRAB 独占隔离,非 SIGCONT 排空 ----
|
||
* 保活 App 从不 SIGSTOP(保 PCM),SDK 输入线程实时读 evdev;launcher 只能靠 EVIOCGRAB 独占
|
||
* 触控设备(真机 goodix 已证 EVIOCGRAB 返回 0)使任何前台进程锁屏期收不到触摸。 */
|
||
CHECK(overlay_keepalive_needs_grab(1) == 1, "S1b keep-alive app needs EVIOCGRAB isolation");
|
||
CHECK(overlay_keepalive_needs_grab(0) == 0, "S1b frozen app -> SIGCONT drain, not grab");
|
||
/* 保活 App 隔离与冻结 App 排空互斥:一条路径而非两条。 */
|
||
CHECK(overlay_drain_required(1) == 0 && overlay_keepalive_needs_grab(1) == 1,
|
||
"S1b keep-alive: grab path (drain==0)");
|
||
CHECK(overlay_drain_required(0) == 1 && overlay_keepalive_needs_grab(0) == 0,
|
||
"S1b frozen: drain path (grab==0)");
|
||
|
||
/* ---- S2 解锁状态栏恢复:必须强制重同步 ---- */
|
||
CHECK(overlay_force_sb_resync() == 1, "S2 force status bar re-sync after unlock");
|
||
|
||
/* ---- S2b 锁屏重铺盖 App 残帧(问题2-②):阈值必须 > SDK present 抑制窗(200ms) ---- */
|
||
CHECK(OVERLAY_LOCK_COVER_MS > 200, "S2b lock re-cover ms > SDK suppression window (200ms)");
|
||
CHECK(OVERLAY_LOCK_COVER_MS == 300, "S2b lock re-cover ms = 300 (marker-window margin)");
|
||
|
||
/* ---- S1c 手动息屏触发锁屏(问题1):超时(auto_slept)与手动(manual_panel_off)唤醒都锁 ---- */
|
||
CHECK(overlay_wake_should_lock(0, 0) == 0, "S1c wake, no sleep -> no lock");
|
||
CHECK(overlay_wake_should_lock(1, 0) == 1, "S1c timeout sleep (auto) -> lock");
|
||
CHECK(overlay_wake_should_lock(0, 1) == 1, "S1c manual power sleep (manual) -> lock (was missing)");
|
||
CHECK(overlay_wake_should_lock(1, 1) == 1, "S1c both -> lock");
|
||
|
||
/* ---- S4 锁屏页自睡(294 遗留):阈值 min(系统,30s),超时灭屏锁态保持,唤醒回锁屏 ---- */
|
||
CHECK(overlay_lock_idle_off_sec(0) == 30, "S4 system 0 (never) -> lock caps 30s");
|
||
CHECK(overlay_lock_idle_off_sec(-1) == 30, "S4 system absent -> lock caps 30s");
|
||
CHECK(overlay_lock_idle_off_sec(30) == 30, "S4 system 30 -> 30");
|
||
CHECK(overlay_lock_idle_off_sec(60) == 30, "S4 system 60 -> 30 (cap, shorter)");
|
||
CHECK(overlay_lock_idle_off_sec(10) == 10, "S4 system 10 -> 10 (respect shorter)");
|
||
CHECK(overlay_lock_idle_off_sec(1) == 1, "S4 system 1 -> 1 (respect shorter)");
|
||
CHECK(overlay_lock_should_sleep(1, 30000, 30000) == 1, "S4 idle>=off & screen on -> self sleep");
|
||
CHECK(overlay_lock_should_sleep(1, 29999, 30000) == 0, "S4 idle<off -> not yet");
|
||
CHECK(overlay_lock_should_sleep(0, 99999, 30000) == 0, "S4 screen off -> no re-sleep");
|
||
CHECK(overlay_lock_wake_now(1, 0) == 1, "S4 power edge -> wake to lock");
|
||
CHECK(overlay_lock_wake_now(0, 1) == 1, "S4 touch -> wake to lock");
|
||
CHECK(overlay_lock_wake_now(0, 0) == 0, "S4 no wake input -> stay asleep");
|
||
|
||
/* ---- M40 F4/P4:锁屏页电源「按下边沿 + 进场 ≥300ms」才熄屏 ----
|
||
* 电平判定会让「打开菜单的那次长按」在 PIN 页出现时立刻把页面熄灭(用户症状)。 */
|
||
CHECK(OVERLAY_LOCK_POWER_GRACE_MS == 300, "F4 lock power grace = 300ms");
|
||
CHECK(overlay_lock_power_off_now(1, 299) == 0, "F4 press edge inside 300ms grace -> no off");
|
||
CHECK(overlay_lock_power_off_now(1, 300) == 1, "F4 press edge at 300ms -> off");
|
||
CHECK(overlay_lock_power_off_now(0, 5000) == 0, "F4 held level (no edge) -> never re-fires");
|
||
CHECK(overlay_lock_power_off_now(1, 5000) == 1, "F4 new press edge after grace -> off");
|
||
|
||
/* ---- M40 F3/P3:叠加层/菜单返回后的 activity 标记排空窗 ---- */
|
||
CHECK(overlay_activity_drain_active(0, 0, 999999) == 0, "F3 no overlay return mark -> activity honored");
|
||
CHECK(overlay_activity_drain_active(1, 1000, 1299) == 1, "F3 marker inside 300ms drain -> ignored");
|
||
CHECK(overlay_activity_drain_active(1, 1000, 1300) == 0, "F3 marker after drain -> honored");
|
||
|
||
/* ---- S3 App 死亡触发主屏重绘:崩溃必须走统一退出路径 ---- */
|
||
CHECK(lock_overlay_app_died_exit(1) == 1, "S3 app died -> unified exit path (redraw home)");
|
||
CHECK(lock_overlay_app_died_exit(0) == 0, "S3 app alive -> normal restore");
|
||
|
||
/* ---- §310 锁屏叠加期中止谓词(lock_screen.h 纯判定)---- */
|
||
CHECK(lck_overlay_should_abort(0, 0) == 0, "S3 abort=0 (menu lock, no overlay pid)");
|
||
CHECK(lck_overlay_should_abort(0, 1) == 0, "S3 abort=0 (no overlay pid, zombie ignored)");
|
||
CHECK(lck_overlay_should_abort(4321, 0) == 0, "S3 abort=0 (overlay pid, app alive)");
|
||
CHECK(lck_overlay_should_abort(4321, 1) == 1, "S3 abort=1 (overlay pid + zombie -> abort lock)");
|
||
|
||
printf("\n%s (%d passed, %d failed)\n", g_fail ? "SOME TESTS FAILED" : "ALL PASS", g_pass, g_fail);
|
||
return g_fail ? 1 : 0;
|
||
}
|