fix(bt): 批①叠加/穿透根治 — /tmp/meow_notif_active从布尔标志改为内容=前台归属app_id(App用MEOW_LOG_APP比较:前台照常上屏收输入/后台常驻自抑+排空输入/空=全抑制),SDK present+input共用共享判定meow_ui_overlay_suppressed_active,launcher 7处转场改写;宿主test_overlay_suppress(T2c)/notif_gesture/overlay_gate/bg全过,0warning;meow_ui.a变M6.36需重编+重链四App

This commit is contained in:
AskaEth committed 2026-09-04 04:05:41 +08:00
1 parent 6bab304660
commit 7a276f609e
6 files changed
+168 -77

No files matched your search

+55 -28
View File
@@ -1394,6 +1394,22 @@ static void notify_app_crash(const char *pkg, int status)
close(fd);
}
/* 写 §10.5 SDK 自抑标记(/tmp/meow_notif_active)。**内容 = 当前前台屏幕归属者 app_id**;
* 空(传 NULL / "")= 菜单前台 / 叠加层覆盖 / 无前台单元(SDK 判「抑制全部 App」)。
* SDK(meow_ui_gfx.c / meow_ui_input.c 共享判定 meow_ui_overlay_suppressed_active)据内容判
* 本进程是否前台:内容==本进程 app_id → 前台不抑制;内容为空 → 全抑制;内容为其它 app_id
* → 后台常驻/非前台 → 自抑上屏 + 排空输入。
* 批①多 App 后台常驻:取代旧「单标志写 1」——单标志无法区分前台/后台,清标志会连后台 App
* 一起放行(真机「前台 Hello 叠后台 ncm 帧 + 触摸穿透一次交互双响应」的根因)。 */
static void notif_active_set(const char *owner)
{
int nfd = open(NOTIF_ACTIVE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (nfd >= 0) {
if (owner && owner[0]) (void)write(nfd, owner, strlen(owner));
close(nfd);
}
}
/* §10.5:App 前台顶部下滑 → 展开「由 launcher 渲染」的通知中心叠加会话。
* 复用电源菜单对 App 的冻结模板(show_power_menu 的 SIGSTOP/读回/叠加/接管/恢复):
* ① SIGSTOP App → ② 写 /tmp/meow_notif_active(+ /tmp/meow_power_menu_active 让 watchdog 让位)
@@ -1433,9 +1449,9 @@ static int run_app_notif_overlay(struct app *a, pid_t pid)
}
}
/* 让位标记:/tmp/meow_notif_active(§10.5 语义同 powmenu_active)。当前 watchdog 只认
* POWMENU_ACTIVE,故同时写它让 watchdog 对电源长按让位;会话结束统一 unlink。 */
int nfd = open(NOTIF_ACTIVE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (nfd >= 0) { write(nfd, "1", 1); close(nfd); }
* POWMENU_ACTIVE,故同时写它让 watchdog 对电源长按让位;会话结束统一恢复通知中心前台。
* 内容为空=抑制全部 App(叠加层覆盖前台 App + 后台常驻 App 一并自抑)。 */
notif_active_set(""); /* 叠加期:全抑制(面板/锁屏盖在前台 App 上) */
int pfd = open(POWMENU_ACTIVE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (pfd >= 0) { write(pfd, "1", 1); close(pfd); }
@@ -1453,30 +1469,32 @@ static int run_app_notif_overlay(struct app *a, pid_t pid)
int died = g_notif_ctrl_died;
if (died) {
/* App 已死:不 SIGCONT、不恢复死帧;back_buf 交还 run_menu 统一重绘 */
unlink(NOTIF_ACTIVE);
/* App 已死:不 SIGCONT、不恢复死帧;back_buf 交还 run_menu 统一重绘。
* 标记置空(全抑制):菜单前台,后台常驻 App 仍自抑(不再放行帧/输入)。 */
notif_active_set("");
unlink(POWMENU_ACTIVE);
logmsg("notif-overlay: app died during session -> unified exit path");
return 1;
}
/* 恢复 App 帧(run_notif_center 关面板后 back_buf 已还原为背景=App 帧;再拍一次兜底
* 覆盖非动画关闭路径)。媒体保活路径(keep_running):先恢复帧再 unlink 标记——
* App 未被冻结仍在跑,标记多留一拍可让 SDK present 自抑覆盖到恢复帧上屏之后,
* 避免「标记先消失 → App 抢在恢复帧前 present 新帧 → 又被旧帧盖回」的一帧回闪。 */
* 覆盖非动画关闭路径)。媒体保活路径(keep_running):先恢复帧再把标记更新为前台归属
* (a->id)——App 未被冻结仍在跑,标记多留一拍可让 SDK present 自抑覆盖到恢复帧上屏之后,
* 避免「标记先消失 → App 抢在恢复帧前 present 新帧 → 又被旧帧盖回」的一帧回闪。
* 标记翻回 a->id:本 App 恢复前台不抑制,后台常驻 App(如 ncm)随之继续自抑(不叠帧/不穿输入)。 */
pm_capture_app_frame();
meow_ui_flush();
if (!keep_running) {
/* §310 输入穿透定案(与 lock-overlay 同源):App 被 SIGSTOP 冻结过 → 在标记仍存在时
* 先 SIGCONT,让 SDK 输入线程排空冻结期缓冲的 evdev 事件 + 对齐 EVIOCGKEY,再等
* OVERLAY_DRAIN_WINDOW_MS 后 unlink——防关面板瞬间把积累触摸回放成 App 内点击。 */
* OVERLAY_DRAIN_WINDOW_MS 后把标记翻回前台——防关面板瞬间把积累触摸回放成 App 内点击。 */
kill(pid, SIGCONT);
usleep(OVERLAY_DRAIN_WINDOW_MS * 1000);
logmsg("notif-overlay: closed -> SIGCONT app, drain %dms, then unlink mark",
logmsg("notif-overlay: closed -> SIGCONT app, drain %dms, then mark fg",
OVERLAY_DRAIN_WINDOW_MS);
} else {
logmsg("notif-overlay: closed -> app never stopped (media keep-alive), no SIGCONT");
}
unlink(NOTIF_ACTIVE);
notif_active_set(a ? a->id : ""); /* 标记翻回前台归属(非空→本 App 解除自抑) */
unlink(POWMENU_ACTIVE);
return 0;
}
@@ -1504,8 +1522,8 @@ static int run_app_lock_overlay(struct app *a, pid_t pid)
}
}
}
int nfd = open(NOTIF_ACTIVE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (nfd >= 0) { write(nfd, "1", 1); close(nfd); }
/* 标记置空=全抑制(锁屏叠在前台 App + 后台常驻 App 上;解锁后翻回前台归属)。 */
notif_active_set("");
int pfd = open(POWMENU_ACTIVE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (pfd >= 0) { write(pfd, "1", 1); close(pfd); }
@@ -1520,9 +1538,9 @@ static int run_app_lock_overlay(struct app *a, pid_t pid)
g_lock_overlay_pid = 0;
if (lr == LCK_OVERLAY_RET_DIED) {
/* 叠加期 App 已死:不 SIGCONT(死进程)、不恢复死帧;unlink 标记交回 waitpid 循环回收,
* run_menu 统一重绘主屏(含状态栏)。launcher 不崩。 */
unlink(NOTIF_ACTIVE);
/* 叠加期 App 已死:不 SIGCONT(死进程)、不恢复死帧;标记置空(菜单前台,后台常驻 App
* 仍自抑)交回 waitpid 循环回收,run_menu 统一重绘主屏(含状态栏)。launcher 不崩。 */
notif_active_set("");
unlink(POWMENU_ACTIVE);
logmsg("lock-overlay: app pid %d died during lock -> unified exit path", pid);
return 1;
@@ -1532,17 +1550,19 @@ static int run_app_lock_overlay(struct app *a, pid_t pid)
meow_ui_flush();
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 内点击(锁屏穿透→「启动奇怪界面」→ 状态栏消失的触发源)。 */
* 仍未更新时**先 SIGCONT**,让 SDK 输入线程排空冻结期缓冲的 evdev 事件副本 + 对齐
* EVIOCGKEY,再等 OVERLAY_DRAIN_WINDOW_MS(> SDK 200ms 节流窗)后把标记翻回前台归属——
* 防解锁瞬间把积累的触摸回放成 App 内点击(锁屏穿透→「启动奇怪界面」→ 状态栏消失的触发源)。 */
kill(pid, SIGCONT);
usleep(OVERLAY_DRAIN_WINDOW_MS * 1000);
logmsg("lock-overlay: closed (lr=%d) -> SIGCONT app, drain %dms, then unlink mark",
logmsg("lock-overlay: closed (lr=%d) -> SIGCONT app, drain %dms, then mark fg",
lr, OVERLAY_DRAIN_WINDOW_MS);
} else {
logmsg("lock-overlay: closed (lr=%d) -> app never stopped (media keep-alive), no SIGCONT", lr);
}
unlink(NOTIF_ACTIVE);
/* 标记翻回前台归属(a->id):本 App 解除自抑恢复前台;后台常驻 App(如 ncm)随之继续自抑
* (不叠帧 / 不穿输入——修复「锁屏解锁后 ncm 歌单帧叠加在 Hello 上 + 交互双响应」)。 */
notif_active_set(a ? a->id : "");
unlink(POWMENU_ACTIVE);
/* §310 状态栏恢复:解锁后强制 g_sb_mode_last=-1 + 立即重叠加顶条(不等 app 循环 1s 慢刷),
* 消除「解锁回 App 无状态栏」的残留态。overlay_force_sb_resync() = 定案恒真。 */
@@ -1579,9 +1599,9 @@ static int launch_app_chain(struct app *a, const char *chain)
logmsg("launch: %s resume from background (pid=%d)", a->name, (int)pid);
if (chain && chain[0]) logmsg("launch: resume ignores chain=\"%s\"", chain);
if (pick_action[0]) logmsg("launch: resume ignores picker action=%s", pick_action);
/* 回前台:清 §10.5 SDK present 自抑标记(无其他 bg App 且无叠加会话时) */
if (meow_bg_count() == 0 && g_notif_ctrl_pid <= 0)
unlink(NOTIF_ACTIVE);
/* 回前台:标记内容置为前台归属(a->id)——本 App 解除自抑恢复前台;仍驻留后台的其它
* App(如 ncm)随内容≠自身而继续自抑(不叠帧/不穿输入;批①多 App 常驻关键)。 */
notif_active_set(a->id);
drain_input();
meow_nav_begin(a->id, NULL); /* 转后台时导航栈已清;回前台从裸态重建 */
ams_report_fg(a->id); /* 批①:单向 best-effort 上报 amsd 置 AMS_FG */
@@ -1596,6 +1616,10 @@ static int launch_app_chain(struct app *a, const char *chain)
return -1;
}
}
/* 冷启动:标记内容置为前台归属(a->id),让本 App 首帧即不被自抑(后台常驻 App 继续自抑)。
* 旧版此处不写标记:若已有后台常驻 App(ncm)残留「1/空」标记,新前台 App 会被误自抑
* → 主界面点 Hello 渲染卡死(状态栏正常)的根因。 */
notif_active_set(a->id);
meow_nav_begin(a->id, chain); /* M3:冷启动/裸启动都以当前链深初始化导航栈(chain 空→depth 0) */
/* M2.12:启动前准备 MeowData/<pkg>/{data,cache}(幂等;卡不在/失败只 log 不崩)。
@@ -2208,10 +2232,10 @@ static int launch_app_chain(struct app *a, const char *chain)
usleep(50000);
}
}
/* 写 §10.5 SDK 自抑标记:App 进程见 /tmp/meow_notif_active → present 画进
* back_buf 不上屏 + 输入线程排空(=UI 冻结);音频经 audiod socket 天然续播。 */
int nfd = open(NOTIF_ACTIVE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (nfd >= 0) { write(nfd, "1", 1); close(nfd); }
/* 写 §10.5 SDK 自抑标记(内容空=菜单前台全抑制):App 进程见 /tmp/meow_notif_active
* 且内容≠自身 → present 画进 back_buf 不上屏 + 输入线程排空(=UI 冻结,不叠前台/不穿输入);
* 音频经 audiod socket 天然续播。 */
notif_active_set("");
meow_write_app_state(-1);
unlink(MEOW_SBAR_MODE_FILE); /* 顶条模式文件由 App SDK 写;转后台清理复位菜单整条 */
g_sb_mode_last = -1;
@@ -2279,6 +2303,9 @@ static int launch_app_chain(struct app *a, const char *chain)
* 让菜单音量/状态栏与真实 DAC 一致(watchdog 可能已改)。 */
settings_load();
meow_nav_exit(); /* M3:前台应用会话结束,清导航栈 */
/* 回菜单:标记置空(菜单前台全抑制)——若仍驻留后台常驻 App(批①),其继续自抑不叠帧/不穿输入;
* 若已无后台 App,置空标记无害(SDK 无抑制目标)。 */
notif_active_set("");
/* 阶段D附录B:源 App 退出 → 清其媒体会话(如该 App 上报过 META),通知中心/播放页回空态 */
meow_media_clear(a->id);
logmsg("app %s exited status=%d", a->name, WEXITSTATUS(status));