meow_ui.a→9a8eb7ef; hello→fc299577; launcher→b33da20a; 宿主5套件+新test_notif_open+qemu分发 全过 出入: SDK符号用meow_ui_前缀防与launcher内同名冲突; 叠加会话真机待验; §10.5文档旧号段已过时
192 lines
8.7 KiB
C
192 lines
8.7 KiB
C
/* 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 <stdio.h>
|
||
#include <string.h>
|
||
#include <stdint.h>
|
||
#include <stdlib.h>
|
||
#include <unistd.h>
|
||
#include <errno.h>
|
||
#include <pthread.h>
|
||
#include <sys/socket.h>
|
||
#include <sys/un.h>
|
||
#include <sys/stat.h>
|
||
#include <fcntl.h>
|
||
|
||
#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<len){ ssize_t w=write(fd, pay+off, len-off); if(w<=0)return -1; off+=(size_t)w; } }
|
||
return 0;
|
||
}
|
||
|
||
static void *srv_thread(void *arg)
|
||
{
|
||
(void)arg;
|
||
int lfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||
if (lfd < 0) return NULL;
|
||
unlink(TEST_SOCK);
|
||
struct sockaddr_un a; memset(&a,0,sizeof a); a.sun_family=AF_UNIX; strncpy(a.sun_path,TEST_SOCK,sizeof a.sun_path-1);
|
||
if (bind(lfd,(struct sockaddr*)&a,sizeof a)<0){ perror("bind"); close(lfd); return NULL; }
|
||
chmod(TEST_SOCK,0666);
|
||
if (listen(lfd,4)<0){ perror("listen"); close(lfd); return NULL; }
|
||
fcntl(lfd, F_SETFL, fcntl(lfd,F_GETFL,0)|O_NONBLOCK); /* 非阻塞 accept:g_stop 时及时退出 */
|
||
g_srv_fd = lfd;
|
||
while (!g_stop) {
|
||
int c = accept(lfd, NULL, NULL);
|
||
if (c < 0) {
|
||
if (errno==EAGAIN || errno==EWOULDBLOCK) { usleep(20000); continue; }
|
||
if (errno==EINTR) continue;
|
||
break;
|
||
}
|
||
/* 读帧(一连接收若干帧;本测试每连接一帧) */
|
||
uint8_t hdr[MEOW_IPC_HDR_LEN];
|
||
size_t off=0;
|
||
while (off<sizeof hdr){ ssize_t r=read(c,hdr+off,sizeof hdr-off); if(r<=0) goto next; off+=(size_t)r; }
|
||
uint32_t magic,len; uint16_t ver,type;
|
||
memcpy(&magic,hdr,4); memcpy(&ver,hdr+4,2); memcpy(&type,hdr+6,2); memcpy(&len,hdr+12,4);
|
||
if (magic != MEOW_IPC_MAGIC || ver != MEOW_IPC_VERSION || len > 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<len){ ssize_t r=read(c,pay+off,len-off); if(r<=0)break; off+=(size_t)r; }
|
||
g_rx[g_rx_n].type=type; g_rx[g_rx_n].plen=(uint16_t)len; memcpy(g_rx[g_rx_n].pay,pay,len);
|
||
g_rx_n++;
|
||
}
|
||
pthread_mutex_unlock(&g_mu);
|
||
/* 回 ACK(m_ack_t,code=MEOW_OK, status=1);best-effort */
|
||
{
|
||
m_ack_t a; a.code=MEOW_OK; a.status=1;
|
||
(void)srv_send(c, MSG_ACK, (uint8_t*)&a, sizeof a);
|
||
}
|
||
next:
|
||
close(c);
|
||
}
|
||
close(lfd);
|
||
unlink(TEST_SOCK);
|
||
return NULL;
|
||
}
|
||
|
||
/* 取第 n 帧(n 从 0 起);返回 1=有,0=无。 */
|
||
static int rx_get(int n, uint16_t *type, uint16_t *plen, uint8_t *pay, int cap)
|
||
{
|
||
pthread_mutex_lock(&g_mu);
|
||
int ok = (n < g_rx_n);
|
||
if (ok) { *type = g_rx[n].type; *plen = g_rx[n].plen;
|
||
size_t c = g_rx[n].plen < (uint16_t)cap ? g_rx[n].plen : (uint16_t)cap;
|
||
memcpy(pay, g_rx[n].pay, c); }
|
||
pthread_mutex_unlock(&g_mu);
|
||
return ok;
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
setenv("MEOW_IPC_SOCK", TEST_SOCK, 1);
|
||
setenv("MEOW_LOG_APP", "os.meow.hello", 1);
|
||
|
||
pthread_t th; pthread_create(&th,NULL,srv_thread,NULL);
|
||
/* 等服务端就绪 */
|
||
for (int i=0;i<50 && g_srv_fd<0;i++) usleep(20000);
|
||
if (g_srv_fd < 0) { fprintf(stderr,"server not ready\n"); return 1; }
|
||
|
||
int fail = 0;
|
||
|
||
/* 1) meow_notify_ipc_notif_open 发 MSG_NOTIF_OPEN(want_ack=1 → 服务端回 ACK,不阻塞) */
|
||
meow_notify_ipc_notif_open("os.meow.hello", 7, 3, 8, 28, 0);
|
||
usleep(100000);
|
||
uint16_t t, pl; uint8_t pay[256];
|
||
if (rx_get(0,&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.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;
|
||
}
|