feat(launcher): M3导航栈+M5通知点击跳转 (agent-202) — nav_stack(≤16深)+MSG_NAV REPORT/EXIT+launch_activity链路注入(MEOW_ACTIVITY/MEOW_CHAIN)+栈根退出回主屏; 通知点击按route_status(0拉起/1 NO ROUTE/2 SOURCE NOT FOUND/-1 NONE关面板不动作); picker协议位预留(0x0070/0x0071); 裸App兼容
launcher 4fe4103a→a42171a1; qemu实测 declare/query/nav report/exit/notify+querynotif 全过 发现: §10.5 App前台通知中心叠加会话(MSG_NOTIF_OPEN)实际未实现,文档超前,待补
This commit is contained in:
1 parent
955dbe1228
commit
85b4aea24f
9 files changed
+321
-39
No files matched your search
@@ -124,6 +124,72 @@ int resolve_chain(const char *app_id, const char *activity, char *out, int *dept
|
||||
}
|
||||
|
||||
|
||||
/* ---- M3 导航栈(FRAMEWORK_DESIGN §3):每 app ≤16 深,v1 同一时刻单前台应用 ----
|
||||
* launcher 侧镜像:launch_* 冷启动时以链路深度初始化;App 经 MSG_NAV{REPORT,depth,current}
|
||||
* 上报栈深变化(launcher 更新);MSG_NAV{EXIT} → 置退出请求,前台 waitpid 循环终止 app 回主屏。
|
||||
* 单一写者=主循环(meow_ipc_process 排空处 / launch_* 前台循环),无需锁。 */
|
||||
static struct {
|
||||
char app_id[MEOW_APP_ID_MAX];
|
||||
int depth; /* 0=无/未上报;1..MEOW_NAV_MAX_DEPTH */
|
||||
char top[MEOW_ACT_MAX]; /* 当前顶层 activity_id(REPORT 上报) */
|
||||
int active; /* 1=前台应用有导航栈 */
|
||||
} g_nav;
|
||||
static volatile int g_nav_exit_req = 0;
|
||||
|
||||
void meow_nav_begin(const char *app_id, const char *chain)
|
||||
{
|
||||
if (!app_id) return;
|
||||
memset(&g_nav, 0, sizeof g_nav);
|
||||
strncpy(g_nav.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||||
g_nav.app_id[MEOW_APP_ID_MAX - 1] = 0;
|
||||
if (chain && chain[0]) {
|
||||
g_nav.depth = chain_depth(chain);
|
||||
if (g_nav.depth > MEOW_NAV_MAX_DEPTH) g_nav.depth = MEOW_NAV_MAX_DEPTH;
|
||||
const char *top = strrchr(chain, ';');
|
||||
top = top ? top + 1 : chain;
|
||||
strncpy(g_nav.top, top, MEOW_ACT_MAX - 1);
|
||||
g_nav.top[MEOW_ACT_MAX - 1] = 0;
|
||||
}
|
||||
g_nav.active = 1;
|
||||
logmsg("nav: begin app=%s chain=\"%s\" depth=%d top=%s",
|
||||
app_id, chain ? chain : "(bare)", g_nav.depth, g_nav.top);
|
||||
}
|
||||
|
||||
void meow_nav_report(const char *app_id, uint32_t depth, const char *current)
|
||||
{
|
||||
if (!app_id) return;
|
||||
if (depth == 0 || depth > MEOW_NAV_MAX_DEPTH) { meow_nav_exit(); return; }
|
||||
g_nav.active = 1;
|
||||
strncpy(g_nav.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||||
g_nav.app_id[MEOW_APP_ID_MAX - 1] = 0;
|
||||
g_nav.depth = (int)depth;
|
||||
if (current) { strncpy(g_nav.top, current, MEOW_ACT_MAX - 1); g_nav.top[MEOW_ACT_MAX - 1] = 0; }
|
||||
logmsg("nav: report app=%s depth=%d top=%s", app_id, g_nav.depth, g_nav.top);
|
||||
}
|
||||
|
||||
void meow_nav_exit(void)
|
||||
{
|
||||
g_nav.active = 0;
|
||||
g_nav.depth = 0;
|
||||
g_nav.top[0] = 0;
|
||||
logmsg("nav: exit (cleared)");
|
||||
}
|
||||
|
||||
void meow_nav_request_exit(void)
|
||||
{
|
||||
g_nav_exit_req = 1;
|
||||
meow_nav_exit();
|
||||
logmsg("nav: EXIT requested");
|
||||
}
|
||||
|
||||
int meow_nav_exit_pending(void)
|
||||
{
|
||||
int r = g_nav_exit_req;
|
||||
g_nav_exit_req = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* ---- M2.17 keep_awake:前台当前顶层 activity 追踪 ----
|
||||
* 前台应用经 IPC MSG_ACT_FOCUS/BACK 上报其当前顶层 activity;fg_keep_awake() 依注册表判断该
|
||||
* activity 是否声明 keep_awake(app.json awake.<id>=1 / route.<id>.keep_awake=1;运行时同类)。
|
||||
@@ -815,10 +881,13 @@ static void notify_app_crash(const char *pkg, int status)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int launch_app(struct app *a)
|
||||
/* launch_app_chain:launch_app / launch_activity 的共享核心。
|
||||
* chain 非空 → 向子进程注入 MEOW_ACTIVITY/MEOW_CHAIN 并初始化 nav_stack(M3);空/NULL → 裸启动。 */
|
||||
static int launch_app_chain(struct app *a, const char *chain)
|
||||
{
|
||||
logmsg("launch: %s (%s)", a->name, a->exec);
|
||||
logmsg("launch: %s (%s) chain=\"%s\"", a->name, a->exec, chain ? chain : "");
|
||||
if (!a->ok) { logmsg("launch blocked: exec not ok"); return -1; }
|
||||
meow_nav_begin(a->id, chain); /* M3:冷启动/裸启动都以当前链深初始化导航栈(chain 空→depth 0) */
|
||||
|
||||
/* M2.12:启动前准备 MeowData/<pkg>/{data,cache}(幂等;卡不在/失败只 log 不崩)。
|
||||
* 应用经环境变量 MEOW_DATA_DIR/MEOW_CACHE_DIR 定位数据(exFAT 无 symlink)。 */
|
||||
@@ -863,7 +932,9 @@ int launch_app(struct app *a)
|
||||
char env_tier[24];
|
||||
char env_fs[20];
|
||||
char env_cls[MEOW_FCLS_COUNT][2][400];
|
||||
char *envp[40]; /* PATH,HOME,log_dir,log_app,log_lvl,font 全局(3),多字体(1),tier(1),class(≤12),fullscreen(1),data,cache */
|
||||
char env_act[MEOW_ACT_MAX + 16]; /* M3:MEOW_ACTIVITY=<target>(链路顶端) */
|
||||
char env_chain[MEOW_CHAIN_MAX + 16]; /* M3:MEOW_CHAIN=<id0>;<id1>;...;<top> */
|
||||
char *envp[48]; /* PATH,HOME,log_dir,log_app,log_lvl,font 全局(3),多字体(1),tier(1),class(≤12),fullscreen(1),data,cache,act,chain */
|
||||
int ne = 0;
|
||||
const char *cp = getenv("PATH");
|
||||
snprintf(env_path, sizeof env_path, "PATH=%s", cp ? cp : "/usr/bin:/bin");
|
||||
@@ -961,6 +1032,18 @@ int launch_app(struct app *a)
|
||||
envp[ne++] = env_data;
|
||||
envp[ne++] = env_cache;
|
||||
}
|
||||
/* M3:冷启动/通知跳转注入 activity 链(FRAMEWORK_DESIGN §3)。chain 非空才注入;
|
||||
* MEOW_ACTIVITY=链路顶端(最后一段=target),MEOW_CHAIN=完整链路。裸启动不注入
|
||||
* (App 走 SDK 默认首页)。 */
|
||||
if (chain && chain[0]) {
|
||||
const char *top = strrchr(chain, ';');
|
||||
top = top ? top + 1 : chain;
|
||||
snprintf(env_act, sizeof env_act, "MEOW_ACTIVITY=%s", top);
|
||||
snprintf(env_chain, sizeof env_chain, "MEOW_CHAIN=%s", chain);
|
||||
envp[ne++] = env_act;
|
||||
envp[ne++] = env_chain;
|
||||
logmsg("launch: M3 env %s / %s", env_act, env_chain);
|
||||
}
|
||||
envp[ne] = NULL;
|
||||
execve(a->exec, argv, envp);
|
||||
int e = errno;
|
||||
@@ -1019,6 +1102,7 @@ int launch_app(struct app *a)
|
||||
* never fires on this unit, §18.12). Volume is snapped on the first
|
||||
* tap and restored when the sequence completes. */
|
||||
int status = 0;
|
||||
int nav_clean_exit = 0; /* M3:MSG_NAV{EXIT} 主动退出 → 不按崩溃上报 */
|
||||
int app_prev_vold = 0;
|
||||
int app_seq_hits = 0;
|
||||
unsigned long long app_seq_last = 0;
|
||||
@@ -1054,6 +1138,17 @@ int launch_app(struct app *a)
|
||||
if (r == pid) break;
|
||||
if (r < 0 && errno != EINTR) break;
|
||||
if (sigterm_flag) { logmsg("sigterm during app"); kill(pid, SIGTERM); break; }
|
||||
/* M3 导航栈:前台会话排空 IPC(App 经 MSG_NAV REPORT/EXIT 上报导航/请求退出)。
|
||||
* REPORT 更新 nav_stack(meow_ipc_process 内单写者);EXIT → 终止应用回主屏。 */
|
||||
meow_ipc_process();
|
||||
if (meow_nav_exit_pending()) {
|
||||
logmsg("nav: app %s MSG_NAV{EXIT} -> terminate, return to home", a->name);
|
||||
nav_clean_exit = 1;
|
||||
kill(pid, SIGTERM);
|
||||
usleep(300000);
|
||||
if (waitpid(pid, &status, WNOHANG) != pid) { kill(pid, SIGKILL); waitpid(pid, &status, 0); }
|
||||
break;
|
||||
}
|
||||
/* M2.11 D:卡被拔(设备节点消失)且前台应用在卡上 → 主动 SIGTERM 干净退出,
|
||||
* 避免应用等 SIGBUS 崩。回菜单走正常应用退出路径。 */
|
||||
if (app_on_card && !sd_device_present()) {
|
||||
@@ -1181,7 +1276,7 @@ int launch_app(struct app *a)
|
||||
/* M2.x:App 异常退出(信号杀 / 非 0 退出码)→ best-effort 直报 meow_crash。
|
||||
* 判据与 svcd reap_children 一致:failed = !(WIFEXITED && WEXITSTATUS==0)。干净 exit(0)
|
||||
* 不上报;sigterm 关停/电源菜单重启路径 status 保持 0(未 waitpid)→ 视为干净退出不上报。 */
|
||||
if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0))
|
||||
if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0) && !nav_clean_exit)
|
||||
notify_app_crash(a->id, status);
|
||||
if (wpid > 0) {
|
||||
/* reap the watchdog: SIGTERM then wait up to 2s (it exits when the
|
||||
@@ -1205,7 +1300,20 @@ int launch_app(struct app *a)
|
||||
/* M2.24:应用运行期音量由 watchdog 写(settings.conf 同源)。返回菜单前 re-load,
|
||||
* 让菜单音量/状态栏与真实 DAC 一致(watchdog 可能已改)。 */
|
||||
settings_load();
|
||||
meow_nav_exit(); /* M3:前台应用会话结束,清导航栈 */
|
||||
logmsg("app %s exited status=%d", a->name, WEXITSTATUS(status));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* M3:裸启动(无 activity 链)。保留旧签名,向下兼容不发 MSG_NAV 的 App。 */
|
||||
int launch_app(struct app *a)
|
||||
{
|
||||
return launch_app_chain(a, NULL);
|
||||
}
|
||||
|
||||
/* M3:以 activity 链路冷启动。注入 MEOW_ACTIVITY/MEOW_CHAIN + 设 nav_stack 栈深。 */
|
||||
int launch_activity(struct app *a, const char *chain)
|
||||
{
|
||||
return launch_app_chain(a, chain);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user