meow_ui.a→3e0ee8f7 launcher→9d0efc2f hello→9609ea6e files→90f5cf07 ncm→be8be221(均已上卡); 真机截图证据 .tmp/meowbug/fix1.png+fix_b2_after.png
187 lines
5.8 KiB
C
187 lines
5.8 KiB
C
/* 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[800];
|
||
snprintf(line, sizeof line, "start %s\n", spec);
|
||
return am_query(line);
|
||
}
|
||
|
||
static int cmd_resolve(const char *spec)
|
||
{
|
||
/* spec: <pkg> <activity>(两参数)。 */
|
||
char line[800];
|
||
snprintf(line, sizeof line, "resolve %s\n", spec);
|
||
return am_query(line);
|
||
}
|
||
|
||
static int cmd_picker(const char *action)
|
||
{
|
||
if (geteuid() != 0) { printf("ERR permission denied (root only)\n"); return 1; }
|
||
char line[800];
|
||
snprintf(line, sizeof line, "picker %s\n", action);
|
||
return am_query(line);
|
||
}
|
||
|
||
static int cmd_picker_status(const char *reqid)
|
||
{
|
||
char line[800];
|
||
if (reqid && reqid[0])
|
||
snprintf(line, sizeof line, "picker-status %s\n", reqid);
|
||
else
|
||
snprintf(line, sizeof line, "picker-status\n");
|
||
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[800];
|
||
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"
|
||
" %s resolve <pkg> <activity> | picker <action> | picker-status [reqid]\n"
|
||
" --sock <path> amsd socket (default %s, or $MEOW_AMS_SOCK)\n",
|
||
a0, 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;
|
||
char spec[768] = ""; /* 子命令后所有位置参数,空格拼接(resolve 需 pkg+act 两参) */
|
||
int spec_n = 0;
|
||
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 {
|
||
int w = snprintf(spec + spec_n, sizeof spec - spec_n, "%s%s",
|
||
spec_n ? " " : "", a);
|
||
if (w < 0) break;
|
||
spec_n += w;
|
||
if ((size_t)spec_n >= sizeof spec - 1) break;
|
||
}
|
||
}
|
||
if (!cmd) { usage(argv[0]); return 2; }
|
||
const char *arg = spec[0] ? spec : NULL;
|
||
|
||
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);
|
||
}
|
||
if (!strcmp(cmd, "resolve")) {
|
||
if (!arg) { fprintf(stderr, "resolve needs <pkg> <activity>\n"); return 2; }
|
||
return cmd_resolve(arg);
|
||
}
|
||
if (!strcmp(cmd, "picker")) {
|
||
if (!arg) { fprintf(stderr, "picker needs <action>\n"); return 2; }
|
||
return cmd_picker(arg);
|
||
}
|
||
if (!strcmp(cmd, "picker-status")) {
|
||
return cmd_picker_status(arg);
|
||
}
|
||
usage(argv[0]);
|
||
return 2;
|
||
}
|