3. Crash类型全景

Android 稳定性问题从来不是单一故障,而是一组跨越 Java 虚拟机、Native 运行时、Linux 内核、系统服务与资源管理子系统的“故障家族”。很多工程师在拿到一份日志时,第一反应是搜索 FATAL EXCEPTION,但真正的稳定性诊断,第一步应当是判断故障发生在哪一层、由谁触发、以什么方式终止。只有先完成类型归类,后续的符号化、堆栈分析、内存快照和复现路径才有意义。

本节的核心目标:建立一张“Crash 类型地图”,把 Java 崩溃、Native 崩溃、Kernel Panic、ANR、Watchdog、OOM、重启与死机放到同一坐标系中,理解它们的触发层、典型日志入口、进程影响范围和用户可感知现象。

一、按“故障发生层”建立分类坐标系

Android 系统可以粗略划分为四层:应用框架层(Java/Kotlin)、Native 运行时层(C/C++、so 库)、系统服务层(system_server、SurfaceFlinger 等)、Linux 内核层。不同层的崩溃,其信号来源、日志文件和恢复策略完全不同。

Java 崩溃由 ART 虚拟机抛出未捕获异常,进程收到 SIGQUIT 或直接终止,日志入口是 logcat 中的 FATAL EXCEPTION 与 tombstone 中的 Java 堆栈。Native 崩溃则由信号触发,如 SIGSEGV、SIGABRT、SIGBUS,由 debuggerd 捕获并生成 tombstone,日志入口是 /data/tombstones/ 与 logcat 中的 DEBUG 段。Kernel Panic 是内核自身无法继续运行,通常由空指针、内存越界、驱动缺陷或硬件异常引发,表现为 Kernel panic - not syncing,随后设备重启或彻底死机。

ANR 与 Watchdog 不是“崩溃”,而是“卡死”类问题。ANR 由 AMS 监测主线程消息超时触发,日志入口是 /data/anr/traces.txt;Watchdog 由 system_server 内部监测关键服务锁超时触发,日志入口是 logcat 中的 WATCHDOG KILLING SYSTEM PROCESS。OOM 则分为 Java 堆 OOM、Native 内存 OOM 和内核 OOM Killer 三类,触发主体分别是 ART、malloc 与内核内存管理子系统。

Android 稳定性故障分层地图 按发生层、触发者、日志入口与恢复方式归类 应用框架层 Java / Kotlin · ART Native 运行时层 C / C++ · so 库 · JNI 系统服务层 system_server · AMS · WMS Linux 内核层 内存管理 · 驱动 · 调度 Java 崩溃 FATAL EXCEPTION 进程终止 · 可捕获 Native 崩溃 SIGSEGV / SIGABRT tombstone · debuggerd ANR 主线程超时 · AMS 触发 traces.txt · 弹窗 OOM Java 堆 / Native / 内核 lmkd · OOM Killer Watchdog system_server 锁超时 杀死系统进程 · 重启 Kernel Panic 内核无法继续运行 pstore · 立即重启 重启与死机(最终表现) 自动重启 · 卡死黑屏 · 无限重启 · 关机 由上层故障或内核故障收敛而来 可捕获 可符号化 影响单进程 系统级监测 影响体验 可能杀进程 系统级故障 影响全局 常伴随重启 用户可感知 需结合日志 回溯根因

二、七类故障的关键特征与日志入口

下表把七类故障放在同一张对照表中,便于在排障时快速定位“应该先看哪个文件”。

类型 触发层 典型日志入口 进程影响 用户现象
Java 崩溃 ART / 应用进程 logcat FATAL EXCEPTION 单进程终止 应用闪退
Native 崩溃 Native 运行时 /data/tombstones/、DEBUG 段 单进程终止 应用闪退、无提示
Kernel Panic Linux 内核 pstore、last_kmsg、串口 整机不可用 突然重启或黑屏
ANR AMS 监测主线程 /data/anr/traces.txt 应用无响应 弹窗“无响应”
Watchdog system_server logcat WATCHDOG KILLING 系统进程被杀 系统重启、界面卡死
OOM ART / malloc / 内核 logcat、dmesg、lmkd 日志 进程被杀或分配失败 后台被杀、闪退
重启与死机 综合表现 boot reason、pstore 整机 自动重启、卡死

三、从日志到归类的判断流程

实际排障时,建议按以下顺序判断,避免一上来就陷入堆栈细节:

  1. 先看设备是否重启:读取 ro.boot.bootreason 或 /sys/fs/pstore/,若存在 Kernel panic 或 watchdog 字样,优先归入内核或系统级故障。
  2. 再看是否有 ANR 弹窗或 traces:检查 /data/anr/ 目录下最新文件的时间戳,确认是否与故障时间吻合。
  3. 再查 tombstone:若存在 Native 崩溃,debuggerd 会生成 tombstone,重点看 signal、fault addr 与 backtrace。
  4. 最后查 logcat 中的 FATAL EXCEPTION:Java 崩溃通常最容易被发现,但也最容易被误判为根因。
判断口诀:先分层,再分类,后定位。重启类问题优先看内核与 Watchdog;闪退类问题优先看 tombstone 与 FATAL EXCEPTION;卡死类问题优先看 ANR traces 与 system_server 日志。

四、典型案例:一次“闪退”背后的三层故障

某应用在低内存设备上频繁闪退,最初日志只显示 Java 层 OutOfMemoryError。继续排查发现:Native 层存在持续增长的 bitmap 缓存,导致进程 RSS 超过阈值;lmkd 触发后杀死进程,Java 层表现为 OOM 崩溃。若只看 Java 堆栈,会误判为“Java 内存泄漏”,而真正根因在 Native 内存未释放。

// 典型 tombstone 片段
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
backtrace:
  #00 pc 000000000001a2b4  /system/lib64/libc.so
  #01 pc 000000000002c1d8  /data/app/libnative.so

// 典型 ANR traces 片段
"main" prio=5 tid=1 Native
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x...
  at android.os.MessageQueue.nativePollOnce(Native method)

五、常见误区与复盘要点

  • 误区一:把 ANR 当崩溃。ANR 是“无响应”,进程可能仍存活,不能按崩溃流程处理。
  • 误区二:只看 Java 堆栈。Native 崩溃、OOM Killer、Watchdog 都可能表现为“应用闪退”,必须交叉验证。
  • 误区三:忽略 boot reason。重启类问题若不看 bootreason,很容易把内核问题误判为应用问题。
  • 复盘要点:建立“故障时间轴”,把 logcat、tombstone、anr、pstore 四类日志按时间对齐,才能还原完整因果链。
稳定性排障最忌讳“单日志定根因”。同一现象可能由不同层触发,必须结合进程状态、系统负载、内存水位与重启记录综合判断。