feat(amsd): meow_amsd 活动管理器一期 + am CLI (agent-212, 用户定案) — svcd托管(trigger=boot); 生命周期注册表(状态/时长/退出码/信号/崩溃计数+历史环形); launcher launch/exit/stdout管道捕获上报(logcat式,崩溃尾巴drain不丢); am status/list/history/start/kill(root门); crash双保险转发; S89预置conf

amsd f8d7f61b / am cfc4cbd4 / launcher 97c1b222(含字库扫描签名门控修CPU100%)
宿主+qemu全链路验证通过
This commit is contained in:
MeowOS committed 2026-08-31 12:45:29 +08:00
1 parent b81e7438e4
commit 5fbf30755c
16 files changed
+1722 -4

No files matched your search

BIN
View File
Binary file not shown.
+140
View File
@@ -0,0 +1,140 @@
/* am.c — MeowOS 活动管理器用户侧 CLI(AMSD_DESIGN.md §3,安卓习惯,进固件 /usr/bin/am)。
*
* 连 amsd sock(--sock/MEOW_AMS_SOCK,默认 /usr/data/meow_ams.sock),发一条命令行,
* 读响应直到 EOF,格式化输出。root 免鉴权(读);写操作(start/kill)一期仅 root/系统身份。
*
* 子命令:
* am status → 在跑 App 表(pkg/状态/pid/运行时长/activity)
* am list → 注册表 + 状态(pkg/name/state/pid/launches/crashes)
* am history [pkg] → 事件历史(每 App 最近 8 条;无 pkg=全部)
* am start <pkg>[/<activity>] → 经 amsd→launcher 拉起
* am kill <pkg> → 经 amsd→launcher 终止(SIGTERM 语义)
*
* 编译(mipsel 静态):zig-mipsel-cc -Os -Wall -Wextra -static am.c -o am
* 宿主:gcc -Os -Wall -Wextra am.c -o am_host
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#define AMS_SOCK_DEFAULT "/usr/data/meow_ams.sock"
#define AMS_SOCK_PATH_MAX 108
#define AMS_RESP_MAX 65536
static const char *g_sock = NULL;
static int connect_path(const char *path)
{
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) { perror("socket"); return -1; }
struct sockaddr_un a;
memset(&a, 0, sizeof a);
a.sun_family = AF_UNIX;
snprintf(a.sun_path, sizeof a.sun_path, "%s", path);
if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) {
fprintf(stderr, "connect %s: %s\n", path, strerror(errno));
close(fd);
return -1;
}
return fd;
}
/* 发送单行命令,读取响应直到 EOF,打印。返回 0=ok。 */
static int am_query(const char *cmd)
{
int fd = connect_path(g_sock);
if (fd < 0) return 1;
ssize_t w = write(fd, cmd, strlen(cmd));
(void)w;
static char resp[AMS_RESP_MAX];
size_t n = 0;
char tmp[2048];
ssize_t r;
while ((r = read(fd, tmp, sizeof tmp)) > 0) {
if (n + (size_t)r < sizeof resp - 1) { memcpy(resp + n, tmp, (size_t)r); n += (size_t)r; }
}
close(fd);
resp[n] = '\0';
fputs(resp, stdout);
return 0;
}
static int cmd_status(void)
{
return am_query("status\n");
}
static int cmd_list(void)
{
return am_query("list\n");
}
static int cmd_history(const char *pkg)
{
char line[512];
if (pkg && pkg[0])
snprintf(line, sizeof line, "history %s\n", pkg);
else
snprintf(line, sizeof line, "history\n");
return am_query(line);
}
static int cmd_start(const char *spec)
{
if (geteuid() != 0) { printf("ERR permission denied (root only)\n"); return 1; }
char line[512];
snprintf(line, sizeof line, "start %s\n", spec);
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];
snprintf(line, sizeof line, "kill %s\n", pkg);
return am_query(line);
}
static void usage(const char *a0)
{
fprintf(stderr,
"usage: %s [--sock <path>] status|list|history [pkg]|start <pkg>[/<act>]|kill <pkg>\n"
" --sock <path> amsd socket (default %s, or $MEOW_AMS_SOCK)\n",
a0, AMS_SOCK_DEFAULT);
}
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;
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; }
}
if (!cmd) { usage(argv[0]); return 2; }
if (!strcmp(cmd, "status")) return cmd_status();
if (!strcmp(cmd, "list")) return cmd_list();
if (!strcmp(cmd, "history")) return cmd_history(arg);
if (!strcmp(cmd, "start")) {
if (!arg) { fprintf(stderr, "start needs <pkg>[/<act>]\n"); return 2; }
return cmd_start(arg);
}
if (!strcmp(cmd, "kill")) {
if (!arg) { fprintf(stderr, "kill needs <pkg>\n"); return 2; }
return cmd_kill(arg);
}
usage(argv[0]);
return 2;
}
BIN
View File
Binary file not shown.
+70
View File
@@ -0,0 +1,70 @@
/* ams_stub.c — meow_amsd 宿主测试桩(不入固件)。
*
* 用途:在宿主集成测试里,把 stdin 的每一行原样发到 amsd socket(command 与 EV 事件均可),
* 然后读取响应直到 EOF 并打印。既当「launcher 上报桩」(注入 EV LAUNCH/EV OUT/EV EXIT),
* 也当通用命令客户端(status/list/history/start/kill)。
*
* 用法:
* printf 'EV LAUNCH os.meow.hello home - 123 12345 100\n' | ./ams_stub_host --sock /tmp/sim_ams.sock
* echo status | ./ams_stub_host --sock /tmp/sim_ams.sock
*
* 编译(宿主):gcc -Os -Wall -Wextra ams_stub.c -o ams_stub_host
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#define AMS_SOCK_DEFAULT "/usr/data/meow_ams.sock"
#define AMS_SOCK_PATH_MAX 108
#define AMS_RESP_MAX 65536
static const char *g_sock = AMS_SOCK_DEFAULT;
int main(int argc, char **argv)
{
const char *env = getenv("MEOW_AMS_SOCK");
if (env && env[0]) g_sock = env;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--sock") && i + 1 < argc) g_sock = argv[++i];
else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
fprintf(stderr, "usage: %s [--sock <path>] (reads lines from stdin -> amsd)\n", argv[0]);
return 0;
} else { fprintf(stderr, "bad arg %s\n", argv[i]); return 2; }
}
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) { perror("socket"); return 1; }
struct sockaddr_un a;
memset(&a, 0, sizeof a);
a.sun_family = AF_UNIX;
snprintf(a.sun_path, sizeof a.sun_path, "%s", g_sock);
if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) {
fprintf(stderr, "connect %s: %s\n", g_sock, strerror(errno));
return 1;
}
char line[2048];
while (fgets(line, sizeof line, stdin)) {
ssize_t w = write(fd, line, strlen(line));
(void)w;
}
/* half-close 写端:告知 amsd「无更多数据」(= launcher fire-and-forget 的 close 语义),
* 事件连接 amsd 即收尾关闭;命令连接 amsd 写回响应后才关闭。 */
shutdown(fd, SHUT_WR);
/* read response until EOF */
static char resp[AMS_RESP_MAX];
size_t n = 0;
char tmp[2048];
ssize_t r;
while ((r = read(fd, tmp, sizeof tmp)) > 0) {
if (n + (size_t)r < sizeof resp - 1) { memcpy(resp + n, tmp, (size_t)r); n += (size_t)r; }
}
close(fd);
resp[n] = '\0';
if (n > 0) fputs(resp, stdout);
return 0;
}
BIN
View File
Binary file not shown.
+40
View File
@@ -0,0 +1,40 @@
#!/bin/bash
# build_amsd.sh — meow_amsd 交叉编译(mipsel 静态)+ 宿主多目标可选。
#
# 目标:R3 Pro II / MeowOS(mipsel-linux-muslsf,静态)。amsd/am 极简仅 POSIX + Linux 基础接口
# + 复用 launcher 的 meow_ipc.h(-I../meow_launcherd),单文件即可固件内/usr/bin。
#
# 用法:
# ./build_amsd.sh # 交叉编译 → meow_amsd(mipsel 静态)
# ./build_amsd.sh am # 交叉编译 am CLI → am(mipsel 静态)
# ./build_amsd.sh host # 宿主编译 meow_amsd_host + am_host + ams_stub_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" -I"$ROOT/patch_v2/meow_launcherd" -Os -Wall -Wextra meow_amsd.c -o meow_amsd_host
"$HOST_CC" -Os -Wall -Wextra am.c -o am_host
"$HOST_CC" -Os -Wall -Wextra ams_stub.c -o ams_stub_host
echo "== host builds =="
ls -la meow_amsd_host am_host ams_stub_host
file meow_amsd_host am_host ams_stub_host
exit 0
fi
if [ "$1" = "am" ]; then
"$CC" -Os -Wall -Wextra -static am.c -o am
echo "== am (mipsel static) =="
ls -la am
md5sum am
file am
exit 0
fi
"$CC" -I"$ROOT/patch_v2/meow_launcherd" -Os -Wall -Wextra -static meow_amsd.c -o meow_amsd
echo "== meow_amsd (mipsel static) =="
ls -la meow_amsd
md5sum meow_amsd
file meow_amsd
BIN
View File
Binary file not shown.
File diff suppressed because it is too large. Load diff
BIN
View File
Binary file not shown.