Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/test_overlay_gate.c
T
AskaEth 63b278e13e fix(watchdog+launcher+sdk): M40 电源键 time64 ABI + 锁屏/叠加残留链
- 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。
真机未验证(设备关机);未刷机、未写设备。
2026-11-10 22:51:00 +08:00

112 lines
8.3 KiB
C
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.
/* 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;
}