fix(launcher,lock): §310 锁屏/叠加三连 bug——输入穿透·状态栏消失·App死亡残影
用户真机 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 未动)。
This commit is contained in:
1 parent
3611cbbbde
commit
bcef8e092e
8 files changed
+203
-11
No files matched your search
@@ -2,6 +2,7 @@
|
|||||||
/* 本文件由拆分工具从 meow_launcherd.c 按职责搬移;逻辑与原文 0-diff(仅 static 可见性按跨模块需求调整)。*/
|
/* 本文件由拆分工具从 meow_launcherd.c 按职责搬移;逻辑与原文 0-diff(仅 static 可见性按跨模块需求调整)。*/
|
||||||
#include "meow_launcher_internal.h"
|
#include "meow_launcher_internal.h"
|
||||||
#include "meow_ams_start.h" /* MSG_AMS_START pending/拉起决策(meow_ams_start.c) */
|
#include "meow_ams_start.h" /* MSG_AMS_START pending/拉起决策(meow_ams_start.c) */
|
||||||
|
#include "overlay_gate.h" /* SIGSTOP 叠加会话关闭顺序/死亡回退纯决策(§310 三连 bug 收敛点) */
|
||||||
|
|
||||||
|
|
||||||
static struct meow_acct g_accts[MEOW_MAX_ACTS]; /* 主循环单写者 */
|
static struct meow_acct g_accts[MEOW_MAX_ACTS]; /* 主循环单写者 */
|
||||||
@@ -1420,14 +1421,19 @@ static int run_app_notif_overlay(struct app *a, pid_t pid)
|
|||||||
* 避免「标记先消失 → App 抢在恢复帧前 present 新帧 → 又被旧帧盖回」的一帧回闪。 */
|
* 避免「标记先消失 → App 抢在恢复帧前 present 新帧 → 又被旧帧盖回」的一帧回闪。 */
|
||||||
pm_capture_app_frame();
|
pm_capture_app_frame();
|
||||||
meow_ui_flush();
|
meow_ui_flush();
|
||||||
unlink(NOTIF_ACTIVE);
|
|
||||||
unlink(POWMENU_ACTIVE);
|
|
||||||
if (!keep_running) {
|
if (!keep_running) {
|
||||||
|
/* §310 输入穿透定案(与 lock-overlay 同源):App 被 SIGSTOP 冻结过 → 在标记仍存在时
|
||||||
|
* 先 SIGCONT,让 SDK 输入线程排空冻结期缓冲的 evdev 事件 + 对齐 EVIOCGKEY,再等
|
||||||
|
* OVERLAY_DRAIN_WINDOW_MS 后 unlink——防关面板瞬间把积累触摸回放成 App 内点击。 */
|
||||||
kill(pid, SIGCONT);
|
kill(pid, SIGCONT);
|
||||||
logmsg("notif-overlay: closed -> SIGCONT app");
|
usleep(OVERLAY_DRAIN_WINDOW_MS * 1000);
|
||||||
|
logmsg("notif-overlay: closed -> SIGCONT app, drain %dms, then unlink mark",
|
||||||
|
OVERLAY_DRAIN_WINDOW_MS);
|
||||||
} else {
|
} else {
|
||||||
logmsg("notif-overlay: closed -> app never stopped (media keep-alive), no SIGCONT");
|
logmsg("notif-overlay: closed -> app never stopped (media keep-alive), no SIGCONT");
|
||||||
}
|
}
|
||||||
|
unlink(NOTIF_ACTIVE);
|
||||||
|
unlink(POWMENU_ACTIVE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1463,18 +1469,43 @@ static int run_app_lock_overlay(struct app *a, pid_t pid)
|
|||||||
meow_theme_reload();
|
meow_theme_reload();
|
||||||
pm_capture_app_frame();
|
pm_capture_app_frame();
|
||||||
|
|
||||||
|
/* 置位叠加期 App pid:run_lock_screen 每圈探测该 App 是否在锁屏期崩溃(§310 残影),
|
||||||
|
* 崩溃即中止锁屏返回 LCK_OVERLAY_RET_DIED,走下方统一退出路径。 */
|
||||||
|
g_lock_overlay_pid = (int)pid;
|
||||||
int lr = run_lock_screen();
|
int lr = run_lock_screen();
|
||||||
|
g_lock_overlay_pid = 0;
|
||||||
|
|
||||||
|
if (lr == LCK_OVERLAY_RET_DIED) {
|
||||||
|
/* 叠加期 App 已死:不 SIGCONT(死进程)、不恢复死帧;unlink 标记交回 waitpid 循环回收,
|
||||||
|
* run_menu 统一重绘主屏(含状态栏)。launcher 不崩。 */
|
||||||
|
unlink(NOTIF_ACTIVE);
|
||||||
|
unlink(POWMENU_ACTIVE);
|
||||||
|
logmsg("lock-overlay: app pid %d died during lock -> unified exit path", pid);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
pm_capture_app_frame();
|
pm_capture_app_frame();
|
||||||
meow_ui_flush();
|
meow_ui_flush();
|
||||||
unlink(NOTIF_ACTIVE);
|
|
||||||
unlink(POWMENU_ACTIVE);
|
|
||||||
if (!keep_running) {
|
if (!keep_running) {
|
||||||
|
/* §310 输入穿透定案(overlay_gate.h):App 被 SIGSTOP 冻结过 → 在 /tmp/meow_notif_active
|
||||||
|
* 仍未 unlink 时**先 SIGCONT**,让 SDK 输入线程排空冻结期缓冲的 evdev 事件副本 + 对齐
|
||||||
|
* EVIOCGKEY,再等 OVERLAY_DRAIN_WINDOW_MS(> SDK 200ms 节流窗)后 unlink——防解锁瞬间
|
||||||
|
* 把积累的触摸回放成 App 内点击(锁屏穿透→「启动奇怪界面」→ 状态栏消失的触发源)。 */
|
||||||
kill(pid, SIGCONT);
|
kill(pid, SIGCONT);
|
||||||
logmsg("lock-overlay: closed (lr=%d) -> SIGCONT app", lr);
|
usleep(OVERLAY_DRAIN_WINDOW_MS * 1000);
|
||||||
|
logmsg("lock-overlay: closed (lr=%d) -> SIGCONT app, drain %dms, then unlink mark",
|
||||||
|
lr, OVERLAY_DRAIN_WINDOW_MS);
|
||||||
} else {
|
} else {
|
||||||
logmsg("lock-overlay: closed (lr=%d) -> app never stopped (media keep-alive), no SIGCONT", lr);
|
logmsg("lock-overlay: closed (lr=%d) -> app never stopped (media keep-alive), no SIGCONT", lr);
|
||||||
}
|
}
|
||||||
|
unlink(NOTIF_ACTIVE);
|
||||||
|
unlink(POWMENU_ACTIVE);
|
||||||
|
/* §310 状态栏恢复:解锁后强制 g_sb_mode_last=-1 + 立即重叠加顶条(不等 app 循环 1s 慢刷),
|
||||||
|
* 消除「解锁回 App 无状态栏」的残留态。overlay_force_sb_resync() = 定案恒真。 */
|
||||||
|
if (overlay_force_sb_resync()) {
|
||||||
|
g_sb_mode_last = -1;
|
||||||
|
if (!a->fullscreen) app_overlay_statusbar();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1956,8 +1987,17 @@ static int launch_app_chain(struct app *a, const char *chain)
|
|||||||
meow_panel_on();
|
meow_panel_on();
|
||||||
meow_auto_slept = 0;
|
meow_auto_slept = 0;
|
||||||
fb_pan_buf0_force();
|
fb_pan_buf0_force();
|
||||||
/* M2.x 锁屏:App 前台唤醒后若需锁屏 → SIGSTOP 叠加锁屏页;解锁/SIGCONT 回应用 */
|
/* M2.x 锁屏:App 前台唤醒后若需锁屏 → SIGSTOP 叠加锁屏页;解锁/SIGCONT 回应用。
|
||||||
if (lck_wake_should_lock()) run_app_lock_overlay(a, pid);
|
* §310:叠加期 App 崩溃(LR==LCK_OVERLAY_RET_DIED)→ 回收僵尸走统一退出路径
|
||||||
|
* (launcher 不崩、run_menu 重绘主屏),同 run_app_notif_overlay 的 died 分支。 */
|
||||||
|
if (lck_wake_should_lock()) {
|
||||||
|
int lr2 = run_app_lock_overlay(a, pid);
|
||||||
|
if (lr2 != 0) {
|
||||||
|
reap_wait(pid, &status);
|
||||||
|
ams_status_valid = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (screen_off_timeout > 0 && meow_screen_on && !meow_auto_slept && !fg_keep_awake()) {
|
if (screen_off_timeout > 0 && meow_screen_on && !meow_auto_slept && !fg_keep_awake()) {
|
||||||
@@ -1980,8 +2020,16 @@ static int launch_app_chain(struct app *a, const char *chain)
|
|||||||
meow_panel_on();
|
meow_panel_on();
|
||||||
meow_auto_slept = 0;
|
meow_auto_slept = 0;
|
||||||
fb_pan_buf0_force();
|
fb_pan_buf0_force();
|
||||||
/* M2.x 锁屏:App 前台唤醒后若需锁屏 → SIGSTOP 叠加锁屏页;解锁/SIGCONT 回应用 */
|
/* M2.x 锁屏:App 前台唤醒后若需锁屏 → SIGSTOP 叠加锁屏页;解锁/SIGCONT 回应用。
|
||||||
if (lck_wake_should_lock()) run_app_lock_overlay(a, pid);
|
* §310:叠加期 App 崩溃 → 回收僵尸走统一退出路径(launcher 不崩、run_menu 重绘主屏)。 */
|
||||||
|
if (lck_wake_should_lock()) {
|
||||||
|
int lr2 = run_app_lock_overlay(a, pid);
|
||||||
|
if (lr2 != 0) {
|
||||||
|
reap_wait(pid, &status);
|
||||||
|
ams_status_valid = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vold && !app_prev_vold) {
|
if (vold && !app_prev_vold) {
|
||||||
|
|||||||
@@ -88,6 +88,20 @@ void lck_manual_lock_clear(void); /* 删标志(幂等) */
|
|||||||
* 取代 lck_lock_required(1) 作为唤醒门——主动锁强制锁屏,覆盖「关闭唤醒锁」的手动锁场景。 */
|
* 取代 lck_lock_required(1) 作为唤醒门——主动锁强制锁屏,覆盖「关闭唤醒锁」的手动锁场景。 */
|
||||||
int lck_wake_should_lock(void);
|
int lck_wake_should_lock(void);
|
||||||
|
|
||||||
|
/* ── 锁屏叠加期 App 存活探针(§310 残影修复,纯判定,宿主可单测;header-only inline)----
|
||||||
|
* 锁屏运行在 App 前台叠加会话中(overlay_pid>0,run_app_lock_overlay 置位)且该进程已成僵尸
|
||||||
|
* (调用方 proc_is_zombie 判定后传入 proc_zombie=1)→ 应中止锁屏走统一退出(返回 1)。
|
||||||
|
* 菜单直接锁屏(overlay_pid=0,无 App 可死)恒 0;此谓词不实际读 /proc。 */
|
||||||
|
static inline int lck_overlay_should_abort(int overlay_pid, int proc_zombie)
|
||||||
|
{
|
||||||
|
return (overlay_pid > 0 && proc_zombie) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* run_lock_screen() 返回值:1=已解锁,0=锁屏期间电源键息屏。叠加期 App 崩溃时返回
|
||||||
|
* LCK_OVERLAY_RET_DIED(-1)——调用方 run_app_lock_overlay 据此外走「统一退出路径」
|
||||||
|
* (不再 SIGCONT 死进程/不恢复死帧,交回 waitpid 循环回收,run_menu 重绘主屏)。 */
|
||||||
|
#define LCK_OVERLAY_RET_DIED (-1)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -12,6 +12,12 @@
|
|||||||
*/
|
*/
|
||||||
#include "meow_launcher_internal.h"
|
#include "meow_launcher_internal.h"
|
||||||
|
|
||||||
|
/* §310 残影:锁屏处于 App 前台叠加会话时置位当前前台 App pid(run_app_lock_overlay 写入)。
|
||||||
|
* run_lock_screen 每圈据此探测 App 是否已死(组合 App 冻结缓冲 evdev 会在解锁瞬间回放成点击 /
|
||||||
|
* 叠加期 OOM 杀让 fb0 留残帧——探到死即中止锁屏,交回 waitpid 循环回收 + run_menu 重绘主屏)。
|
||||||
|
* 菜单直接锁屏(无 App)时保持 0 = 不探测。 */
|
||||||
|
int g_lock_overlay_pid = 0;
|
||||||
|
|
||||||
/* ---- 键盘几何(480×720):3 列×4 行圆角按钮 ---- */
|
/* ---- 键盘几何(480×720):3 列×4 行圆角按钮 ---- */
|
||||||
#define LK_X0 32 /* 首列左缘 */
|
#define LK_X0 32 /* 首列左缘 */
|
||||||
#define LK_COLW 130 /* 列宽 */
|
#define LK_COLW 130 /* 列宽 */
|
||||||
@@ -156,6 +162,17 @@ int run_lock_screen(void)
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* §310 残影:锁屏叠加期 App 崩溃(僵尸)→ 中止锁屏走统一退出路径(交回 waitpid 循环
|
||||||
|
* 回收 + run_menu 重绘主屏含状态栏)。仅当 run_app_lock_overlay 置位 g_lock_overlay_pid
|
||||||
|
* 才探(菜单直接锁屏无 App 可死,恒不中止)。 */
|
||||||
|
if (g_lock_overlay_pid > 0 &&
|
||||||
|
lck_overlay_should_abort(g_lock_overlay_pid, proc_is_zombie(g_lock_overlay_pid))) {
|
||||||
|
logmsg("lock: overlay app pid %d died during lock -> abort (unified exit path)",
|
||||||
|
g_lock_overlay_pid);
|
||||||
|
g_lock_overlay_pid = 0;
|
||||||
|
goto died;
|
||||||
|
}
|
||||||
|
|
||||||
/* 锁定到期自动解禁(清计数+戳),仅重画状态行 */
|
/* 锁定到期自动解禁(清计数+戳),仅重画状态行 */
|
||||||
if (lock_until > 0 && now >= lock_until) {
|
if (lock_until > 0 && now >= lock_until) {
|
||||||
lck_lock_remaining();
|
lck_lock_remaining();
|
||||||
@@ -260,6 +277,12 @@ done:
|
|||||||
kp_close(&kp_keys);
|
kp_close(&kp_keys);
|
||||||
logmsg("lock: exit unlocked=%d screen_on=%d", unlocked, meow_screen_on);
|
logmsg("lock: exit unlocked=%d screen_on=%d", unlocked, meow_screen_on);
|
||||||
return unlocked;
|
return unlocked;
|
||||||
|
died:
|
||||||
|
if (tfd >= 0) close(tfd);
|
||||||
|
kp_close(&kp_power);
|
||||||
|
kp_close(&kp_keys);
|
||||||
|
logmsg("lock: exit overlay-app-died -> LCK_OVERLAY_RET_DIED");
|
||||||
|
return LCK_OVERLAY_RET_DIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 电源菜单「锁定」:**主动锁屏**(用户定案 2026-09-02 强化)。
|
/* 电源菜单「锁定」:**主动锁屏**(用户定案 2026-09-02 强化)。
|
||||||
|
|||||||
@@ -827,10 +827,14 @@ void settings_sync_cache_listener(const char *key);
|
|||||||
void settings_volume_adj(int delta);
|
void settings_volume_adj(int delta);
|
||||||
int settings_volume_get(void);
|
int settings_volume_get(void);
|
||||||
int show_power_menu(void);
|
int show_power_menu(void);
|
||||||
/* M2.x 锁屏:阻塞式锁屏页(渲染+输入);返回 1=已解锁(回主屏),0=锁屏期间电源键息屏(屏已关)。
|
/* M2.x 锁屏:阻塞式锁屏页(渲染+输入);返回 1=已解锁(回主屏),0=锁屏期间电源键息屏(屏已关),
|
||||||
|
* -1(LCK_OVERLAY_RET_DIED)=锁屏叠加期 App 崩溃(run_app_lock_overlay 走统一退出路径)。
|
||||||
* meow_lock_screen_engage() 供电源菜单「锁定」与唤醒路径用;未配凭据时 no-op。 */
|
* meow_lock_screen_engage() 供电源菜单「锁定」与唤醒路径用;未配凭据时 no-op。 */
|
||||||
int run_lock_screen(void);
|
int run_lock_screen(void);
|
||||||
int meow_lock_screen_engage(void);
|
int meow_lock_screen_engage(void);
|
||||||
|
/* §310 残影:锁屏处于 App 前台叠加会话时置位当前 App pid(run_app_lock_overlay 写入,
|
||||||
|
* run_lock_screen 每圈据此 proc_is_zombie 探测;菜单直接锁屏时保持 0=不探)。 */
|
||||||
|
extern int g_lock_overlay_pid;
|
||||||
/* 设置页「锁屏 PIN」数字输入模态(系统级 PIN 设置/修改输入):满 4 位返回 1 并拷贝到 out,电源=取消返回 0。 */
|
/* 设置页「锁屏 PIN」数字输入模态(系统级 PIN 设置/修改输入):满 4 位返回 1 并拷贝到 out,电源=取消返回 0。 */
|
||||||
int lck_input_pin_modal(const char *title, char *out, int outcap);
|
int lck_input_pin_modal(const char *title, char *out, int outcap);
|
||||||
/* 设置页「锁屏 PIN」独立子页面(subpage.c 脚手架;阻塞到返回)。 */
|
/* 设置页「锁屏 PIN」独立子页面(subpage.c 脚手架;阻塞到返回)。 */
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,45 @@
|
|||||||
|
/* overlay_gate.h — SIGSTOP 叠加会话(通知中心 §10.5 / 锁屏 M2.x)关闭与死亡回退的**纯决策**。
|
||||||
|
*
|
||||||
|
* 宿主可单测(无信号/无设备/无文件系统依赖,全部 static inline);app_launcher.c 的两处叠加
|
||||||
|
* 关闭路径(run_app_notif_overlay / run_app_lock_overlay)调用,避免把「排空窗口」「中止条件」
|
||||||
|
* 这类时序/判定散落内联难验证。三个 bug 的定案语义都收敛到这里:
|
||||||
|
*
|
||||||
|
* ① 输入穿透(S1 根因):App 被 SIGSTOP 冻结过 → 关闭时必须在 /tmp/meow_notif_active 仍存在
|
||||||
|
* 时先 SIGCONT,让 SDK 输入线程(meow_ui_input.c overlay_input_suppressed)排空冻结期缓冲的
|
||||||
|
* evdev 事件副本 + 对齐 EVIOCGKEY,再等 OVERLAY_DRAIN_WINDOW_MS 后 unlink 标记。
|
||||||
|
* 若反序(unlink->SIGCONT,改动前写法),App 在无隔离态恢复 → 解冻瞬间把积累的触摸回放成
|
||||||
|
* App 内点击(锁屏穿透 /「启动奇怪界面」/ 解锁后状态栏消失的触发源)。
|
||||||
|
* ② 状态栏恢复(S2):解锁后强制 g_sb_mode_last=-1 让 app 循环立即重叠加,不等 1s 慢刷。
|
||||||
|
* ③ 死亡重绘(S3):锁屏叠加中 App 崩溃(/proc/<pid>/stat==Z)→ 中止锁屏走统一退出路径,
|
||||||
|
* 由 waitpid 循环回收 + run_menu dirty=1 重绘主屏(含状态栏)。
|
||||||
|
*/
|
||||||
|
#ifndef MEOW_OVERLAY_GATE_H
|
||||||
|
#define MEOW_OVERLAY_GATE_H
|
||||||
|
|
||||||
|
/* SDK overlay_input_suppressed() 的标记存在性节流窗是 200ms;排空窗须 > 该值(留 100ms 余量),
|
||||||
|
* 保证 App 恢复后 SDK 输入线程确实重新 stat 到标记再整批丢弃缓冲事件。 */
|
||||||
|
#define OVERLAY_DRAIN_WINDOW_MS 300
|
||||||
|
|
||||||
|
/* ① 排空是否必要:App 被 SIGSTOP 冻结过(非保活)才需要「SIGCONT 保持隔离 → 排窗 → unlink」;
|
||||||
|
* 媒体保活(keep_running,从未 STOP)直接「恢复帧上屏 → unlink」(自抑随标记消失自然解除)。 */
|
||||||
|
static inline int overlay_drain_required(int keep_running)
|
||||||
|
{
|
||||||
|
return !keep_running ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ③ 锁屏叠加中 App 崩溃是否触发「统一退出路径」(= 中止锁屏、交回 waitpid 循环回收、run_menu 重绘)。
|
||||||
|
* proc_zombie=1(/proc/<pid>/stat==Z)→ 走退出(返回 1);否则正常恢复(返回 0)。 */
|
||||||
|
static inline int lock_overlay_app_died_exit(int proc_zombie)
|
||||||
|
{
|
||||||
|
return proc_zombie ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ② 解锁后是否需要强制状态栏重同步(返回 1):始终需要——把 g_sb_mode_last 拨回 -1,
|
||||||
|
* 使 run_menu / app 循环的「模式变化→立即重叠加」分支命中(-1 != m 恒真除非 m==-1,
|
||||||
|
* 但 m==-1 表示无模式文件=展开态,同样被 app_overlay_statusbar 兜底到展开整条)。 */
|
||||||
|
static inline int overlay_force_sb_resync(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MEOW_OVERLAY_GATE_H */
|
||||||
@@ -75,6 +75,14 @@ int main(void)
|
|||||||
meow_settings_save();
|
meow_settings_save();
|
||||||
CHECK(lck_wake_should_lock() == 1, "wake_should_lock=1 (wake=1)");
|
CHECK(lck_wake_should_lock() == 1, "wake_should_lock=1 (wake=1)");
|
||||||
|
|
||||||
|
/* ---- §310 残影:锁屏叠加期 App 崩溃中止探针(纯判定)----
|
||||||
|
* 锁屏在 App 前台叠加会话(overlay_pid>0)且该 App 已成僵尸 → 中止锁屏(返回 1);
|
||||||
|
* 菜单直接锁屏(overlay_pid=0)恒不中止;叠加期 App 仍活(proc_zombie=0)也不中止。 */
|
||||||
|
CHECK(lck_overlay_should_abort(0, 0) == 0, "overlay abort=0 (no overlay pid, not zombie)");
|
||||||
|
CHECK(lck_overlay_should_abort(1234, 0) == 0, "overlay abort=0 (overlay pid, app alive)");
|
||||||
|
CHECK(lck_overlay_should_abort(0, 1) == 0, "overlay abort=0 (no overlay pid, zombie ignored)");
|
||||||
|
CHECK(lck_overlay_should_abort(1234, 1) == 1, "overlay abort=1 (overlay pid + zombie -> unified exit)");
|
||||||
|
|
||||||
/* ---- 面板一次性解锁恢复口(bypass 标志)---- */
|
/* ---- 面板一次性解锁恢复口(bypass 标志)---- */
|
||||||
CHECK(lck_unlock_once_consume() == 0, "unlock_once_consume=0 when flag absent");
|
CHECK(lck_unlock_once_consume() == 0, "unlock_once_consume=0 when flag absent");
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/* 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;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user