WIP checkpoint (M2.53→M2.54 工作区): 字体归MeowOS/fonts+SDK跟随+多字体(进行中)+boot板载+状态栏28+亮度/音量修复+文档刷新

This commit is contained in:
MeowOS Dev committed 2026-08-30 03:27:24 +08:00
1 parent 245bee2946
commit 064635b3c4
44 files changed
+2834 -308

No files matched your search

+281
View File
@@ -0,0 +1,281 @@
/*
* test_notify_ipc.c — 宿主测试:任务 #5 SDK↔IPC 桥(meow_notify_ipc.{h,c})。
*
* 用本地 AF_UNIX stub socket(回环)验证:
* T1 枚举↔字符串映射:CAT_PROGRESS→"progress"、CAT_MEDIA→"media" + media=1;
* T2 timeout 映射:-1(ONGOING)→expire=0xFFFFFFFF + ongoing=1;0(NEVER)→expire=0;
* >0→该毫秒 + ongoing=0;
* T3 回读 MSG_NOTIFY_ACK 拿 launcher 分配的 nid;replaces_id 原样透传;progress 钳位;
* T4 无 socket 降级:connect 失败 → meow_notify_ipc_send 返回 0,不崩;
* T5 dismiss:meow_notify_ipc_dismiss(nid) 发出 MSG_NOTIFY_DISMISS 帧(负载=nid)。
*
* 编译(宿主 gcc,不依赖 meow_ui.a 其余 TU):
* gcc -o test_notify_ipc test_notify_ipc.c meow_notify_ipc.c \
* -I. -I../meow_launcherd -lpthread
* 运行:./test_notify_ipc (全部 PASS 退出码 0,任一 FAIL 退出码 1)
*/
#include "meow_notify_ipc.h"
#include "meow_ui.h"
#include "meow_ipc.h" /* 帧头 / m_notify_t / m_ack_t / MSG_*(同源校验) */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <pthread.h>
/* ---- 捕获:stub 服务端解析到的帧内容(mutex 保护;客户端返回后读取) ---- */
typedef struct {
uint32_t type; /* 收到的帧类型 */
m_notify_t n; /* MSG_NOTIFY 负载 */
uint32_t dismiss_id; /* MSG_NOTIFY_DISMISS 负载 */
uint32_t req_id;
uint32_t nid_to_return; /* ACK 中回填的 status */
int got; /* 已收到一帧 */
} cap_t;
static cap_t g_cap;
static pthread_mutex_t g_cap_mu = PTHREAD_MUTEX_INITIALIZER;
static void cap_store(uint32_t type, uint32_t req_id, const uint8_t *pay, uint32_t len,
uint32_t nid_to_return)
{
pthread_mutex_lock(&g_cap_mu);
memset(&g_cap, 0, sizeof g_cap);
g_cap.type = type;
g_cap.req_id = req_id;
g_cap.nid_to_return = nid_to_return;
if (type == MSG_NOTIFY && len >= sizeof(m_notify_t)) memcpy(&g_cap.n, pay, sizeof(m_notify_t));
if (type == MSG_NOTIFY_DISMISS && len >= 4) memcpy(&g_cap.dismiss_id, pay, 4);
g_cap.got = 1;
pthread_mutex_unlock(&g_cap_mu);
}
/* ---- stub 服务端线程:accept 一个连接 → 读一帧 → 校验由主线程做,这里只收 + 回 ACK ---- */
static int g_listen_fd = -1;
static void *server_thread(void *arg)
{
(void)arg;
int c = accept(g_listen_fd, NULL, NULL);
if (c < 0) return NULL;
/* 读 16B 头 */
uint8_t hdr[MEOW_IPC_HDR_LEN];
uint32_t off = 0;
while (off < sizeof hdr) {
ssize_t r = read(c, hdr + off, sizeof hdr - off);
if (r <= 0) { close(c); return NULL; }
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);
uint32_t req_id; memcpy(&req_id, hdr + 8, 4);
if (magic != MEOW_IPC_MAGIC || ver != MEOW_IPC_VERSION) { close(c); return NULL; }
if (len > MEOW_IPC_MAX) { close(c); return NULL; }
uint8_t pay[MEOW_IPC_MAX];
off = 0;
while (off < len) {
ssize_t r = read(c, pay + off, len - off);
if (r <= 0) { close(c); return NULL; }
off += (size_t)r;
}
cap_store(type, req_id, pay, len, (uint32_t)strtoul(getenv("TEST_NID"), NULL, 0));
/* MSG_NOTIFY → 回 m_ack_t(code=OK, status=nid_to_return);
* MSG_NOTIFY_DISMISS → 回 m_ack_t(code=OK, status=0,同 launcher 行为)。 */
if (type == MSG_NOTIFY || type == MSG_NOTIFY_DISMISS) {
m_ack_t a;
memset(&a, 0, sizeof a);
a.code = MEOW_OK;
a.status = (type == MSG_NOTIFY) ? (uint32_t)strtoul(getenv("TEST_NID"), NULL, 0) : 0;
uint8_t rhdr[MEOW_IPC_HDR_LEN];
uint32_t rmagic = MEOW_IPC_MAGIC;
uint16_t rver = MEOW_IPC_VERSION, rtype = (uint16_t)(type == MSG_NOTIFY ? MSG_NOTIFY_ACK : MSG_ACK);
uint32_t rlen = sizeof a;
memcpy(rhdr + 0, &rmagic, 4);
memcpy(rhdr + 4, &rver, 2);
memcpy(rhdr + 6, &rtype, 2);
memcpy(rhdr + 8, &req_id, 4);
memcpy(rhdr + 12, &rlen, 4);
off = 0;
while (off < sizeof rhdr) { ssize_t w = write(c, rhdr + off, sizeof rhdr - off); if (w <= 0) break; off += (size_t)w; }
off = 0;
while (off < rlen) { ssize_t w = write(c, (uint8_t*)&a + off, rlen - off); if (w <= 0) break; off += (size_t)w; }
}
close(c);
return NULL;
}
static int failures = 0;
static void check(const char *name, int cond)
{
printf("%s %s\n", cond ? "PASS" : "FAIL", name);
if (!cond) failures++;
}
/* 建 listening socket,返回 fd;路径写入 sock_path。 */
static int arb_listen(char *sock_path, size_t slen)
{
static int count = 0;
snprintf(sock_path, slen, "/tmp/meow_notify_ipc_%d_%d.sock", (int)getpid(), count++);
unlink(sock_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, sock_path, sizeof a.sun_path - 1);
if (bind(fd, (struct sockaddr *)&a, sizeof a) < 0) { perror("bind"); close(fd); return -1; }
if (listen(fd, 1) < 0) { perror("listen"); close(fd); return -1; }
return fd;
}
int main(void)
{
setenv("MEOW_LOG_APP", "testapp", 1); /* 固定 app_id,供 stub 校验 */
/* ---------- T1/T2/T3:映射 + ACK 回 nid ---------- */
{
char sock[108];
g_listen_fd = arb_listen(sock, sizeof sock);
if (g_listen_fd < 0) { fprintf(stderr, "cannot create listener\n"); return 2; }
setenv("MEOW_IPC_SOCK", sock, 1);
setenv("TEST_NID", "0x1234", 1);
pthread_t th;
pthread_create(&th, NULL, server_thread, NULL);
meow_notify nt;
memset(&nt, 0, sizeof nt);
nt.cat = MEOW_NOTIFY_CAT_PROGRESS;
nt.urgency = MEOW_NOTIFY_URG_NORMAL;
nt.title = "下载中";
nt.body = "70%";
nt.timeout_ms = 5000; /* >0 → expire=5000, ongoing=0 */
nt.progress = 150; /* 钳位 → 100 */
uint32_t nid = meow_notify_ipc_send(&nt, 0);
pthread_join(th, NULL);
close(g_listen_fd);
check("T3 send 返回 launcher nid(0x1234)", nid == 0x1234);
pthread_mutex_lock(&g_cap_mu);
int got = g_cap.got;
const m_notify_t *cn = &g_cap.n;
pthread_mutex_unlock(&g_cap_mu);
check("T3 stub 收到 MSG_NOTIFY 帧", got && g_cap.type == MSG_NOTIFY);
check("T1 CAT_PROGRESS→category=progress", !strcmp(cn->category, "progress"));
check("T2 timeout>0→expire_timeout=5000", cn->expire_timeout == 5000);
check("T2 timeout>0→ongoing=0", cn->ongoing == 0);
check("T1 media=0(非媒体)", cn->media == 0);
check("T1 progress 钳位 150→100", cn->progress == 100);
check("T2 replaces_id 透传=0", cn->replaces_id == 0);
check("T1 app_id=testapp", !strcmp(cn->app_id, "testapp"));
check("T1 summary=下载中", !strcmp(cn->summary, "下载中"));
}
/* ---------- T1/T2:媒体类型 + ONGOING(-1) ---------- */
{
char sock[108];
g_listen_fd = arb_listen(sock, sizeof sock);
setenv("MEOW_IPC_SOCK", sock, 1);
setenv("TEST_NID", "0x9999", 1);
pthread_t th;
pthread_create(&th, NULL, server_thread, NULL);
meow_notify nt;
memset(&nt, 0, sizeof nt);
nt.cat = MEOW_NOTIFY_CAT_MEDIA;
nt.urgency = MEOW_NOTIFY_URG_CRITICAL;
nt.title = "Now Playing";
nt.timeout_ms = MEOW_NOTIFY_TIMEOUT_ONGOING; /* -1 */
uint32_t nid = meow_notify_ipc_send(&nt, 0);
pthread_join(th, NULL);
close(g_listen_fd);
check("T3 send(media/ongoing) 返回 nid(0x9999)", nid == 0x9999);
check("T1 CAT_MEDIA→category=media", !strcmp(g_cap.n.category, "media"));
check("T1 CAT_MEDIA→media=1", g_cap.n.media == 1);
check("T2 ONGOING(-1)→expire=0xFFFFFFFF", g_cap.n.expire_timeout == 0xFFFFFFFFu);
check("T2 ONGOING(-1)→ongoing=1", g_cap.n.ongoing == 1);
}
/* ---------- T2:NEVER(0) 超时 ---------- */
{
char sock[108];
g_listen_fd = arb_listen(sock, sizeof sock);
setenv("MEOW_IPC_SOCK", sock, 1);
setenv("TEST_NID", "0x1", 1);
pthread_t th;
pthread_create(&th, NULL, server_thread, NULL);
meow_notify nt;
memset(&nt, 0, sizeof nt);
nt.cat = MEOW_NOTIFY_CAT_GENERAL;
nt.title = "x";
nt.timeout_ms = MEOW_NOTIFY_TIMEOUT_NEVER; /* 0 */
(void)meow_notify_ipc_send(&nt, 0);
pthread_join(th, NULL);
close(g_listen_fd);
check("T2 NEVER(0)→expire=0 & ongoing=0",
g_cap.n.expire_timeout == 0 && g_cap.n.ongoing == 0);
check("T1 CAT_GENERAL→category=general", !strcmp(g_cap.n.category, "general"));
}
/* ---------- T3:replaces_id 透传 ---------- */
{
char sock[108];
g_listen_fd = arb_listen(sock, sizeof sock);
setenv("MEOW_IPC_SOCK", sock, 1);
setenv("TEST_NID", "0xBEEF", 1);
pthread_t th;
pthread_create(&th, NULL, server_thread, NULL);
meow_notify nt;
memset(&nt, 0, sizeof nt);
nt.cat = MEOW_NOTIFY_CAT_MESSAGE;
nt.title = "repl";
nt.timeout_ms = 0;
(void)meow_notify_ipc_send(&nt, 0x42u);
pthread_join(th, NULL);
close(g_listen_fd);
check("T3 replaces_id 透传=0x42", g_cap.n.replaces_id == 0x42u);
}
/* ---------- T4:无 socket 降级不崩 ---------- */
{
/* 指向不存在路径 */
char dead[108];
snprintf(dead, sizeof dead, "/tmp/meow_notify_ipc_dead_%d.sock", (int)getpid());
unlink(dead);
setenv("MEOW_IPC_SOCK", dead, 1);
meow_notify nt;
memset(&nt, 0, sizeof nt);
nt.cat = MEOW_NOTIFY_CAT_EMAIL;
nt.title = "no-socket";
nt.timeout_ms = 0;
uint32_t nid = meow_notify_ipc_send(&nt, 0);
check("T4 无 socket→返回 0(降级不崩)", nid == 0);
meow_notify_ipc_dismiss(0x1234); /* 无 socket 静默,不崩 */
check("T4 dismiss 无 socket 静默不崩", 1);
}
/* ---------- T5:dismiss 发 MSG_NOTIFY_DISMISS ---------- */
{
char sock[108];
g_listen_fd = arb_listen(sock, sizeof sock);
setenv("MEOW_IPC_SOCK", sock, 1);
pthread_t th;
pthread_create(&th, NULL, server_thread, NULL);
meow_notify_ipc_dismiss(0xABCDu);
pthread_join(th, NULL);
close(g_listen_fd);
check("T5 stub 收到 MSG_NOTIFY_DISMISS 帧", g_cap.got && g_cap.type == MSG_NOTIFY_DISMISS);
check("T5 dismiss 负载=nid=0xABCD", g_cap.dismiss_id == 0xABCDu);
}
printf("\n%s (%d failure%s)\n", failures ? "RESULT: FAIL" : "RESULT: PASS",
failures, failures == 1 ? "" : "s");
return failures ? 1 : 0;
}