/* test_fg_act.c — M2.17 keep_awake:前台顶层 activity(fg_act)清空兜底宿主单测。 * * 验证「App 会话退出/崩溃回收时清 fg_act」这一 launcher 兜底所依赖的状态机: * - meow_fg_act_set(app,act) 依注册表 route.keep_awake → fg_keep_awake()==1; * - App 会话结束(本工程在 launch_app_chain 退出尾调 meow_fg_act_back())→ fg 清空、 * fg_keep_awake() 回 0(主页不再被 keep_awake 卡住自动息屏); * - App 存活时(仅有 ACT_FOCUS,未会话结束)fg_act 保持不清。 * 该测试把真实 app_launcher.c 整包含进来(同 test_lock_screen / test_notif_panel 手法), * 用 -ffunction-sections -Wl,--gc-sections 只保留 main() 触及的 fg_act 原语,其余重函数 * (fork/exec/waitpid/fb)被剔除,故只需 stub logmsg。 * * 运行(patch_v2/meow_launcherd 下): * gcc -D_GNU_SOURCE -Wall -Wextra -ffunction-sections -Wl,--gc-sections \ * -I. -o test_fg_act test_fg_act.c && ./test_fg_act * 全 PASS -> exit 0。 */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include /* logmsg:fg_act 原语的唯一外部依赖(app_launcher.c 内定义,需在 include 前提供)。 */ void logmsg(const char *fmt, ...) { (void)fmt; } #include "app_launcher.c" /* 真实实现:g_accts/g_naccts/meow_fg_act_{set,back}/fg_keep_awake */ static int g_fail = 0; #define CHECK(cond, msg) do { \ if (!(cond)) { fprintf(stderr, "FAIL: %s (%s:%d)\n", msg, __FILE__, __LINE__); g_fail++; } \ else fprintf(stderr, "ok: %s\n", msg); \ } while (0) int main(void) { /* ---- 基线:无上报 = 主界面(非 keep_awake)---- */ CHECK(fg_keep_awake() == 0, "baseline: empty fg_act -> keep_awake=0"); /* ---- 注册 ncm 的 player activity 声明 keep_awake(模拟 app.json awake)---- */ struct meow_acct *a = meow_acct_upsert("dev.player.ncm"); CHECK(a != NULL, "register dev.player.ncm"); a->nroute = 1; strncpy(a->routes[0].act, "player", sizeof a->routes[0].act - 1); a->routes[0].act[sizeof a->routes[0].act - 1] = 0; a->routes[0].keep_awake = 1; /* ---- sim A:App 存活、正报 keep_awake activity(如 ncm 播放页)---- * 这是「App 在 keep_awake activity 时 fg_act 保持(不清)」的契约点。 */ meow_fg_act_set("dev.player.ncm", "player"); CHECK(fg_keep_awake() == 1, "ncm playing -> keep_awake=1 (保持, 不清)"); CHECK(strcmp(g_fg_app, "dev.player.ncm") == 0, "fg_app kept while app alive"); CHECK(strcmp(g_fg_act, "player") == 0, "fg_act kept while app alive"); /* ---- sim B:App 会话结束/崩溃回收(launch_app_chain 退出尾调用 meow_fg_act_back())---- */ meow_fg_act_back(); CHECK(fg_keep_awake() == 0, "app session end -> keep_awake=0 (兜底已清)"); CHECK(g_fg_act[0] == 0, "fg_act cleared on session end"); CHECK(g_fg_app[0] == 0, "fg_app cleared on session end"); /* ---- sim C:ACT_FOCUS(home) 正常弹回 home(agent-356)→ 非 keep_awake,且可再被兜底幂等清 ---- */ meow_fg_act_set("dev.player.ncm", "home"); /* home 未声明 keep_awake */ CHECK(fg_keep_awake() == 0, "ACT_FOCUS(home) -> keep_awake=0"); meow_fg_act_back(); /* 兜底幂等:再清一次不冲突 */ CHECK(g_fg_act[0] == 0 && fg_keep_awake() == 0, "back after home focus idempotent"); /* ---- sim D:act 为空(set(NULL act))/未知 app / 未知 act → 非 keep_awake ---- */ meow_fg_act_set("dev.player.ncm", NULL); CHECK(fg_keep_awake() == 0, "set(act=NULL) -> keep_awake=0"); meow_fg_act_set("no.such.app", "player"); CHECK(fg_keep_awake() == 0, "unregistered app -> keep_awake=0"); meow_fg_act_set("dev.player.ncm", "notascreen"); CHECK(fg_keep_awake() == 0, "unknown act in known app -> keep_awake=0"); if (g_fail) { fprintf(stderr, "\n== %d assertion(s) FAILED ==\n", g_fail); return 1; } fprintf(stderr, "\n== test_fg_act ALL PASS ==\n"); return 0; }