feat(bt): 批①后台常驻框架实施 — meow_media_app_resident按app会话判活跃+should_keep三参(keepalive||bg_audio&&resident)+background_keepalive声明解析透传+amsd EV BG/FG上报;宿主test_media39/test_bgplay/test_bg_keep19全过,0warning;落盘APP_BACKGROUND_KEEPALIVE_P1;降配(nice)待真机未做

This commit is contained in:
AskaEth committed 2026-09-04 00:39:29 +08:00
1 parent 7e68313981
commit f3ae06d7cd
10 files changed
+330 -30

No files matched your search

+44 -7
View File
@@ -123,6 +123,24 @@ static void ams_report_exit(const struct app *a, int status, long long dur_ms)
ams_report_exit_id(a->id, status, dur_ms);
}
/* 批①后台常驻上报(单向 best-effort):转后台 `EV BG <app> <pid>`、回前台 `EV FG <app>`。
* amsd 收到后置 AMS_BG/AMS_FG(批③后台管理页元数据来源);旧 launcher 不发、amsd 不识别也不崩。 */
static void ams_report_bg(const char *app_id, pid_t pid)
{
if (!app_id || !app_id[0]) return;
char line[256];
int l = snprintf(line, sizeof line, "EV BG %s %d\n", app_id, (int)pid);
if (l > 0) ams_send(line, l);
}
static void ams_report_fg(const char *app_id)
{
if (!app_id || !app_id[0]) return;
char line[256];
int l = snprintf(line, sizeof line, "EV FG %s\n", app_id);
if (l > 0) ams_send(line, l);
}
/* ---- stdout/stderr 管道捕获(AMSD_DESIGN §5):前台 waitpid 循环排空 + 按行转发 ---- */
static char g_ams_out_line[1024]; /* 未完结行缓冲(无 \n) */
static int g_ams_out_n = 0;
@@ -319,6 +337,7 @@ static void meow_acct_sync(const char *app_id, const struct app *ap)
a->framework = ap->framework;
a->background = ap->background; /* M4 */
a->background_audio = ap->background_audio;
a->background_keepalive = ap->background_keepalive; /* 批① */
strncpy(a->icon, ap->icon, 128);
app_name_copy(a->name, (int)sizeof a->name, ap->name);
strncpy(a->exec, ap->exec, 128);
@@ -648,6 +667,7 @@ void meow_parse_app_json(FILE *f, struct app *a)
int fonts = 0, fonts_set = 0; /* app.json "fonts":<档>(0=默认4K常用 1=大字库GBK 2=Full;缺省 0) */
int background = 0; /* M4:app.json background=true(可注册无头后台服务) */
int bg_audio = 0; /* M4:app.json background_audio=true(播放中退出转后台保活) */
int bg_keepalive = 0; /* 批①:app.json background_keepalive=true(进入后台即保活,不依赖媒体会话) */
struct app tmp;
memset(&tmp, 0, sizeof tmp);
while (fgets(buf, sizeof buf, f)) {
@@ -779,6 +799,17 @@ void meow_parse_app_json(FILE *f, struct app *a)
bg_audio = 1;
}
}
/* "background_keepalive":true(批①:进入后台即保活,不依赖媒体会话=通用常驻)。
* 注意 "background_keepalive" 是 "background" 的前缀:若本行先命中上方 background 分支,
* json_str(buf,"background") 读出的是 "_keepalive…" ≠ true → 自然留 0,无害;
* json_str 键前缀独立性(util.c:544 ident_ch)保证 "background"/"background_audio" 独立匹配不受影响。 */
if (!bg_keepalive && strstr(buf, "background_keepalive")) {
char v[8] = "";
if (json_str(buf, "background_keepalive", v, sizeof v) > 0) {
if (!strcmp(v, "true") || !strcmp(v, "1") || !strcmp(v, "yes"))
bg_keepalive = 1;
}
}
/* service.<svc>=mode:restart:max:window_ms(M1 解析存储,保活 M4) */
char *sp = strstr(buf, "service.");
if (sp && tmp.nsvc < MEOW_MAX_SVCS) {
@@ -833,6 +864,7 @@ void meow_parse_app_json(FILE *f, struct app *a)
a->fonts = (char)(fonts < 0 ? 0 : (fonts > 2 ? 2 : fonts)); /* 注入 MEOW_FONT_TIER env */
a->background = background ? '1' : 0; /* M4:后台服务注册权限 */
a->background_audio = bg_audio ? '1' : 0; /* M4:后台播放保活 */
a->background_keepalive = bg_keepalive ? '1' : 0; /* 批①:后台即保活(通用常驻) */
strncpy(a->icon, icon, 128);
a->nroute = tmp.nroute;
if (tmp.nroute) memcpy(a->routes, tmp.routes, sizeof(a->routes[0]) * (size_t)tmp.nroute);
@@ -1551,6 +1583,7 @@ static int launch_app_chain(struct app *a, const char *chain)
unlink(NOTIF_ACTIVE);
drain_input();
meow_nav_begin(a->id, NULL); /* 转后台时导航栈已清;回前台从裸态重建 */
ams_report_fg(a->id); /* 批①:单向 best-effort 上报 amsd 置 AMS_FG */
}
if (!resumed) {
/* 二进制依赖启动前检查(app.json depends):required 缺失阻断启动,optional 缺失放行。
@@ -1931,14 +1964,17 @@ static int launch_app_chain(struct app *a, const char *chain)
break;
}
if (meow_nav_exit_pending()) {
/* M4 后台播放保活:声明 background_audio 且该 App 媒体会话 PLAYING → 不终止,
* 进程+音频流保留转后台(UI 冻结走 §10.5 SDK present 自抑,**非 SIGSTOP**——
* SIGSTOP 会冻结同进程播放线程断供 PCM,§10.5 真机实证)。登记失败
*(槽满/已存在)回落下方真退序列。卡拔例外不适用保活(bg 表 tick 照杀)。 */
/* 批①后台保活:声明 background_keepalive → 恒保活;或声明 background_audio 且该 App
* 媒体会话活跃(PLAYING/PAUSED/BUFFER,见 meow_media_app_resident)→ 保活。进程+音频流
* 保留转后台(UI 冻结走 §10.5 SDK present 自抑,**非 SIGSTOP**——SIGSTOP 会冻结同进程
* 播放线程断供 PCM,§10.5 真机实证)。登记失败(槽满/已存在)回落下方真退序列。
* 卡拔例外不适用保活(bg 表 tick 照杀)。 */
if (meow_bg_should_keep(a->background_audio == '1',
meow_media_app_playing(a->id)) &&
meow_bg_add(a->id, pid, out_fd, app_on_card) == 0) {
logmsg("bg: app %s nav-exit -> 后台保活(播放中,pid=%d 保留,SDK present 自抑)",
meow_media_app_resident(a->id),
a->background_keepalive == '1') &&
meow_bg_add(a->id, pid, out_fd, app_on_card,
a->background_keepalive == '1') == 0) {
logmsg("bg: app %s nav-exit -> 后台保活(活跃(播放/暂停/缓冲),pid=%d 保留,SDK present 自抑)",
a->name, (int)pid);
to_background = 1;
break;
@@ -2177,6 +2213,7 @@ static int launch_app_chain(struct app *a, const char *chain)
meow_dirty_add(0, SB_BAR_Y, fb_xres, SB_BAR_H);
settings_load();
meow_nav_exit(); /* 前台会话导航栈清栈(App 本体栈内存活;回前台时裸态重建) */
ams_report_bg(a ? a->id : "", pid); /* 批①:单向 best-effort 上报 amsd 置 AMS_BG */
return 0;
}
/* §10.5:App 前台会话结束,清会话标记(ipc_dispatch 不再受理 MSG_NOTIF_OPEN) */