/* meow_ams_start.c — MSG_AMS_START 拉起决策(AMSD_DESIGN §4.3)。 * * 独立模块(无 launcher 内部依赖,仅 meow_ipc.h):持有 pending-start 状态 + 拉起决策, * 经 ops 注入真实启动链路(launch_app/launch_activity + resolve_chain + logmsg), * 使「am start」在 run_menu 主循环中真正拉起目标 App。 * * 根因修复:历史实现 `meow_ams_pending_start_set` 返回 `-MEOW_ERR_BUSY`(=+8,正)而非 * 负错误码,ipc_dispatch 的 `rc<0?-rc:MEOW_OK` 因此把「有前台 App 拒绝」误判为 OK(0), * 且拒绝发生在置 pending 之前 → amsd 报 OK 但 App 永不拉起。本模块统一为负 MEOW_ERR_*。 * * 单一写者约定:pending 状态只在主循环上下文写入/消费(ipc_dispatch 写、run_menu 消费), * 与 launcher 「单写者」纪律一致,无需锁。 */ #include "meow_ams_start.h" #include #include struct meow_ams_start_state { char pkg[MEOW_APP_ID_MAX]; char act[MEOW_ACT_MAX]; int pending; /* picker 上下文(二期;pick_armed=1 时 next launch 注入 env) */ char pick_action[24]; char pick_caller[MEOW_APP_ID_MAX]; uint32_t pick_req; int pick_armed; }; static struct meow_ams_start_state g_ams; /* 主循环单写者,无锁 */ static struct meow_ams_ops g_ops; static int g_busy; /* =g_app_session_active 镜像(主循环每圈同步) */ void meow_ams_ops_init(const struct meow_ams_ops *ops) { if (ops) g_ops = *ops; else memset(&g_ops, 0, sizeof g_ops); } void meow_ams_set_busy(int busy) { g_busy = busy; } int meow_ams_pending_start_set(const char *pkg, const char *act) { if (!pkg || !pkg[0]) return MEOW_ERR_INVAL; /* 负错误码(根因修复) */ if (g_busy) return MEOW_ERR_BUSY; /* 有前台 App:拒绝(负错误码) */ snprintf(g_ams.pkg, sizeof g_ams.pkg, "%s", pkg); g_ams.act[0] = 0; if (act && act[0]) snprintf(g_ams.act, sizeof g_ams.act, "%s", act); g_ams.pending = 1; return 0; } int meow_ams_pending_start_set_ex(const char *pkg, const char *act, const char *pick_action, uint32_t pick_req, const char *pick_caller) { int rc = meow_ams_pending_start_set(pkg, act); if (rc != 0) return rc; /* 拒绝(有前台 App / 参数非法) */ g_ams.pick_action[0] = 0; g_ams.pick_caller[0] = 0; g_ams.pick_req = 0; g_ams.pick_armed = 0; if (pick_action && pick_action[0]) { snprintf(g_ams.pick_action, sizeof g_ams.pick_action, "%s", pick_action); if (pick_caller) snprintf(g_ams.pick_caller, sizeof g_ams.pick_caller, "%s", pick_caller); g_ams.pick_req = pick_req; g_ams.pick_armed = 1; } return 0; } int meow_ams_take_picker(char *action, int action_len, char *caller, int caller_len, uint32_t *req) { if (!g_ams.pick_armed) return 0; g_ams.pick_armed = 0; if (action && action_len > 0) snprintf(action, action_len, "%s", g_ams.pick_action); if (caller && caller_len > 0) snprintf(caller, caller_len, "%s", g_ams.pick_caller); if (req) *req = g_ams.pick_req; return 1; } int meow_ams_start_consume(const char *const *ids, int napps, int state, char *toast, int toast_len, int *app_ran, int *idx_out) { if (app_ran) *app_ran = 0; if (idx_out) *idx_out = -1; if (!g_ams.pending || g_busy) return 0; /* 无待拉起 / 前台 App 会话中 */ if (state != 0) { /* 应用列表未就绪:保留 pending(不丢「am start」),等 run_menu 2s 重扫后重试。 */ if (toast && toast_len > 0) snprintf(toast, toast_len, "AMS START: app list not ready"); return 2; } int idx = -1; for (int i = 0; i < napps; i++) if (ids[i] && !strcmp(ids[i], g_ams.pkg)) { idx = i; break; } if (idx < 0) { g_ams.pending = 0; if (toast && toast_len > 0) snprintf(toast, toast_len, "AMS START: NO APP %s", g_ams.pkg); return 1; } char chain[MEOW_CHAIN_MAX] = ""; if (g_ams.act[0]) { int depth = 0; int rc = g_ops.resolve ? g_ops.resolve(g_ams.pkg, g_ams.act, chain, &depth) : MEOW_ERR_NOENT; if (rc != MEOW_OK) { g_ams.pending = 0; if (toast && toast_len > 0) snprintf(toast, toast_len, "AMS: NO ROUTE %s/%s", g_ams.pkg, g_ams.act); return 1; } } g_ams.pending = 0; if (idx_out) *idx_out = idx; /* 复用既有启动链路(launch_app/launch_activity 阻塞至 app 退出或 exec 失败) * chain 空=裸启动;非空=经 resolve_chain 的 activity 链(含参透传)。 * 启动失败(lr<0)不在此设 toast:调用方经 idx_out 拿到 apps[idx].name 打 launch_fail_toast。 */ int lr = g_ops.launch ? g_ops.launch(idx, chain[0] ? chain : NULL) : -MEOW_ERR_INTERNAL; if (app_ran) *app_ran = (lr == 0); return 1; }