fix(amsd): launcher 重启后 amsd 失联三修 — am 命令连接被陈旧 revents 提前关闭/ipc_xchg 无超时冻结/无自动重连

launcher 重启后 am start/kill (MSG_AMS_START/KILL 0x00A0/0x00A1) 不再转发到 launcher。

根因(均在 meow_amsd.c,launcher 无需改):
① am 命令连接被提前关闭(真根因):poll 循环 pfds[] 每圈未清零,上一连接关闭残留的
   POLLHUP/POLLERR 落在 pfds[2+i];accept 后同圈用陈旧 revents 处理新连接 → 误判 HUP/ERR
   提前 close(am 收 SIGPIPE/141)。launcher 重启后 EV 事件连接密集、每条约关闭 → 必触发。
   修:每圈 memset(pfds,0,sizeof pfds),新连接当轮 revents=0、下轮才处理。
② ipc_xchg 无收发超时 → 阻塞 read 冻结整个单线程 amsd(launcher 接受但不回包窗口)。
   修:设 SO_SNDTIMEO/SO_RCVTIMEO(tv_usec<1000000,否则 setsockopt 返 EINVAL 静默失效)。
③ ams_request_ctl 加指数短退避重试(2 次,250ms 基数),launcher 数秒内回来即自动恢复。

验证(宿主端到端):假 launcher 杀→重启 am start 恢复 OK;注入多条 EV 后 am list×10 全
exit=0(无 141);哑 launcher(接受不回包)am start ~2s 有界返回 ERR 且 amsd 存活可继续
am list。meow_amsd mipsel md5 c6c2eda2d63ac73c4b6fac29008e0c9b(am 不变 d687d8bc)。
不动 launcher/sdk/根目录文档。
This commit is contained in:
MeowOS committed 2026-08-31 19:38:33 +08:00
1 parent 21ff5e82ea
commit 6d1189eadc
3 files changed
+25 -1

No files matched your search

Binary file not shown.
+25 -1
View File
@@ -65,6 +65,9 @@
#define AMS_SOCK_PATH_MAX 108
#define AMS_BOOTTS_LEN 64
#define AMS_REQ_MAX 512 /* 命令响应缓冲 */
#define AMS_IPC_TIMEOUT_MS 1200 /* launcher IPC 单次收发超时:amsd 绝不为一次转发阻塞无限久 */
#define AMS_IPC_RETRY 2 /* launcher 一次性不可达/超时 → 短退避重连一次 */
#define AMS_IPC_BACKOFF_MS 250 /* 重连退避基数 */
/* 每 App 状态(一期:STOPPED/FG;BG 预留二期) */
enum { AMS_STOPPED = 0, AMS_FG = 1, AMS_BG = 2 };
@@ -735,6 +738,15 @@ static int ipc_xchg(uint16_t type, const void *payload, uint32_t len,
{
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) return -1;
/* 收发加超时:launcher 刚刚重启/主循环未就绪(接受但不回包)时,amsd 的阻塞
* read 会永远挂起,冻结整个单线程守护。设 SO_SNDTIMEO/SO_RCVTIMEO 让单次转发
* 有界,超时即返回失败 → ams_request_ctl 退避重连,绝不无限阻塞。
* 注意:tv_usec 必须 < 1000000(否则 setsockopt 返回 EINVAL,超时静默失效)。 */
struct timeval tv;
tv.tv_sec = AMS_IPC_TIMEOUT_MS / 1000;
tv.tv_usec = (AMS_IPC_TIMEOUT_MS % 1000) * 1000;
(void)setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
(void)setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
struct sockaddr_un a;
memset(&a, 0, sizeof a);
a.sun_family = AF_UNIX;
@@ -781,10 +793,13 @@ static int ipc_xchg(uint16_t type, const void *payload, uint32_t len,
return (int)rtype;
}
/* 向 launcher 申请 start/kill。返回 0=launcher 回 code(a_out 输出);-1=launcher 不通。 */
/* 向 launcher 申请 start/kill。返回 0=launcher 回 code(a_out 输出);-1=launcher 不通。
* launcher 重启窗口(svcd/sysui 重启 launcher、或 amsd 先行启动)内连接会暂不可达/超时:
* 这里做「指数式短退避重试」——launcher 数秒内回来即自动恢复转发(无需人工重发)。 */
static int ams_request_ctl(uint16_t type, const void *payload, uint32_t len, uint32_t *code)
{
uint8_t rbuf[64];
for (int attempt = 0; attempt < AMS_IPC_RETRY; attempt++) {
int rt = ipc_xchg(type, payload, len, rbuf, sizeof rbuf);
if (rt == MSG_ACK) {
m_ack_t a;
@@ -793,6 +808,10 @@ static int ams_request_ctl(uint16_t type, const void *payload, uint32_t len, uin
return 0;
}
if (rt == MSG_ERR) return MEOW_ERR_INTERNAL;
/* 一次连接失败/超时(launcher 未就绪)→ 短退避再试;仍失败则返回 -1。 */
if (attempt + 1 < AMS_IPC_RETRY)
usleep((useconds_t)(AMS_IPC_BACKOFF_MS * (attempt + 1)) * 1000);
}
return -1;
}
@@ -1364,6 +1383,11 @@ static int run_daemon(void)
unsigned long long last_cleanup = 0;
while (!g_shutdown) {
/* 每圈清零:谨防上一轮已关闭连接残留的 POLLHUP/POLLERR 落在 pfds[2+i] 上。
* 若不清,accept 后同一轮就用「陈旧 revents」处理新连接——误判其 HUP/ERR
* 而提前 close(am CLI 收到 SIGPIPE、命令被丢弃),launcher 重启后 EV 事件
* 连接密集必触发,表现为 `am start` 不再转发到 launcher。 */
memset(pfds, 0, sizeof pfds);
pfds[0].fd = g_listen_fd; pfds[0].events = POLLIN; pfds[0].revents = 0;
pfds[1].fd = g_sigpipe[0]; pfds[1].events = POLLIN; pfds[1].revents = 0;
for (int i = 0; i < nfds - 2; i++) {
Binary file not shown.