netsimd 卡住后,这台机器上所有模拟器都开不了机

未關閉
#32 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

維護者通常 1 天內回覆

還沒有人認領這個 Issue。

評估

難度
4/5
預估耗時
3-5 天
新手友好度
12/100
Issue 類型
缺陷
描述清晰度
基本清楚
活躍度
活躍
技術堆疊
go, grpc

研究方向

Start with the netsim discovery path: the shared netsim.ini under TMPDIR, the lock file in that directory, and how the emulator launch chooses between netsim and the legacy WiFi stack. Reproduce the hang by stubbing a TCP listener that never answers HTTP/2, then check whether launching with -feature -WiFiPacketStream -feature -BluetoothEmulation avoids starting netsimd at all. Done means boot succeeds with the fake netsimd present, and four concurrent boots run without a failure or self-exit.

由索引模型根據 Issue 內容生成。

描述

bug P1 platform:windows

现象

同一台机器上,4 台实例几乎同时开机(间隔约 2 s)并跑下载负载,CPU 很紧。不到两分钟,其中 3 台的模拟器日志出现:

Got goaway [11] err=UNAVAILABLE:GOAWAY received; Error code: 11; Debug Text: Buffers full

随后这 3 台自己退出了。从这时起,这台机器上任何模拟器都开不了机,只开 1 台也不行:

  • 开机后约 36 s,日志出现 detected a hanging thread 'QEMU2 main loop';
  • emulator.exe 退出码 0xC0000005;
  • modavd start 报 launch_failed。

确认没有模拟器在跑以后,把那个 netsimd.exe 结束掉,开机马上恢复。0.36.0 就有,不是新改出来的。

原因

  1. 一个 Windows 用户的所有模拟器共用一个 netsimd。
    • 模拟器和 netsimd 都在 TMPDIR(没设时是 %LOCALAPPDATA%\Temp)下的 netsim.ini 里互相找对方,锁也在这个目录里。
    • 所以不管是哪个 ModAVD 根目录、哪个 SDK,连的都是最先起来的那个 netsimd,Android Studio 的模拟器也一样。
  2. netsimd 卡住是 gRPC 内存配额用完了。
    • netsimd 的 gRPC 服务端只有一个处理线程,所有连接合计只有一份内存配额(AOSP 源码里是 1 MiB)。
    • 超了以后,gRPC 回收内存时会断开连接,发出来的就是 Buffers full(错误码 11)。
    • 卡住以后,已经连上的还能用,新连接一连上就被断开;客户端全退了也不恢复(推断:异常断开的客户端占的内存没有释放)。
  3. 新开的模拟器被挂死检测主动杀掉。
    • WiFi 后端在 QEMU 主线程上同步连 netsim;它和蓝牙共用一把全局锁,各自重试约 19 s。
    • 加起来主线程卡了 35 s 以上,超过挂死检测的 2 × 15 s,检测器就故意让进程崩掉,所以退出码是 0xC0000005。
    • 每次重试另起的 netsimd,看到锁被卡住的那个占着,就让位退出。
    • 模拟器本来会在连不上 netsim 时改用旧的 WiFi 栈,但还没轮到这一步,进程就已经被杀了。
  4. 正在跑的实例断流后退出:GOAWAY 以后蓝牙会重连,WiFi 不会,还会往已经结束的流上继续写,进程随即退出。这样退出没有先 sync。

影响

  • 一出事就是整台机器:这个用户的所有模拟器都开不了机,包括别的根目录里的;正在跑的实例也可能退出。
  • 不会自己恢复:卡住的 netsimd 至少 4 分钟都没有自己退出。
  • 多开挂机的场景(同时开 4 台左右,CPU 紧)最容易碰到。目前只在最苛刻的条件下碰到过 1 次;每台间隔 10 s 开机的 24 轮都没再出现。
  • 和 #22 是同一个根子。#22 是同机开着两个根目录时,关机后 netsimd 久久不退,挡住 modavd update,原因也是几个根目录共用一个 netsimd。下面的方案 1 或方案 2 做完,#22 也一起解决,可以一起关。

建议修法

  1. 首选:不用 netsim。起模拟器时加 -feature -WiFiPacketStream -feature -BluetoothEmulation:
    • WiFi 改走 qemu 自带的旧栈(连不上 netsim 时本来就退回这条路),不模拟蓝牙;
    • 整机不再起 netsimd,这个问题和 #22 一起消失。
    • 要回归:客体 WiFi 显示已连接、能联网、游戏下载、MAA。
  2. 回归不过就退一步:
    • 每个根目录单设 TMPDIR(比如 <根目录>\tmp\netsim),一个根目录的 netsimd 卡住不再连累别人。要实测几个 netsimd 抢固定的 HCI 端口 6402 会不会出问题。
    • 卡住时自动恢复:开机失败、日志里有主循环挂死时,确认本根目录没有实例在跑,就按 netsim.ini 里的 pid 结束本根目录的 netsimd,再重试一次。
  3. 另开跟进,不在这个 issue 里做:
    • 模拟器侧:连 netsim 设总时限,不要在主线程上等;WiFi 流断了以后不再往上写。
    • netsim 侧:全局 1 MiB 配额、异常断开的客户端不清理,报给上游。

验收

  • 用一个只接 TCP、不回 HTTP/2 的假 netsimd 占住发现目录,模拟它卡住:
    • 采用方案 1 时,开机照常,整个过程不起 netsimd;
    • 采用方案 2 时,换一个根目录开机照常,本根目录开机失败一次后自动恢复。
  • 同一台机器上 4 台每隔 2 s 开机、跑下载负载,连续 10 轮,不出现开机失败,也没有实例自己退出。

相关:#22,ModAVD#34(这次是在 #34 的多开 A/B 里碰到的)。

主要語言
Go
星號
0
分支
1
平均合併
2 小時 42 分鐘
30 天內合併 PR
13

環境準備

這個專案沒有提供開發容器、Dockerfile 或貢獻指南,環境需要你自己搭建:先看它的 README,通用步驟見我們的新手貢獻指南。

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

ModAVD/ModAVDManager 的其他 Issue

查看 ModAVD/ModAVDManager 的全部 Issue

相似的 Issue

更多 Go Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。