Android稳定性-35-last_kmsg、pstore 与 vmcore:重启和内核异常怎么分析
重启和内核异常 是 Android 稳定性测试里非常容易被写成一句话的问题,但真正能推动开发定位的材料,必须包含现象、时间、系统状态、关键日志、复现路径和排除项。本文围绕 pstore 建立一条可执行的排查链路:先判断问题类型,再采集正确证据,然后把证据按时间线组织成结论。
这篇不是命令清单,而是面向测试开发的定位方法。你应该能在读完后知道工具在哪里、每个输出看什么、哪些结论不能轻易下,以及怎样把一次偶现问题整理成开发可以继续分析的报告。
一、先定义 pstore 问题的边界
很多定位失败不是工具不会用,而是一开始没有定义边界。遇到 重启和内核异常 时,先把它拆成可验证的问题:是否发生在前台应用、是否影响整个系统、adb 是否在线、是否发生重启、是否能复现、是否和长稳时长相关。边界越清楚,后面的日志越少走弯路。
对 pstore 类问题,不要直接写“系统不稳定”。至少要写出发生时间、持续时间、用户可见现象、设备连接状态、任务类型、恢复方式,以及问题前后有没有 crash、ANR、watchdog、panic、资源上涨或服务重启。
二、定位工具在系统里的位置
这类问题通常跨越 App、Framework、Native Service、HAL 和 Kernel。工具也要分层使用:logcat 负责过程日志,bugreport 负责系统快照,dropbox 负责异常索引,dumpsys 负责服务状态,Perfetto 负责时间线,procfs 和 pstore 负责底层现场。
| 层级 | 工具 | 看什么 | 典型输出 |
|---|---|---|---|
| App/Framework | logcat、dropbox、traces | crash、ANR、主线程和 binder | logcat_all.txt、anr traces |
| System Server | dumpsys、event log | Activity、Window、Power、Display 状态 | dumpsys_window.txt |
| Native | tombstone、Perfetto | native crash、调度、合成、binder | tombstone_XX、pftrace |
| Kernel | pstore、dmesg、procfs | panic、资源、调度和驱动错误 | console-ramoops、proc 文件 |
| 平台 | 自动化报告、录屏 | 触发动作和用户视角 | 任务日志、截图、视频 |
三、第一轮采集命令
第一轮采集的目标是固定现场,不是立刻证明根因。命令应当在问题发生后尽快执行,并把输出保存到以设备、时间、任务命名的目录。
1 | adb devices |
如果设备正在卡住,优先采集不会改变现场的命令。比如先 date、uptime、dumpsys、logcat -d,再考虑按键唤醒、重启设备或重新启动服务。任何会改变状态的动作都要记录在时间线里。
四、关键日志入口和关键词
排查 pstore 时,日志搜索要围绕事件链,而不是只搜 error。建议先搜时间窗口,再搜关键词。相关关键词包括:last_kmsg, pstore/ramoops, vmcore, kmsg, dmesg, panic。还要结合 am_、wm_、power、display、binder、watchdog、lmkd、tombstone、panic 等系统词。
1 | rg -n "watchdog|ANR|am_anr|am_crash|binder|timeout|killing|lowmemory|panic|reboot|SurfaceFlinger" logcat_all.txt |
关键词只是入口。看到命中后要回看前后 1 到 5 分钟,确认它是原因、结果还是无关噪声。
五、时间线怎么搭
稳定性问题必须按时间线写。建议建立四列:平台动作、用户可见现象、系统日志、系统状态。每个证据都落到秒级时间,无法确定时写明来源。
| 时间 | 平台/用户现象 | 系统证据 | 判断 |
|---|---|---|---|
| T-300s | 任务正常运行 | 资源指标开始抬升或日志出现 timeout | 可能是前兆 |
| T-30s | 页面开始变慢 | event log 出现 input 或 binder 延迟 | 进入异常窗口 |
| T | 问题可见 | dropbox/dumpsys/perfetto 命中 | 核心现场 |
| T+60s | 恢复或重启 | 服务重启、LMKD、boot reason | 判断恢复路径 |
| T+300s | 二次采集 | bugreport、pstore、tombstone | 补充证据 |
六、pstore、last_kmsg 和 vmcore 分别解决什么
last_kmsg 是老方案,保存上一次 kernel log,很多新内核已经转向 pstore/ramoops。/sys/fs/pstore/console-ramoops-* 通常保存 panic 前后的 console 日志,dmesg-ramoops-* 可能保存上一轮 dmesg,pmsg-ramoops-* 可能包含 Android pmsg 日志。vmcore 则是内核崩溃转储,体积大,通常需要 crash 工具、vmlinux 和符号表分析。
测试侧的价值是判断是否有 Kernel panic、Oops、BUG:、Unable to handle kernel NULL pointer dereference、watchdog bite、subsys-restart、thermal shutdown 等证据,并保持原始文件不被二次开机覆盖。不要把 pstore 里的第一条 call trace 当完整根因,很多时候真正触发点在 panic 前几十秒的驱动错误。
七、如何判断根因方向
对 pstore 类问题,根因方向通常不是单点日志,而是一组证据共同指向。比如前台应用 ANR 同时出现 system_server binder 阻塞,不能直接归因到应用;CPU 高但 Perfetto 显示关键线程在 uninterruptible sleep,不能简单说是计算耗时;黑屏时 Power 状态是 ON、Display 是 ON、SurfaceFlinger 没有合成,则优先看显示链路。
判断根因时先问三个问题:异常是否发生在问题前,异常是否能解释用户现象,异常是否有独立证据支持。如果三个问题有一个回答不上来,就只能写“相关线索”,不能写“根因”。
八、表格化对比:现象、证据和下一步
| 现象 | 优先证据 | 支持判断 | 下一步 |
|---|---|---|---|
| 局部应用异常 | app crash、app ANR、进程状态 | 只影响单包,系统服务正常 | 交给应用并附主线程栈 |
| 系统服务阻塞 | watchdog、dumpsys、traces | system_server 关键线程等待 | 看锁、binder、CPU、对端服务 |
| Native/HAL 异常 | tombstone、Perfetto、HAL 日志 | native backtrace 或 HAL 超时 | 符号化并找模块 owner |
| Kernel/驱动异常 | pstore、dmesg、bootreason | panic、oops、硬件复位 | 交 kernel/vendor 并保留原始 pstore |
| 资源耗尽 | meminfo、fd、thread、binder、lmkd | 指标持续上涨并触发失败 | 做趋势图和最小复现 |
九、完整案例
背景:一台 userdebug 设备执行长稳任务,任务包含 Monkey、业务页面巡检和定时截图。第 7 小时平台记录到异常,现象属于 重启和内核异常。adb 仍能连接,但用户侧体验异常持续约 90 秒。
处理过程:先保存 date、uptime 和 bugreport,确认没有人为重启;再按问题时间窗口提取 logcat、dropbox 和 dumpsys。日志显示异常前 2 分钟已经出现 last_kmsg 相关告警,问题发生时 panic 相关状态异常。Perfetto 或系统快照进一步证明关键线程没有正常推进。最后根据证据排除脚本误触、网络波动和单一应用 crash,把问题收敛到对应系统链路。
结论写法:本次问题不是“偶现卡住”这种泛描述,而是“在某任务压力下,某链路在 T 到 T+90s 之间停止推进,导致用户可见异常;恢复后系统未重启,核心证据见附件 A/B/C”。
十、常见误判
第一,只看最后一条 error。最后打印的日志经常是结果,不是原因。第二,把平台脚本异常当系统异常,或者把系统异常推给脚本。两者要靠设备状态和用户可见现象区分。第三,只用截图证明问题。截图证明现象,不证明链路。第四,不保留原始文件,只摘录几行。开发无法复核时,结论可信度会明显下降。第五,忽略版本差异。user、userdebug、eng 的日志权限和服务输出不同,同一命令在不同版本可见内容不一样。
十一、复现和二次采集策略
如果问题能复现,要把第一轮被动采集升级为主动采集。复现前开启循环 logcat、定时 dumpsys、关键指标采样和 Perfetto 触发条件。长稳任务建议每 30 到 60 秒采集一次轻量指标,每次异常立即抓重型快照。
1 | while true; do |
循环采集要控制体积,避免日志本身把设备拖慢。关键是让指标能覆盖异常前的斜率,而不是只拿到异常后的静态值。
十二、检查清单
- 是否明确问题类型、发生时间、持续时间和恢复方式
- 是否确认 adb 在线状态、boot id、uptime 和 firstboot
- 是否保存完整 logcat、bugreport、dropbox 或对应底层文件
- 是否按时间窗口提取关键日志,而不是只搜 error
- 是否把 last_kmsg, pstore/ramoops, vmcore 等核心证据串成时间线
- 是否区分根因、触发条件、伴随现象和恢复动作
- 是否排除脚本误触、网络异常、设备离线、手动操作
- 是否保留原始附件路径和命令版本
- 是否写出未确认项和下一步需要的 owner
- 是否提供可复现任务、参数和环境信息
十三、输出物模板
1 | 问题标题:重启和内核异常 - 设备/版本/任务/发生时间 |
十四、提单时怎么写才有效
有效提单不追求把所有日志贴满正文,而是让读者 3 分钟内理解问题链路。正文写结论和证据摘要,附件放原始文件。关键日志要带文件名、时间点和检索关键词。对 pstore 问题,要明确你判断的是“疑似方向”还是“已由多项证据支持的方向”。
如果证据不足,也要诚实说明。比如“未抓到异常窗口 Perfetto,当前只能根据 dropbox 和 logcat 判断 system_server 可能被阻塞”。这种写法比强行下结论更容易推进,因为它告诉开发下一轮需要补什么。
十五、小结
last_kmsg、pstore 与 vmcore 的核心不是记命令,而是建立证据链。先定义现象,再固定时间窗口,然后按层采集:logcat 看过程,dumpsys 看状态,dropbox 看异常索引,Perfetto 看时间线,procfs/pstore 看底层现场。最后用表格、案例、检查清单和模板把结论变成可复核的工程材料。
稳定性问题通常不会因为一条日志就被解决,但一条组织良好的排查链路,能显著减少争论,把“偶现不好查”推进到“下一步由哪个模块验证”。
十六、采集目录和命名规范
pstore/last_kmsg/vmcore 问题最怕多轮采集后文件混在一起。建议目录使用 serial_build_task_time 命名,下面固定放 00_meta、01_raw、02_filtered、03_trace、04_report。00_meta 保存设备型号、系统版本、任务参数、开始时间、问题时间和操作者动作。01_raw 保存原始 bugreport、logcat、dumpsys、pstore 或 trace,任何过滤结果都不要覆盖原始文件。02_filtered 保存按时间窗口裁剪出来的关键片段。03_trace 放 Perfetto、systrace、录屏和截图。04_report 放时间线、初步结论和待确认项。
文件命名要能从名字看出来源和时间,例如 logcat_20260325_021000_022000_threadtime.txt、dumpsys_window_T_plus_10s.txt、perfetto_black_screen_30s.pftrace。这样开发拿到附件后不需要反复询问“这份日志是什么时候抓的”。
十七、时间校准方法
pstore/last_kmsg/vmcore 分析必须说明时间如何校准。自动化平台记录的是宿主机时间,Android 日志记录的是设备时间,bugreport 里还可能混有 elapsed realtime、uptime 和 wall clock。稳定性报告里至少写三项:宿主机当前时间、设备 date 输出、设备 uptime 输出。发生重启时,再补 ro.runtime.firstboot、sys.boot_completed 和 boot id。
如果问题发生在凌晨或设备离线恢复后,时间漂移更常见。不要只写“约 2 点”。更可靠的写法是:“平台记录 02:14:30,设备 date 与宿主机差 +3 秒;logcat 以设备时间为准”。如果无法校准,也要写明无法校准,并扩大日志窗口。
十八、自动化平台应该提前埋哪些点
事后定位依赖现场,但现场往往在问题发生后消失。因此平台侧要提前记录心跳:每分钟保存 date、uptime、adb 状态、前台包名、屏幕状态、关键进程 pid、top 摘要和最近 200 行事件日志。对长稳任务,还应保存任务动作流水,例如点击了哪个页面、执行了哪个 shell 命令、是否发生过 adb reconnect。
这些信息看起来零碎,但在 pstore/last_kmsg/vmcore 问题里经常决定方向。比如黑屏时如果前台包名已切到 Launcher,说明可能不是原应用页面;重启后 boot id 变化能证明确实重启;CPU 高之前动作流水显示正在批量扫描媒体,就能把复现范围缩小到媒体服务链路。
十九、如何做最小复现
最小复现不是把长稳任务原样跑 12 小时,而是从时间线里找触发条件。先看异常前 5 到 15 分钟发生了哪些重复动作,再把动作拆成可控变量:应用页面、网络状态、亮灭屏、插拔电、后台切换、压力参数、温度、内存水位和并发任务。每次只改变一个变量,记录 pstore/last_kmsg/vmcore 是否复现。
如果问题只在长时间后出现,要保留“预热阶段”和“触发阶段”。例如先循环进入页面 300 次制造资源累积,再单独执行一次唤醒或切换动作触发异常。这样比直接跑整套任务更容易让开发在本地复现,也方便验证修复是否有效。
二十、如何区分根因、诱因和后果
稳定性报告里常把三者混在一起。根因是直接导致系统进入异常状态的缺陷,诱因是触发缺陷的外部条件,后果是系统异常后的连锁表现。pstore/last_kmsg/vmcore 问题尤其需要拆开写。例如 CPU 高可能是根因,也可能是异常恢复时的后果;ANR 可能是应用主线程问题,也可能是 system_server 已经阻塞后的表现;重启可能是 watchdog 主动拉起,也可能是 kernel panic 后的结果。
判断标准是时间和因果:先发生且能解释后续现象的证据更接近根因;只在异常后出现的日志通常是后果;改变压力参数后复现概率变化的因素多半是诱因。报告中用“根因证据”“诱因条件”“伴随现象”分段,会比一句“疑似某模块问题”更有用。
二十一、版本差异和权限限制
不同 Android 版本、不同厂商 user 版本对日志权限限制不同。/data/anr、/data/tombstones、/data/system/dropbox、/sys/fs/pstore、binder debugfs 等路径在 user 版本上可能不可读。命令失败不代表没有证据,可能需要 bugreport、厂商诊断包、userdebug 复现或工程开关。
因此提单时要把命令失败也记录下来:命令、返回值、权限错误、设备版本。开发看到权限限制后,可以判断是否需要提供 eng/userdebug 包或打开额外日志。不要为了拿日志随意 root、remount 或清数据,因为这些动作可能改变复现条件。
二十二、证据摘录的尺度
正文摘录要短而准。每类证据摘 3 到 10 行关键内容即可,但必须附上原始文件名和行号或时间点。pstore/last_kmsg/vmcore 问题常见的有效摘录包括:异常 tag、reason、blocked thread、pid/tid、调用栈顶部、boot reason、资源数值、线程状态、Perfetto 时间范围。不要把几百行日志直接贴到正文里,读者会失去主线。
摘录时保留原始大小写和关键字段,不要凭印象改写。比如 Input dispatching timed out、system_server_watchdog、Kernel panic - not syncing、Too many open files 这些字符串本身就是检索入口。中文解释可以放在摘录下面。
二十三、跨团队交接方式
pstore/last_kmsg/vmcore 往往需要应用、Framework、性能、内核、显示、厂商 HAL 多个 owner 协作。测试侧交接时不要只按组织结构派单,而要按证据指向派单。应用 owner 需要包名、版本、操作路径和应用栈;Framework owner 需要 system_server traces、dumpsys 和 event log;Kernel/vendor owner 需要 pstore、dmesg、tombstone、符号版本和硬件批次。
如果证据跨层,建议在报告开头写“当前优先 owner”和“需要协同 owner”。例如“优先显示 HAL,协同 Framework Window/Display”,比同时抄送所有团队更有效。每个 owner 看到自己需要看的附件,推进速度会快很多。
二十四、回归验证怎么设计
修复后不能只跑一次原场景。要验证三个层面:第一,原始复现路径是否不再触发;第二,关键指标是否恢复到基线,例如 pstore/last_kmsg/vmcore 相关计数、延迟、资源曲线或异常 tag 是否消失;第三,长稳压力下是否没有新的连锁问题。回归报告也要保留同样的采集目录,便于和修复前对比。
如果原问题是偶现,要用概率表达结果,例如“修复前 5/20 次复现,修复后同条件 0/50 次复现,最长连续运行 24 小时”。这比“未复现”更有工程意义。若仍然出现相似现象,要确认是否同一根因,不要自动复用旧结论。
二十五、最终小结
pstore/last_kmsg/vmcore 的排查价值不在于某个单独命令,而在于把现场变成可复核的证据链。测试开发要做到三件事:第一,问题发生时尽快固定现场;第二,按时间线把日志、状态、trace 和平台动作串起来;第三,明确哪些是已证实结论,哪些只是下一步线索。
当报告能同时包含具体背景、工具位置、命令入口、表格、案例、误判、检查清单和输出模板时,问题就不再是“偶现不好查”,而是一个可以被分层分析、跨团队交接和回归验证的工程任务。
二十六、异常分级和优先级判断
pstore/last_kmsg/vmcore 问题进入缺陷系统前,建议先做分级。影响单个三方应用且可恢复的问题,可以按普通应用稳定性处理;影响系统导航、锁屏、输入、显示、电源、电话、网络等核心能力的问题,应提高优先级;出现自动重启、数据丢失、无法恢复、反复 watchdog、kernel panic 或资源耗尽导致系统级不可用时,应按高优先级推进。
分级不是为了夸大问题,而是为了匹配响应速度和日志要求。高优先级问题需要保存更完整的现场,包括原始 bugreport、trace、pstore、录屏和自动化动作流水;普通问题则可以先提供最小复现和关键日志。分级依据要写在报告中,例如“影响整机输入,adb 在线但屏幕 90 秒无响应,因此按系统级卡死处理”。
二十七、趋势采样比单点截图更重要
长稳问题往往不是瞬间发生,而是指标逐步偏离。对 pstore/last_kmsg/vmcore,单点截图只能说明某一刻异常,趋势采样才能说明异常如何形成。建议把关键指标按固定周期落盘:CPU、内存、FD、线程数、binder 调用、前台窗口、屏幕状态、温度、电量、boot id 和任务阶段。采样间隔要根据问题类型选择,资源泄漏可以 30 到 60 秒,卡顿黑屏可以 1 到 5 秒,重启类问题至少要有心跳记录。
趋势图不一定要复杂,CSV 加简单折线就能说明很多问题。比如 FD 每次进入页面增加 8 个且退出不下降,线程数每轮增加 1 个,PSS 每 30 分钟台阶式上涨,CPU 高峰与掉帧窗口完全重叠,这些都比“看起来变高了”更有说服力。趋势采样也能帮助排除误判:如果异常前指标长期稳定,根因可能不是资源累积。
二十八、附件验收标准
提交 pstore/last_kmsg/vmcore 问题前,自己先按附件验收一遍。第一,原始文件能打开,压缩包没有损坏。第二,文件名能看出设备、时间和来源。第三,关键证据在正文中有索引,开发不需要从头翻完整 bugreport。第四,隐私或账号信息已按团队规则脱敏,但没有破坏关键字段。第五,所有命令输出都来自同一台设备和同一次复现,不能把不同轮次的日志混成一个结论。
如果必须混用多轮日志,要明确标注“复现 A”“复现 B”。例如第一轮只有 dropbox,第二轮补到了 Perfetto,就不能把第二轮 Perfetto 当成第一轮的直接证据,只能写“同路径二次复现补充证明”。这种严谨性会减少后续争论。
二十九、报告口径示例
推荐报告口径是“事实、证据、判断、缺口”四段式。事实描述用户可见现象和发生条件;证据列出关键日志、状态和 trace;判断只写证据能支持的方向;缺口说明还需要谁继续分析。以 pstore/last_kmsg/vmcore 为例,不要写“系统有 bug 导致异常”,而要写“在某任务压力下,T 时刻出现某系统状态异常,与用户可见现象时间一致,当前证据指向某链路;尚缺少某层日志确认具体函数或驱动返回”。
这种口径看起来克制,但更容易被接受。它既没有把测试侧无法证明的内容说死,也没有把问题扔给开发自行猜测。稳定性测试的专业性,恰恰体现在能把不完整现场整理成边界清晰、方向明确、下一步可执行的材料。
三十、基线对比和环境控制
分析 pstore/last_kmsg/vmcore 时要有基线。基线可以来自同版本正常设备、同设备问题前的采样、上一版稳定构建或关闭压力项后的对照结果。没有基线时,很多数字无法解释:线程 180 个可能正常也可能异常,PSS 900MB 可能是业务需要也可能是泄漏,CPU 60% 可能是前台动画也可能是死循环。报告里写清楚基线来源,能让结论更稳。
环境控制同样重要。电源、温度、网络、账号、SIM 卡、屏幕亮度、日志开关、Monkey seed、任务并发数都会影响稳定性表现。复现和回归时尽量保持一致;必须改变时,要在记录里说明。否则一次“修复后不复现”可能只是温度下降或压力减小带来的假象。
三十一、给开发的最短阅读路径
最后给开发留一条最短阅读路径:先看 summary.md 的 10 行摘要,再看 timeline.md 的核心时间线,然后按正文索引打开 3 到 5 个关键附件。摘要里写清楚“现象是什么、证据指向哪里、已排除什么、需要谁继续看”。对于 pstore/last_kmsg/vmcore,建议在摘要末尾附上一个明确请求,例如“请 Display HAL owner 确认 T 时刻 present fence timeout 的返回路径”或“请 Framework owner 确认 system_server android.display 线程等待的 binder 对端”。
这条路径能减少沟通成本。稳定性问题常常附件很多,如果没有阅读顺序,开发会先看到噪声;如果阅读顺序清楚,开发能快速进入关键上下文。测试开发的交付物不只是日志集合,而是经过筛选、排序和解释的工程证据包。