/* app/reader_ipc.c — 系统翻页信号接收(见 app/reader_ipc.h)。 */ #include "reader_ipc.h" #include "../reader_internal.h" /* reader_page_key() */ #include "meow_ipc.h" #include #include #include #include #include #include #include #include #include static pthread_mutex_t g_mu = PTHREAD_MUTEX_INITIALIZER; static int g_fd = -1; static pthread_t g_thr; static int g_thr_on = 0; static volatile int g_quit = 0; static const char *sock_path(void) { const char *e = getenv("MEOW_IPC_SOCK"); return (e && e[0]) ? e : MEOW_IPC_PATH; } static void app_id_of(char *out, int outsz) { const char *e = getenv("MEOW_LOG_APP"); snprintf(out, (size_t)outsz, "%s", (e && e[0]) ? e : "os.meow.reader"); } static int connect_path(const char *path) { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) return -1; 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 (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) { close(fd); return -1; } return fd; } static int write_all(int fd, const uint8_t *p, size_t n) { size_t off = 0; while (off < n) { ssize_t w = write(fd, p + off, n - off); if (w < 0) { if (errno == EINTR) continue; return 0; } if (w == 0) return 0; off += (size_t)w; } return 1; } static int read_all(int fd, uint8_t *p, size_t n) { size_t off = 0; while (off < n) { ssize_t r = read(fd, p + off, n - off); if (r < 0) { if (errno == EINTR) continue; return 0; } if (r == 0) return 0; off += (size_t)r; } return 1; } static int send_frame(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len) { uint8_t hdr[MEOW_IPC_HDR_LEN]; uint32_t magic = MEOW_IPC_MAGIC; uint16_t ver = MEOW_IPC_VERSION; memcpy(hdr + 0, &magic, 4); memcpy(hdr + 4, &ver, 2); memcpy(hdr + 6, &type, 2); memcpy(hdr + 8, &req_id, 4); memcpy(hdr + 12, &len, 4); if (!write_all(fd, hdr, sizeof hdr)) return -1; if (len && payload && !write_all(fd, payload, len)) return -1; return 0; } static int read_frame(int fd, uint16_t *type, uint8_t *rbuf, uint32_t rcap) { uint8_t hdr[MEOW_IPC_HDR_LEN]; if (!read_all(fd, hdr, sizeof hdr)) return -1; uint32_t magic, len; uint16_t ver; 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) return -1; if (len > rcap) len = rcap; if (len > 0 && !read_all(fd, rbuf, len)) return -1; return (int)len; } static int conn_locked(void) { if (g_fd >= 0) return g_fd; int fd = connect_path(sock_path()); if (fd < 0) return -1; char app[MEOW_APP_ID_MAX]; app_id_of(app, (int)sizeof app); m_hello_t h; memset(&h, 0, sizeof h); snprintf(h.app_id, sizeof h.app_id, "%s", app); h.version = 1; h.flags = 0; /* 非媒体源;仅声明存在,收系统翻页信号 */ if (send_frame(fd, MSG_HELLO, 1, &h, sizeof h) != 0) { close(fd); return -1; } uint8_t rbuf[256]; uint16_t rt; if (read_frame(fd, &rt, rbuf, sizeof rbuf) < 0 || (rt != MSG_ACK && rt != MSG_ERR)) { close(fd); return -1; } g_fd = fd; return fd; } static void mark_dead_locked(void) { if (g_fd >= 0) { close(g_fd); g_fd = -1; } } static void *ipc_thread_main(void *arg) { (void)arg; while (!g_quit) { pthread_mutex_lock(&g_mu); int fd = g_fd; if (fd < 0) fd = conn_locked(); /* 懒连/重连(best-effort;失败则重试) */ pthread_mutex_unlock(&g_mu); if (fd < 0) { usleep(500000); continue; } struct pollfd p; p.fd = fd; p.events = POLLIN; p.revents = 0; int pr = poll(&p, 1, 200); if (pr < 0 && errno != EINTR) { pthread_mutex_lock(&g_mu); mark_dead_locked(); pthread_mutex_unlock(&g_mu); continue; } if (pr > 0 && (p.revents & (POLLHUP | POLLERR | POLLNVAL))) { pthread_mutex_lock(&g_mu); mark_dead_locked(); pthread_mutex_unlock(&g_mu); continue; } if (pr > 0 && (p.revents & POLLIN)) { uint8_t rbuf[MEOW_IPC_MAX]; uint16_t type; int n = read_frame(fd, &type, rbuf, sizeof rbuf); if (n < 0) { pthread_mutex_lock(&g_mu); mark_dead_locked(); pthread_mutex_unlock(&g_mu); continue; } /* UI 线程经 reader_on_tick 消费(跨线程仅置 pending 计数,不直接改页) */ if (type == MSG_KEY_PAGEUP) reader_page_key(-1); else if (type == MSG_KEY_PAGEDOWN) reader_page_key(1); } } pthread_mutex_lock(&g_mu); mark_dead_locked(); pthread_mutex_unlock(&g_mu); return NULL; } void reader_ipc_start(void) { pthread_mutex_lock(&g_mu); int need = !g_thr_on; if (need) { g_quit = 0; g_thr_on = 1; } pthread_mutex_unlock(&g_mu); if (need) { pthread_attr_t at; pthread_attr_init(&at); pthread_attr_setstacksize(&at, 64 * 1024); /* 小栈:阅读态 ≤8MB 纪律 */ pthread_create(&g_thr, &at, ipc_thread_main, NULL); pthread_attr_destroy(&at); pthread_detach(g_thr); } } void reader_ipc_stop(void) { pthread_mutex_lock(&g_mu); g_quit = 1; mark_dead_locked(); g_thr_on = 0; pthread_mutex_unlock(&g_mu); }