fix(sdk+launcher): 图标不渲染真根因(agent-219) — meow_ui_img.c scale_buf cover 采样把乘写成除(÷缩放比→采到源图左上角透明区,全丢); 改乘+居中裁剪偏移修正; 宿主旧测试用纯色图掩盖了该bug。+ main_menu App退出/结构变化重绘时 fb_pan_buf0_force 无条件pan回buffer0(防App翻页留buffer1致菜单残帧)
meow_ui.a→3e0ee8f7 launcher→9d0efc2f hello→9609ea6e files→90f5cf07 ncm→be8be221(均已上卡); 真机截图证据 .tmp/meowbug/fix1.png+fix_b2_after.png
This commit is contained in:
1 parent
05a19a9ea3
commit
ab4da09e75
45 files changed
+1926
-147
No files matched your search
Binary file not shown.
+53
-7
@@ -86,15 +86,41 @@ static int cmd_history(const char *pkg)
|
||||
static int cmd_start(const char *spec)
|
||||
{
|
||||
if (geteuid() != 0) { printf("ERR permission denied (root only)\n"); return 1; }
|
||||
char line[512];
|
||||
char line[800];
|
||||
snprintf(line, sizeof line, "start %s\n", spec);
|
||||
return am_query(line);
|
||||
}
|
||||
|
||||
static int cmd_resolve(const char *spec)
|
||||
{
|
||||
/* spec: <pkg> <activity>(两参数)。 */
|
||||
char line[800];
|
||||
snprintf(line, sizeof line, "resolve %s\n", spec);
|
||||
return am_query(line);
|
||||
}
|
||||
|
||||
static int cmd_picker(const char *action)
|
||||
{
|
||||
if (geteuid() != 0) { printf("ERR permission denied (root only)\n"); return 1; }
|
||||
char line[800];
|
||||
snprintf(line, sizeof line, "picker %s\n", action);
|
||||
return am_query(line);
|
||||
}
|
||||
|
||||
static int cmd_picker_status(const char *reqid)
|
||||
{
|
||||
char line[800];
|
||||
if (reqid && reqid[0])
|
||||
snprintf(line, sizeof line, "picker-status %s\n", reqid);
|
||||
else
|
||||
snprintf(line, sizeof line, "picker-status\n");
|
||||
return am_query(line);
|
||||
}
|
||||
|
||||
static int cmd_kill(const char *pkg)
|
||||
{
|
||||
if (geteuid() != 0) { printf("ERR permission denied (root only)\n"); return 1; }
|
||||
char line[512];
|
||||
char line[800];
|
||||
snprintf(line, sizeof line, "kill %s\n", pkg);
|
||||
return am_query(line);
|
||||
}
|
||||
@@ -103,8 +129,9 @@ static void usage(const char *a0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s [--sock <path>] status|list|history [pkg]|start <pkg>[/<act>]|kill <pkg>\n"
|
||||
" %s resolve <pkg> <activity> | picker <action> | picker-status [reqid]\n"
|
||||
" --sock <path> amsd socket (default %s, or $MEOW_AMS_SOCK)\n",
|
||||
a0, AMS_SOCK_DEFAULT);
|
||||
a0, a0, AMS_SOCK_DEFAULT);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -112,17 +139,25 @@ int main(int argc, char **argv)
|
||||
const char *env = getenv("MEOW_AMS_SOCK");
|
||||
g_sock = (env && env[0]) ? env : AMS_SOCK_DEFAULT;
|
||||
|
||||
const char *cmd = NULL, *arg = NULL;
|
||||
const char *cmd = NULL;
|
||||
char spec[768] = ""; /* 子命令后所有位置参数,空格拼接(resolve 需 pkg+act 两参) */
|
||||
int spec_n = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const char *a = argv[i];
|
||||
if (!strcmp(a, "--sock") && i + 1 < argc) g_sock = argv[++i];
|
||||
else if (!strcmp(a, "-h") || !strcmp(a, "--help")) { usage(argv[0]); return 0; }
|
||||
else if (a[0] == '-') { usage(argv[0]); return 2; }
|
||||
else if (!cmd) cmd = a;
|
||||
else if (!arg) arg = a;
|
||||
else { fprintf(stderr, "extra arg %s\n", a); return 2; }
|
||||
else if (!cmd) { cmd = a; }
|
||||
else {
|
||||
int w = snprintf(spec + spec_n, sizeof spec - spec_n, "%s%s",
|
||||
spec_n ? " " : "", a);
|
||||
if (w < 0) break;
|
||||
spec_n += w;
|
||||
if ((size_t)spec_n >= sizeof spec - 1) break;
|
||||
}
|
||||
}
|
||||
if (!cmd) { usage(argv[0]); return 2; }
|
||||
const char *arg = spec[0] ? spec : NULL;
|
||||
|
||||
if (!strcmp(cmd, "status")) return cmd_status();
|
||||
if (!strcmp(cmd, "list")) return cmd_list();
|
||||
@@ -135,6 +170,17 @@ int main(int argc, char **argv)
|
||||
if (!arg) { fprintf(stderr, "kill needs <pkg>\n"); return 2; }
|
||||
return cmd_kill(arg);
|
||||
}
|
||||
if (!strcmp(cmd, "resolve")) {
|
||||
if (!arg) { fprintf(stderr, "resolve needs <pkg> <activity>\n"); return 2; }
|
||||
return cmd_resolve(arg);
|
||||
}
|
||||
if (!strcmp(cmd, "picker")) {
|
||||
if (!arg) { fprintf(stderr, "picker needs <action>\n"); return 2; }
|
||||
return cmd_picker(arg);
|
||||
}
|
||||
if (!strcmp(cmd, "picker-status")) {
|
||||
return cmd_picker_status(arg);
|
||||
}
|
||||
usage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
Binary file not shown.
Regular → Executable
File mode changed.
Binary file not shown.
@@ -56,6 +56,9 @@
|
||||
#define AMS_HIST 8 /* 每 App 最近事件数 */
|
||||
#define AMS_MAX_APPS 64
|
||||
#define AMS_MAX_CONNS 32
|
||||
#define AMS_MAX_ROUTES 8 /* 每 App 路由数(MEOW_MAX_ROUTES 对齐) */
|
||||
#define AMS_MAX_PICKERS 8 /* picker action → handler 注册表 */
|
||||
#define AMS_MAX_PENDING 8 /* 进行中 picker 请求(结果关联) */
|
||||
#define AMS_TICK_MS 1000
|
||||
#define AMS_CLEANUP_MS 60000
|
||||
#define AMS_PATH_MAX 512
|
||||
@@ -70,7 +73,13 @@ struct ams_ev {
|
||||
char detail[192]; /* 事件描述(exit=0 / sig=11 / ams_start=... 等) */
|
||||
long epoch; /* 墙钟秒 */
|
||||
long up; /* uptime 秒 */
|
||||
char kind[16]; /* launch / exit / crash / ams_start / ams_kill */
|
||||
char kind[16]; /* launch / exit / crash / ams_start / ams_kill / picker_result */
|
||||
};
|
||||
|
||||
/* 路由行(来自 app.json route.<id>=<chain>;运行时经 DECLARE 增量并集)。 */
|
||||
struct ams_route {
|
||||
char act[16]; /* route 键后缀 */
|
||||
char chain[MEOW_CHAIN_MAX];
|
||||
};
|
||||
|
||||
struct ams_app {
|
||||
@@ -90,10 +99,33 @@ struct ams_app {
|
||||
int last_kind; /* 0=干净 exit 1=exit 2=sig */
|
||||
int last_code;
|
||||
long long last_dur_ms;
|
||||
/* §6.2 二期:路由权威(resolve 用;静态 app.json + 运行时 DECLARE 并集覆盖) */
|
||||
int nroute;
|
||||
struct ams_route routes[AMS_MAX_ROUTES];
|
||||
struct ams_ev hist[AMS_HIST];
|
||||
int hist_n, hist_idx;
|
||||
};
|
||||
|
||||
/* picker action → handler app(app.json picker.<action>=<chain>;amsd 权威路由)。 */
|
||||
struct ams_picker {
|
||||
char action[24];
|
||||
char app_id[MEOW_APP_ID_MAX];
|
||||
char chain[MEOW_CHAIN_MAX]; /* handler 入口 activity 链(v2 常空=裸启动,handler 读 env) */
|
||||
int used; /* 注册表命中 */
|
||||
};
|
||||
|
||||
/* 进行中 picker 请求(`am picker`/App 发起;结果经 PICKER_RESULT 关联)。 */
|
||||
struct ams_pending {
|
||||
int active;
|
||||
uint32_t req_id;
|
||||
char caller[MEOW_APP_ID_MAX];
|
||||
char action[24];
|
||||
char app_id[MEOW_APP_ID_MAX]; /* handler app(记录用) */
|
||||
int done; /* 结果已回 */
|
||||
int code;
|
||||
char value[256];
|
||||
};
|
||||
|
||||
/* stdout 捕获会话(一期同一时刻仅一个前台 App → 单槽) */
|
||||
struct ams_out {
|
||||
int active;
|
||||
@@ -119,6 +151,10 @@ static int g_sigpipe[2] = {-1, -1};
|
||||
static int g_listen_fd = -1;
|
||||
static struct ams_app g_apps[AMS_MAX_APPS];
|
||||
static int g_napps = 0;
|
||||
static struct ams_picker g_pickers[AMS_MAX_PICKERS]; /* §6.2 二期:picker 权威路由表 */
|
||||
static int g_npickers = 0;
|
||||
static struct ams_pending g_pending[AMS_MAX_PENDING]; /* §6.2 二期:进行中 picker */
|
||||
static uint32_t g_pick_req_seq = 1; /* req_id 单调分配 */
|
||||
|
||||
struct ams_conn {
|
||||
int fd;
|
||||
@@ -353,6 +389,92 @@ static void appjson_get(const char *content, const char *key, char *out, size_t
|
||||
out[l] = '\0';
|
||||
}
|
||||
|
||||
/* §6.2 二期:在 content 二分/扁平解析 route.<id>=<chain>(或 JSON "route.<id>":"<chain>")到 app。
|
||||
* 跳过 route.<id>.fullscreen / .keep_awake 子键;chain 取直链(';' 分隔保持原样)。 */
|
||||
static void ams_parse_routes(const char *content, struct ams_app *a)
|
||||
{
|
||||
if (!content || !a) return;
|
||||
const char *p = content;
|
||||
while ((p = strstr(p, "route.")) != NULL) {
|
||||
const char *q = p + 6;
|
||||
char id[16] = "";
|
||||
int idl = 0;
|
||||
while (*q && *q != '"' && *q != ':' && *q != '=' && *q != '.' && idl < 15)
|
||||
id[idl++] = *q++;
|
||||
id[idl] = 0;
|
||||
if (idl > 0 && *q == '.') { p = q; continue; } /* route.<id>.xxx 子键,跳过 */
|
||||
if (idl > 0) {
|
||||
const char *vp = q;
|
||||
while (*vp && *vp != ':' && *vp != '=') vp++;
|
||||
if (*vp == ':' || *vp == '=') vp++;
|
||||
while (*vp == ' ' || *vp == '\t') vp++;
|
||||
if (*vp == '"') vp++;
|
||||
char chain[MEOW_CHAIN_MAX] = "";
|
||||
int vl = 0;
|
||||
while (*vp && *vp != '"' && *vp != ',' && *vp != '\n' &&
|
||||
*vp != '\r' && vl < MEOW_CHAIN_MAX - 1)
|
||||
chain[vl++] = *vp++;
|
||||
chain[vl] = 0;
|
||||
while (vl > 0 && (chain[vl - 1] == ' ' || chain[vl - 1] == '\t')) chain[--vl] = 0;
|
||||
int ri = -1;
|
||||
for (int i = 0; i < a->nroute; i++)
|
||||
if (!strcmp(a->routes[i].act, id)) { ri = i; break; }
|
||||
if (ri < 0) {
|
||||
if (a->nroute >= AMS_MAX_ROUTES) { p = vp; continue; }
|
||||
ri = a->nroute++;
|
||||
}
|
||||
scopy(a->routes[ri].act, sizeof a->routes[ri].act, id);
|
||||
scopy(a->routes[ri].chain, sizeof a->routes[ri].chain, chain);
|
||||
p = vp;
|
||||
} else {
|
||||
p += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* §6.2 二期:解析 picker.<action>=<chain> 到全局 picker 表(action → handler app_id)。
|
||||
* app_id = 当前扫描目录名(=该 app.json 所属 App)。链 v2 常空=裸启动(handler 读 env)。 */
|
||||
static void ams_parse_pickers(const char *content, const char *app_id)
|
||||
{
|
||||
if (!content || !app_id) return;
|
||||
const char *p = content;
|
||||
while ((p = strstr(p, "picker.")) != NULL) {
|
||||
const char *q = p + 7;
|
||||
char action[24] = "";
|
||||
int al = 0;
|
||||
while (*q && *q != '"' && *q != ':' && *q != '=' && *q != '.' && al < 23)
|
||||
action[al++] = *q++;
|
||||
action[al] = 0;
|
||||
if (al > 0) {
|
||||
const char *vp = q;
|
||||
while (*vp && *vp != ':' && *vp != '=') vp++;
|
||||
if (*vp == ':' || *vp == '=') vp++;
|
||||
while (*vp == ' ' || *vp == '\t') vp++;
|
||||
if (*vp == '"') vp++;
|
||||
char chain[MEOW_CHAIN_MAX] = "";
|
||||
int vl = 0;
|
||||
while (*vp && *vp != '"' && *vp != ',' && *vp != '\n' &&
|
||||
*vp != '\r' && vl < MEOW_CHAIN_MAX - 1)
|
||||
chain[vl++] = *vp++;
|
||||
chain[vl] = 0;
|
||||
struct ams_picker *pk = NULL;
|
||||
for (int i = 0; i < g_npickers; i++)
|
||||
if (!strcmp(g_pickers[i].action, action)) { pk = &g_pickers[i]; break; }
|
||||
if (!pk && g_npickers < AMS_MAX_PICKERS) {
|
||||
pk = &g_pickers[g_npickers++];
|
||||
memset(pk, 0, sizeof *pk);
|
||||
scopy(pk->action, sizeof pk->action, action);
|
||||
}
|
||||
if (pk) {
|
||||
scopy(pk->app_id, sizeof pk->app_id, app_id);
|
||||
scopy(pk->chain, sizeof pk->chain, chain);
|
||||
pk->used = 1;
|
||||
}
|
||||
}
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
|
||||
/* 扫描 --apps 下每个目录(app_id=目录名;name/exec 从 app.json 抽,缺省回退)。 */
|
||||
static void registry_scan(void)
|
||||
{
|
||||
@@ -396,13 +518,22 @@ static void registry_scan(void)
|
||||
scopy(a->exec, sizeof a->exec, dir);
|
||||
path_append(a->exec, sizeof a->exec, "/meow");
|
||||
}
|
||||
/* §6.2 二期:路由权威表(静态 app.json route.*)+ picker 表(picker.<action>=<chain>) */
|
||||
ams_parse_routes(content, a);
|
||||
ams_parse_pickers(content, a->pkg);
|
||||
n++;
|
||||
}
|
||||
closedir(d);
|
||||
g_napps = n;
|
||||
emit_log("registry scan: %d app(s) from %s", g_napps, g_apps_dir);
|
||||
for (int i = 0; i < g_napps; i++)
|
||||
emit_log(" app %s name=%s exec=%s", g_apps[i].pkg, g_apps[i].name, g_apps[i].exec);
|
||||
for (int i = 0; i < g_napps; i++) {
|
||||
struct ams_app *a = &g_apps[i];
|
||||
emit_log(" app %s name=%s exec=%s routes=%d", a->pkg, a->name, a->exec, a->nroute);
|
||||
for (int r = 0; r < a->nroute; r++)
|
||||
emit_log(" route %s=%s", a->routes[r].act, a->routes[r].chain);
|
||||
}
|
||||
for (int i = 0; i < g_npickers; i++)
|
||||
emit_log(" picker %s -> %s (chain=%s)", g_pickers[i].action, g_pickers[i].app_id, g_pickers[i].chain);
|
||||
}
|
||||
|
||||
/* ---- App 表辅助 ---- */
|
||||
@@ -428,6 +559,81 @@ static struct ams_app *app_get(const char *pkg)
|
||||
return a;
|
||||
}
|
||||
|
||||
/* ---- §6.2 二期:路由权威(resolve/declare/picker)---- */
|
||||
|
||||
/* 路由规则与 launcher resolve_chain 一致(FRAMEWORK_DESIGN §2):
|
||||
* route 缺失(app 未声明任何路由)→ chain=activity、深度 1 兜底;
|
||||
* 声明了路由但 activity 非 route 键 → -MEOW_ERR_NOENT。返回 0=成功。 */
|
||||
static int amsd_resolve_chain(const char *app_id, const char *activity, char *out, int *depth)
|
||||
{
|
||||
if (!out || !depth) return MEOW_ERR_INVAL;
|
||||
if (!activity) activity = "";
|
||||
struct ams_app *a = app_find(app_id);
|
||||
if (!a) return MEOW_ERR_NOENT;
|
||||
if (a->nroute == 0) {
|
||||
snprintf(out, MEOW_CHAIN_MAX, "%s", activity);
|
||||
*depth = activity[0] ? 1 : 0;
|
||||
return MEOW_OK;
|
||||
}
|
||||
for (int i = 0; i < a->nroute; i++) {
|
||||
if (!strcmp(a->routes[i].act, activity)) {
|
||||
snprintf(out, MEOW_CHAIN_MAX, "%s", a->routes[i].chain);
|
||||
const char *c = a->routes[i].chain;
|
||||
int d = c[0] ? 1 : 0;
|
||||
for (; *c; c++) if (*c == ';') d++;
|
||||
*depth = d;
|
||||
return MEOW_OK;
|
||||
}
|
||||
}
|
||||
return MEOW_ERR_NOENT;
|
||||
}
|
||||
|
||||
/* 应用一组运行时 route entries(NUL 分隔 "id=chain")到 ams_app(并集覆盖,同 launcher)。 */
|
||||
static void amsd_apply_routes(struct ams_app *a, const char *entries)
|
||||
{
|
||||
const char *p = entries;
|
||||
while (*p) {
|
||||
const char *eq = strchr(p, '=');
|
||||
if (eq && eq > p) {
|
||||
int idlen = (int)(eq - p);
|
||||
if (idlen >= 16) idlen = 15;
|
||||
char id[16];
|
||||
memcpy(id, p, idlen); id[idlen] = 0;
|
||||
const char *chain = eq + 1;
|
||||
int ri = -1;
|
||||
for (int i = 0; i < a->nroute; i++)
|
||||
if (!strcmp(a->routes[i].act, id)) { ri = i; break; }
|
||||
if (ri < 0) {
|
||||
if (a->nroute >= AMS_MAX_ROUTES) { p += strlen(p) + 1; continue; }
|
||||
ri = a->nroute++;
|
||||
}
|
||||
scopy(a->routes[ri].act, sizeof a->routes[ri].act, id);
|
||||
scopy(a->routes[ri].chain, sizeof a->routes[ri].chain, chain);
|
||||
}
|
||||
p += strlen(p) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* hex 解码(小写/大写 2 字符/字节)到 out[outsz],返回字节数(含尾部 NUL 由调用方处理)。 */
|
||||
static int ams_hex_decode(const char *hex, char *out, int outsz)
|
||||
{
|
||||
int n = 0;
|
||||
const char *p = hex;
|
||||
while (p[0] && p[1] && n < outsz - 1) {
|
||||
int hi = (p[0] >= '0' && p[0] <= '9') ? p[0] - '0'
|
||||
: (p[0] >= 'a' && p[0] <= 'f') ? p[0] - 'a' + 10
|
||||
: (p[0] >= 'A' && p[0] <= 'F') ? p[0] - 'A' + 10 : -1;
|
||||
int lo = (p[1] >= '0' && p[1] <= '9') ? p[1] - '0'
|
||||
: (p[1] >= 'a' && p[1] <= 'f') ? p[1] - 'a' + 10
|
||||
: (p[1] >= 'A' && p[1] <= 'F') ? p[1] - 'A' + 10 : -1;
|
||||
if (hi < 0 || lo < 0) break;
|
||||
out[n++] = (char)((hi << 4) | lo);
|
||||
p += 2;
|
||||
}
|
||||
out[n] = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void hist_push(struct ams_app *a, const char *kind, const char *detail,
|
||||
long epoch, long up)
|
||||
{
|
||||
@@ -668,6 +874,146 @@ static void handle_out(char **t, int nt)
|
||||
out_append(pkg, pid, epoch, up, text);
|
||||
}
|
||||
|
||||
/* ---- §6.2 二期:picker 编排(amsd 路由权威) ---- */
|
||||
|
||||
static struct ams_picker *picker_find(const char *action)
|
||||
{
|
||||
if (!action || !action[0]) return NULL;
|
||||
for (int i = 0; i < g_npickers; i++)
|
||||
if (g_pickers[i].used && !strcmp(g_pickers[i].action, action)) return &g_pickers[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void pending_record(uint32_t req_id, const char *action, int code, const char *value)
|
||||
{
|
||||
for (int i = 0; i < AMS_MAX_PENDING; i++) {
|
||||
struct ams_pending *p = &g_pending[i];
|
||||
if (!p->active) continue;
|
||||
if (p->req_id != req_id) continue;
|
||||
if (action[0] && strcmp(p->action, action) != 0) continue;
|
||||
p->done = 1;
|
||||
p->code = code;
|
||||
scopy(p->value, sizeof p->value, value);
|
||||
emit_log("picker result: req=%u action=%s code=%d value=%s", req_id, p->action, code, p->value);
|
||||
struct ams_app *h = app_find(p->app_id);
|
||||
if (h) {
|
||||
char detail[192];
|
||||
snprintf(detail, sizeof detail, "req=%u caller=%s act=%s code=%d val=%.96s",
|
||||
req_id, p->caller, action, code, value);
|
||||
hist_push(h, "picker_result", detail, (long)time(NULL), read_uptime_sec());
|
||||
}
|
||||
return;
|
||||
}
|
||||
emit_log("picker result: no pending req=%u (dropped)", req_id);
|
||||
}
|
||||
|
||||
/* picker 启动:解析 action → handler;alloc/更新 pending;经 launcher MSG_AMS_START(picker) 拉起。
|
||||
* write_resp:写响应到 resp(cmd_picker 用;PICKER_CALL 事件传 NULL 不写)。返回 0=ok启动。 */
|
||||
static int picker_start(const char *caller, uint32_t req_id, const char *action,
|
||||
char *resp, int rn)
|
||||
{
|
||||
struct ams_picker *pk = picker_find(action);
|
||||
if (!pk) {
|
||||
if (resp) snprintf(resp, rn, "ERR no picker handler for action: %s\n", action ? action : "");
|
||||
emit_log("AMS picker %s -> no handler", action ? action : "");
|
||||
return -1;
|
||||
}
|
||||
struct ams_app *h = app_find(pk->app_id);
|
||||
if (!h) {
|
||||
if (resp) snprintf(resp, rn, "ERR handler app not registered: %s\n", pk->app_id);
|
||||
emit_log("AMS picker %s -> handler %s not registered", action, pk->app_id);
|
||||
return -1;
|
||||
}
|
||||
/* 找/建 pending 槽(同 req_id 去重;满则覆盖最旧 done) */
|
||||
struct ams_pending *p = NULL;
|
||||
for (int i = 0; i < AMS_MAX_PENDING; i++)
|
||||
if (g_pending[i].active && g_pending[i].req_id == req_id) { p = &g_pending[i]; break; }
|
||||
if (!p) {
|
||||
for (int i = 0; i < AMS_MAX_PENDING; i++)
|
||||
if (!g_pending[i].active || g_pending[i].done) { p = &g_pending[i]; break; }
|
||||
}
|
||||
if (!p) p = &g_pending[0]; /* 全占满→覆盖 0(最旧) */
|
||||
memset(p, 0, sizeof *p);
|
||||
p->active = 1;
|
||||
p->req_id = req_id;
|
||||
scopy(p->caller, sizeof p->caller, caller ? caller : "");
|
||||
scopy(p->action, sizeof p->action, action ? action : "");
|
||||
scopy(p->app_id, sizeof p->app_id, pk->app_id);
|
||||
/* 裸启动 handler(activity 空;picker 上下文经 MSG_AMS_START 扩载荷注入 env) */
|
||||
m_ams_start_t s;
|
||||
memset(&s, 0, sizeof s);
|
||||
scopy(s.app_id, sizeof s.app_id, pk->app_id);
|
||||
if (pk->chain[0]) scopy(s.activity, sizeof s.activity, pk->chain);
|
||||
s.picker = 1;
|
||||
s.picker_req_id = req_id;
|
||||
scopy(s.picker_action, sizeof s.picker_action, pk->action);
|
||||
scopy(s.picker_caller, sizeof s.picker_caller, caller ? caller : "");
|
||||
uint32_t code = MEOW_ERR_INTERNAL;
|
||||
int rt = ams_request_ctl(MSG_AMS_START, &s, sizeof s, &code);
|
||||
if (rt != 0) {
|
||||
p->active = 0;
|
||||
if (resp) snprintf(resp, rn, "ERR launcher offline\n");
|
||||
emit_log("AMS picker %s -> launcher offline", action);
|
||||
return -1;
|
||||
}
|
||||
if (code != MEOW_OK) {
|
||||
if (resp) snprintf(resp, rn, "ERR launcher refused: %s (code=%u)\n", pk->app_id, code);
|
||||
emit_log("AMS picker %s -> launcher refused code=%u", action, code);
|
||||
return -1;
|
||||
}
|
||||
if (resp) snprintf(resp, rn, "OK pending %u %s\n", req_id, pk->app_id);
|
||||
emit_log("AMS picker %s -> %s (req=%u, caller=%s)", action, pk->app_id, req_id, caller ? caller : "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* `am picker <action>`:alloc req_id(CLI 无 caller),启动,回 OK pending。 */
|
||||
static int cmd_picker(const char *action, char *resp, int rn)
|
||||
{
|
||||
if (!action || !action[0]) { snprintf(resp, rn, "ERR picker needs <action>\n"); return 1; }
|
||||
uint32_t req_id = g_pick_req_seq++;
|
||||
if (g_pick_req_seq == 0) g_pick_req_seq = 1;
|
||||
picker_start("", req_id, action, resp, rn); /* 内部写 OK pending / ERR */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* `picker-status [reqid]`:列正在/已决 picker。 */
|
||||
static int cmd_picker_status(const char *reqstr, char *resp, int rn)
|
||||
{
|
||||
int l = snprintf(resp, rn, "# amd picker status\n");
|
||||
int found = 0;
|
||||
for (int i = 0; i < AMS_MAX_PENDING; i++) {
|
||||
struct ams_pending *p = &g_pending[i];
|
||||
if (!p->active) continue;
|
||||
if (reqstr && reqstr[0] && (uint32_t)atoi(reqstr) != p->req_id) continue;
|
||||
found = 1;
|
||||
const char *state = p->done ? "done" : "pending";
|
||||
int m = snprintf(resp + l, rn - l, "PICK %u %s %s %d %s\n",
|
||||
p->req_id, p->action, p->app_id, p->done ? p->code : -1,
|
||||
p->done ? p->value : state);
|
||||
if (m > 0) l += m;
|
||||
}
|
||||
if (!found) { int m = snprintf(resp + l, rn - l, "(none)\n"); if (m > 0) l += m; }
|
||||
return l;
|
||||
}
|
||||
|
||||
/* `am resolve <pkg> <act>`:查 amsd 权威路由表。 */
|
||||
static int cmd_resolve(const char *pkg, const char *act, char *resp, int rn)
|
||||
{
|
||||
if (!pkg || !pkg[0] || !act || !act[0]) {
|
||||
snprintf(resp, rn, "ERR resolve needs <pkg> <activity>\n");
|
||||
return 1;
|
||||
}
|
||||
char chain[MEOW_CHAIN_MAX];
|
||||
int depth = 0;
|
||||
int rc = amsd_resolve_chain(pkg, act, chain, &depth);
|
||||
if (rc != 0) {
|
||||
snprintf(resp, rn, "ERR resolve %s/%s failed (%d)\n", pkg, act, rc);
|
||||
return 1;
|
||||
}
|
||||
snprintf(resp, rn, "CHAIN %s %s %d %s\n", pkg, act, depth, chain);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ---- am CLI 命令处理 ---- */
|
||||
static int cmd_status(char *resp, int rn)
|
||||
{
|
||||
@@ -819,7 +1165,41 @@ static int dispatch_line(char *line, char *resp, int rn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 命令:status/list/history/start/kill */
|
||||
/* §6.2 二期事件(launcher → amsd 一次性转发,无响应):DECLARE / PICKER_CALL / PICKER_RESULT */
|
||||
if (strncmp(line, "DECLARE ", 8) == 0 || strncmp(line, "PICKER_", 7) == 0) {
|
||||
char *tok[8];
|
||||
int nt = 0;
|
||||
char *save = NULL;
|
||||
for (int i = 0; i < (int)(sizeof tok / sizeof tok[0]); i++) {
|
||||
char *tk = strtok_r(i == 0 ? line : NULL, " ", &save);
|
||||
if (!tk) break;
|
||||
tok[nt++] = tk;
|
||||
}
|
||||
if (nt >= 1) {
|
||||
if (!strcmp(tok[0], "DECLARE") && nt >= 4) {
|
||||
struct ams_app *a = app_get(tok[1]);
|
||||
char entries[MEOW_IPC_CARGO];
|
||||
if (a) {
|
||||
int bl = ams_hex_decode(tok[3], entries, sizeof entries);
|
||||
(void)bl;
|
||||
amsd_apply_routes(a, entries);
|
||||
emit_log("DECLARE %s n=%s routes=%d", tok[1], tok[2], a->nroute);
|
||||
}
|
||||
} else if (!strcmp(tok[0], "PICKER_CALL") && nt >= 4) {
|
||||
uint32_t req = (uint32_t)atoi(tok[2]);
|
||||
(void)picker_start(tok[1], req, tok[3], NULL, 0);
|
||||
} else if (!strcmp(tok[0], "PICKER_RESULT") && nt >= 5) {
|
||||
uint32_t req = (uint32_t)atoi(tok[1]);
|
||||
int code = atoi(tok[3]);
|
||||
char value[256];
|
||||
(void)ams_hex_decode(tok[4], value, sizeof value);
|
||||
pending_record(req, tok[2], code, value);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 命令:status/list/history/start/kill/resolve/picker/picker-status */
|
||||
char *save = NULL;
|
||||
char *cmd = strtok_r(line, " ", &save);
|
||||
if (!cmd) return 0;
|
||||
@@ -841,6 +1221,19 @@ static int dispatch_line(char *line, char *resp, int rn)
|
||||
cmd_kill(arg, resp, rn);
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(cmd, "resolve")) {
|
||||
if (!arg) { snprintf(resp, rn, "ERR resolve needs <pkg> <activity>\n"); return 1; }
|
||||
char *act = strtok_r(NULL, " ", &save);
|
||||
return cmd_resolve(arg, act, resp, rn) > 0;
|
||||
}
|
||||
if (!strcmp(cmd, "picker")) {
|
||||
if (!arg) { snprintf(resp, rn, "ERR picker needs <action>\n"); return 1; }
|
||||
cmd_picker(arg, resp, rn);
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(cmd, "picker-status")) {
|
||||
return cmd_picker_status(arg, resp, rn) > 0;
|
||||
}
|
||||
snprintf(resp, rn, "ERR unknown cmd: %s\n", cmd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Binary file not shown.
Reference in new issue
Block a user