3. Crash类型全景
Android 稳定性问题从来不是单一故障,而是一组跨越 Java 虚拟机、Native 运行时、Linux 内核、系统服务与资源管理子系统的“故障家族”。很多工程师在拿到一份日志时,第一反应是搜索 FATAL EXCEPTION,但真正的稳定性诊断,第一步应当是判断故障发生在哪一层、由谁触发、以什么方式终止。只有先完成类型归类,后续的符号化、堆栈分析、内存快照和复现路径才有意义。
一、按“故障发生层”建立分类坐标系
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 与内核内存管理子系统。
二、七类故障的关键特征与日志入口
下表把七类故障放在同一张对照表中,便于在排障时快速定位“应该先看哪个文件”。
| 类型 | 触发层 | 典型日志入口 | 进程影响 | 用户现象 |
|---|---|---|---|---|
| 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 | 整机 | 自动重启、卡死 |
三、从日志到归类的判断流程
实际排障时,建议按以下顺序判断,避免一上来就陷入堆栈细节:
- 先看设备是否重启:读取
ro.boot.bootreason或/sys/fs/pstore/,若存在Kernel panic或watchdog字样,优先归入内核或系统级故障。 - 再看是否有 ANR 弹窗或 traces:检查
/data/anr/目录下最新文件的时间戳,确认是否与故障时间吻合。 - 再查 tombstone:若存在 Native 崩溃,
debuggerd会生成 tombstone,重点看signal、fault addr与backtrace。 - 最后查 logcat 中的 FATAL EXCEPTION:Java 崩溃通常最容易被发现,但也最容易被误判为根因。
四、典型案例:一次“闪退”背后的三层故障
某应用在低内存设备上频繁闪退,最初日志只显示 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 四类日志按时间对齐,才能还原完整因果链。