用户真机 M6.2 实测三症状,全部位于锁屏/通知中心叠加路径。根因与修法: S1 锁屏输入穿透(PIN 触摸打到下层 App / 解锁后「启动奇怪界面」) 根因:run_app_lock_overlay / run_app_notif_overlay 关闭路径先 unlink /tmp/meow_notif_active 再 SIGCONT App——App 被 SIGSTOP 冻结期间缓冲的 evdev 触摸事件在解除瞬间被 SDK 输入线程在无隔离态回放成 App 内点击(穿透触发)。 修法:反序——标记仍在时先 SIGCONT,让 SDK 输入线程排空冻结期缓冲事件 + EVIOCGKEY 对齐,等 OVERLAY_DRAIN_WINDOW_MS(300ms > SDK 200ms 节流) 再 unlink。 S2 解锁后状态栏消失(App 无状态栏全屏残留) 根因:S1 的回放点击常把 App 导航进全屏页(状态栏随 app.json/fullscreen 隐掉); 叠加关闭路径也未强制状态栏重同步。 修法:解锁后 g_sb_mode_last=-1 + 立即 app_overlay_statusbar() 重叠加(不等 1s 慢刷)。 S3 App 异常死亡(OOM sig=9)残影——fb0 停 App 死帧、无状态栏、launcher 不重绘主屏 根因:锁屏叠加(run_app_lock_overlay→run_lock_screen)阻塞于 lock_screen 内, App 叠加期崩溃不被感知(notif 叠加有 run_notif_center 的 proc_is_zombie 探测, 锁屏独缺),launcher 卡在锁屏会话永不回 menu 重绘。 修法:run_app_lock_overlay 置位 g_lock_overlay_pid,run_lock_screen 每圈 proc_is_zombie 探测,App 死即中止锁屏(LCK_OVERLAY_RET_DIED)走统一退出路径 (reap_wait 回收 + ams_status_valid + break → run_menu 重绘主屏含状态栏)。 新增 overlay_gate.h(纯决策,宿主可单测)+ test_overlay_gate.c(10 断言)+ test_lock_screen.c 扩展(4 断言 overlay-abort)。launcher 全量宿主回归 + SDK 叠加/状态栏回归(overlay_suppress/sb_collapse/notif_open/notif_gesture/ sdk_fixes/sdk_input_keys)全 PASS;mipsel 交叉 -Wall -Wextra 0 warning。 md5 136dc67c086a9d75c0ad9c83d519ff0d(/usr/bin 只读,待固件打包;fw_content.conf 未动)。
51 lines
3.0 KiB
C
51 lines
3.0 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 重绘主屏含状态栏)。
|
||
*
|
||
* 编译运行(在 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");
|
||
|
||
/* ---- S2 解锁状态栏恢复:必须强制重同步 ---- */
|
||
CHECK(overlay_force_sb_resync() == 1, "S2 force status bar re-sync after unlock");
|
||
|
||
/* ---- 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;
|
||
}
|