launcher 61f6b0db→3c7c2ec7; qemu IPC 往返+宿主存储单测+mock crash socket 全过; 顺带清理既有告警(util.c/app_launcher.c/meow_ipc.c)
382 lines
14 KiB
C
382 lines
14 KiB
C
/* meow_ipc.c — MeowOS IPC 测试钩子(阶段 D · M0+M1;与 evtool 同定位)。
|
||
*
|
||
* 向 meow_launcherd 的 AF_UNIX IPC(FRAMEWORK_DESIGN §1)发帧、收应答并打印。
|
||
* 静态 MIPS32r2 musl(用 zig-mipsel-cc 编译),qemu-mipsel 亦可用。
|
||
*
|
||
* 子命令:
|
||
* meow_ipc hello <app_id> [version] [flags] → MSG_HELLO,期望 MSG_ACK
|
||
* meow_ipc ping [app_id] → hello 别名(默认 meow_ipc)
|
||
* meow_ipc query <app_id> <activity> → MSG_ACT_QUERY,期望 MSG_ACT_RESULT
|
||
* meow_ipc declare <app_id> <route_id=chain> [...] → MSG_ACT_DECLARE,期望 MSG_ACK
|
||
* 全局:
|
||
* --sock <path> 覆盖 socket 路径(默认可被 MEOW_IPC_SOCK 覆盖,再回退 /usr/data/meow_ipc.sock)
|
||
*/
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <stdint.h>
|
||
#include <unistd.h>
|
||
#include <fcntl.h>
|
||
#include <errno.h>
|
||
#include <sys/socket.h>
|
||
#include <sys/un.h>
|
||
#include <sys/stat.h>
|
||
#include "meow_ipc.h"
|
||
|
||
static const char *g_sock = NULL;
|
||
|
||
static void print_err(const m_err_t *e)
|
||
{
|
||
fprintf(stderr, "ERR 0x%x: %.*s\n", e->code, e->msg_len < 64 ? e->msg_len : 64, e->msg);
|
||
}
|
||
|
||
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;
|
||
strncpy(a.sun_path, path, sizeof a.sun_path - 1);
|
||
if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) {
|
||
fprintf(stderr, "connect %s: %s\n", path, strerror(errno));
|
||
close(fd);
|
||
return -1;
|
||
}
|
||
return fd;
|
||
}
|
||
|
||
/* 发一帧(头+负载),读回一帧(头+负载)。返回应答类型;-1=失败。 */
|
||
static int xchg(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len,
|
||
uint8_t *rbuf, uint32_t rcap)
|
||
{
|
||
uint8_t hdr[MEOW_IPC_HDR_LEN];
|
||
uint32_t magic = MEOW_IPC_MAGIC;
|
||
uint16_t ver = MEOW_IPC_VERSION;
|
||
memcpy(hdr + 0, &magic, 4);
|
||
memcpy(hdr + 4, &ver, 2);
|
||
memcpy(hdr + 6, &type, 2);
|
||
memcpy(hdr + 8, &req_id, 4);
|
||
memcpy(hdr + 12, &len, 4);
|
||
size_t off = 0;
|
||
while (off < sizeof hdr) {
|
||
ssize_t w = write(fd, hdr + off, sizeof hdr - off);
|
||
if (w <= 0) { perror("write hdr"); return -1; }
|
||
off += (size_t)w;
|
||
}
|
||
if (len && payload) {
|
||
size_t p = 0;
|
||
while (p < len) {
|
||
ssize_t w = write(fd, (const uint8_t *)payload + p, len - p);
|
||
if (w <= 0) { perror("write payload"); return -1; }
|
||
p += (size_t)w;
|
||
}
|
||
}
|
||
/* read response header */
|
||
uint8_t rhdr[MEOW_IPC_HDR_LEN];
|
||
off = 0;
|
||
while (off < sizeof rhdr) {
|
||
ssize_t r = read(fd, rhdr + off, sizeof rhdr - off);
|
||
if (r <= 0) { perror("read hdr"); return -1; }
|
||
off += (size_t)r;
|
||
}
|
||
uint32_t rmagic, rlen;
|
||
uint16_t rver, rtype;
|
||
memcpy(&rmagic, rhdr, 4);
|
||
memcpy(&rver, rhdr + 4, 2);
|
||
memcpy(&rtype, rhdr + 6, 2);
|
||
memcpy(&rlen, rhdr + 12, 4);
|
||
if (rmagic != MEOW_IPC_MAGIC) { fprintf(stderr, "bad resp magic %08x\n", rmagic); return -1; }
|
||
if (rver != MEOW_IPC_VERSION) { fprintf(stderr, "bad resp version %u\n", rver); return -1; }
|
||
if (rlen > rcap) rlen = rcap;
|
||
off = 0;
|
||
while (off < rlen) {
|
||
ssize_t r = read(fd, rbuf + off, rlen - off);
|
||
if (r <= 0) { perror("read payload"); return -1; }
|
||
off += (size_t)r;
|
||
}
|
||
return (int)rtype;
|
||
}
|
||
|
||
static int cmd_hello(const char *app_id, uint32_t version, uint32_t flags)
|
||
{
|
||
const char *sock = g_sock;
|
||
int fd = connect_path(sock);
|
||
if (fd < 0) return 1;
|
||
m_hello_t h;
|
||
memset(&h, 0, sizeof h);
|
||
strncpy(h.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||
h.version = version;
|
||
h.flags = flags;
|
||
uint8_t rbuf[256];
|
||
int rt = xchg(fd, MSG_HELLO, 1, &h, sizeof h, rbuf, sizeof rbuf);
|
||
close(fd);
|
||
if (rt == MSG_ACK) {
|
||
m_ack_t a;
|
||
memcpy(&a, rbuf, sizeof a);
|
||
printf("HELLO ok: code=%d status=%u (apps registered)\n", a.code, a.status);
|
||
return a.code == MEOW_OK ? 0 : 1;
|
||
}
|
||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||
fprintf(stderr, "HELLO: unexpected resp type 0x%04x\n", rt);
|
||
return 1;
|
||
}
|
||
|
||
static int cmd_query(const char *app_id, const char *activity)
|
||
{
|
||
int fd = connect_path(g_sock);
|
||
if (fd < 0) return 1;
|
||
m_act_query_t q;
|
||
memset(&q, 0, sizeof q);
|
||
strncpy(q.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||
strncpy(q.activity, activity, MEOW_ACT_MAX - 1);
|
||
uint8_t rbuf[256];
|
||
int rt = xchg(fd, MSG_ACT_QUERY, 2, &q, sizeof q, rbuf, sizeof rbuf);
|
||
close(fd);
|
||
if (rt == MSG_ACT_RESULT) {
|
||
m_act_result_t r;
|
||
memcpy(&r, rbuf, sizeof r);
|
||
size_t cl = r.chain_len < MEOW_CHAIN_MAX ? r.chain_len : MEOW_CHAIN_MAX - 1;
|
||
char chain[MEOW_CHAIN_MAX];
|
||
memcpy(chain, r.chain, cl);
|
||
chain[cl] = 0;
|
||
printf("QUERY ok: app=%s act=%s depth=%u chain=%s\n", app_id, activity,
|
||
r.depth, cl ? chain : "(empty)");
|
||
return r.code == MEOW_OK ? 0 : 1;
|
||
}
|
||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||
fprintf(stderr, "QUERY: unexpected resp type 0x%04x\n", rt);
|
||
return 1;
|
||
}
|
||
|
||
static int cmd_declare(const char *app_id, int nent, char **ents)
|
||
{
|
||
int fd = connect_path(g_sock);
|
||
if (fd < 0) return 1;
|
||
m_act_declare_t d;
|
||
memset(&d, 0, sizeof d);
|
||
strncpy(d.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||
int n = 0;
|
||
char *p = d.entries;
|
||
for (int i = 0; i < nent && n < 8; i++) {
|
||
size_t l = strlen(ents[i]);
|
||
if (l + 1 > (size_t)(d.entries + sizeof d.entries - p)) break;
|
||
memcpy(p, ents[i], l + 1);
|
||
p += l + 1;
|
||
n++;
|
||
}
|
||
d.count = (uint16_t)n;
|
||
uint32_t len = (uint32_t)(sizeof d.app_id + 2 + 2 + (p - d.entries));
|
||
uint8_t rbuf[256];
|
||
int rt = xchg(fd, MSG_ACT_DECLARE, 3, &d, len, rbuf, sizeof rbuf);
|
||
close(fd);
|
||
if (rt == MSG_ACK) {
|
||
m_ack_t a;
|
||
memcpy(&a, rbuf, sizeof a);
|
||
printf("DECLARE ok: app=%s n=%d code=%d\n", app_id, n, a.code);
|
||
return a.code == MEOW_OK ? 0 : 1;
|
||
}
|
||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||
fprintf(stderr, "DECLARE: unexpected resp type 0x%04x\n", rt);
|
||
return 1;
|
||
}
|
||
|
||
static int cmd_focus(const char *app_id, const char *activity)
|
||
{
|
||
int fd = connect_path(g_sock);
|
||
if (fd < 0) return 1;
|
||
m_act_focus_t f;
|
||
memset(&f, 0, sizeof f);
|
||
strncpy(f.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||
strncpy(f.activity, activity, MEOW_ACT_MAX - 1);
|
||
uint8_t rbuf[256];
|
||
int rt = xchg(fd, MSG_ACT_FOCUS, 4, &f, sizeof f, rbuf, sizeof rbuf);
|
||
close(fd);
|
||
if (rt == MSG_ACK) {
|
||
m_ack_t a;
|
||
memcpy(&a, rbuf, sizeof a);
|
||
printf("FOCUS ok: app=%s act=%s code=%d\n", app_id, activity, a.code);
|
||
return a.code == MEOW_OK ? 0 : 1;
|
||
}
|
||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||
fprintf(stderr, "FOCUS: unexpected resp type 0x%04x\n", rt);
|
||
return 1;
|
||
}
|
||
|
||
static int cmd_back(void)
|
||
{
|
||
int fd = connect_path(g_sock);
|
||
if (fd < 0) return 1;
|
||
uint8_t rbuf[256];
|
||
int rt = xchg(fd, MSG_ACT_BACK, 5, NULL, 0, rbuf, sizeof rbuf);
|
||
close(fd);
|
||
if (rt == MSG_ACK) {
|
||
m_ack_t a;
|
||
memcpy(&a, rbuf, sizeof a);
|
||
printf("BACK ok: code=%d\n", a.code);
|
||
return a.code == MEOW_OK ? 0 : 1;
|
||
}
|
||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||
fprintf(stderr, "BACK: unexpected resp type 0x%04x\n", rt);
|
||
return 1;
|
||
}
|
||
|
||
/* M2a:推送通知 → MSG_NOTIFY,期望 MSG_NOTIFY_ACK。 */
|
||
static int cmd_notify(const char *app_id, const char *category, const char *summary,
|
||
const char *body, uint32_t replaces_id, int ongoing, int media, int progress)
|
||
{
|
||
int fd = connect_path(g_sock);
|
||
if (fd < 0) return 1;
|
||
m_notify_t n;
|
||
memset(&n, 0, sizeof n);
|
||
strncpy(n.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||
strncpy(n.category, category, sizeof n.category - 1);
|
||
strncpy(n.summary, summary, sizeof n.summary - 1);
|
||
if (body) strncpy(n.body, body, sizeof n.body - 1);
|
||
n.replaces_id = replaces_id;
|
||
n.ongoing = ongoing ? 1 : 0;
|
||
n.media = media ? 1 : 0;
|
||
n.progress = progress;
|
||
n.expire_timeout = ongoing ? 0xFFFFFFFFu : 0; /* ONGOING 常驻 */
|
||
uint8_t rbuf[256];
|
||
int rt = xchg(fd, MSG_NOTIFY, 6, &n, sizeof n, rbuf, sizeof rbuf);
|
||
close(fd);
|
||
if (rt == MSG_NOTIFY_ACK) {
|
||
m_ack_t a;
|
||
memcpy(&a, rbuf, sizeof a);
|
||
printf("NOTIFY ok: id=%u code=%d\n", a.status, a.code);
|
||
return a.code == MEOW_OK ? 0 : 1;
|
||
}
|
||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||
fprintf(stderr, "NOTIFY: unexpected resp type 0x%04x\n", rt);
|
||
return 1;
|
||
}
|
||
|
||
/* M2a:撤下通知 → MSG_NOTIFY_DISMISS,期望 MSG_ACK。 */
|
||
static int cmd_dismiss(uint32_t id)
|
||
{
|
||
int fd = connect_path(g_sock);
|
||
if (fd < 0) return 1;
|
||
uint8_t rbuf[256];
|
||
int rt = xchg(fd, MSG_NOTIFY_DISMISS, 7, &id, sizeof id, rbuf, sizeof rbuf);
|
||
close(fd);
|
||
if (rt == MSG_ACK) {
|
||
m_ack_t a;
|
||
memcpy(&a, rbuf, sizeof a);
|
||
printf("DISMISS ok: id=%u code=%d\n", id, a.code);
|
||
return a.code == MEOW_OK ? 0 : 1;
|
||
}
|
||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||
fprintf(stderr, "DISMISS: unexpected resp type 0x%04x\n", rt);
|
||
return 1;
|
||
}
|
||
|
||
/* 查询当前内存活跃通知集 → MSG_NOTIFY_QUERY,期望 MSG_NOTIFY_QUERY_RESULT(打印 JSON 文本)。
|
||
* 可选 <app_id> 过滤(缺省=全部)。 */
|
||
static int cmd_querynotif(const char *app_id)
|
||
{
|
||
int fd = connect_path(g_sock);
|
||
if (fd < 0) return 1;
|
||
uint8_t rbuf[MEOW_IPC_MAX];
|
||
int rt = xchg(fd, MSG_NOTIFY_QUERY, 8, app_id, app_id ? (uint32_t)strlen(app_id) : 0,
|
||
rbuf, sizeof rbuf);
|
||
close(fd);
|
||
if (rt == MSG_NOTIFY_QUERY_RESULT) {
|
||
m_notify_query_result_t r;
|
||
memcpy(&r, rbuf, sizeof r);
|
||
uint32_t tl = r.text_len < sizeof r.text ? r.text_len : sizeof r.text - 1;
|
||
printf("QUERY ok: code=%d len=%u\n%s\n", r.code, (unsigned)tl, r.text);
|
||
return r.code == MEOW_OK ? 0 : 1;
|
||
}
|
||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||
fprintf(stderr, "QUERY: unexpected resp type 0x%04x\n", rt);
|
||
return 1;
|
||
}
|
||
|
||
/* 一键清除(保留 ongoing/media/progress)→ MSG_NOTIFY_DISMISS_ALL,期望 MSG_ACK(status=清除数)。 */
|
||
static int cmd_dismissall(void)
|
||
{
|
||
int fd = connect_path(g_sock);
|
||
if (fd < 0) return 1;
|
||
uint8_t rbuf[256];
|
||
int rt = xchg(fd, MSG_NOTIFY_DISMISS_ALL, 9, NULL, 0, rbuf, sizeof rbuf);
|
||
close(fd);
|
||
if (rt == MSG_ACK) {
|
||
m_ack_t a;
|
||
memcpy(&a, rbuf, sizeof a);
|
||
printf("DISMISS_ALL ok: code=%d cleared=%u\n", a.code, a.status);
|
||
return a.code == MEOW_OK ? 0 : 1;
|
||
}
|
||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||
fprintf(stderr, "DISMISS_ALL: unexpected resp type 0x%04x\n", rt);
|
||
return 1;
|
||
}
|
||
|
||
int main(int argc, char **argv)
|
||
{
|
||
const char *env = getenv("MEOW_IPC_SOCK");
|
||
g_sock = (env && env[0]) ? env : MEOW_IPC_PATH;
|
||
|
||
/* parse leading global options */
|
||
int i = 1;
|
||
for (; 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: meow_ipc [--sock <path>] hello|ping|query|declare ...\n");
|
||
return 0;
|
||
}
|
||
else break;
|
||
}
|
||
if (i >= argc) { fprintf(stderr, "bad args; try --help\n"); return 1; }
|
||
|
||
const char *cmd = argv[i];
|
||
if (!strcmp(cmd, "hello")) {
|
||
if (i + 1 >= argc) { fprintf(stderr, "hello needs <app_id>\n"); return 1; }
|
||
uint32_t ver = (i + 2 < argc) ? (uint32_t)strtoul(argv[i + 2], NULL, 0) : 1;
|
||
uint32_t flg = (i + 3 < argc) ? (uint32_t)strtoul(argv[i + 3], NULL, 0) : 0;
|
||
return cmd_hello(argv[i + 1], ver, flg);
|
||
}
|
||
if (!strcmp(cmd, "ping")) {
|
||
const char *app = (i + 1 < argc) ? argv[i + 1] : "meow_ipc";
|
||
return cmd_hello(app, 1, 0);
|
||
}
|
||
if (!strcmp(cmd, "query")) {
|
||
if (i + 2 >= argc) { fprintf(stderr, "query needs <app_id> <activity>\n"); return 1; }
|
||
return cmd_query(argv[i + 1], argv[i + 2]);
|
||
}
|
||
if (!strcmp(cmd, "declare")) {
|
||
if (i + 2 >= argc) { fprintf(stderr, "declare needs <app_id> <route_id=chain> [...]\n"); return 1; }
|
||
return cmd_declare(argv[i + 1], argc - i - 2, argv + i + 2);
|
||
}
|
||
if (!strcmp(cmd, "focus")) {
|
||
if (i + 2 >= argc) { fprintf(stderr, "focus needs <app_id> <activity>\n"); return 1; }
|
||
return cmd_focus(argv[i + 1], argv[i + 2]);
|
||
}
|
||
if (!strcmp(cmd, "back")) {
|
||
return cmd_back();
|
||
}
|
||
if (!strcmp(cmd, "notify")) {
|
||
/* notify <app_id> <category> <summary> [body] [replaces_id] [ongoing] [media] [progress] */
|
||
if (i + 2 >= argc) { fprintf(stderr, "notify needs <app_id> <category> <summary>\n"); return 1; }
|
||
const char *body = (i + 4 < argc) ? argv[i + 4] : "";
|
||
uint32_t rid = (i + 5 < argc) ? (uint32_t)strtoul(argv[i + 5], NULL, 0) : 0;
|
||
int ongoing = (i + 6 < argc) ? atoi(argv[i + 6]) : 0;
|
||
int media = (i + 7 < argc) ? atoi(argv[i + 7]) : 0;
|
||
int progress = (i + 8 < argc) ? atoi(argv[i + 8]) : -1;
|
||
return cmd_notify(argv[i + 1], argv[i + 2], argv[i + 3], body, rid, ongoing, media, progress);
|
||
}
|
||
if (!strcmp(cmd, "dismiss")) {
|
||
if (i + 1 >= argc) { fprintf(stderr, "dismiss needs <id>\n"); return 1; }
|
||
return cmd_dismiss((uint32_t)strtoul(argv[i + 1], NULL, 0));
|
||
}
|
||
if (!strcmp(cmd, "querynotif")) {
|
||
const char *app = (i + 1 < argc) ? argv[i + 1] : NULL;
|
||
return cmd_querynotif(app);
|
||
}
|
||
if (!strcmp(cmd, "dismissall")) {
|
||
return cmd_dismissall();
|
||
}
|
||
fprintf(stderr, "unknown cmd %s; try --help\n", cmd);
|
||
return 1;
|
||
}
|