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:
AskaEth committed 2026-09-02 03:41:39 +08:00
1 parent 3611cbbbde
commit bcef8e092e
8 files changed
+203 -11

No files matched your search

+58 -10
View File
@@ -2,6 +2,7 @@
/* 本文件由拆分工具从 meow_launcherd.c 按职责搬移;逻辑与原文 0-diff(仅 static 可见性按跨模块需求调整)。*/
#include "meow_launcher_internal.h"
#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]; /* 主循环单写者 */
@@ -1420,14 +1421,19 @@ static int run_app_notif_overlay(struct app *a, pid_t pid)
* 避免「标记先消失 → App 抢在恢复帧前 present 新帧 → 又被旧帧盖回」的一帧回闪。 */
pm_capture_app_frame();
meow_ui_flush();
unlink(NOTIF_ACTIVE);
unlink(POWMENU_ACTIVE);
if (!keep_running) {
/* §310 输入穿透定案(与 lock-overlay 同源):App 被 SIGSTOP 冻结过 → 在标记仍存在时
* 先 SIGCONT,让 SDK 输入线程排空冻结期缓冲的 evdev 事件 + 对齐 EVIOCGKEY,再等
* OVERLAY_DRAIN_WINDOW_MS 后 unlink——防关面板瞬间把积累触摸回放成 App 内点击。 */
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 {
logmsg("notif-overlay: closed -> app never stopped (media keep-alive), no SIGCONT");
}
unlink(NOTIF_ACTIVE);
unlink(POWMENU_ACTIVE);
return 0;
}
@@ -1463,18 +1469,43 @@ static int run_app_lock_overlay(struct app *a, pid_t pid)
meow_theme_reload();
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();
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();
meow_ui_flush();
unlink(NOTIF_ACTIVE);
unlink(POWMENU_ACTIVE);
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);
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 {
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;
}
@@ -1956,8 +1987,17 @@ static int launch_app_chain(struct app *a, const char *chain)
meow_panel_on();
meow_auto_slept = 0;
fb_pan_buf0_force();
/* M2.x 锁屏:App 前台唤醒后若需锁屏 → SIGSTOP 叠加锁屏页;解锁/SIGCONT 回应用 */
if (lck_wake_should_lock()) run_app_lock_overlay(a, pid);
/* M2.x 锁屏:App 前台唤醒后若需锁屏 → SIGSTOP 叠加锁屏页;解锁/SIGCONT 回应用。
* §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()) {
@@ -1980,8 +2020,16 @@ static int launch_app_chain(struct app *a, const char *chain)
meow_panel_on();
meow_auto_slept = 0;
fb_pan_buf0_force();
/* M2.x 锁屏:App 前台唤醒后若需锁屏 → SIGSTOP 叠加锁屏页;解锁/SIGCONT 回应用 */
if (lck_wake_should_lock()) run_app_lock_overlay(a, pid);
/* M2.x 锁屏:App 前台唤醒后若需锁屏 → SIGSTOP 叠加锁屏页;解锁/SIGCONT 回应用。
* §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) {