feat(sdk+launcher): SDK nav/media封装 + §10.5 App前台唤起通知中心 (agent-206) — meow_ui_nav.c(env栈初始化+report/request_exit) + meow_ui_media.c(懒连断线重连, meta上报+playctl接收) + MSG_NOTIF_OPEN=0x28/CLOSE=0x29(0x25/26已被占); SDK顶部下滑手势→IPC; launcher App前台会话叠加通知中心(SIGSTOP→读帧→接管输入→恢复SIGCONT, 面板内App崩溃即关); hello接线验证
meow_ui.a→9a8eb7ef; hello→fc299577; launcher→b33da20a; 宿主5套件+新test_notif_open+qemu分发 全过 出入: SDK符号用meow_ui_前缀防与launcher内同名冲突; 叠加会话真机待验; §10.5文档旧号段已过时
This commit is contained in:
1 parent
21519ce2e4
commit
9b4195724c
37 files changed
+1042
-21
No files matched your search
@@ -0,0 +1,191 @@
|
||||
/* 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;
|
||||
}
|
||||
Reference in new issue
Block a user