feat(bt): 批①宽限期补充 — 全App入后台表(bg_since_ms)+未声明App宽限30min(MEOW_BG_GRACE_MS)超时回收+声明常驻/媒体活跃不清+槽满LRU回收最旧未声明;test_bgplay全过/0warning;devdocs APP_BACKGROUND_KEEPALIVE_P1 §9;M6.34需先重编meow_ui.a(meow_img_pixels)

This commit is contained in:
AskaEth committed 2026-09-04 01:48:31 +08:00
1 parent effce6d0db
commit 45c633868f
4 files changed
+264 -62

No files matched your search

+109 -16
View File
@@ -7,7 +7,10 @@
* should_keep=0(停播后再退出=真退);
* 3) 后台 App 崩溃照收:子进程被杀 → bg_tick WNOHANG 回收 → on_bg_dead + 清槽;
* 4) 卡拔例外:on_card=1 + card_present 假 0 → tick SIGTERM 回收(防 SIGBUS);
* 5) bg 表满(MEOW_BG_MAX)→ MEOW_ERR_NOMEM;重复 add → MEOW_ERR_EXISTS;
* 4b) 批①+宽限:未声明(keepalive=0)媒体不活跃超 MEOW_BG_GRACE_MS 回收(含恰等边界不回收);
* 声明常驻(keepalive=1)或媒体活跃(META PLAYING)超 grace 不清;
* 5) bg 表满(MEOW_BG_MAX)→ LRU 回收最久未激活的未声明槽新增成功;全为声明常驻 → MEOW_ERR_NOMEM
* (不回收声明常驻);pid<=0 → MEOW_ERR_INVAL;重复 add → MEOW_ERR_EXISTS;
* 6) 服务注册:exec 不可执行 → NOENT;同名在跑 → EXISTS;
* 7) 退避重启 1s/2s + max_restart=2 熔断(假时钟注入):清通知回调 + 注册连接收到
* MSG_SYS{SVC_DEAD=2} + circuit 后不再拉起;重注册复位熔断重新拉起;
@@ -154,6 +157,7 @@ int main(void)
ops.now_ms = fake_now_ms;
ops.card_present = fake_card;
ops.on_bg_dead = fake_bg_dead;
ops.media_resident = meow_media_app_resident; /* 批①+宽限:媒体活跃判定(宽限回收/槽满LRU) */
ops.notif_clear_app = fake_notif_clear;
ops.send_frame = fake_send_frame;
ops.log_dir = NULL;
@@ -267,33 +271,122 @@ int main(void)
"卡拔 → 卡上后台 App SIGTERM 回收(防 SIGBUS)");
g_card = 1;
/* ---- 5) 表满 / 重复 ---- */
/* ---- 5) 表满:LRU 回收最久未激活的未声明槽 / 全常驻满→NOMEM / 重复 / 参数 ---- */
{
pid_t k[MEOW_BG_MAX];
char id[MEOW_APP_ID_MAX];
int i, full = 0;
int i;
pid_t gextra = 0;
for (i = 0; i < MEOW_BG_MAX; i++) {
k[i] = spawn_sleeper();
snprintf(id, sizeof id, "dev.test.full%d", i);
meow_bg_add(id, k[i], -1, 0, 0);
snprintf(id, sizeof id, "dev.test.lru%d", i);
CHECK(meow_bg_add(id, k[i], -1, 0, 0) == 0, "lru 填表(未声明 keepalive=0)");
}
snprintf(id, sizeof id, "dev.test.full%d", MEOW_BG_MAX);
/* 5.1 表满 + 全未声明 → 新增 LRU 回收最旧(lru0,bg_since_ms 最小),新 App 入表成功 */
{
pid_t extra = spawn_sleeper();
full = (meow_bg_add(id, extra, -1, 0, 0) == MEOW_ERR_NOMEM);
kill(extra, SIGKILL); waitpid(extra, NULL, 0); /* 未入表,就地清理 */
pid_t e2 = spawn_sleeper();
gextra = e2;
CHECK(meow_bg_add("dev.test.lrunew", e2, -1, 0, 0) == 0,
"表满全未声明 → LRU 回收最旧槽并成功新增");
CHECK(meow_bg_count() == MEOW_BG_MAX, "回收后仍满 4 槽");
CHECK(meow_bg_is_backgrounded("dev.test.lrunew") == 1, "新增 App 在后台表");
CHECK(meow_bg_is_backgrounded("dev.test.lru0") == 0, "最久未激活未声明 lru0 被回收摘表");
CHECK(kill(k[0], 0) < 0, "lru0 进程已终止(SIGTERM 真退回收)");
}
CHECK(full, "bg 表满 → MEOW_ERR_NOMEM");
snprintf(id, sizeof id, "dev.test.full%d", 0);
CHECK(meow_bg_add(id, 0, -1, 0, 0) == MEOW_ERR_INVAL, "pid<=0 → INVAL");
CHECK(meow_bg_add(id, k[0], -1, 0, 0) == MEOW_ERR_EXISTS, "重复 app_id → EXISTS");
for (i = 0; i < MEOW_BG_MAX; i++) {
snprintf(id, sizeof id, "dev.test.full%d", i);
/* 5.2 重复 add → EXISTS;pid<=0 → INVAL(lru0 已回收,表内为 lrunew/lru1/lru2/lru3) */
CHECK(meow_bg_add("dev.test.lrunew", 999999, -1, 0, 0) == MEOW_ERR_EXISTS, "重复 app_id → EXISTS");
CHECK(meow_bg_add("dev.test.lrunew", 0, -1, 0, 0) == MEOW_ERR_INVAL, "pid<=0 → INVAL");
/* 5.3 清空剩余(take + 杀进程防泄漏) */
for (i = 1; i < MEOW_BG_MAX; i++) {
snprintf(id, sizeof id, "dev.test.lru%d", i);
meow_bg_take(id, NULL, NULL);
kill(k[i], SIGKILL); waitpid(k[i], NULL, 0);
}
meow_bg_take("dev.test.lrunew", NULL, NULL);
kill(gextra, SIGKILL); waitpid(gextra, NULL, 0);
CHECK(meow_bg_count() == 0, "清空后 bg 表空(未声明)");
}
/* ---- 5b) 表满 + 全为声明常驻(keepalive=1)→ 拒绝新入 NOMEM(不回收声明常驻,保安全) ---- */
{
pid_t d[MEOW_BG_MAX];
char id[MEOW_APP_ID_MAX];
int i;
for (i = 0; i < MEOW_BG_MAX; i++) {
d[i] = spawn_sleeper();
snprintf(id, sizeof id, "dev.test.dec%d", i);
CHECK(meow_bg_add(id, d[i], -1, 0, 1) == 0, "声明常驻填表(keepalive=1)");
}
{
pid_t e2 = spawn_sleeper();
CHECK(meow_bg_add("dev.test.decnew", e2, -1, 0, 0) == MEOW_ERR_NOMEM,
"全声明常驻满 → 新增 NOMEM(不回退真退,保安全)");
kill(e2, SIGKILL); waitpid(e2, NULL, 0); /* 未入表,就地清理 */
}
for (i = 0; i < MEOW_BG_MAX; i++) {
snprintf(id, sizeof id, "dev.test.dec%d", i);
meow_bg_take(id, NULL, NULL);
kill(d[i], SIGKILL); waitpid(d[i], NULL, 0);
}
CHECK(meow_bg_count() == 0, "声明常驻清空后 bg 表空");
}
/* ================= 批①+宽限:宽限超时回收 / 声明常驻与媒体活跃不清 ================= */
g_ms = 100000; /* 本组从干净时间基准起(后续 svc 段用相对 g_ms,不受影响) */
/* 5c) 未声明 + 媒体不活跃:grace 内保活;恰等 MEOW_BG_GRACE_MS 不回收(严格 >);超界回收 */
{
pid_t s1 = spawn_sleeper();
g_bg_dead = 0;
CHECK(meow_bg_add("dev.test.grace1", s1, -1, 0, 0) == 0, "grace1 入表(未声明 keepalive=0)");
g_ms = 100000u + MEOW_BG_GRACE_MS; /* 恰好等于宽限(非严格大于) */
meow_bg_tick();
CHECK(meow_bg_is_backgrounded("dev.test.grace1") == 1 && g_bg_dead == 0,
"grace 边界:恰等 MEOW_BG_GRACE_MS 不回收(严格 > 才回收)");
g_ms = 100000u + MEOW_BG_GRACE_MS + 1; /* 超界 1ms */
pump_bg_until(cond_bg_dead, NULL);
CHECK(meow_bg_is_backgrounded("dev.test.grace1") == 0 && meow_bg_count() == 0,
"超 grace 未再启动 → 回收摘表");
CHECK(g_bg_dead == 1, "宽限回收触发 on_bg_dead(通知 amsd)+ 进程经 SIGTERM 退出");
}
/* 5d) 声明常驻(keepalive=1)超 grace 不清(无限期) */
{
pid_t k1 = spawn_sleeper();
CHECK(meow_bg_add("dev.test.gracekeep", k1, -1, 0, 1) == 0, "gracekeep 入表(keepalive=1)");
g_ms = 100000u + MEOW_BG_GRACE_MS + 100000;
meow_bg_tick();
CHECK(meow_bg_is_backgrounded("dev.test.gracekeep") == 1,
"声明常驻 keepalive=1 超 grace 不清(无限期)");
meow_bg_take("dev.test.gracekeep", NULL, NULL);
kill(k1, SIGKILL); waitpid(k1, NULL, 0);
}
/* 5e) 媒体活跃(META PLAYING,keepalive=0)超 grace 不清(resident 保护) */
{
int sp2[2];
pid_t m1;
CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp2) == 0, "grace media socketpair");
{
m_meta_t meta;
memset(&meta, 0, sizeof meta);
snprintf(meta.app_id, sizeof meta.app_id, "dev.test.gracemedia");
meta.state = MEOW_MEDIA_PLAYING;
meow_media_meta(&meta, sp2[0]);
}
m1 = spawn_sleeper();
CHECK(meow_bg_add("dev.test.gracemedia", m1, -1, 0, 0) == 0,
"gracemedia 入表(keepalive=0 但媒体活跃)");
g_ms = 100000u + MEOW_BG_GRACE_MS + 100000;
meow_bg_tick();
CHECK(meow_media_app_resident("dev.test.gracemedia") == 1, "gracemedia media_resident=1");
CHECK(meow_bg_is_backgrounded("dev.test.gracemedia") == 1,
"媒体活跃超 grace 不清(resident 保护)");
meow_bg_take("dev.test.gracemedia", NULL, NULL);
kill(m1, SIGKILL); waitpid(m1, NULL, 0);
meow_media_clear("dev.test.gracemedia");
close(sp2[0]); close(sp2[1]);
}
CHECK(meow_bg_count() == 0, "take 全部后 bg 表空");
/* ================= 无头后台服务 ================= */
write_test_svc();