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

Offen
#32 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Anfängerfreundlichkeit
12/100
Issue-Typ
Bug
Klarheit
Größtenteils klar
Aktivitätsstatus
Aktiv
Tech-Stack
go, grpc
Bereich
networking, tooling

Rechercherichtung

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.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

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 里碰到的)。

Vorherrschende Sprache
Go
Sterne
0
Forks
1
Ø Merge
2 Std. 42 Min.
Gemergte PRs (30 T.)
13

Entwicklungsumgebung

Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus ModAVD/ModAVDManager

Alle Issues in ModAVD/ModAVDManager

Ähnliche Issues

Weitere Issues zu Go

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.