fix: 后台页杀按钮点不动 — app.json framework=1 被误当「不可杀」门控 + am kill 无前台会话不可执行
根因(2026-11-04 真机 dev.player.ncm pid=7520): - bg_page.c bgm_app_meta 把 app.json 的 framework 字段映射进 bgmgr_row.framework,而 bgmgr_can_kill 把它当「系统/框架 App 禁止 kill」。但 framework=1 在 MeowOS 里意为「用 meow_ui.a 的 SDK 框架 App」(docs/APP_DEV_GUIDE.md §9,推荐值,真机 4 个 App 全写 1) → 后台页每行「杀」按钮被置灰,bgm_row_tap 命中后直接 return 1、不调 meow_bg_terminate; 「一键清除后台」同理 0 行可杀。整条链路无日志,故只能靠翻 app.json 才定位(全部设备日志里 "后台管理页终止后台App" 出现 0 次 = 4 次进页从未真正杀过)。 - 面板 killfg 正常是因为走 am kill → amsd → MSG_AMS_KILL,无 framework 门控;但它其实靠 amsd 1200ms×2 超时兜底 kill(pid,SIGTERM) 才杀成:util.c 原本在无前台 App 会话时只回 ACK -2((uint32_t)MEOW_ERR_NOENT),ACK 及时到达时 amsd 判「launcher refused」完全不杀 (ams_20260915_031339.log 实证),ACK 迟到才侥幸成功(2026-11-04 真机)。 修复: - meow_bgmgr: 门控位 framework → protected_app(系统级受保护标记;当前无 App 置位,launcher 自身组件本就不在 App 表/后台表内)。bg_page 不再把 a->framework 送进门控。 - bg_page: 行副文本改存 ctx 持久缓冲(原 rbuf[].sub 指向 bgm_rows 栈帧 → 悬垂,副标题乱码); 门控拒绝/未命中后台表各留一行 logmsg,「点了没反应」从此可查。 - util.c MSG_AMS_KILL: 先查后台保活表 → meow_bg_terminate 就地走真退序列(与页面「杀」按钮 同一通道,故 am kill 与页面按钮行为对称),无前台会话也能杀;否则仍走 pending / ACK -2。 - amsd cmd_kill/cmd_start: ipc 失败原因细分(connect failed / timeout, no reply / ...),日志 不再笼统写 "launcher offline"(响应串保留该字样,MeowPanel api_ams_ctl 依此映射 503)。 - meow_bgplay: meow_bg_terminate 注释/日志写明「后台管理页 / am kill」双入口同通道。 测试(宿主 gcc,产物在 $TMPDIR): - test_bgpage 40 checks:新增 framework=1 仍判可杀且按钮真 terminate(本 bug 回归)、 受保护行按钮不杀但留诊断日志、sub 持久化 + 栈抖动不变(悬垂回归)。 - test_bgmgr 30 checks:protected_app 门控矩阵 + framework=1 可杀回归。 - test_bgplay 92 PASS:新增 4b meow_bg_terminate 全链路(受理→term_at_ms→tick SIGTERM→ on_bg_dead→清槽;空/不在表分别 INVAL/NOENT);TEST_SVC_PATH 改取 $TMPDIR (Termux 无 /tmp,原 fputs(NULL) 直接 abort)。 - amsd 宿主集成(fake launcher 桩,4 例):ACK 0→terminate 且不盲杀;ACK -2→refused 不盲杀; 无 launcher→direct SIGTERM (connect failed);挂起不回→direct SIGTERM (timeout, no reply)。 0warning:util.c 与 main 同告警逐行一致(仅 SDK 头既有 typedef 重定义),其余文件干净。
This commit is contained in:
1 parent
a73bcb9841
commit
6b52740ff1
11 files changed
+249
-84
No files matched your search
@@ -1,11 +1,12 @@
|
||||
/* test_bgmgr.c — 批③ 后台管理页 逻辑层宿主单测(meow_bgmgr)。
|
||||
*
|
||||
* 验证:
|
||||
* 1) bgmgr_collect:enumerate 后台表 → app_meta 补 name/icon/framework/is_fg → proc_sample 补
|
||||
* 1) bgmgr_collect:enumerate 后台表 → app_meta 补 name/icon/protected_app/is_fg → proc_sample 补
|
||||
* pcpu/rss_kb;行 killable 预判正确;name 回退 app_id。
|
||||
* 2) bgmgr_can_kill 门控矩阵:framework=1 → 0(**框架 App 不 kill**);is_fg=1 → 0(当前前台不 kill);
|
||||
* pid<=0 → 0(非后台/无进程);普通后台(非框架/非前台/pid>0)→ 1。
|
||||
* 3) bgmgr_kill_all 一键清:框架 App 不杀、当前前台不杀、非后台不杀;其余逐一 kill;返回 kill 数。
|
||||
* 2) bgmgr_can_kill 门控矩阵:protected_app=1 → 0(**受保护 App 不 kill**);is_fg=1 → 0(当前前台不 kill);
|
||||
* pid<=0 → 0(非后台/无进程);普通后台(非受保护/非前台/pid>0)→ 1。
|
||||
* 3) bgmgr_kill_all 一键清:受保护 App 不杀、当前前台不杀、非后台不杀;其余逐一 kill;返回 kill 数。
|
||||
* 3b) 回归:app.json framework=1(SDK 框架 App 标志,现有 App 全写 1)**不影响**可杀性。
|
||||
* 4) bgmgr_status_str / bgmgr_mem_str 文案。
|
||||
* 只依赖 meow_bgmgr.c + meow_ipc.h(纯 C);宿主 gcc 直编:
|
||||
* gcc -Wall -Wextra -std=gnu99 test_bgmgr.c meow_bgmgr.c -o test_bgmgr
|
||||
@@ -17,7 +18,9 @@
|
||||
#include "meow_bgmgr.h"
|
||||
|
||||
static int g_fails = 0;
|
||||
static int g_checks = 0;
|
||||
#define CHECK(cond, msg) do { \
|
||||
g_checks++; \
|
||||
if (cond) printf("PASS: %s\n", msg); \
|
||||
else { printf("FAIL: %s\n", msg); g_fails++; } } while (0)
|
||||
|
||||
@@ -33,7 +36,7 @@ static int fake_enumerate(void *ctx, bgmgr_row_t *rows, int max)
|
||||
{
|
||||
(void)ctx;
|
||||
if (max < 4) return 0;
|
||||
/* 4 个后台行:hello=普通、reader=常驻、sysguard=framework、fgapp=当前前台 */
|
||||
/* 4 个后台行:hello=普通、reader=常驻、sysguard=受保护、fgapp=当前前台 */
|
||||
memset(&rows[0], 0, sizeof rows[0]);
|
||||
snprintf(rows[0].app_id, sizeof rows[0].app_id, "%s", g_meta_app[0]);
|
||||
rows[0].pid = 1001; rows[0].keepalive = 0; rows[0].on_card = 0; rows[0].bg_since_ms = 1000;
|
||||
@@ -52,10 +55,10 @@ static int fake_enumerate(void *ctx, bgmgr_row_t *rows, int max)
|
||||
return 4;
|
||||
}
|
||||
|
||||
/* meta:hello/reader/sysguard/fgapp 各给名字;sysguard 标 framework;pid==1004 标前台。 */
|
||||
/* meta:hello/reader/sysguard/fgapp 各给名字;sysguard 标受保护;pid==1004 标前台。 */
|
||||
static int fake_app_meta(void *ctx, const char *app_id, pid_t pid,
|
||||
char *name, int nl, char *icon, int il,
|
||||
char *framework, int *is_fg)
|
||||
char *protected_app, int *is_fg)
|
||||
{
|
||||
(void)ctx;
|
||||
if (!strcmp(app_id, "os.meow.hello")) snprintf(name, nl, "播放");
|
||||
@@ -64,8 +67,8 @@ static int fake_app_meta(void *ctx, const char *app_id, pid_t pid,
|
||||
else if (!strcmp(app_id, "os.meow.fgapp")) snprintf(name, nl, "前台应用");
|
||||
else return -1; /* 未注册 → name 回退 app_id */
|
||||
snprintf(icon, il, "/tmp/icon_%s.png", app_id);
|
||||
*framework = (!strcmp(app_id, "os.meow.sysguard")) ? '1' : 0;
|
||||
*is_fg = (pid == 1004) ? 1 : 0; /* fgapp 标前台 */
|
||||
*protected_app = (!strcmp(app_id, "os.meow.sysguard")) ? '1' : 0;
|
||||
*is_fg = (pid == 1004) ? 1 : 0; /* fgapp 标前台 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -112,9 +115,9 @@ int main(void)
|
||||
printf("=== 1) collect ===\n");
|
||||
CHECK(n == 4, "collect returns 4 rows");
|
||||
CHECK(!strcmp(rows[0].name, "播放") && rows[0].pid == 1001, "row0 hello name/pid");
|
||||
CHECK(rows[0].framework == 0, "row0 hello not framework");
|
||||
CHECK(rows[0].protected_app == 0, "row0 hello not protected");
|
||||
CHECK(!strcmp(rows[1].name, "阅读") && rows[1].keepalive == 1, "row1 reader keepalive");
|
||||
CHECK(rows[2].framework == '1', "row2 sysguard framework");
|
||||
CHECK(rows[2].protected_app == '1', "row2 sysguard protected");
|
||||
CHECK(rows[3].is_fg == 1, "row3 fgapp is_fg");
|
||||
CHECK(rows[0].pcpu > 0 && rows[0].rss_kb > 0, "row0 pcpu/rss populated");
|
||||
CHECK(rows[0].killable == 1 && rows[2].killable == 0, "killable prefilled by can_kill");
|
||||
@@ -132,7 +135,7 @@ int main(void)
|
||||
}
|
||||
|
||||
printf("=== 2) can_kill gating ===\n");
|
||||
CHECK(bgmgr_can_kill(&rows[2]) == 0, "framework app NOT killable");
|
||||
CHECK(bgmgr_can_kill(&rows[2]) == 0, "protected app NOT killable");
|
||||
CHECK(bgmgr_can_kill(&rows[3]) == 0, "fg app NOT killable (is_fg)");
|
||||
CHECK(bgmgr_can_kill(&rows[0]) == 1, "normal bg app killable");
|
||||
CHECK(bgmgr_can_kill(&rows[1]) == 1, "keepalive bg app killable");
|
||||
@@ -155,11 +158,21 @@ int main(void)
|
||||
if (!strcmp(g_killed_app[i], "os.meow.fgapp")) killed_fg = 1;
|
||||
if (!strcmp(g_killed_app[i], "os.meow.hello")) killed_bg = 1;
|
||||
}
|
||||
CHECK(killed_fw == 0, "kill_all did NOT kill framework app");
|
||||
CHECK(killed_fw == 0, "kill_all did NOT kill protected app");
|
||||
CHECK(killed_fg == 0, "kill_all did NOT kill fg app");
|
||||
CHECK(killed_bg == 1, "kill_all killed a real bg app");
|
||||
CHECK(bgmgr_kill_all(&ops, rows, n, NULL) == 0, "kill_all NULL kill_fn -> 0");
|
||||
|
||||
/* 回归(2026-11-04 真机):app.json framework=1 是「SDK 框架 App」标志(现有 App 全写 1),
|
||||
* **不是**受保护位。旧实现把它当门控 → dev.player.ncm 等所有后台 App 都不可杀、按钮置灰。 */
|
||||
printf("=== 3b) framework(SDK) ≠ 受保护 ===\n");
|
||||
{
|
||||
bgmgr_row_t sdk; memset(&sdk, 0, sizeof sdk);
|
||||
snprintf(sdk.app_id, sizeof sdk.app_id, "dev.player.ncm");
|
||||
sdk.pid = 7520; sdk.protected_app = 0;
|
||||
CHECK(bgmgr_can_kill(&sdk) == 1, "SDK 框架 App(framework=1)后台仍可杀");
|
||||
}
|
||||
|
||||
printf("=== 4) status/mem str ===\n");
|
||||
CHECK(!strcmp(bgmgr_status_str(&rows[1]), "常驻"), "status_str keepalive=常驻");
|
||||
CHECK(!strcmp(bgmgr_status_str(&rows[0]), "后台"), "status_str normal=后台");
|
||||
@@ -167,7 +180,7 @@ int main(void)
|
||||
CHECK(!strcmp(bgmgr_mem_str(512), "512KB"), "mem_str(<1MB)=KB");
|
||||
CHECK(!strcmp(bgmgr_mem_str(2048), "2.0MB"), "mem_str(>=1MB)=MB");
|
||||
|
||||
if (g_fails == 0) printf("\nALL PASS (%d checks)\n", 20);
|
||||
if (g_fails == 0) printf("\nALL PASS (%d checks)\n", g_checks);
|
||||
else printf("\n%d FAILED\n", g_fails);
|
||||
return g_fails ? 1 : 0;
|
||||
}
|
||||
Reference in new issue
Block a user