Android稳定性-07-Android 底层稳定性问题:Kernel Panic、OOM、重启与卡死
做 底层稳定性 相关的 Android 稳定性测试时,最重要的不是先给现象下结论,而是把问题放回系统链路里。
底层稳定性关注系统是否被内核、驱动、内存、电源或硬件状态打断。它的证据往往在重启前后,采集窗口短,丢失后很难补。
这篇文章的目标不是罗列术语,而是把测试人员在现场应该问的问题、应该抓的证据、应该避免的误判,以及可以交付给开发的输出物写清楚。
一、具体问题背景
长稳设备突然离线、adb 断开、屏幕冻结、自动重启,是最难追的稳定性问题。难点不是现象复杂,而是发生后现场被破坏:重启清掉日志,卡死无法执行命令,panic 只留下 pstore 或串口。
底层问题需要预埋采集策略。测试开始前就要确认 pstore、ramoops、串口、持久化 logcat、dropbox、thermal 和 power 日志是否可用。
围绕“Kernel Panic、OOM、重启与卡死如何进入稳定性分析”,测试同学需要从现象、时间线、层级和证据四个维度同时推进。只描述用户看到什么不够,还要说明系统内部哪个阶段开始偏离基线。
稳定性缺陷的价值不只在复现,还在于缩短定位路径。一个高质量问题单应当让接手开发能立刻知道先看哪类日志、哪个进程、哪个服务、哪个时间点。
二、它在 Android 稳定性测试里的位置
这是系列里最接近 Kernel 和硬件的一篇。它把系统重启、卡死、OOM、panic 从用户态现象拆到底层证据,帮助测试把“机器挂了”写成可分析的问题。
在测试计划里,它不是孤立专项,而是和 Monkey、长稳、启动、功耗、性能、温度、网络、媒体、相机、车机/平板/手机形态的业务场景交叉。交叉越多,越需要统一的证据标准。
如果这一层没有定义清楚,后续问题会出现两个后果:严重问题被轻描淡写,偶发问题因为缺少证据无法关闭。
三、先给问题建立分层模型
围绕 底层稳定性,建议先按下面几层拆解。分层不是为了显得复杂,而是为了避免在错误层级反复试错。
Kernel Panic:内核主动 panic 或 BUG/Oops,常见于驱动空指针、非法访问、watchdog bite。
OOM/LMKD:内存压力下内核 OOM killer 或用户态 lmkd 杀进程,可能导致关键进程死亡或连锁重启。
重启链路:区分正常重启、用户触发、watchdog、thermal、power key、modem/subsystem reset。
卡死/Hang:CPU stuck、I/O hang、不可中断睡眠、调度停滞,可能 adb 不通但设备未重启。
测试报告里最好显式写出当前证据支持哪一层、排除了哪一层、还有哪一层没有证据。这样开发、测试和项目经理对风险边界会更一致。
四、关键观察对象和判断信号
现场判断可以先抓四类信号:时间信号、进程信号、资源信号和用户可见信号。时间信号用于对齐问题发生点,进程信号用于判断影响范围,资源信号用于发现压力来源,用户可见信号用于评估严重度。
不要只问“有没有复现”。更有价值的问题是:复现前系统有没有变慢,复现时哪个服务先异常,复现后系统能否自动恢复,恢复后是否留下 dropbox、tombstone、pstore 或 traces。
对于 底层稳定性,最应该记录的不是单条日志,而是从触发动作到异常出现之间的完整链路。只要链路完整,即使偶现一次也能推进定位。
五、关键命令和日志入口
下面这些命令不是每次都全部执行,但它们覆盖了最常用的入口。测试脚本可以按场景自动化保存,避免人工复现时漏抓。
重启原因:
1 | adb shell getprop sys.boot.reason |
采集 重启原因 时要同时记录设备时间、电脑时间和测试步骤编号,否则后续很难把日志与操作对齐。
内核证据:
dmesg、/proc/last_kmsg 和 /sys/fs/pstore 在 user 版本上经常不可读,且新内核上 last_kmsg 可能已经被 pstore/ramoops 取代。命令失败不等于没有内核证据,要结合 bugreport、厂商诊断包、串口日志或 userdebug 复现继续补证。
1 | adb shell dmesg > dmesg.txt |
采集 内核证据 时要同时记录设备时间、电脑时间和测试步骤编号,否则后续很难把日志与操作对齐。
内存压力:
1 | adb shell dumpsys meminfo |
采集 内存压力 时要同时记录设备时间、电脑时间和测试步骤编号,否则后续很难把日志与操作对齐。
卡死预案:
sysrq 需要内核支持和足够权限,且写入重定向必须发生在设备侧 shell 里。不要在量产用户设备上随意触发,只适合实验室 userdebug/eng 或已授权工程环境。
1 | adb shell 'echo w > /proc/sysrq-trigger' |
采集 卡死预案 时要同时记录设备时间、电脑时间和测试步骤编号,否则后续很难把日志与操作对齐。
六、测试维度和证据表
| 观察项 | 主要判断 | 证据入口 |
| — | — | — |
| Kernel Panic | 自动重启,pstore 有 console/ramoops | pstore、last_kmsg、串口 |
| OOM | 进程被杀、桌面重启、系统降级 | lmkd、am_kill、meminfo、psi |
| Watchdog Bite | 硬件/内核 watchdog 复位 | bootreason、pstore、kernel log |
| 卡死 | 画面冻结,adb 可能断开 | sysrq、串口、ftrace、功耗状态 |
表格里的入口要和问题单附件一一对应。只写“已抓日志”没有意义,最好写清楚附件名、采集时间、采集命令和异常时间点。
七、时间线比单点日志更重要
稳定性问题经常不是瞬间发生,而是先有资源曲线变化,再出现服务延迟,最后才变成用户可见故障。没有时间线,分析者只能在一堆日志里猜。
建议至少记录四个时间点:场景开始时间、最后一次正常时间、首次异常时间、恢复或重启时间。若是自动化场景,应把脚本步骤号、seed、循环次数和设备状态写入日志。
对于 底层稳定性,时间线还要覆盖相关进程或服务的状态变化。比如 PID 是否变化、服务是否重启、关键属性是否切换、队列长度是否增长。
八、分层分析方法
第一步先确认用户可见现象是否稳定复现:Kernel Panic、OOM、重启与卡死如何进入稳定性分析 不能只靠截图描述,要说明触发条件、复现概率和影响范围。
第二步判断问题停留在哪个系统层级。App 层看主线程和生命周期,Framework 看服务调用和状态机,native/HAL 看 tombstone 与 service dump,Kernel 看 pstore、dmesg、bootreason 和资源压力。
第三步寻找“第一个异常”。后面的 Crash、ANR、重启、黑屏可能只是连锁反应。时间上最早、影响范围最大、能解释后续现象的证据,通常更接近首因。
第四步形成可验证假设。好的初步归因应该能推出验证动作:如果是资源泄漏,长稳曲线应改善;如果是 Binder 等待,服务端栈应变化;如果是驱动 hang,pstore 或 vendor log 应不再出现同类签名。
九、如何区分必现、偶现和环境问题
必现问题更适合缩短路径,先做最小复现;偶现问题更依赖自动化证据和周期性快照;环境问题则要把外设、网络、温度、电量、账号、数据量、SIM/蓝牙/Wi-Fi 状态写清楚。
不要因为问题偶现就降低严重度。系统级稳定性问题即使概率低,只要影响重启、黑屏、核心服务不可用,也应该按高优先级处理。
也不要因为环境复杂就放弃归因。复杂环境可以拆成变量矩阵:单设备/多设备、充电/不充电、弱网/正常网络、高温/常温、清数据/保留数据、首启/非首启。
十、完整案例:高温视频压力 6 小时后设备自动重启
**现象:**视频循环播放加充电场景下设备离线后自动回来,测试脚本记录到一次 reboot,用户态 logcat 在重启前中断。
**采集:**重启后第一时间拉取 bootreason、pstore、dmesg、thermal zone、battery stats、dropbox 和测试温度曲线。
**分析:**ro.boot.bootreason 显示 watchdog,pstore 中有 GPU driver hang 相关栈,thermal 日志显示温度高但未达到关机阈值。
**初步归因:**不是普通 thermal shutdown,也不是 App Crash,而是高温压力下 GPU/显示驱动 hang 后触发 watchdog 复位。
**修复验证:**更新 GPU 驱动超时恢复逻辑后,重复高温视频、亮灭屏和后台切换压力 3 轮,每轮 8 小时,未再出现 watchdog bootreason。
这个案例的关键点是把现象和系统链路连接起来。问题单里应避免只写最终结论,而要保留从采集到分析再到验证的路径。
如果后续修复没有覆盖原始触发条件,只能说明某个局部现象暂时消失,不能说明稳定性风险已经关闭。
十一、常见误判
设备重启后只抓当前 logcat,遗漏 pstore。
看到内存低就把所有重启归为 OOM。
bootreason 写 reboot 就停止分析,不继续看 pstore 和电源日志。
卡死时反复拔插设备,破坏现场而没有先做 sysrq 或串口采集。
误判的共同原因是证据太窄:只看一个进程、只看最后一段日志、只看用户态、只看平均指标。稳定性测试要主动扩展证据宽度。
十二、检查清单
测试前是否确认 pstore/ramoops 可用
重启后是否第一时间拉取 bootreason 和 pstore
是否保存温度、电量、充电、网络、外设状态
是否区分 kernel panic、watchdog、thermal、用户态重启
OOM 是否有 lmkd/am_kill/meminfo 证据链
卡死是否有 sysrq、串口或 ftrace 预案
是否记录重启前最后一个业务动作
修复验证是否覆盖压力、温度和长稳组合
清单不是形式化动作。每一项都应该对应报告里的文字、附件或图表。没有证据的勾选应当视为无效。
十三、输出物模板
下面是一份可以直接放进缺陷系统的输出物模板。字段可以按团队习惯调整,但核心信息不要省略。
1 |
|
十四、和自动化平台的结合
如果测试平台只保存最终结果,稳定性分析会非常被动。建议平台在每轮场景开始、每次失败、每小时巡检、设备离线、重启后上线这几个节点自动拉取快照。
快照内容至少包括 logcat ring buffer、top、meminfo、cpuinfo、关键 dumpsys、设备属性、温度、电量、存储空间和进程列表。底层问题还要尽量拉 pstore 或触发 sysrq。
针对 底层稳定性,平台还可以把关键指标做趋势图。趋势图能把“偶现”变成“异常前已有征兆”,这是长稳测试最有价值的部分。
十五、修复验证怎么做才算闭环
修复验证不能只跑一次原步骤。至少要包含原始复现场景、扩大压力场景、长时间稳定性场景和相邻功能回归。
验证时要比较修复前后的关键证据,而不是只看现象有没有再出现。比如耗时是否下降、PID 是否稳定、内存是否不再增长、队列是否不再堆积、bootreason 是否不再出现同类值。
如果问题原本是偶现,验证轮次要按风险提高。影响重启、黑屏、核心服务不可用的问题,建议至少多设备、多轮次、跨夜验证。
十六、交付给开发时的沟通重点
好的稳定性问题单应当降低开发的第一小时成本。开发打开问题后,应能立刻看到异常时间、首个异常、关键附件、初步假设和建议查看的模块。
沟通时尽量避免“感觉像”“可能是系统问题”这种表述。可以写“当前证据显示调用端等待某服务返回,但服务端线程栈还缺失,需要补抓”。这比泛泛甩锅更容易推进。
如果证据不足,也要明确不足在哪里:缺少重启前 pstore,缺少服务端栈,缺少 perfetto,缺少对照版本。把缺口写清楚,本身就是有效输出。
十七、扩展阅读和后续文章关联
这篇文章与系统架构、核心进程、Binder、启动流程、问题分类、底层异常和典型现象是互相补充的。遇到复杂问题时不要只停在本文,而要按链路跳到对应专题继续分析。
如果问题表现为 App 到系统服务调用卡住,优先回到 Binder;如果表现为开机或桌面异常,优先回到启动流程和核心进程;如果表现为重启或 adb 断开,优先回到底层稳定性;如果表现为黑屏、卡顿、无响应,则按典型现象链路拆。
十八、专项场景设计
围绕 底层稳定性,专项场景不能只追求时长,还要覆盖容易触发状态切换的路径。长时间运行能发现累积问题,但很多稳定性缺陷发生在切换瞬间:进前台、退后台、亮屏、灭屏、网络切换、包扫描、服务重启、资源回收。
建议把场景拆成“基线场景、压力场景、扰动场景、恢复场景”四类。基线场景用于确认版本本身是否正常,压力场景用于放大资源瓶颈,扰动场景用于打断状态机,恢复场景用于确认异常后系统是否能回到可用状态。
高温充电视频压力:执行前记录设备状态,执行中保留周期快照,执行后确认关键进程、关键服务和用户可见状态是否回到基线。
低内存大应用切换:执行前记录设备状态,执行中保留周期快照,执行后确认关键进程、关键服务和用户可见状态是否回到基线。
I/O 长时间读写:执行前记录设备状态,执行中保留周期快照,执行后确认关键进程、关键服务和用户可见状态是否回到基线。
外设插拔与休眠唤醒:执行前记录设备状态,执行中保留周期快照,执行后确认关键进程、关键服务和用户可见状态是否回到基线。
弱电/掉电/快速重启:执行前记录设备状态,执行中保留周期快照,执行后确认关键进程、关键服务和用户可见状态是否回到基线。
场景设计还要注意互斥变量。比如高温和低电量同时出现时,不能直接把结果归因到单一模块;弱网和低内存同时出现时,要用对照组拆开网络等待与资源回收。
十九、指标基线和异常阈值
底层稳定性 的指标建议至少覆盖:bootreason、panic/oops 签名、LMKD 杀进程曲线、PSI 压力、thermal 状态、watchdog bite 次数。指标不是为了做漂亮报表,而是为了在问题出现前发现趋势,在问题出现后支撑归因。
| 指标类型 | 记录方式 | 判断方法 |
|---|---|---|
| 稳态指标 | 固定周期采集 bootreason 等数据 | 和同版本前一轮、上一稳定版本、同批设备对比 |
| 瞬时指标 | 异常发生时立刻抓取 dumpsys、top、trace、日志 | 观察是否有突增、阻塞、服务重启或队列堆积 |
| 趋势指标 | 每 5 到 15 分钟保存一次快照 | 观察是否单调增长、周期性抖动或在触发动作后不恢复 |
| 门禁指标 | 和发布标准绑定 | 超过门禁直接阻塞或要求风险签核 |
阈值不要只写绝对数字。更稳妥的方式是同时给出绝对阈值、相对退化比例和用户影响。例如启动时间增加 20% 且超过产品体验线,比单纯写“启动慢”更容易决策。
二十、证据判读细节
判读日志时先看时间,再看层级,最后看具体错误。很多日志里会有大量 warning,它们未必是根因;真正有价值的是第一个状态变化、第一次耗时超阈值、第一次进程死亡、第一次资源压力异常。
对 底层稳定性 来说,建议把证据分成三列:已经证明的事实、合理怀疑的方向、仍然缺失的证据。事实只能来自日志、dump、trace、截图、平台记录;怀疑可以写,但必须说明下一步用什么验证。
如果多个证据互相矛盾,不要强行给结论。比如用户看到黑屏但 Window 显示可见,可能说明问题在 Surface 或 HWC;如果 boot_completed 已经为 1 但桌面不可交互,说明启动完成和可用完成不是同一个概念。
二十一、缺陷分级和发布风险
Kernel panic、watchdog bite、无日志重启、adb 断连卡死,都应要求底层证据;没有 pstore 的问题不能简单关闭为无法分析。
分级时建议同时考虑四个因素:影响范围、恢复能力、复现概率和证据完整度。影响范围越接近系统全局,恢复能力越差,复现概率越高,优先级越高。证据不完整不代表风险低,只代表需要补采。
对于阻塞类问题,报告里要明确写出阻塞理由:是否导致重启、是否导致核心功能不可用、是否影响首启或主路径、是否无法自动恢复、是否存在数据丢失风险。这样项目讨论时不会只围绕“复现概率高不高”打转。
二十二、复现最小化策略
稳定性问题经常来自复杂场景,但修复定位需要最小化路径。最小化不是删除所有条件,而是逐步去掉不必要变量,保留能触发同一异常签名的关键条件。
可以按下面顺序缩小:先固定版本和设备,再固定脚本 seed,再固定业务步骤,再拆掉网络、温度、外设、数据量等变量。每去掉一个变量,都要确认异常签名是否仍然一致。
如果 底层稳定性 的异常只在复杂场景出现,也要把复杂场景保留下来作为验收场景。最小复现用于定位,原始长链路用于验证修复没有只覆盖局部。
二十三、修复验证的对照方法
修复验证至少需要三个对照:修复前问题版本、修复后目标版本、已知稳定基线版本。没有基线时,只能证明“本轮没复现”,很难证明退化已经恢复。
验证报告要比较关键证据,而不是只写 pass。比如修复前线程栈卡在同一锁,修复后不再出现;修复前内存持续增长,修复后曲线稳定;修复前 bootreason 是 watchdog,修复后多轮压力不再出现。
如果修复涉及底层、核心服务或公共 Framework,验证范围要扩大到相邻功能。一个局部修复可能改变时序,导致其他链路出现新的稳定性问题。
二十四、团队协作边界
测试、应用、Framework、系统服务、驱动和平台团队需要共享同一条时间线。测试负责把现象和证据收齐,开发负责解释模块内部状态,平台负责补齐自动化采集和趋势报表。
不要把“归属不清”变成问题停滞的理由。归属不清时,先由最能解释第一异常的模块牵头,同时列出需要其他模块补充的证据。这样比在缺陷系统里反复改 owner 更有效。
底层问题证据窗口短,采集不及时会让一次高价值复现变成一句“设备重启”。
二十五、排障决策树
底层稳定性 的排障可以写成一棵简单决策树。第一问不是“哪个模块错了”,而是“当前证据能否说明问题发生在哪个层级”。先保住重启前后的内核证据,再区分 panic、watchdog、OOM、thermal、power 和 hang。
1 | 用户可见现象 |
如果决策树走到某一步没有证据,就不要跳过。缺少证据本身要写进问题单,并在下一轮复现前补上自动采集。这样做会让偶现问题逐步收敛,而不是每次复现都从头开始。
二十六、附件命名和归档规范
稳定性问题的附件经常很多,命名混乱会直接增加分析成本。建议按“时间点_设备_场景_内容”命名,例如 20260102-213000_deviceA_monkey_logcat_all.txt、20260102-213005_deviceA_after_anr_bugreport.zip。
同一问题至少保留三组附件:异常前最近一次周期快照、异常发生时即时快照、异常后恢复或重启后的快照。对于 底层稳定性,这三组附件能帮助判断异常是突然发生还是逐步劣化,也能排除恢复过程引入的新噪声。
归档时不要只上传压缩包。问题单正文里要列出关键附件索引:哪个文件看首个异常,哪个文件看进程状态,哪个文件看资源曲线,哪个文件看修复验证。开发不应该靠猜去翻附件。
二十七、回归矩阵示例
| 回归维度 | 基础用例 | 压力用例 | 通过标准 |
|---|---|---|---|
| 场景覆盖 | pstore、bootreason、OOM、sysrq、thermal | 在原场景上叠加长时间、弱网、低内存或高温 | 用户可见现象不复现,关键日志无同类签名 |
| 指标覆盖 | panic 签名、bootreason、LMKD 曲线、PSI、温度 | 周期采集并和基线对比 | 无持续增长、无明显退化、无门禁失败 |
| 设备覆盖 | 单设备复现验证 | 多设备、多批次或不同硬件版本 | 不出现设备特异性新增问题 |
| 时间覆盖 | 最小步骤验证 | 跨夜长稳或多轮循环 | 异常概率降到发布门禁以内 |
回归矩阵要和风险匹配。普通应用 Crash 可以用较小矩阵验证;影响 system_server、启动、显示、底层重启的问题,必须扩大设备数和时长,并保留完整证据链。
二十八、报告里的结论应该怎么写
结论不要写成“怀疑某模块问题”就结束。更好的写法是:当前证据支持什么,已经排除了什么,还缺什么,下一步如何验证。例如:当前 traces 显示调用端等待系统服务返回,服务端线程栈指向同一锁等待;暂未发现 Kernel panic 和进程死亡;下一轮需要补充 Binder transactions 与服务端 debug dump。
底层稳定性 的结论还要区分“现象结论”和“根因结论”。现象结论可以在证据不足时先给出,比如“桌面可见但输入无响应”;根因结论必须能被日志或代码变更验证,比如“某服务锁顺序导致 Binder 线程池耗尽”。
当修复验证完成后,结论应补上版本、验证轮次和残留风险:修复版本 X 在 3 台设备上完成 24 小时回归,未再出现同类日志签名;仍建议在 OTA 首启场景加入一轮扩展验证。这样的结论能支撑关闭,也方便后续版本追溯。
二十九、版本发布前复核
底层稳定性的发布复核重点,是确认每次重启和卡死都有 bootreason 或 pstore 解释。没有解释的重启不应轻易关闭;OOM 要证明是预期回收还是异常泄漏;thermal 和 power 相关问题要结合温度、电流、电量和外设状态一起判断。
发布前还要复核附件是否能独立说明问题:一个不了解背景的人,只看问题单、时间线和附件索引,应该能够复原触发过程、看到第一个异常、理解初步归因,并知道修复验证覆盖了什么。如果做不到,说明报告还停留在“记录现象”,没有达到稳定性测试输出标准。
最后要复核残留风险。并不是所有问题都必须在当前版本修完,但每个残留问题都要说明影响范围、触发概率、规避方案、监控方式和后续计划。对用户可见的黑屏、无响应、重启、核心服务不可用,风险接受必须非常谨慎;对只在实验室极端压力下出现的问题,也要确认是否可能被真实用户路径触发。
这一步看起来像流程,实际是在保护版本质量。稳定性缺陷的代价通常发生在发布后,复核越具体,线上不可控风险越少。
三十、线上监控与问题复盘
稳定性测试不应该在版本发布时结束。发布后的监控要继续沿用测试阶段的分类和证据语言,否则实验室问题和线上问题会变成两套体系,复盘时很难合并。建议把 Crash、ANR、Watchdog、Native Crash、重启、黑屏、卡顿、无响应分别建立看板,并保留版本、设备、地区、触发路径和恢复结果。
线上监控要特别关注低频高损问题。一次系统重启、一次无法恢复的黑屏、一次 system_server watchdog,数量可能不高,但用户影响远大于普通闪退。看板不能只按数量排序,还要按影响范围和恢复能力排序。对系统稳定性来说,严重度和频率同样重要。
复盘时要回到测试设计本身:这个问题是否在实验室场景里覆盖过,覆盖过为什么没有发现,没有覆盖是因为场景缺失、采集缺失、门禁缺失,还是因为版本差异。复盘的输出应当转化为下一轮自动化场景、采集脚本、门禁阈值或检查清单,而不是只停留在“以后注意”。
还要建立问题签名库。相同堆栈、相同 bootreason、相同 tombstone top frame、相同 Binder 等待关系、相同 SurfaceFlinger/HWC 错误,都应该能被归并。签名库能减少重复分析,也能帮助判断修复是否真正覆盖同类问题。
最后,稳定性指标要服务于决策,而不是服务于报表。一个版本如果没有明显 Crash,但存在无法解释的重启;或者没有 ANR 弹框,但存在大量输入延迟和长帧;或者启动总耗时达标,但 Launcher 首帧后不可交互,这些都不能简单判定为稳定。测试结论必须回到用户是否可用、系统是否可恢复、问题是否可诊断这三个基本问题。
三十一、小结
Kernel Panic、OOM、重启与卡死如何进入稳定性分析 的答案不是一个单指标,而是一套从现象到证据、从分层到归因、从修复到验证的闭环。
对测试同学来说,掌握 底层稳定性 的核心价值,是把“发现了一个问题”升级为“交付了一个可定位、可验证、可关闭的问题”。
稳定性测试的质量最终体现在报告是否能解释风险。只要报告能说明影响范围、首个异常、证据链、误判排除和验证结果,它就能真正帮助版本决策。