根因(真机日志实证,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 待打包,未刷机)
173 lines
8.4 KiB
C
173 lines
8.4 KiB
C
/* 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;
|
||
}
|