/* test_notif_open.c — 宿主验证 §10.5「App 前台划出通知中心」的 SDK 侧上报链路: * 1. m_notif_open_t / m_notif_close_t 帧组装解析(round-trip)。 * 2. meow_notify_ipc_notif_open/close 经真实 AF_UNIX socket 发到 mock launcher, * 服务端收到 MSG_NOTIF_OPEN / MSG_NOTIF_CLOSE 且字段正确。 * 3. meow_ui_sys_notif_pull(origin_y)(顶部下滑系统手势钩子)→ 经 IPC 发 MSG_NOTIF_OPEN, * 服务端收到(origin_y/hotzone 由 SDK 填)。不渲染系统 UI——纯上报。 * 4. meow_notify_ipc_send_raw 的 want_ack 路径(服务端回 ACK,不阻塞)。 * * 编译(宿主 gcc,链 meow_notify_ipc + meow_ui_sys + gfx/theme/vol/log + 打桩 font/global): * gcc -Wall -o test_notif_open test_notif_open.c test_host_stub.c \ * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_notify_ipc.c \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * 运行:./test_notif_open */ #include "meow_ui.h" #include "meow_ui_sys.h" /* meow_ui_sys_notif_pull */ #include "meow_notify_ipc.h" /* meow_notify_ipc_notif_open/close + send_raw */ #include "meow_ipc.h" /* MSG_NOTIF_OPEN/CLOSE + m_notif_open_t/m_notif_close_t */ #include #include #include #include #include #include #include #include #include #include #include #define TEST_SOCK "/tmp/meow_notif_open_test.sock" #define ACK_CODE 0x4D00u /* 普通测试 ACK 载荷标记 */ static int g_srv_fd = -1; static int g_stop = 0; /* 服务端捕获到的帧(互斥保护) */ static pthread_mutex_t g_mu = PTHREAD_MUTEX_INITIALIZER; static struct { uint16_t type; /* 收到的帧 type */ uint16_t plen; /* payload 长 */ uint8_t pay[256]; } g_rx[8]; static int g_rx_n = 0; static int srv_send(int fd, uint16_t type, uint8_t *pay, uint32_t len) { uint8_t hdr[MEOW_IPC_HDR_LEN]; uint32_t magic = MEOW_IPC_MAGIC; uint16_t ver = MEOW_IPC_VERSION; uint32_t ack = ACK_CODE; memcpy(hdr+0,&magic,4); memcpy(hdr+4,&ver,2); memcpy(hdr+6,&type,2); memcpy(hdr+8,&ack,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) return -1; off+=(size_t)w; } if (len && pay) { off=0; while (off 256) goto next; pthread_mutex_lock(&g_mu); if (g_rx_n < 8) { uint8_t pay[256]; memset(pay,0,sizeof pay); off=0; while(off=sizeof(m_notif_open_t)) { m_notif_open_t o; memcpy(&o,pay,sizeof o); if (strcmp(o.app_id,"os.meow.hello")==0 && o.event_seq==7 && o.origin_x==3 && o.origin_y==8 && o.hotzone==28 && o.flags==0) { printf("PASS notif_open: type=0x%04x app=%s seq=%u oy=%u hz=%u\n", t, o.app_id, o.event_seq, o.origin_y, o.hotzone); } else { printf("FAIL notif_open: field mismatch\n"); fail=1; } } else { printf("FAIL notif_open: unexpected frame type=0x%04x plen=%u\n", t, pl); fail=1; } /* 2) meow_ui_sys_notif_pull(5):顶部下滑系统手势 → SDK 上报 MSG_NOTIF_OPEN(不渲染系统 UI)。 * app_id 走 env MEOW_LOG_APP;hotzone=状态栏激活(28);fullscreen=0 → flags=0。 */ meow_ui_sys_notif_pull(5); usleep(100000); if (rx_get(1,&t,&pl,pay,sizeof pay) && t==MSG_NOTIF_OPEN && pl>=sizeof(m_notif_open_t)) { m_notif_open_t o; memcpy(&o,pay,sizeof o); if (strcmp(o.app_id,"os.meow.hello")==0 && o.origin_y==5 && o.hotzone==28 && o.flags==0) { printf("PASS sys_notif_pull: gesture->MSG_NOTIF_OPEN app=%s oy=%u hz=%u nseq=%u\n", o.app_id, o.origin_y, o.hotzone, o.event_seq); } else { printf("FAIL sys_notif_pull: field mismatch\n"); fail=1; } } else { printf("FAIL sys_notif_pull: unexpected frame type=0x%04x plen=%u\n", t, pl); fail=1; } /* 3) meow_notify_ipc_notif_close 发 MSG_NOTIF_CLOSE */ meow_notify_ipc_notif_close("os.meow.hello", 0); usleep(100000); if (rx_get(2,&t,&pl,pay,sizeof pay) && t==MSG_NOTIF_CLOSE && pl>=sizeof(m_notif_close_t)) { m_notif_close_t o; memcpy(&o,pay,sizeof o); if (strcmp(o.app_id,"os.meow.hello")==0 && o.reason==0) { printf("PASS notif_close: type=0x%04x app=%s reason=%u\n", t, o.app_id, o.reason); } else { printf("FAIL notif_close: field mismatch\n"); fail=1; } } else { printf("FAIL notif_close: unexpected frame type=0x%04x plen=%u\n", t, pl); fail=1; } /* 4) 帧组装解析 round-trip:构造 m_notif_open_t 序列化 → 解析恢复各字段。 */ { m_notif_open_t a; memset(&a,0,sizeof a); snprintf(a.app_id,sizeof a.app_id,"os.meow.hello"); a.event_seq=9; a.origin_x=2; a.origin_y=32; a.hotzone=4; a.flags=1; m_notif_open_t b; memset(&b,0,sizeof b); memcpy(&b,&a,sizeof a); if (b.event_seq==9 && b.origin_y==32 && b.hotzone==4 && b.flags==1 && b.app_id[0]=='o') printf("PASS roundtrip: m_notif_open_t 44B (sz=%zu)\n", sizeof a); else { printf("FAIL roundtrip\n"); fail=1; } } /* 5) meow_notify_ipc_send_raw want_ack 路径(无效帧类型,服务端回 ERR? no——回 ACK;不崩即可) */ { uint32_t x = 0x12345678u; int r = meow_notify_ipc_send_raw(MSG_NOTIF_OPEN, &x, sizeof x, 1); /* want_ack 读到 ACK 即返回 0;无服务端才 -1。这里服务端在跑,应为 0。 */ printf("%s send_raw(MSG_NOTIF_OPEN, want_ack) -> %d\n", r==0?"PASS":"FAIL", r); if (r!=0) fail=1; } g_stop = 1; pthread_join(th, NULL); /* 服务端线程自关 lfd 并退出 */ if (fail) { printf("RESULT: FAIL\n"); return 1; } printf("RESULT: ALL PASS\n"); return 0; }