/* * test_notify_post.c — 宿主交叉验证:SDK send 的 IPC 帧 → launcher 真·中央存储。 * * 把 SDK 的 meow_notify_ipc.c(映射+传输)与 launcher 的 meow_notif.c(真·中央存储, * meow_notif_post/dismiss)接到一起,stub 掉 meow_settings 后端;服务端复刻 * meow_launcherd.c:6427-6440 的 m_notify_t→meow_notif_t 映射 + MSG_NOTIFY_ACK 应答。 * * 验证:SDK meow_notify_ipc_send() 产出的帧被 meow_notif_post() 真实落库并回分配 nid>0; * 随后 meow_notify_ipc_dismiss() 经 meow_notif_dismiss() 撤下(count 归 0)。 * * 编译(宿主 gcc): * gcc -o test_notify_post test_notify_post.c meow_notify_ipc.c \ * ../meow_launcherd/meow_notif.c -I. -I../meow_launcherd -lpthread */ #include "meow_notify_ipc.h" #include "meow_ui.h" #include "meow_ipc.h" #include "meow_notif.h" /* launcher 真·中央存储 */ #include #include #include #include #include #include #include #include #include /* ---- stub:settings 后端(键缺省 → meow_notif.c 用默认配额) ---- */ int meow_settings_get_int(const char *key, int *out) { (void)key; (void)out; return MEOW_ERR_NOENT; } /* ---- 复刻 launcher 的 m_notify_t → meow_notif_t 映射(meow_launcherd.c:6427-6440) ---- * 注:与 launcher 同款 snprintf(dest 较 src 小会有 format-truncation 提示),launcher 自身 * 以其编译 flags 构建无警告;此处仅为宿主测试,用 pragma 压掉以免 -Werror 干扰。 */ #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-truncation" #endif static void launcher_map(const m_notify_t *mn, meow_notif_t *n) { memset(n, 0, sizeof *n); n->id = mn->replaces_id; /* 0=>新建;>0=>替换(不存在则新建) */ snprintf(n->app_id, sizeof n->app_id, "%s", mn->app_id); snprintf(n->category, sizeof n->category, "%s", mn->category); snprintf(n->summary, sizeof n->summary, "%s", mn->summary); snprintf(n->body, sizeof n->body, "%s", mn->body); snprintf(n->app_icon, sizeof n->app_icon, "%s", mn->app_icon); snprintf(n->target_activity, sizeof n->target_activity, "%s", mn->target_activity); n->expire_timeout = mn->expire_timeout; n->progress = mn->progress; n->urgency = mn->urgency; /* 0-3;旧调用=0 → LOW(静默) */ n->ongoing = mn->ongoing; n->media = mn->media; } #if defined(__GNUC__) #pragma GCC diagnostic pop #endif static int g_listen_fd = -1; static int g_stop = 0; static uint32_t g_posted_nid = 0; static meow_notif_t g_stored; /* 回读 launcher 存储的最近一条通知(store_cb) */ static int g_store_called = 0; static int store_cb(const meow_notif_t *n, void *ctx) { (void)ctx; if (n) { g_stored = *n; g_store_called = 1; } return 1; /* 只取第一条 */ } static void reply_ack(int c, uint16_t type, uint32_t req_id, uint32_t status) { m_ack_t a; memset(&a, 0, sizeof a); a.code = MEOW_OK; a.status = status; uint8_t rhdr[MEOW_IPC_HDR_LEN]; uint32_t mag = MEOW_IPC_MAGIC; uint16_t ver = MEOW_IPC_VERSION, t = type; uint32_t rl = sizeof a; memcpy(rhdr+0,&mag,4); memcpy(rhdr+4,&ver,2); memcpy(rhdr+6,&t,2); memcpy(rhdr+8,&req_id,4); memcpy(rhdr+12,&rl,4); size_t o = 0; while (o < sizeof rhdr) { ssize_t w = write(c, rhdr+o, sizeof rhdr-o); if (w<=0) break; o += (size_t)w; } o = 0; while (o < rl) { ssize_t w = write(c, (uint8_t*)&a+o, rl-o); if (w<=0) break; o += (size_t)w; } } static void *server(void *arg) { (void)arg; meow_notif_init(); while (!g_stop) { int c = accept(g_listen_fd, NULL, NULL); if (c < 0) { if (errno == EAGAIN && g_stop) break; if (errno == EBADF) break; usleep(1000); continue; } uint8_t hdr[MEOW_IPC_HDR_LEN]; size_t o = 0; while (o < sizeof hdr) { ssize_t r = read(c, hdr+o, sizeof hdr-o); if (r<=0) break; o += (size_t)r; } if (o < sizeof hdr) { close(c); continue; } uint32_t type, len, req_id; memcpy(&type, hdr+6, 2); memcpy(&req_id, hdr+8, 4); memcpy(&len, hdr+12, 4); if (len > MEOW_IPC_MAX) { close(c); continue; } uint8_t pay[MEOW_IPC_MAX]; o = 0; while (o < len) { ssize_t r = read(c, pay+o, len-o); if (r<=0) break; o += (size_t)r; } if (type == MSG_NOTIFY && len >= sizeof(m_notify_t)) { m_notify_t mn; memcpy(&mn, pay, sizeof mn); meow_notif_t n; launcher_map(&mn, &n); uint32_t nid = 0; int rc = meow_notif_post(&n, &nid); if (rc == NOTIF_OK) g_posted_nid = nid; reply_ack(c, MSG_NOTIFY_ACK, req_id, (rc == NOTIF_OK) ? nid : (uint32_t)rc); fprintf(stderr, "[post-srv] post rc=%d nid=%u cat=%s\n", rc, nid, mn.category); } else if (type == MSG_NOTIFY_DISMISS && len >= 4) { uint32_t id; memcpy(&id, pay, 4); int rc = meow_notif_dismiss(id); reply_ack(c, MSG_ACK, req_id, 0); fprintf(stderr, "[post-srv] dismiss id=%u rc=%d\n", id, rc); } close(c); } return NULL; } static int make_listen(char *path, size_t n) { snprintf(path, n, "/tmp/meow_notify_post_%d.sock", (int)getpid()); unlink(path); int fd = socket(AF_UNIX, SOCK_STREAM, 0); 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 (bind(fd, (struct sockaddr*)&a, sizeof a) < 0 || listen(fd, 4) < 0) { close(fd); return -1; } fcntl(fd, F_SETFL, O_NONBLOCK); g_listen_fd = fd; return 0; } static int failures = 0; static void check(const char *name, int cond) { printf("%s %s\n", cond ? "PASS" : "FAIL", name); if (!cond) failures++; } int main(void) { setenv("MEOW_LOG_APP", "intgapp", 1); char sock[108]; if (make_listen(sock, sizeof sock) != 0) { fprintf(stderr, "cannot listen\n"); return 2; } setenv("MEOW_IPC_SOCK", sock, 1); pthread_t th; pthread_create(&th, NULL, server, NULL); /* SDK send → launcher 真存储。media + ONGOING 走全部映射分支。 */ meow_notify nt; memset(&nt, 0, sizeof nt); nt.cat = MEOW_NOTIFY_CAT_MEDIA; nt.urgency = MEOW_NOTIFY_URG_HIGH; nt.title = "正在播放"; nt.timeout_ms = -1; nt.progress = 40; nt.icon = "os.meow.hello/icon.png"; uint32_t nid = meow_notify_ipc_send(&nt, 0); check("send 经 launcher 真存储回 nid>0", nid != 0); check("send 拿到 launcher 分配的 nid(与 post 一致)", g_posted_nid == nid); check("launcher 存储 count(media app)=1", meow_notif_count("intgapp") == 1); /* 回读 launcher 存储,验证 urgency/icon/progress 全链路落库 */ g_store_called = 0; memset(&g_stored, 0, sizeof g_stored); meow_notif_list(NULL, store_cb, NULL); check("post 存储 urgency=HIGH(2)", g_store_called && g_stored.urgency == MEOW_NOTIFY_URG_HIGH); check("post 存储 icon→app_icon", g_stored.app_icon[0] && !strcmp(g_stored.app_icon, "os.meow.hello/icon.png")); check("post 存储 progress=40", g_stored.progress == 40); /* SDK dismiss → launcher 撤下 */ meow_notify_ipc_dismiss(nid); check("dismiss 后 launcher 存储 count=0", meow_notif_count("intgapp") == 0); g_stop = 1; close(g_listen_fd); pthread_join(th, NULL); meow_notif_shutdown(); printf("\n%s (%d failure%s)\n", failures ? "RESULT: FAIL" : "RESULT: PASS", failures, failures == 1 ? "" : "s"); return failures ? 1 : 0; }