Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/test_ams_start.c
T
MeowOS 980d161972 fix(launcher/amsd): amsd MSG_AMS_START 拉起缺口——pending-start 抽 meow_ams_start 模块复用启动链 + 负错误码符修复
根因(真机日志实证,M2.92 遗留):meow_ams_pending_start_set 误返回正错误码
(-MEOW_ERR_BUSY=+8/-MEOW_ERR_INVAL=+1),ipc_dispatch 的 rc<0?-rc:MEOW_OK 把「有前台 App
拒绝/空包名非法」误判为 OK(0) → amsd 报 OK 但 pending 未置位 → App 永不拉起(am start 报 OK
但界面没出现/进程未起)。

launcher:
- 新增自包含模块 meow_ams_start.c/.h(ops 注入 launch=launch_app/launch_activity、
  resolve=resolve_chain、log=logmsg):pending 状态 + 拉起决策 + picker 上下文。
- set 统一返回负 MEOW_ERR_*(根因修复);consume 复用既有启动链路真正拉起目标 App,
  列表未就绪(state!=0)保留 pending 待 2s 重扫重试,不再静默丢弃。
- main_menu run_menu 改经 meow_ams_start_consume 消费(保留 launch_fail_toast/菜单收尾);
  app_launcher 移除旧 g_ams_start/g_ams_pick_* 迁入模块;util meow_ipc_process 顶部同步 busy、
  meow_ipc_init 末尾 meow_ams_launcher_init()。
- build_launcher.sh 编入 meow_ams_start.c;meow_launcher_internal.h 更新挂点声明。

amsd(协议层归属说明):cmd_start 的 busy 判定对照 launcher ACK 正幅度(busy=8),
原 (uint32_t)MEOW_ERR_BUSY=0xFFFFFFF8 永不匹配 → busy 落入 launcher offline,改 (uint32_t)(-MEOW_ERR_BUSY)。

验证:宿主 test_ams_start.c 33 断言全 PASS(合法->拉起链、activity chain 透传、空包名/非法/busy
不拉起不崩、列表未就绪保留 pending、无路由 NO ROUTE、启动失败 idx 回报、picker 取回);
launcher 目录全量回归 test_media/bgplay/depends/notif_panel/notif_tf/settings_brightness/
vol_ramp_jack/host_icon + test_font_tier/weight 全 PASS;mipsel -Wall -Wextra 0 warning。
新 md5:meow_launcherd a8200ae1b0aa68d7262749db87377d49、meow_amsd 7ddc677ce7938bc9b95c83c17bc78295。(M2.98 待打包,未刷机)
2026-09-01 19:40:29 +08:00

173 lines
8.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* test_ams_start.c — 宿主单测:MSG_AMS_START 拉起决策(meow_ams_start.c)。
*
* 覆盖(AMSD_DESIGN §4.3 缺口回归):
* 1) 合法 MSG_AMS_START(裸启动 act 空)→ 置 pending → consume → ops.launch(idx, NULL);
* 2) 合法 MSG_AMS_START + activity → resolve → consume → ops.launch(idx, chain);
* 3) 参数非法(pkg 空)→ meow_ams_pending_start_set 返回 MEOW_ERR_INVAL,不置位、不拉起、不崩;
* 4) 有前台 App(busy)→ set 返回 MEOW_ERR_BUSY(负错误码,根因修复),不拉起;
* 5) 列表未就绪(state!=0)→ consume 返回 2(pending 保留),不拉起;后就绪再 consume → 拉起;
* 6) pkg 不在应用表 → consume 返回 1,toast「NO APP」,不拉起;
* 7) activity 无路由 → consume 返回 1,toast「NO ROUTE」,不拉起;
* 8) 启动失败(ops.launch 返 <0)→ consume 返回 1,app_ran=0,idx_out 命中(供 launch_fail_toast);
* 9) picker 扩载荷:set_ex 武装 → take_picker 取回并清位。
* 只依赖 meow_ams_start.c + meow_ipc.h(纯 C),宿主 gcc 直编:
* gcc -Wall -Wextra -std=gnu99 test_ams_start.c meow_ams_start.c -o test_ams_start
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "meow_ams_start.h"
#include "meow_ipc.h"
static int g_fails = 0;
#define CHECK(cond, msg) do { \
if (cond) printf("PASS: %s\n", msg); \
else { printf("FAIL: %s\n", msg); g_fails++; } } while (0)
/* ---- 假件 ---- */
static int g_launch_calls = 0; /* ops.launch 被调次数 */
static int g_launch_last_idx = -1;
static char g_launch_last_chain[MEOW_CHAIN_MAX];
static int g_launch_ret = 0; /* 可注入:0=成功 / <0=启动失败 */
static int g_resolve_calls = 0;
static int g_resolve_rc = MEOW_OK; /* 可注入:MEOW_OK / MEOW_ERR_NOENT */
static int g_log_calls = 0;
static int fake_launch(int idx, const char *chain)
{
g_launch_calls++;
g_launch_last_idx = idx;
if (chain) snprintf(g_launch_last_chain, sizeof g_launch_last_chain, "%s", chain);
else g_launch_last_chain[0] = 0;
return g_launch_ret;
}
static int fake_resolve(const char *app_id, const char *activity,
char *chain, int *depth)
{
(void)app_id;
g_resolve_calls++;
if (g_resolve_rc != MEOW_OK) return g_resolve_rc;
snprintf(chain, MEOW_CHAIN_MAX, "%s", activity); /* 简化:chain=activity */
if (depth) *depth = 1;
return MEOW_OK;
}
static void fake_log(const char *fmt, ...) { (void)fmt; g_log_calls++; }
static void reset_fakes(void)
{
g_launch_calls = 0; g_launch_last_idx = -1;
g_launch_last_chain[0] = 0; g_launch_ret = 0;
g_resolve_calls = 0; g_resolve_rc = MEOW_OK;
g_log_calls = 0;
meow_ams_set_busy(0);
}
/* 应用表:id 主键串 + 用于 idx 断言 */
static const char *g_ids[3] = { "dev.player.ncm", "os.meow.files", "os.meow.hello" };
int main(void)
{
static struct meow_ams_ops ops;
ops.launch = fake_launch;
ops.resolve = fake_resolve;
ops.log = fake_log;
meow_ams_ops_init(&ops);
char toast[64];
int app_ran = 0, idx = -1;
/* ---- 1) 合法裸启动(act 空)→ consume → ops.launch ---- */
reset_fakes();
CHECK(meow_ams_pending_start_set("dev.player.ncm", "") == 0, "set(bare): 受理");
int r = meow_ams_start_consume(g_ids, 3, 0, toast, sizeof toast, &app_ran, &idx);
CHECK(r == 1 && g_launch_calls == 1, "consume(bare): 拉起链路被调");
CHECK(g_launch_last_idx == 0, "consume(bare): idx 命中 dev.player.ncm");
CHECK(g_launch_last_chain[0] == 0, "consume(bare): chain 空(裸启动)");
CHECK(app_ran == 1, "consume(bare): app_ran=1");
/* ---- 2) activity 链 → resolve → consume → ops.launch(chain) ---- */
reset_fakes();
CHECK(meow_ams_pending_start_set("os.meow.files", "pick") == 0, "set(act): 受理");
r = meow_ams_start_consume(g_ids, 3, 0, toast, sizeof toast, &app_ran, &idx);
CHECK(r == 1 && g_resolve_calls == 1, "consume(act): resolve 被调");
CHECK(g_launch_calls == 1 && g_launch_last_idx == 1, "consume(act): ops.launch(idx=1)");
CHECK(g_launch_last_chain[0] && strcmp(g_launch_last_chain, "pick") == 0,
"consume(act): chain 透传 pick");
/* ---- 3) 参数非法(pkg 空)→ INVAL,不置位、不拉起 ---- */
reset_fakes();
CHECK(meow_ams_pending_start_set("", "") == MEOW_ERR_INVAL, "set(空 pkg): 返回负错误码 MEOW_ERR_INVAL");
CHECK(meow_ams_pending_start_set(NULL, NULL) == MEOW_ERR_INVAL, "set(NULL pkg): MEOW_ERR_INVAL");
r = meow_ams_start_consume(g_ids, 3, 0, toast, sizeof toast, &app_ran, &idx);
CHECK(r == 0 && g_launch_calls == 0, "consume: 空 pkg 未置位 → 不拉起");
/* ---- 4) busy(有前台 App)→ BUSY,不拉起 ---- */
reset_fakes();
meow_ams_set_busy(1);
CHECK(meow_ams_pending_start_set("os.meow.hello", "") == MEOW_ERR_BUSY,
"set(busy): 返回负错误码 MEOW_ERR_BUSY(根因修复:旧实现返回 +8 被误判 OK)");
r = meow_ams_start_consume(g_ids, 3, 0, toast, sizeof toast, &app_ran, &idx);
CHECK(r == 0 && g_launch_calls == 0, "consume(busy): 不拉起");
meow_ams_set_busy(0);
/* ---- 5) 列表未就绪(state!=0)→ 保留 pending,后就绪拉起 ---- */
reset_fakes();
CHECK(meow_ams_pending_start_set("dev.player.ncm", "") == 0, "set: 受理");
r = meow_ams_start_consume(g_ids, 3, 2, toast, sizeof toast, &app_ran, &idx);
CHECK(r == 2 && g_launch_calls == 0, "consume(state!=0): 返回 2 保留 pending,不拉起");
CHECK(toast[0] && strstr(toast, "not ready"), "consume(state!=0): toast=列表未就绪");
r = meow_ams_start_consume(g_ids, 3, 0, toast, sizeof toast, &app_ran, &idx);
CHECK(r == 1 && g_launch_calls == 1 && g_launch_last_idx == 0,
"consume(后就绪): pending 保留后拉起成功");
/* ---- 6) pkg 不在应用表 → NO APP,不拉起 ---- */
reset_fakes();
CHECK(meow_ams_pending_start_set("no.such.app", "") == 0, "set(未知app): 受理");
r = meow_ams_start_consume(g_ids, 3, 0, toast, sizeof toast, &app_ran, &idx);
CHECK(r == 1 && g_launch_calls == 0, "consume(未知app): 不拉起");
CHECK(toast[0] && strstr(toast, "NO APP"), "consume(未知app): toast=NO APP");
/* ---- 7) activity 无路由 → NO ROUTE,不拉起 ---- */
reset_fakes();
g_resolve_rc = MEOW_ERR_NOENT;
CHECK(meow_ams_pending_start_set("os.meow.files", "nope") == 0, "set(nope): 受理");
r = meow_ams_start_consume(g_ids, 3, 0, toast, sizeof toast, &app_ran, &idx);
CHECK(r == 1 && g_launch_calls == 0, "consume(无路由): 不拉起");
CHECK(toast[0] && strstr(toast, "NO ROUTE"), "consume(无路由): toast=NO ROUTE");
g_resolve_rc = MEOW_OK;
/* ---- 8) 启动失败(ops.launch<0)→ app_ran=0,idx_out 命中 ---- */
reset_fakes();
g_launch_ret = -2; /* MEOW_ERR_NOENT */
CHECK(meow_ams_pending_start_set("dev.player.ncm", "") == 0, "set: 受理");
r = meow_ams_start_consume(g_ids, 3, 0, toast, sizeof toast, &app_ran, &idx);
CHECK(r == 1 && g_launch_calls == 1, "consume(启动失败): 拉起被调(失败)");
CHECK(app_ran == 0 && idx == 0, "consume(启动失败): app_ran=0 且 idx_out=0(供 launch_fail_toast)");
g_launch_ret = 0;
/* ---- 9) picker 扩载荷:set_ex 武装 → take_picker 取回并清位 ---- */
reset_fakes();
CHECK(meow_ams_pending_start_set_ex("os.meow.files", "pick", "pick_file", 7, "dev.player.ncm") == 0,
"set_ex(picker): 受理");
char act[24] = "", caller[MEOW_APP_ID_MAX] = "";
uint32_t req = 0;
CHECK(meow_ams_take_picker(act, sizeof act, caller, sizeof caller, &req) == 1,
"take_picker: 有上下文");
CHECK(strcmp(act, "pick_file") == 0 && req == 7 && strcmp(caller, "dev.player.ncm") == 0,
"take_picker: action/req/caller 正确");
CHECK(meow_ams_take_picker(act, sizeof act, caller, sizeof caller, &req) == 0,
"take_picker: 二次取回=0(一次性清位)");
/* 非 picker 启动:set(非 set_ex)不武装 picker */
reset_fakes();
CHECK(meow_ams_pending_start_set("dev.player.ncm", "") == 0, "set(bare): 受理");
CHECK(meow_ams_take_picker(act, sizeof act, caller, sizeof caller, &req) == 0,
"take_picker: 普通启动无 picker 上下文");
printf("\n%s (%d fails)\n", g_fails ? "FAILED" : "ALL PASS", g_fails);
return g_fails ? 1 : 0;
}