fix(§10.5): 通知中心叠加媒体保活——播放中 App 不 SIGSTOP(修播放中滑通知中心音乐停)
- launcher: run_app_notif_overlay 入口 meow_media_app_playing() 判定(当前源+PLAYING+app_id 匹配) → 不 SIGSTOP/不 SIGCONT,App 续跑保 PCM;非播放中维持 SIGSTOP 模板;关闭时 unlink 标记挪到 恢复帧上屏后(防未冻结 App 抢 present 一帧回闪)。 - SDK gfx: present() 见 /tmp/meow_notif_active(env MEOW_NOTIF_ACTIVE_FILE 覆写)自抑上屏, 仅 App 进程(系统 UI/launcher 不抑制),200ms 节流 stat,脏区累积解除后一次上屏; meow_gfx_overlay_suppressed_count 供单测断言。 - SDK input: 叠加期排空丢弃本进程 evdev 副本 + EVIOCGKEY 位图静默对齐(防面板点击被 App 双重消费/解除后边沿误判),进入沿复位触摸状态机。 - 宿主:新 test_overlay_suppress T1-T4 + test_media §8(8 用例)全 PASS;test_notif_*/ test_sdk_*/test_vol_ramp_jack 等回归全过;zig-mipsel -Wall -Wextra 全 TU 0 warning。 - meow_launcherd fbb82036(/usr/bin 只读待固件,fw_content.conf 已更)/ meow_ui.a d6242fc2 / hello a073535a / files 2b799d07(已热更到卡);ncm 未重链(ncm_app 他 agent 在改)。
This commit is contained in:
1 parent
820d1e52bf
commit
ad9778476a
19 files changed
+254
-13
No files matched your search
Binary file not shown.
Binary file not shown.
@@ -1201,6 +1201,9 @@ static void notify_app_crash(const char *pkg, int status)
|
|||||||
* ① SIGSTOP App → ② 写 /tmp/meow_notif_active(+ /tmp/meow_power_menu_active 让 watchdog 让位)
|
* ① SIGSTOP App → ② 写 /tmp/meow_notif_active(+ /tmp/meow_power_menu_active 让 watchdog 让位)
|
||||||
* → ③ pm_capture_app_frame 读回 App 帧当背景 → ④ run_notif_center(apps={a},1) 叠加渲染
|
* → ③ pm_capture_app_frame 读回 App 帧当背景 → ④ run_notif_center(apps={a},1) 叠加渲染
|
||||||
* + 接管输入 → ⑤ 关闭后恢复 App 帧 → unlink active → SIGCONT App。
|
* + 接管输入 → ⑤ 关闭后恢复 App 帧 → unlink active → SIGCONT App。
|
||||||
|
* 媒体保活分支(定案):当前媒体源==本 App 且 PLAYING(meow_media_app_playing)→ ①不 SIGSTOP、
|
||||||
|
* ⑤不 SIGCONT;App 继续跑保 PCM 供流,上屏由 SDK present 层见 ②的标记自抑,输入由 SDK
|
||||||
|
* 输入线程见标记排空(防面板点击被 App 双重消费)。非播放中 App 维持 SIGSTOP 模板。
|
||||||
* 差异:背景=App 帧(非应用列表);关闭后回 App(非回 run_menu);点通知首期 = dismiss + 关面板
|
* 差异:背景=App 帧(非应用列表);关闭后回 App(非回 run_menu);点通知首期 = dismiss + 关面板
|
||||||
* + SIGCONT 回当前 App(不跨 app 启动,见 NOTIF_CENTER_APP_OVERLAY_PLAN §3.2)。
|
* + SIGCONT 回当前 App(不跨 app 启动,见 NOTIF_CENTER_APP_OVERLAY_PLAN §3.2)。
|
||||||
* App 崩溃探测:run_notif_center 循环内 read /proc/<pid>/stat 状态位(zombie)周期探测
|
* App 崩溃探测:run_notif_center 循环内 read /proc/<pid>/stat 状态位(zombie)周期探测
|
||||||
@@ -1210,14 +1213,25 @@ static void notify_app_crash(const char *pkg, int status)
|
|||||||
static int run_app_notif_overlay(struct app *a, pid_t pid)
|
static int run_app_notif_overlay(struct app *a, pid_t pid)
|
||||||
{
|
{
|
||||||
if (!back_buf_ok || !fb) { logmsg("notif-overlay: no back_buf (direct mode) skip"); return 0; }
|
if (!back_buf_ok || !fb) { logmsg("notif-overlay: no back_buf (direct mode) skip"); return 0; }
|
||||||
logmsg("notif-overlay: open (app=%s pid=%d) SIGSTOP", a->name, pid);
|
/* 媒体保活(定案):当前媒体源==本前台 App 且 state==PLAYING → 不 SIGSTOP。ncm 等播放类
|
||||||
if (kill(pid, SIGSTOP) < 0) {
|
* App 的播放线程同进程,冻结即 PCM 断供(真机报告:播放中滑下通知中心音乐停)。改为:
|
||||||
logmsg("notif-overlay: SIGSTOP %d fail: %s", pid, strerror(errno));
|
* App 继续跑(音频照常喂 audiod、媒体上报照常),SDK present 层见 /tmp/meow_notif_active
|
||||||
|
* 自抑上屏(只画进 back_buf 不 present,防重绘穿透叠加层);关闭时不补 SIGCONT(没 STOP 过)。
|
||||||
|
* 非播放中 App 维持现状 SIGSTOP。 */
|
||||||
|
int keep_running = meow_media_app_playing(a->id);
|
||||||
|
if (keep_running) {
|
||||||
|
logmsg("notif-overlay: open (app=%s pid=%d) PLAYING -> no SIGSTOP (SDK present suppressed)",
|
||||||
|
a->name, pid);
|
||||||
} else {
|
} else {
|
||||||
/* 等 App 进入 stopped 态(/proc/pid/stat 状态位 'T';超时兜底);frozen 后才能读回帧 */
|
logmsg("notif-overlay: open (app=%s pid=%d) SIGSTOP", a->name, pid);
|
||||||
for (int i = 0; i < 100; i++) {
|
if (kill(pid, SIGSTOP) < 0) {
|
||||||
if (proc_is_stopped(pid)) break;
|
logmsg("notif-overlay: SIGSTOP %d fail: %s", pid, strerror(errno));
|
||||||
usleep(10000);
|
} else {
|
||||||
|
/* 等 App 进入 stopped 态(/proc/pid/stat 状态位 'T';超时兜底);frozen 后才能读回帧 */
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
if (proc_is_stopped(pid)) break;
|
||||||
|
usleep(10000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* 让位标记:/tmp/meow_notif_active(§10.5 语义同 powmenu_active)。当前 watchdog 只认
|
/* 让位标记:/tmp/meow_notif_active(§10.5 语义同 powmenu_active)。当前 watchdog 只认
|
||||||
@@ -1240,19 +1254,27 @@ static int run_app_notif_overlay(struct app *a, pid_t pid)
|
|||||||
g_notif_ctrl_pid = 0;
|
g_notif_ctrl_pid = 0;
|
||||||
int died = g_notif_ctrl_died;
|
int died = g_notif_ctrl_died;
|
||||||
|
|
||||||
unlink(NOTIF_ACTIVE);
|
|
||||||
unlink(POWMENU_ACTIVE);
|
|
||||||
if (died) {
|
if (died) {
|
||||||
/* App 已死:不 SIGCONT、不恢复死帧;back_buf 交还 run_menu 统一重绘 */
|
/* App 已死:不 SIGCONT、不恢复死帧;back_buf 交还 run_menu 统一重绘 */
|
||||||
|
unlink(NOTIF_ACTIVE);
|
||||||
|
unlink(POWMENU_ACTIVE);
|
||||||
logmsg("notif-overlay: app died during session -> unified exit path");
|
logmsg("notif-overlay: app died during session -> unified exit path");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* 恢复 App 帧(run_notif_center 关面板后 back_buf 已还原为背景=App 帧;再拍一次兜底
|
/* 恢复 App 帧(run_notif_center 关面板后 back_buf 已还原为背景=App 帧;再拍一次兜底
|
||||||
* 覆盖非动画关闭路径)+ SIGCONT。 */
|
* 覆盖非动画关闭路径)。媒体保活路径(keep_running):先恢复帧再 unlink 标记——
|
||||||
|
* App 未被冻结仍在跑,标记多留一拍可让 SDK present 自抑覆盖到恢复帧上屏之后,
|
||||||
|
* 避免「标记先消失 → App 抢在恢复帧前 present 新帧 → 又被旧帧盖回」的一帧回闪。 */
|
||||||
pm_capture_app_frame();
|
pm_capture_app_frame();
|
||||||
meow_ui_flush();
|
meow_ui_flush();
|
||||||
kill(pid, SIGCONT);
|
unlink(NOTIF_ACTIVE);
|
||||||
logmsg("notif-overlay: closed -> SIGCONT app");
|
unlink(POWMENU_ACTIVE);
|
||||||
|
if (!keep_running) {
|
||||||
|
kill(pid, SIGCONT);
|
||||||
|
logmsg("notif-overlay: closed -> SIGCONT app");
|
||||||
|
} else {
|
||||||
|
logmsg("notif-overlay: closed -> app never stopped (media keep-alive), no SIGCONT");
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -120,6 +120,13 @@ int meow_media_has_source(void)
|
|||||||
return (s && s->state != MEOW_MEDIA_STOPPED) ? 1 : 0;
|
return (s && s->state != MEOW_MEDIA_STOPPED) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int meow_media_app_playing(const char *app_id)
|
||||||
|
{
|
||||||
|
const meow_media_session_t *s = meow_media_current();
|
||||||
|
if (!s || !app_id || !app_id[0]) return 0;
|
||||||
|
return (s->state == MEOW_MEDIA_PLAYING && strcmp(s->app_id, app_id) == 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int send_playctl(const meow_media_session_t *s, uint32_t cmd, int64_t seek_ms)
|
static int send_playctl(const meow_media_session_t *s, uint32_t cmd, int64_t seek_ms)
|
||||||
{
|
{
|
||||||
if (!s || !s->used || !g_ops || !g_ops->send) return -1;
|
if (!s || !s->used || !g_ops || !g_ops->send) return -1;
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ const meow_media_session_t *meow_media_current(void);
|
|||||||
/* 是否有活动媒体源:当前源存在且 state != 0(停止)。通知中心卡片/播放页据此显示。 */
|
/* 是否有活动媒体源:当前源存在且 state != 0(停止)。通知中心卡片/播放页据此显示。 */
|
||||||
int meow_media_has_source(void);
|
int meow_media_has_source(void);
|
||||||
|
|
||||||
|
/* §10.5 叠加会话保活判定:当前源(最近活跃会话)存在、state==PLAYING 且 app_id 匹配。
|
||||||
|
* launcher 据此决定通知中心叠加不 SIGSTOP 该 App(保 PCM 供流),SDK present 层自抑上屏。 */
|
||||||
|
int meow_media_app_playing(const char *app_id);
|
||||||
|
|
||||||
/* 向当前源下发 PLAYCTL(卡片按钮/播放页/媒体键/控制器)。返回 0=已发,-1=无源/发送失败。 */
|
/* 向当前源下发 PLAYCTL(卡片按钮/播放页/媒体键/控制器)。返回 0=已发,-1=无源/发送失败。 */
|
||||||
int meow_media_playctl(uint32_t cmd, int64_t seek_ms);
|
int meow_media_playctl(uint32_t cmd, int64_t seek_ms);
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
* 4) PLAYCTL 下发字节格式(socketpair 对端可读回 MSG_PLAYCTL 帧,cmd/seek 正确);
|
* 4) PLAYCTL 下发字节格式(socketpair 对端可读回 MSG_PLAYCTL 帧,cmd/seek 正确);
|
||||||
* 5) meow_media_playctl 无源 → -1;
|
* 5) meow_media_playctl 无源 → -1;
|
||||||
* 6) clear(app) 清会话 → current()=NULL。
|
* 6) clear(app) 清会话 → current()=NULL。
|
||||||
|
* 8) meow_media_app_playing(§10.5 叠加保活分支:当前源+PLAYING+app_id 匹配才 1)。
|
||||||
* 只依赖 meow_media.c + meow_ipc.h(纯 C),宿主 gcc 直编。
|
* 只依赖 meow_media.c + meow_ipc.h(纯 C),宿主 gcc 直编。
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -170,6 +171,26 @@ int main(void)
|
|||||||
fill_meta(&m, "", MEOW_MEDIA_PLAYING, 0, 0, "x", "y");
|
fill_meta(&m, "", MEOW_MEDIA_PLAYING, 0, 0, "x", "y");
|
||||||
CHECK(meow_media_meta(&m, sv[0]) == -1, "meta empty app_id == -1");
|
CHECK(meow_media_meta(&m, sv[0]) == -1, "meta empty app_id == -1");
|
||||||
|
|
||||||
|
/* 8) §10.5 叠加保活分支判定 meow_media_app_playing(launcher 不 SIGSTOP 的入口判据) */
|
||||||
|
meow_media_clear(NULL);
|
||||||
|
CHECK(meow_media_app_playing("com.ncm") == 0, "app_playing: no source == 0");
|
||||||
|
fill_meta(&m, "com.ncm", MEOW_MEDIA_PLAYING, 1000, 240000, "Song A", "Artist A");
|
||||||
|
meow_media_meta(&m, sv[0]);
|
||||||
|
CHECK(meow_media_app_playing("com.ncm") == 1, "app_playing: current+PLAYING+match == 1");
|
||||||
|
CHECK(meow_media_app_playing("com.other") == 0, "app_playing: app_id mismatch == 0");
|
||||||
|
CHECK(meow_media_app_playing("") == 0, "app_playing: empty app_id == 0");
|
||||||
|
CHECK(meow_media_app_playing(NULL) == 0, "app_playing: NULL app_id == 0");
|
||||||
|
fill_meta(&m, "com.ncm", MEOW_MEDIA_PAUSED, 1000, 240000, "Song A", "Artist A");
|
||||||
|
meow_media_meta(&m, sv[0]);
|
||||||
|
CHECK(meow_media_app_playing("com.ncm") == 0, "app_playing: PAUSED == 0 (SIGSTOP as usual)");
|
||||||
|
fill_meta(&m, "com.ncm", MEOW_MEDIA_PLAYING, 2000, 240000, "Song A", "Artist A");
|
||||||
|
meow_media_meta(&m, sv[0]);
|
||||||
|
/* 当前源被别的 App 抢走(后者 PAUSED 也抢走「最近活跃」)→ 本 App 播放中也不再保活 */
|
||||||
|
fill_meta(&m, "com.player2", MEOW_MEDIA_PAUSED, 0, 180000, "Song B", "Artist B");
|
||||||
|
meow_media_meta(&m, sv[0]);
|
||||||
|
CHECK(meow_media_app_playing("com.ncm") == 0, "app_playing: not current source == 0");
|
||||||
|
meow_media_clear(NULL);
|
||||||
|
|
||||||
printf("\n%s (%d fails)\n", g_fails ? "FAILED" : "ALL PASS", g_fails);
|
printf("\n%s (%d fails)\n", g_fails ? "FAILED" : "ALL PASS", g_fails);
|
||||||
return g_fails ? 1 : 0;
|
return g_fails ? 1 : 0;
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -42,6 +42,11 @@
|
|||||||
#define MUI_DEFAULT_W 480
|
#define MUI_DEFAULT_W 480
|
||||||
#define MUI_DEFAULT_H 720
|
#define MUI_DEFAULT_H 720
|
||||||
|
|
||||||
|
/* §10.5 叠加让位标记:与 launcher meow_launcher_internal.h NOTIF_ACTIVE 同路径。
|
||||||
|
* 通知中心叠加会话期存在;宿主/单测可经 MEOW_NOTIF_ACTIVE_FILE 覆写路径(进程内只解析一次)。 */
|
||||||
|
#define MEOW_NOTIF_ACTIVE_DEFAULT "/tmp/meow_notif_active"
|
||||||
|
#define MEOW_OVERLAY_CHK_MS 200 /* 存在性检查节流:别每帧 stat */
|
||||||
|
|
||||||
/* 脏矩形上限(超出合并为全屏) */
|
/* 脏矩形上限(超出合并为全屏) */
|
||||||
#define MUI_DIRTY_MAX 12
|
#define MUI_DIRTY_MAX 12
|
||||||
|
|
||||||
@@ -939,10 +944,42 @@ static int statusbar_touched(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- §10.5 叠加让位自抑(present 层)----
|
||||||
|
* /tmp/meow_notif_active 存在 = 通知中心叠加会话进行中(launcher 正在 fb 上渲染面板)。
|
||||||
|
* App 进程(非系统 UI 渲染者)此时不上屏;200ms 节流缓存存在性(别每帧 stat)。
|
||||||
|
* 计数 g_overlay_suppressed 供宿主单测断言(meow_gfx_overlay_suppressed_count)。 */
|
||||||
|
static unsigned long long g_overlay_suppressed = 0;
|
||||||
|
|
||||||
|
static int overlay_present_suppressed(void)
|
||||||
|
{
|
||||||
|
if (meow_ui_sys_render_enabled()) return 0; /* launcher(系统 UI)渲染面板,照常上屏 */
|
||||||
|
static char s_path[108];
|
||||||
|
static int s_path_init = 0;
|
||||||
|
static unsigned long long s_last_chk = 0;
|
||||||
|
static int s_last_res = 0;
|
||||||
|
if (!s_path_init) {
|
||||||
|
const char *e = getenv("MEOW_NOTIF_ACTIVE_FILE");
|
||||||
|
snprintf(s_path, sizeof s_path, "%s", (e && e[0]) ? e : MEOW_NOTIF_ACTIVE_DEFAULT);
|
||||||
|
s_path_init = 1;
|
||||||
|
}
|
||||||
|
unsigned long long now = now_ms();
|
||||||
|
if (s_last_chk && now - s_last_chk < MEOW_OVERLAY_CHK_MS) return s_last_res;
|
||||||
|
s_last_chk = now;
|
||||||
|
s_last_res = (access(s_path, F_OK) == 0) ? 1 : 0;
|
||||||
|
return s_last_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long meow_gfx_overlay_suppressed_count(void) { return g_overlay_suppressed; }
|
||||||
|
|
||||||
static void present(void)
|
static void present(void)
|
||||||
{
|
{
|
||||||
if (!g_init_ok || !g_back_buf) return;
|
if (!g_init_ok || !g_back_buf) return;
|
||||||
if (!(g_dirty_full || g_ndirty > 0)) return;
|
if (!(g_dirty_full || g_ndirty > 0)) return;
|
||||||
|
/* §10.5 叠加让位自抑(仅 App 进程):App 前台播放中唤起通知中心时 launcher 不 SIGSTOP
|
||||||
|
* (保 PCM 供流,ncm 播放线程同进程),改由 App 进程在此自抑上屏——绘制照常进 back_buf,
|
||||||
|
* 只是不 present 到 fb,防 App 重绘穿透 launcher 叠加层。系统 UI 进程(launcher 渲染面板)
|
||||||
|
* 不抑制。抑制期脏区保留累积(超上限自然升级整帧),标记消失后下一次 present 一次上屏。 */
|
||||||
|
if (overlay_present_suppressed()) { g_overlay_suppressed++; return; }
|
||||||
/* 帧率门控(A-1/A-2,从 launcher 迁入):present 距上次 ≥ period(1000/eff_rate) 才呈现;
|
/* 帧率门控(A-1/A-2,从 launcher 迁入):present 距上次 ≥ period(1000/eff_rate) 才呈现;
|
||||||
* 未满周期则保留脏区(不 dirty_reset),下一轮再试。refresh_always_max=1 时跳过门控(恒满速)。 */
|
* 未满周期则保留脏区(不 dirty_reset),下一轮再试。refresh_always_max=1 时跳过门控(恒满速)。 */
|
||||||
unsigned long long now = now_ms();
|
unsigned long long now = now_ms();
|
||||||
|
|||||||
@@ -136,6 +136,30 @@ static int meow_input_jack_debounce(void)
|
|||||||
return g_jack_changed_at && (now - g_jack_changed_at) < 800;
|
return g_jack_changed_at && (now - g_jack_changed_at) < 800;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- §10.5 叠加让位:通知中心叠加会话期输入排空(播放中 App 不被 SIGSTOP 的配套)----
|
||||||
|
* 媒体播放中的 App 前台唤起通知中心时 launcher 不冻结 App(保 PCM 供流,ncm 播放线程同进程),
|
||||||
|
* App 输入线程仍在读同一批 evdev 设备(每 fd 各收一份事件副本,与 launcher 互不剥夺)——若不
|
||||||
|
* 抑制,面板上的一次点击会被 App 再消费一次(如面板媒体卡片「暂停」与 App 同坐标控件双重触发)。
|
||||||
|
* 故标记存在期:排空本进程 fd 队列并丢弃、EVIOCGKEY 位图静默对齐(不产生边沿语义,系统键动作
|
||||||
|
* 叠加期由 launcher/watchdog 单侧承担)。200ms 节流缓存存在性(与 present 层同口径,别每圈 stat)。 */
|
||||||
|
static int overlay_input_suppressed(void)
|
||||||
|
{
|
||||||
|
static char s_path[108];
|
||||||
|
static int s_path_init = 0;
|
||||||
|
static unsigned long long s_last_chk = 0;
|
||||||
|
static int s_last_res = 0;
|
||||||
|
if (!s_path_init) {
|
||||||
|
const char *e = getenv("MEOW_NOTIF_ACTIVE_FILE"); /* 宿主/单测覆写(进程内只解析一次) */
|
||||||
|
snprintf(s_path, sizeof s_path, "%s", (e && e[0]) ? e : "/tmp/meow_notif_active");
|
||||||
|
s_path_init = 1;
|
||||||
|
}
|
||||||
|
unsigned long long now = now_ms();
|
||||||
|
if (s_last_chk && now - s_last_chk < 200) return s_last_res;
|
||||||
|
s_last_chk = now;
|
||||||
|
s_last_res = (access(s_path, F_OK) == 0) ? 1 : 0;
|
||||||
|
return s_last_res;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- 系统按键语义(M2.55:SDK 输入层消化,App 前台也生效)----
|
/* ---- 系统按键语义(M2.55:SDK 输入层消化,App 前台也生效)----
|
||||||
* 物理键是系统资源(APPS.md §3.4.1),语义全局统一。本函数在输入线程执行系统动作:
|
* 物理键是系统资源(APPS.md §3.4.1),语义全局统一。本函数在输入线程执行系统动作:
|
||||||
* 电源 116 → 息屏/亮屏/长按菜单(内核/sys_server/watchdog),SDK 不动(维持现状);
|
* 电源 116 → 息屏/亮屏/长按菜单(内核/sys_server/watchdog),SDK 不动(维持现状);
|
||||||
@@ -451,9 +475,34 @@ static void *input_thread(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int overlay_was = 0; /* §10.5:上一圈是否处于叠加抑制(进入沿复位触摸状态机用) */
|
||||||
while (g_thread_run) {
|
while (g_thread_run) {
|
||||||
if (nfd == 0) { usleep(20000); continue; }
|
if (nfd == 0) { usleep(20000); continue; }
|
||||||
int r = poll(fds, nfd, 20);
|
int r = poll(fds, nfd, 20);
|
||||||
|
/* §10.5 叠加让位:通知中心叠加会话期(标记存在)排空并丢弃本进程事件副本——面板输入
|
||||||
|
* 由 launcher 接管,App 不得再消费(防面板点击被 App 双重触发);EVIOCGKEY 位图静默
|
||||||
|
* 对齐(不产生边沿语义/系统键动作,解除后不会把面板期按键误判为新边沿)。 */
|
||||||
|
if (overlay_input_suppressed()) {
|
||||||
|
if (!overlay_was) { /* 进入沿:复位触摸状态机,防抑制期丢失抬手致 t_down 卡死 */
|
||||||
|
overlay_was = 1;
|
||||||
|
t_down = 0; t_press_valid = 0; t_origin_valid = 0;
|
||||||
|
t_cx = t_cy = -1; t_dx = t_dy = 0; t_down_ms = 0; t_mv_x = t_mv_y = -1;
|
||||||
|
t_long_fired = 0;
|
||||||
|
}
|
||||||
|
if (r > 0)
|
||||||
|
for (int i = 0; i < nfd; i++) {
|
||||||
|
if (!(fds[i].revents & POLLIN)) continue;
|
||||||
|
unsigned char junk[64];
|
||||||
|
while (read(fds[i].fd, junk, sizeof junk) > 0) { /* 整批丢弃 */ }
|
||||||
|
}
|
||||||
|
for (int i = 0; i < nfd; i++) {
|
||||||
|
unsigned char cur[KEY_MAX / 8 + 1];
|
||||||
|
if (ioctl(fds[i].fd, EVIOCGKEY(sizeof cur), cur) == 0)
|
||||||
|
memcpy(prev_key[i], cur, sizeof cur);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
overlay_was = 0;
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (errno != EINTR) usleep(20000);
|
if (errno != EINTR) usleep(20000);
|
||||||
} else if (r > 0) {
|
} else if (r > 0) {
|
||||||
|
|||||||
@@ -148,6 +148,10 @@ void meow_gfx_ring_arc(int cx, int cy, int r, int th, int start_deg,
|
|||||||
/* 是否运行于真实 fb 之上(0 = 头less/离屏,qemu/宿主)。 */
|
/* 是否运行于真实 fb 之上(0 = 头less/离屏,qemu/宿主)。 */
|
||||||
int meow_gfx_is_device(void);
|
int meow_gfx_is_device(void);
|
||||||
|
|
||||||
|
/* §10.5 叠加让位:present 因 /tmp/meow_notif_active 存在而被自抑的累计次数
|
||||||
|
* (仅 App 进程会自抑;宿主单测断言用,设备上无调用方)。 */
|
||||||
|
unsigned long long meow_gfx_overlay_suppressed_count(void);
|
||||||
|
|
||||||
/* 中文/日文字库(mfont)是否已加载(状态栏「蓝牙」CJK 与回退 "BT" 二选一)。 */
|
/* 中文/日文字库(mfont)是否已加载(状态栏「蓝牙」CJK 与回退 "BT" 二选一)。 */
|
||||||
int meow_gfx_mfont_ready(void);
|
int meow_gfx_mfont_ready(void);
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,97 @@
|
|||||||
|
/* test_overlay_suppress.c — §10.5 叠加让位 present 自抑宿主验证(离屏 480x720,16bpp)。
|
||||||
|
*
|
||||||
|
* 背景:媒体播放中的 App 前台唤起通知中心时 launcher 不 SIGSTOP(保 PCM 供流),改由 SDK
|
||||||
|
* present 层见 /tmp/meow_notif_active(宿主用 MEOW_NOTIF_ACTIVE_FILE 覆写)自抑上屏。
|
||||||
|
*
|
||||||
|
* 覆盖:
|
||||||
|
* T1 无标记:flush 正常上屏(frames_presented 递增,抑制计数 0);
|
||||||
|
* T2 有标记:flush 被抑制(只画进 back_buf 不 present:frames 不变、抑制计数递增);
|
||||||
|
* T2b 抑制期第二次 flush 仍被抑制(200ms 节流缓存内行为一致);
|
||||||
|
* T3 标记消失:下一次 flush 恢复上屏(抑制期累积脏区一次上屏,无需重画);
|
||||||
|
* T4 系统 UI 进程(launcher,system_mode=1)即使有标记也不抑制(面板必须照常上屏)。
|
||||||
|
*
|
||||||
|
* 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global):
|
||||||
|
* gcc -Wall -Wextra -o test_overlay_suppress test_overlay_suppress.c test_host_stub.c \
|
||||||
|
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
||||||
|
* meow_ui_draw.c meow_ui_view.c meow_notify_ipc.c \
|
||||||
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread
|
||||||
|
*/
|
||||||
|
#include "meow_ui.h"
|
||||||
|
#include "meow_ui_internal.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#define MARKER "/tmp/test_notif_active_sdk"
|
||||||
|
|
||||||
|
static void marker_write(void)
|
||||||
|
{
|
||||||
|
int fd = open(MARKER, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
|
assert(fd >= 0);
|
||||||
|
if (write(fd, "1", 1) < 0) assert(0);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
setenv("MEOW_UI_DUMP", "/tmp/overlay_suppress.ppm", 1);
|
||||||
|
setenv("MEOW_NOTIF_ACTIVE_FILE", MARKER, 1);
|
||||||
|
unlink(MARKER);
|
||||||
|
meow_ui_opts o = { 480, 720 };
|
||||||
|
assert(meow_ui_init(&o) == 0);
|
||||||
|
meow_ui_set_refresh_always_max(1); /* 绕过帧率门控:每次 flush 都直达 present 判定 */
|
||||||
|
|
||||||
|
/* T1:无标记正常上屏(默认 App 进程模式:render_enabled==0) */
|
||||||
|
assert(meow_ui_sys_render_enabled() == 0);
|
||||||
|
meow_ui_clear(0x112233);
|
||||||
|
meow_ui_flush();
|
||||||
|
assert(meow_ui_frames_presented() == 1);
|
||||||
|
assert(meow_gfx_overlay_suppressed_count() == 0);
|
||||||
|
printf("T1 PASS: no marker -> presented=1 suppressed=0\n");
|
||||||
|
|
||||||
|
/* T2:有标记 → 抑制(等 >200ms 越过存在性节流缓存) */
|
||||||
|
marker_write();
|
||||||
|
usleep(250000);
|
||||||
|
unsigned long long f0 = meow_ui_frames_presented();
|
||||||
|
meow_ui_clear(0x223344);
|
||||||
|
meow_ui_flush();
|
||||||
|
assert(meow_ui_frames_presented() == f0);
|
||||||
|
assert(meow_gfx_overlay_suppressed_count() == 1);
|
||||||
|
printf("T2 PASS: marker present -> suppressed (frames frozen at %llu)\n", f0);
|
||||||
|
|
||||||
|
/* T2b:抑制期再次 flush 仍抑制(节流缓存内一致) */
|
||||||
|
meow_ui_clear(0x334455);
|
||||||
|
meow_ui_flush();
|
||||||
|
assert(meow_ui_frames_presented() == f0);
|
||||||
|
assert(meow_gfx_overlay_suppressed_count() == 2);
|
||||||
|
printf("T2b PASS: still suppressed within throttle window\n");
|
||||||
|
|
||||||
|
/* T3:标记消失 → 恢复上屏(抑制期累积的整帧脏一次上屏,无需重画) */
|
||||||
|
unlink(MARKER);
|
||||||
|
usleep(250000);
|
||||||
|
meow_ui_flush();
|
||||||
|
assert(meow_ui_frames_presented() == f0 + 1);
|
||||||
|
assert(meow_gfx_overlay_suppressed_count() == 2);
|
||||||
|
printf("T3 PASS: marker gone -> present resumed (accumulated dirty flushed)\n");
|
||||||
|
|
||||||
|
/* T4:系统 UI 进程(launcher)不抑制——通知中心面板本身必须照常上屏 */
|
||||||
|
meow_ui_sys_set_system_mode(1);
|
||||||
|
assert(meow_ui_sys_render_enabled() == 1);
|
||||||
|
marker_write();
|
||||||
|
usleep(250000);
|
||||||
|
unsigned long long f1 = meow_ui_frames_presented();
|
||||||
|
meow_ui_clear(0x445566);
|
||||||
|
meow_ui_flush();
|
||||||
|
assert(meow_ui_frames_presented() == f1 + 1);
|
||||||
|
assert(meow_gfx_overlay_suppressed_count() == 2); /* 不再增长 */
|
||||||
|
unlink(MARKER);
|
||||||
|
printf("T4 PASS: system-UI process (launcher) never suppressed\n");
|
||||||
|
|
||||||
|
meow_ui_shutdown();
|
||||||
|
printf("ALL PASS\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
# ---- 用户态/服务守护二进制(usr/bin,全部 chmod 755 静态 MIPS)----
|
# ---- 用户态/服务守护二进制(usr/bin,全部 chmod 755 静态 MIPS)----
|
||||||
patch_v2/bootmenu/meow_bootmenu|/usr/bin/meow_bootmenu|4441822d87e76bfce2ce584604ac3830|引导选单 M2.85(sysui让位 agent-216)
|
patch_v2/bootmenu/meow_bootmenu|/usr/bin/meow_bootmenu|4441822d87e76bfce2ce584604ac3830|引导选单 M2.85(sysui让位 agent-216)
|
||||||
patch_v2/meow_launcherd/meow_launcherd|/usr/bin/meow_launcherd|eba4f2b25f01fe756fbf36a9c0844823|主屏 launcher M2.95+(App 前台状态栏 settings.conf mtime 1s 节流重读,修 App 内音量%不刷新;PLAYCTL cmd=6 toggle 透传注释)
|
patch_v2/meow_launcherd/meow_launcherd|/usr/bin/meow_launcherd|fbb82036566b8808e2449d899ecaf3b0|主屏 launcher M2.95+(§10.5 叠加媒体保活:前台 App 播放中开通知中心不 SIGSTOP,SDK present/输入见 /tmp/meow_notif_active 自抑)
|
||||||
patch_v2/meow_watchdog/meow_watchdog|/usr/bin/meow_watchdog|96e80c855e8ca7fd772a2826adbd2639|应用看门狗 M2.95(+音量反转修复)
|
patch_v2/meow_watchdog/meow_watchdog|/usr/bin/meow_watchdog|96e80c855e8ca7fd772a2826adbd2639|应用看门狗 M2.95(+音量反转修复)
|
||||||
patch_v2/meow_svcd/meow_svcd|/usr/bin/meow_svcd|605646c4cc93f2baf29071ea6bc870ea|服务管理器 M2.77(+崩溃上报 meow_crash agent-187)
|
patch_v2/meow_svcd/meow_svcd|/usr/bin/meow_svcd|605646c4cc93f2baf29071ea6bc870ea|服务管理器 M2.77(+崩溃上报 meow_crash agent-187)
|
||||||
mips-repo/bins/meow_mdns/bin/meow_mdns|/usr/bin/meow_mdns|d6b0151bda26768f19952dae1342610d|mDNS 应答器 M2.78(启动竞态+换IP重检 agent-194)
|
mips-repo/bins/meow_mdns/bin/meow_mdns|/usr/bin/meow_mdns|d6b0151bda26768f19952dae1342610d|mDNS 应答器 M2.78(启动竞态+换IP重检 agent-194)
|
||||||
|
|||||||
Reference in new issue
Block a user