系统基建线(agent-139): svcd subreaper加固 + meow_sysui总监 + 启动链

- svcd: 审计确认现网已子进程化(fork+execv+setpgid+waitpid+SIGCHLD+set_cloexec,无system()); 增量 prctl(PR_SET_CHILD_SUBREAPER) 代收孤儿孙进程 → fb2d608b
- meow_sysui(新增): 系统进程总监, 仿svcd成熟模式(信号自管道/poll/双探测kill/waitpid/subreaper/状态机), 监护自己fork+exec进程, 按sysui.d/<name>.conf逐条拉起, 无级联/有限次兜底/主循环绝不exit/空配置空转 → 173013cc
- 启动链 S70meow_sysui → S89meow_svcd → S90meow_bootmenu; svcd拉起权判归(sysui在→交监管,不在→回退现网重挂循环)
- 宿主集成测试过(常崩/稳定隔离/无级联/subreaper收尸/端到端); meow_ui.a未动
- 需加到固件打包(build_fw_apps_m267.sh): sysui→/usr/bin/meow_sysui, svcd覆盖(fb2d608b), S70+S89; 校验 svcd 762e84d0→fb2d608b, 新增 sysui 173013cc
This commit is contained in:
MeowOS committed 2026-08-30 19:07:47 +08:00
1 parent c4e648be0e
commit 2a6c4e97c5
9 files changed
+1390 -7

No files matched your search

+27 -7
View File
@@ -1,16 +1,19 @@
#!/bin/sh #!/bin/sh
# #
# S89meow_svcd - MeowOS 服务管理器开机自启 + 主机名应用 + 板载服务预置 # S89meow_svcd - MeowOS 服务管理器协同启动 + 主机名应用 + 板载服务预置
# #
# 位置:S84ssh 之后、S90meow_bootmenu 之前(S80 < S84 < S89 < S90)。 # 位置:S70meow_sysui 之后、S90meow_bootmenu 之前(S70 < S84 < S89 < S90)。
# * rcS 顺序执行 /etc/init.d/S??*,而 S90meow_bootmenu 里 `exec /usr/bin/meow_bootmenu # * rcS 顺序执行 /etc/init.d/S??*,而 S90meow_bootmenu 里 `exec /usr/bin/meow_bootmenu
# --fork` 会阻塞 rcS(选单后 exec meow_launcherd 或 fork 播放器监督),故任何 S90 # --fork` 会阻塞 rcS(选单后 exec meow_launcherd 或 fork 播放器监督),故任何 S90
# 之后的 init.d(如 S91/S92)**都不会执行**——svcd 必须排在 S90 之前。 # 之后的 init.d(如 S91/S92)**都不会执行**——svcd 必须排在 S90 之前。
# * 本脚本只装「稳定框架/KB级设置」:meow_svcd(固件 /usr/bin/)+ 板载服务配置 # * 本脚本只装「稳定框架/KB级设置」:主机名 + 板载服务配置
# (/usr/data/meow/services.d/,Data 区,首启预置 mdnsd.conf)+ 应用主机名。 # (/usr/data/meow/services.d/,Data 区,首启预置 mdnsd.conf)。
# * **svcd 拉起权**:若 meow_sysui(系统进程总监)已运行 → svcd 由 sysui 监管拉起
# (sysui.d/svcd.conf),本脚本仅在其已运行时 `meow_svcd reload` 让 svcd 补载 mdnsd.conf,
# 不重复拉起、不重挂(避免与 sysui 双重监护 svcd)。仅当 **sysui 未运行**时才回退到
# 现网的「重挂循环」自监护(旧固件/无 sysui 场景,向后兼容)。
# #
# 红线:不 killall、不碰播放器信号、不刷机。svcd 以 -f 前台被本脚本重挂循环拉起 # 红线:不 killall、不碰播放器信号、不刷机。svcd 以 -f 前台被 sysui(或重挂循环)拉起;
#(失败降级不死——若 svcd 死,其所托管服务已是独立子进程、被 init 收养继续运行);
# 服务本身(mdnsd)由 svcd 按 restart=on-fail 托管。 # 服务本身(mdnsd)由 svcd 按 restart=on-fail 托管。
# #
case "$1" in case "$1" in
@@ -54,9 +57,26 @@ EOF
echo -n "skip mdnsd.conf (/usr/data/meow not writable) " echo -n "skip mdnsd.conf (/usr/data/meow not writable) "
fi fi
# 3) 拉起 meow_svcd(-f 前台,重挂循环防死;/tmp/meow_svcd.stop 标记防停循环) # 3) svcd 拉起权判归:sysui 运行 → 交给 sysui 监管;否则回退重挂循环。
rm -f /tmp/meow_svcd.stop rm -f /tmp/meow_svcd.stop
sysui_alive=0
if [ -x /usr/bin/meow_sysui ] && ps | grep -q "[m]eow_sysui"; then
sysui_alive=1
fi
if [ "$sysui_alive" = "1" ]; then
# svcd 由 meow_sysui 监管拉起;此处仅补载刚预置的 mdnsd.conf(若 svcd 已在跑)
if [ -x /usr/bin/meow_svcd ]; then if [ -x /usr/bin/meow_svcd ]; then
if [ -f /tmp/meow_svcd.pid ] && kill -0 "$(cat /tmp/meow_svcd.pid 2>/dev/null)" 2>/dev/null; then
/usr/bin/meow_svcd reload 2>/dev/null
echo -n "supervised by sysui (svcd running, reload) "
else
# svcd 未在跑:交给 sysui 按兜底(有限次重试)拉起,此处不干预,防双重拉起
echo -n "defer to meow_sysui (svcd down) "
fi
else
echo -n "MISSING /usr/bin/meow_svcd "
fi
elif [ -x /usr/bin/meow_svcd ]; then
if [ -f /tmp/meow_svcd.pid ] && kill -0 "$(cat /tmp/meow_svcd.pid 2>/dev/null)" 2>/dev/null; then if [ -f /tmp/meow_svcd.pid ] && kill -0 "$(cat /tmp/meow_svcd.pid 2>/dev/null)" 2>/dev/null; then
echo "already running" echo "already running"
else else
Binary file not shown.
+6
View File
@@ -66,6 +66,7 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <sys/prctl.h>
#include <poll.h> #include <poll.h>
/* ---- 默认路径 / 常量 ---- */ /* ---- 默认路径 / 常量 ---- */
@@ -1143,6 +1144,11 @@ static void shutdown_all(void)
static int start_daemon(void) static int start_daemon(void)
{ {
if (setup_signals() != 0) return 1; if (setup_signals() != 0) return 1;
/* 设为子进程回收者:被监管服务若派生出孙进程,在服务(直接子进程)退出后
* 由 svcd 收尸而非 reparent 到 init,强化「服务崩溃隔离(僵死/孤儿)」一环。
* 失败不致命:仅记录并继续。 */
if (prctl(PR_SET_CHILD_SUBREAPER, 1) != 0)
svcd_log("PR_SET_CHILD_SUBREAPER failed: %s (continue)", strerror(errno));
if (setup_socket() != 0) return 1; if (setup_socket() != 0) return 1;
write_pidfile(); write_pidfile();
+2
View File
@@ -128,6 +128,8 @@ FAILED 崩溃且不再重启(超 max_restart / restart=never)
- **不读服务输出**:子进程继承 svcd stdio(stdout/stderr 落同一 sink),svcd **不 - **不读服务输出**:子进程继承 svcd stdio(stdout/stderr 落同一 sink),svcd **不
设管道读服务体**——服务写多少都不进 svcd 内存,天然规避「输出撑爆 → svcd 崩」。 设管道读服务体**——服务写多少都不进 svcd 内存,天然规避「输出撑爆 → svcd 崩」。
- **后退避**:重启间隔受 `backoff_ms` 约束,防崩溃-重启热循环拖垮系统。 - **后退避**:重启间隔受 `backoff_ms` 约束,防崩溃-重启热循环拖垮系统。
- **孤儿/僵死隔离**:`start_daemon()` 设 `PR_SET_CHILD_SUBREAPER`——服务若派生孙进程,
在服务(直接子进程)退出后由 svcd 收尸而非 reparent 到 init,避免游离/僵死进程;失败仅记日志继续。
- 服务崩**绝不**连带 supervisor:svcd 是 supervisor 的子进程且自身不死;服务是 - 服务崩**绝不**连带 supervisor:svcd 是 supervisor 的子进程且自身不死;服务是
svcd 的子进程,服务死只影响 svcd 内部一张表。 svcd 的子进程,服务死只影响 svcd 内部一张表。
+92
View File
@@ -0,0 +1,92 @@
#!/bin/sh
#
# S70meow_sysui - MeowOS 系统进程总监(Supervisor Tree 顶层)
#
# 位置:**最早**(早于 S84ssh / S89meow_svcd / S90meow_bootmenu)。
# * 定案启动链:meow_sysui 先起(S70)→ meow_svcd(由 sysui 拉起)→ 各项服务子进程。
# * S90meow_bootmenu 里 `exec /usr/bin/meow_bootmenu --fork` 会阻塞 rcS,故任何 S90 之后
# 的 init.d 都不执行——sysui 必须排在 S90 之前(S70 满足)。
#
# 职责:监管系统进程(launcher / meow_svcd / meow_mdns / …),一个崩只拉起它、绝不级联。
# 本脚本只做三件事:
# 1) 预置板载监管配置 /usr/data/meow/sysui.d/*.conf(首启建,已存在不覆盖);
# 2) 拉起 meow_sysui(默认后台 daemon);
# 3) stop 时优雅停 sysui(其会 SIGTERM 被监管的 svcd 并收尸)。
#
# 红线:不 killall、不碰播放器信号、不刷机、不碰 recovery_all。sysui 自身最小依赖,
# 失败兜底(某被监管进程起不来 → 仅记日志 + 有限次重试,不阻塞其它/不拖垮自身)。
#
case "$1" in
start)
echo -n "Starting meow_sysui (S70): "
# 1) 预置板载监管配置(Data 区可写才建;已存在不覆盖)
if [ -d /usr/data/meow ] && [ -w /usr/data/meow ]; then
mkdir -p /usr/data/meow/sysui.d
if [ -f /usr/data/meow/sysui.d/svcd.conf ]; then
echo -n "svcd.conf exists "
else
cat > /usr/data/meow/sysui.d/svcd.conf <<'EOF'
# meow_sysui 监管条目:meow_svcd(服务管理器)。系统进程总监 → svcd 被监管 → 服务为 svcd 子进程。
# 语义同 services.d:key=value,'#'/';' 注释,未知键忽略。无 trigger——enabled=1 即常驻监护。
exec=/usr/bin/meow_svcd
args=-f
enabled=1
restart=always
backoff_ms=3000
max_restart=5
EOF
chmod 644 /usr/data/meow/sysui.d/svcd.conf
echo -n "provisioned svcd.conf "
fi
# launcher 当前由 S90meow_bootmenu 的 exec 拥有生命周期;待 bootmenu 让位后交 sysui。
# 此处仅登记(enabled=0),避免双重拉起。mdns 是 svcd 的服务子进程,由 svcd 负责,
# 本阶段不直接监管(或作兜底条目,默认关)。
if [ -f /usr/data/meow/sysui.d/launcher.conf ]; then
echo -n "launcher.conf exists "
else
cat > /usr/data/meow/sysui.d/launcher.conf <<'EOF'
# 预留:launcher(系统 UI 渲染宿主)。现网由 S90meow_bootmenu exec 拥有 → 启用前需 bootmenu 让位。
# 真把 launcher 交给 sysui 监管后,把 enabled=1(并停用 bootmenu 的 exec launcher 路径)。
exec=/usr/bin/meow_launcherd
args=
enabled=0
restart=always
backoff_ms=3000
max_restart=5
EOF
chmod 644 /usr/data/meow/sysui.d/launcher.conf
echo -n "provisioned launcher.conf "
fi
else
echo -n "skip provision (/usr/data/meow not writable) "
fi
# 2) 拉起 meow_sysui(默认后台 daemon;S89meow_svcd 会因 sysui 在而把 svcd 拉起权交还 sysui)
rm -f /tmp/meow_sysui.stop
if [ -x /usr/bin/meow_sysui ]; then
if [ -f /tmp/meow_sysui.pid ] && kill -0 "$(cat /tmp/meow_sysui.pid 2>/dev/null)" 2>/dev/null; then
echo "already running"
else
/usr/bin/meow_sysui
echo "started"
fi
else
echo "MISSING /usr/bin/meow_sysui"
fi
;;
stop)
echo -n "Stopping meow_sysui: "
touch /tmp/meow_sysui.stop
for p in $(ps | grep "[m]eow_sysui" | awk '{print $1}'); do kill "$p" 2>/dev/null; done
echo "OK"
;;
restart|reload)
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
;;
esac
exit 0
+28
View File
@@ -0,0 +1,28 @@
#!/bin/bash
# build_sysui.sh — meow_sysui 交叉编译(mipsel 静态)+ 宿主编译可选。
#
# 目标:R3 Pro II / MeowOS(mipsel-linux-muslsf,静态)。sysui 极简无外部依赖,
# 仅 POSIX + Linux 基础接口(同 svcd),单文件满足「固件内、不入卡」。
#
# 用法:
# ./build_sysui.sh # 交叉编译 → patch_v2/meow_sysui/meow_sysui(mipsel 静态)
# ./build_sysui.sh host # 宿主编译 → patch_v2/meow_sysui/meow_sysui_host(集成测试用)
set -e
cd "$(dirname "$0")"
ROOT="$HOME/Project/R3ProII"
CC="$ROOT/.tools/zig-mipsel-cc"
if [ "$1" = "host" ]; then
HOST_CC="${CC_HOST:-cc}"
"$HOST_CC" -Os -Wall -Wextra meow_sysui.c -o meow_sysui_host
echo "== host build =="
ls -la meow_sysui_host
file meow_sysui_host
exit 0
fi
"$CC" -Os -Wall -Wextra -static meow_sysui.c -o meow_sysui
echo "== meow_sysui (mipsel static) =="
ls -la meow_sysui
md5sum meow_sysui
file meow_sysui
BIN
View File
Binary file not shown.
File diff suppressed because it is too large. Load diff
+130
View File
@@ -0,0 +1,130 @@
# meow_sysui — MeowOS 系统进程总监
系统进程**总监**:监管系统进程(launcher / meow_svcd / meow_mdns / 未来媒体服务 / MeowPanel),
**一个崩 → 只拉起它,绝不级联、绝不拖垮自身**。自身**最小依赖、不渲染、不承载重逻辑** → 最稳。
由开机启动链 `etc/init.d/S70meow_sysui` 拉起(早于 S89meow_svcd),居顶层监管。
权威锚点:`FRAMEWORK_DESIGN §10.1`(进程角色/Supervisor 树)、`docs/MEOWOS_SPEC_REF §4`、
`devdocs/plan/SYS_BASELINE.md`(本线方案)。
二进制入口:`patch_v2/meow_sysui/meow_sysui`(mipsel 静态,~113KB,<200KB 固件阈值)。
宿主编译:`patch_v2/meow_sysui/meow_sysui_host`。
---
## 1. 定位与监管模型
- **只监护自己 fork+exec 出来的进程**:`waitpid` 需为父进程,这是「一个崩只拉起它」的可靠前提;
sysui **不做**「adopt 外部 pid」式监护(那只 probe `kill(pid,0)`、无法真正 waitpid/重启)。
- 要监管什么由配置决定;**默认配置只开启 `meow_svcd`**(符合定案「sysui 总监 → svcd 被监管 →
服务为 svcd 子进程」)。`launcher` 当前由 S90meow_bootmenu 的 `exec` 拥有,配置中登记但
`enabled=0`(避免双重拉起;真正移交需 bootmenu 让位,见 §6)。
- `meow_mdns` 是 svcd 的服务子进程(svcd 负责 spawn/restart),sysui 本阶段**不直接监管**它
(避免与 svcd 双重管理);`§10.1` 的「mdns 崩→svcd 拉起(或 sysui 兜底)」——兜底可后续
在 `sysui.d/` 加一条 meow_mdns 条目实现(默认关)。
## 2. 配置:`/usr/data/meow/sysui.d/<name>.conf`(板载权威,目录式)
复用 services.d 语义:一个被监管进程一个 `<name>.conf`,`key=value`,`#`/`;` 注释,未知键忽略(前向兼容)。
| 字段 | 必填 | 说明 | 默认 |
|---|---|---|---|
| `exec` | ✅ | 被监管二进制绝对路径 | 无(缺省 → 跳过该条目) |
| `args` | 否 | 空格切分,支持单/双引号与 `\` 转义 | 无 |
| `env` | 否 | `K=V`,可多条;exec 前 `setenv` | 无 |
| `enabled` | 否 | `1`=监护该进程;`0`=只登记不拉起 | 0 |
| `restart` | 否 | `always`/`on-fail`/`never` | `on-fail` |
| `backoff_ms` | 否 | 崩溃后重启退避毫秒(固定) | 2000 |
| `max_restart` | 否 | 连续重启上限,超限 → `failed` 停止自动重启;`-1`=无限 | 5 |
> **无 `trigger`**:sysui 只管**常驻系统进程**(launcher/svcd/mdns),`enabled=1` 即拉起/常驻监管,
> 拔卡无关(系统进程不认卡)。卡相关服务归 svcd 的 `services.d`。
> TF 卡 `MeowOS/sysui.d/` 作为扩展点本阶段不读(代码只读板载,最小化)。
示例(`svcd.conf`,由 S70 首启预置):
```ini
# 系统进程总监 → svcd 被监管 → 服务为 svcd 子进程
exec = /usr/bin/meow_svcd
args = -f
enabled = 1
restart = always
backoff_ms = 3000
max_restart = 5
```
## 3. 状态机
```
DISABLED enabled=0,永不自动拉起
STOPPED 未运行(被停 / 等待退避)
RUNNING 子进程存活
STOPPING 已发 SIGTERM,等退出(SYSUI_STOP_GRACE_MS=2500 后 SIGKILL 兜底)
FAILED 反复崩/起不来且超 max_restart,停止自动重启(有限次兜底)
```
转换(主循环事件驱动 + 周期 tick,同 svcd):
- **子进程死亡**(`waitpid` 匹配):无 `stop_requested`/`restart_pending` → 按该条目 `restart`
策略决定重建(先进 `backoff_ms` 退避)或落 `FAILED`/`STOPPED`;稳定运行 `SYSUI_STABLE_MS=30s`
清零 `restart_count`。**只处理该条目,无级联。**
- **`kill(pid,0)` 存活探测**:`tick` 里对 `RUNNING` 条目做 `kill(pid,0)`;若 `ESRCH`(子进程已死
未收尸/异常)→ 视同死亡走重建策略(对应「kill(pid,0)/waitpid 探测」定案)。
- **`stop` 命令**:`STOPPING → STOPPED`(置 `user_stopped`,抑制自动拉起)。
- **`restart` 命令**:收尸后原地 respawn(清零计数)。
- **配置变更**:`reload` 命令重读 `sysui.d/`;新增→监护,移除→停,配置变更→重启该条。
## 4. 崩溃隔离 / 护固件(防开不了机)
- **独立进程**:每个被监管进程 `fork()+execv()` + `setpgid(0,0)`,sysui 只经 `waitpid`/`SIGCHLD`
感知;无中间层内存共享、无 dlopen。
- **一个崩不全部崩**:`reap_children()` 只命中死掉的那条;重启只作用于该条;主循环绝不在子进程
死亡时 `exit`。
- **有限次兜底**:某进程起不来/反复崩 → `restart_count++`,超 `max_restart` → `FAILED` **停止自动重启**,
仅记日志(`sysui: <name> exceeded max_restart -> FAILED`);绝不崩溃-重启热循环拖垮系统。
重新尝试需 `reload`/配置变更(`scan_and_reconcile` 仅在启动与 reload 执行——**不在每 tick 调用**,
否则会每秒重置 FAILED、破坏「有限次」语义)。
- **自身不死**:主循环只在 `SIGTERM/SIGINT` 退出;`SIGPIPE` 置 `SIG_IGN`;poll `EINTR` 续跑。
- **空配置可跑**:无 `sysui.d/` 或全 `enabled=0` → 空转存活(只写日志/status),不报错、不阻塞后续 S84/S89/S90。
- **子进程回收者**:`PR_SET_CHILD_SUBREAPER`——被监管进程若派生孙进程,在直接子进程退出后由 sysui
收尸而非 reparent 到 init,强化「孤儿/僵死隔离」(失败仅日志,不硬失败)。
## 5. CLI / 控制协议 / 日志
守护默认后台常驻(无子命令即启动);`-f/--foreground` 供 init/调试。控制走 AF_UNIX 单行文本
(默认 `/tmp/meow_sysui.sock`):
```
meow_sysui status [name|all] # 列出各被监管进程 + 全局(daemon 未运行则打印状态文件)
meow_sysui reload # 重读 sysui.d/
meow_sysui start <name|all>
meow_sysui stop <name|all>
meow_sysui restart <name|all>
meow_sysui pid
```
- 状态文件 `/tmp/meow_sysui.status`;pidfile `/tmp/meow_sysui.pid`。
- status 回显:每条目 服务名/状态/pid/重启次数+max_restart/backoff_ms/最近退出码/是否启用/exec;
TTY 带 ANSI 配色(表头 dim、服务名加粗青、RUNNING=绿、FAILED=红、STOPPED·STOPPING=黄、DISABLED=灰),
非 TTY 自动去色。
- 日志:stderr(`-f`)+ 默认追加 `/tmp/meow_sysui.log` + `syslog(LOG_DAEMON)` 尝试。
## 6. 迁移说明 / 边界(诚实标注)
- **launcher 监管**:现网 launcher 由 `S90meow_bootmenu` 的 `exec` 拉起(bootmenu 拥有其生命周期)。
sysui **本阶段不拉起 launcher**(`sysui.d/launcher.conf` 默认 `enabled=0` + 注释);
launcher 真正归 sysui 需 bootmenu 让位(后续迁移)。sysui 代码完全支持加一条 launcher 条目即可。
- **mdns 监管**:由 svcd 负责;sysui 兜底条目默认关。
## 7. 编译
```bash
./build_sysui.sh # mipsel 静态 → meow_sysui(0 warning)
./build_sysui.sh host # 宿主编译 → meow_sysui_host(集成测试)
```
## 后续(不在本阶段)
- launcher 正式移交 sysui 监管(依赖 bootmenu 让位)。
- `MeowOS/sysui.d/` TF 双源扩展(复用 svcd 板载优先语义)。
- 与 meow_watchdog / 崩溃捕获的职责对齐(见 WORK_STATE SDK 缺失清单 #5)。