Android 16上,一个看似常规的操作——用Java调试器(JDWP)连接一个大型可调试应用——会在几秒内让整个进程冻结,紧接着弹出ANR对话框,系统杀进程。同样的应用,只要不连调试器就跑得好好的,小应用连接也丝滑。这不是偶发的卡顿,而是一个确认的结构性死锁:垃圾收集器(GC)与原生调试层(libjdwp/libopenjdkjvmti)在ART内发生了全VM范围的上锁顺序死锁

正方会立刻把它定性为严重运行时缺陷:JDWP是每个后端工程师日常依赖的工具,一个能让进程“致盲”的死锁意味着调试效率的腰斩,甚至让线上问题排查彻底失败。反观反方,可以冷静地指出,这个bug的复现门槛极高——必须运行Android 16、必须部署大型应用、并且必须用debuggable版本。普通用户的Release包不受影响,而且目前已精确回溯到ART主模块的一次更新,在versionCode 361143214及更早版本上不存在,从371000140起稳定复现。换句话说,它更像一次模块回归,而非系统原生问题。

打开网易新闻 查看精彩图片

两方都没错。但决定这个bug严重性的,恰恰是它暴露出的诊断层面失能。当死锁发生时,整个运行时是“盲”的:kill -3 或 ANR dump都无法拿到Java堆栈。系统日志直接记录“SuspendThreadByPeer timed out”,原因是GC线程卡在处理系统弱引用的半路上,安全点永远无法到达。开发者唯一能用的手段是跳过Java层的原生线程转储(ptrace)加上每线程的内核等待通道。这说明当问题真的出现时,你拿到的诊断数据降级到了原始形态,排查难度陡增。

截至目前,该bug已被独立复现于两台毫无关联的设备上——一台是原厂的Samsung Galaxy S22硬件,另一台是零OEM定制的Google Play模拟器镜像。这排除了厂商驱动干扰。并且,在Android操作系统版本保持不变的条件下,通过二分法锁定了引发死锁的ART主模块更新窗口。描述该缺陷的公开issue编号为 #530992434,并附有MIT许可的最小复现项目。

争论这个bug是否严重,本质是在争论开发基础设施的韧性。我的判断是:只要它能让一个本来可控的操作让整个调试链路失活,而且诊断数据需要切换到极其原生的手段才能获取,它就值得一个快速修复。毕竟,调试器的失明,就是工程师的失明。