/* bench/nav_exit_sim.c — 任务2:home 根页左滑「回桌面后台」宿主验证。 * * 场景(0 真实请求/0 真实 launcher):fake launcher IPC socket(MEOW_IPC_SOCK)。调 * ipc_media_nav_exit(),断言: * ① fake launcher 收到一条 MSG_NAV 帧,nav_type==MEOW_NAV_EXIT、app_id=="dev.player.ncm"; * ② 本函数**不**置 g_app_quit(进程保留,媒体会话继续上报 PLAYING,任务2 ③ 保活前提)。 * 这验证「从网易云主页面侧滑返回不再退出进程,而请求 launcher 退后台(有歌在播则 M4 保活)」。 * * 编译(宿主,ncm_app 目录下): * gcc -O1 -DJSMN_HEADER -I. -Icore -Iapp -I../sdk -I../meow_launcherd \ * -c bench/nav_exit_sim.c -o /tmp/ne.o * gcc -O1 -DJSMN_HEADER -I. -Icore -Iapp -I../sdk -I../meow_launcherd \ * -c app/play/ipc_media.c -o /tmp/ne_ipc.o * gcc -O1 -o nav_exit_sim /tmp/ne.o /tmp/ne_ipc.o -lpthread * 运行:./nav_exit_sim (0 网络;PASS/FAIL 退出码) */ #include "../app/ncm_app_internal.h" #include "meow_ipc.h" #include #include #include #include #include #include #include ncm_app_state_t g_st; ncm_play_run_t g_play = { .mu = PTHREAD_MUTEX_INITIALIZER, .state = NCM_PC_STOPPED, .cur_song = -1 }; volatile int g_app_quit = 0; volatile int g_net_ready = 1; int g_host_mock = 0; size_t ncm_strlcpy(char *dst, const char *src, size_t sz) { size_t n = 0; if (sz) { while (src[n] && n < sz - 1) { dst[n] = src[n]; n++; } dst[n] = 0; } while (src[n]) n++; return n; } void meow_log(meow_log_level lvl, const char *fmt, ...) { (void)lvl; (void)fmt; } /* ipc_media.c 的其余依赖(本 sim 不驱动播放/封面/歌词,仅服务链接与消息类型) */ uint64_t meow_ui_time_ms(void) { return 0; } int player_manager_playing_song(void) { return g_play.cur_song; } int player_manager_current_song(ncm_song_t *out) { (void)out; return -1; } void player_manager_pause(int on) { (void)on; } void player_manager_next(int dir) { (void)dir; } void player_manager_seek(int64_t ms) { (void)ms; } int player_manager_state(void) { return g_play.state; } const char *cover_current_path(void) { return NULL; } int lyric_count(void) { return 0; } /* ---- fake launcher ---- */ static const char *g_sock = "/tmp/nav_exit_launcher.sock"; static uint16_t g_got_type = 0; static int g_got_nav_type = -1; static char g_got_app[MEOW_APP_ID_MAX]; static int g_got = 0; static void *server(void *arg) { (void)arg; unlink(g_sock); int lfd = socket(AF_UNIX, SOCK_STREAM, 0); if (lfd < 0) return NULL; struct sockaddr_un a; memset(&a, 0, sizeof a); a.sun_family = AF_UNIX; strncpy(a.sun_path, g_sock, sizeof a.sun_path - 1); if (bind(lfd, (struct sockaddr *)&a, sizeof a) != 0) { close(lfd); return NULL; } listen(lfd, 1); int fd = accept(lfd, NULL, NULL); if (fd < 0) { close(lfd); return NULL; } uint8_t rbuf[MEOW_IPC_MAX]; ssize_t n = read(fd, rbuf, sizeof rbuf); if (n >= (ssize_t)MEOW_IPC_HDR_LEN) { uint32_t magic, len; uint16_t ver, type; memcpy(&magic, rbuf, 4); memcpy(&ver, rbuf + 4, 2); memcpy(&type, rbuf + 6, 2); memcpy(&len, rbuf + 12, 4); if (magic == MEOW_IPC_MAGIC && ver == MEOW_IPC_VERSION && len <= (uint32_t)(n - MEOW_IPC_HDR_LEN)) { g_got_type = type; if (type == MSG_NAV && len >= sizeof(m_nav_t)) { m_nav_t nv; memcpy(&nv, rbuf + MEOW_IPC_HDR_LEN, sizeof nv); g_got_nav_type = (int)nv.nav_type; nv.app_id[MEOW_APP_ID_MAX - 1] = 0; snprintf(g_got_app, sizeof g_got_app, "%s", nv.app_id); } g_got = 1; } } close(fd); close(lfd); return NULL; } int main(void) { int fail = 0; setenv("MEOW_IPC_SOCK", g_sock, 1); pthread_t th; if (pthread_create(&th, NULL, server, NULL) != 0) { printf("FAIL server thread\n"); return 1; } usleep(50000); int rc = ipc_media_nav_exit(); pthread_join(th, NULL); if (rc != 0) { printf("FAIL ipc_media_nav_exit rc=%d\n", rc); fail = 1; } if (!g_got) { printf("FAIL fake launcher received no frame\n"); fail = 1; } else if (g_got_type != MSG_NAV) { printf("FAIL expected MSG_NAV (0x%04x) got 0x%04x\n", MSG_NAV, g_got_type); fail = 1; } else if (g_got_nav_type != MEOW_NAV_EXIT) { printf("FAIL expected MEOW_NAV_EXIT got %d\n", g_got_nav_type); fail = 1; } else if (strcmp(g_got_app, "dev.player.ncm") != 0) { printf("FAIL expected app_id dev.player.ncm got \"%s\"\n", g_got_app); fail = 1; } else { printf("PASS nav_exit: type=0x%04x nav_type=EXIT app=%s\n", g_got_type, g_got_app); } if (g_app_quit != 0) { printf("FAIL g_app_quit set (process must stay alive for bg keepalive)\n"); fail = 1; } else printf("PASS nav_exit did NOT set g_app_quit (process/alive, media keeps reporting PLAYING)\n"); unlink(g_sock); if (fail) { printf("nav_exit_sim FAIL\n"); return 1; } printf("nav_exit_sim PASS\n"); return 0; }