Android 7系统异常问题排查(一)异常机制全景图

Android 7系统异常问题排查(一)异常机制全景图
系列目录第一篇异常机制全景图 | 第二篇Kernel Panic 与系统重启 | 第三篇Tombstone 机制 | 第四篇System Server Watchdog | 第五篇System Server 崩溃 | 第六篇ANR 机制 | 第七篇Java 层崩溃 | 第八篇Trace 机制 | 第九篇日志系统 | 第十篇实战方法论一、为什么需要全景图你可能遇到过这些场景设备突然黑屏重启日志里只留下一句Kernel panic - not syncingApp 弹出应用无响应对话框但不知道是主线程卡死还是 Binder 调用超时某个 native 进程悄无声息地消失只在/data/tombstones/留下一个二进制文件系统整体卡死几十秒后自动重启用户只看到系统在重启这些表象背后对应的是不同层级、不同类型的异常机制。如果缺乏全局认知拿到一份tombstone或traces.txt时很容易陷入看得懂每行字却不知道从哪里下手的困境。本文从AOSP 7Android Nougat源码出发绘制一张完整的 Android 异常机制全景图让你在面对任何异常时都能快速判断这是什么类型的异常属于哪一层的问题应该看什么日志/文件从哪里开始分析二、异常分类体系Android 的异常机制可以从两个维度进行分类层次维度和表现维度。2.1 按层次划分四层异常模型Android 系统从底层硬件到上层应用可以分为四个层次每一层都有各自的异常检测和处理机制┌──────────────────────────────────────────────┐ │ 第四层应用程序层 (App) │ │ ├─ Java Crash (UncaughtExceptionHandler) │ │ ├─ ANR (Application Not Responding) │ │ └─ Native Crash in App (JNI 层崩溃) │ ├──────────────────────────────────────────────┤ │ 第三层Framework 框架层 │ │ ├─ System Server 崩溃 │ │ ├─ System Server Watchdog (系统看门狗) │ │ └─ Binder 通信异常 (DeadObject 等) │ ├──────────────────────────────────────────────┤ │ 第二层Native 原生层 │ │ ├─ Native 进程崩溃 → Tombstone │ │ ├─ debuggerd (崩溃调试守护进程) │ │ └─ 信号处理 (SIGSEGV/SIGABRT/SIGBUS 等) │ ├──────────────────────────────────────────────┤ │ 第一层Linux 内核层 │ │ ├─ Kernel Panic (内核崩溃) │ │ ├─ Hard/Soft Lockup (内核死锁) │ │ ├─ OOM Killer / LMK (内存不足杀进程) │ │ └─ 硬件异常 (内存位翻转、总线错误等) │ └──────────────────────────────────────────────┘各层职责与关键源码路径层次职责关键源码路径 (AOSP 7)Kernel内核自身稳定性硬件异常处理kernel/panic.c,kernel/watchdog.cNative守护进程/原生服务崩溃监控system/core/debuggerd/Framework系统服务存活检测进程管理frameworks/base/services/core/java/com/android/server/App应用崩溃收集、ANR 检测frameworks/base/core/java/android/app/2.2 按表现划分六大异常类型异常类型表现检测者典型产物Kernel Panic内核崩溃手机黑屏重启无任何提示内核panic()函数last_kmsg,ramoopsWatchdog Timeout系统卡死系统整体无响应数十秒后自动重启System Server Watchdogdropbox,traces.txtSystem Server Crash系统服务崩溃系统界面消失短暂黑屏后恢复Zygote / init 进程dropbox,tombstoneANR应用无响应弹出应用无响应对话框AMS InputDispatchertraces.txt,dropboxApp Crash应用崩溃弹出已停止运行对话框RuntimeInit.KillApplicationHandlerdropbox,logcatNative Crash原生进程崩溃服务/进程异常退出debuggerd daemontombstone_xx文件这六种异常正是后续 9 篇博客的核心主题。三、异常检测与传递链路理解异常在各层之间如何传递是定位问题的关键。3.1 硬件异常 → 内核 panic → 系统重启硬件异常 (如内存位翻转) │ ▼ 内核检测到不可恢复的错误 │ ├─ arm64: do_sea() / do_bad() 等异常向量 │ └─ 调用 die() → panic() ▼ panic() 执行 ├─ local_irq_disable() — 关中断 ├─ pr_emerg() dump_stack() — 打印 panic 信息和调用栈 ├─ smp_send_stop() — 停止所有其他 CPU 核心 ├─ kmsg_dump() — 将内核日志写入 pstore/ramoops └─ emergency_restart() — 硬件复位 ▼ 设备重启 ├─ BootLoader 读取重启原因 (reboot reason) ├─ 内核启动 → init 进程挂载 pstore → 恢复 last_kmsg └─ Zygote 启动 → 系统恢复关键设计panic()先打印日志再停止其他 CPU——因为smp_send_stop()之后当前 CPU 是唯一存活的如果先停 CPU 就无法输出日志了。3.2 用户态崩溃链路App Java 层崩溃以一次应用 Java 层崩溃为例App 线程中抛出未捕获异常 (如 NullPointerException) │ ▼ Thread.dispatchUncaughtException() │ ▼ ThreadGroup.uncaughtException() │ ▼ RuntimeInit.KillApplicationHandler.uncaughtException() │ ├─ 收集异常信息 (类名、消息、堆栈) │ ├─ 通过 Binder 调用 AMS.handleApplicationCrash() │ └─ Process.killProcess(Process.myPid()) — 立即自杀 ▼ AMS.handleApplicationCrash() 处理 ├─ 将 CrashInfo 写入 DropBoxManagerService ├─ 弹出应用已停止运行对话框 (AppErrorDialog) └─ 更新 ProcessRecord 的崩溃计数源码路径frameworks/base/core/java/com/android/internal/os/RuntimeInit.java// RuntimeInit 中设置的 UncaughtExceptionHandlerprivatestaticfinalclassKillApplicationHandlerimplementsThread.UncaughtExceptionHandler{// ...OverridepublicvoiduncaughtException(Threadt,Throwablee){// ... 收集 CrashInfoActivityManagerNative.getDefault().handleApplicationCrash(mApplicationObject,newApplicationErrorReport.CrashInfo(e));// 立即杀死自身进程Process.killProcess(Process.myPid());System.exit(10);}}关键设计handleApplicationCrash()调用完成后才执行killProcess()——确保 AMS 有机会记录崩溃信息后再让进程退出。3.3 System Server 崩溃链路System Server 崩溃的处理链路更特殊——因为它是系统服务进程由 Zygote fork 而来system_server 崩溃 (Java/Native/OOM) │ ▼ Zygote 检测到 system_server 子进程退出 │ ▼ Zygote 自身退出因为 system_server 是其关键子进程 │ ▼ init 进程检测到 Zygote 退出 → 根据 init.zygote*.rc 中的配置重新拉起 Zygote │ (onrestart restart audioserver / cameraserver / media / netd) ▼ 新 Zygote fork 出新 system_server (--start-system-server) │ ▼ System Server 启动 → 恢复所有系统服务 (AMS, WMS, PMS ...) │ ▼ 用户感知界面短暂卡顿/黑屏后恢复 (类似热重启)源码路径system/core/rootdir/init.zygote32_64.rcservice zygote /system/bin/app_process32 -Xzygote /system/bin \ --zygote --start-system-server --socket-namezygote class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart netd关键设计Zygote 的onrestart配置的是重启其依赖的 native 服务audioserver、cameraserver 等而非 system_server——因为 system_server 是 Zygote 自己 fork 的新 Zygote 启动时会通过--start-system-server参数自动重新 fork。四、异常产物对照表理解什么异常 → 产什么日志 → 日志在哪里这个映射关系是问题定位的第一步异常场景异常产物存储位置解读工具Kernel Paniclast_kmsg/ramoops/proc/last_kmsg或/sys/fs/pstore/文本查看 (内核栈回溯)Native Crashtombstone_xx/data/tombstones/(最多 10 个)ndk-stack,addr2lineApp/System Crash (Java)dropbox 条目/data/system/dropbox/dumpsys dropboxANRtraces.txt/data/anr/文本查看 (线程状态分析)Watchdog 超时dropbox 条目 traces/data/system/dropbox//data/anr/同上通用logcat 缓冲区logd 守护进程管理adb logcat4.1 DropBox 条目类型速查DropBox 中存放了各类异常的详细信息通过dumpsys dropbox --print可以查看。关键条目类型包括DropBox Tag对应异常包含内容system_server_crashSystem Server 崩溃异常堆栈、进程信息system_server_watchdogSystem Server Watchdog各线程堆栈、锁信息SYSTEM_TOMBSTONENative 系统进程崩溃完整的 tombstone 文本SYSTEM_BOOT系统重启重启原因data_app_crash普通应用崩溃异常类名、消息、堆栈data_app_anr应用 ANRCPU 使用率、线程堆栈五、问题定位一般流程无论面对什么类型的异常都可以遵循以下通用的排障流程┌─────────────────────────────────────────┐ │ 第一步识别异常类型 │ │ ├─ 黑屏重启→ Kernel Panic / Watchdog │ │ ├─ 弹 ANR 框→ ANR │ │ ├─ 弹 FC 框→ App Crash │ │ ├─ 进程消失→ Native Crash / LMK │ │ └─ 系统卡死→ Watchdog │ ├─────────────────────────────────────────┤ │ 第二步收集第一手日志 │ │ ├─ adb bugreport bugreport.zip │ │ ├─ /data/anr/traces.txt │ │ ├─ /data/tombstones/tombstone_* │ │ ├─ /proc/last_kmsg (或 pstore) │ │ └─ adb logcat -b all -d logcat.txt │ ├─────────────────────────────────────────┤ │ 第三步从产物中定位关键信息 │ │ ├─ 异常签名致命信号/异常类名 │ │ ├─ 时间戳确定异常发生的精确时间 │ │ ├─ 调用栈找到出错的代码路径 │ │ └─ 上下文异常发生前后的系统状态 │ ├─────────────────────────────────────────┤ │ 第四步推断根因 │ │ ├─ 代码逻辑错误→ 修改代码 │ │ ├─ 资源竞争/死锁→ 调整同步策略 │ │ ├─ 内存不足→ 优化内存使用 │ │ └─ 硬件故障→ 更换硬件 / 降频 │ ├─────────────────────────────────────────┤ │ 第五步验证修复 │ │ ├─ 复现测试 │ │ ├─ 增加日志打点 │ │ └─ 回归测试 │ └─────────────────────────────────────────┘六、AOSP 7 源码模块索引为了方便后续深入源码阅读这里整理出 AOSP 7 中与异常机制相关的核心源码目录6.1 内核层文件功能kernel/panic.c内核 panic 核心实现kernel/watchdog.cSoft/Hard lockup 检测drivers/staging/android/lowmemorykiller.cAndroid LMK 驱动fs/pstore/panic 日志持久化框架6.2 Native 层路径功能system/core/debuggerd/崩溃调试守护进程tombstone 生成器system/core/libbacktrace/调用栈回溯库system/core/logd/日志守护进程bionic/libc/Bionic C 库信号处理相关bionic/linker/动态链接器6.3 Framework 层路径功能frameworks/base/services/core/java/com/android/server/Watchdog.javaSystem Server 看门狗frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javaAMSANR 检测、崩溃处理frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java广播 ANR 超时检测frameworks/base/services/core/java/com/android/server/am/ActiveServices.java服务 ANR 超时检测frameworks/base/services/core/java/com/android/server/DropBoxManagerService.java异常日志持久化frameworks/base/core/java/com/android/internal/os/RuntimeInit.javaUncaughtExceptionHandler 设置6.4 输入系统Input ANR 相关路径功能frameworks/base/services/core/java/com/android/server/input/InputManagerService.java输入管理服务frameworks/native/services/inputflinger/InputDispatcher.cpp输入分发器Native 层七、系列博客预告本文是系列的第 1 篇后续 9 篇将逐一深入剖析每一种异常机制篇次标题核心内容2内核异常Kernel Panic 与系统重启panic 流程、hard/soft lockup、pstore/ramoops3Native 异常Tombstone 机制深度解析debuggerd 源码、信号处理、墓碑还原4Framework 异常上System Server WatchdogMonitor vs HandlerChecker、超时处理5Framework 异常下System Server 崩溃崩溃链路、Zygote 重启、boot loop6应用异常上ANR 机制全解Input/Broadcast/Service ANRtraces.txt 精读7应用异常下APK Java 层崩溃UncaughtExceptionHandler、FC 流程、堆栈分析8系统追踪Trace 机制与性能诊断ftrace/atrace/systrace 实战9日志系统从 logcat 到 bugreportlogd、dmesg、dropbox、bugreport 全景10实战篇异常问题定位方法论典型案例、工具链串联、排障 Checklist八、总结这篇全景图的核心要点可以归纳为四个牢记牢记四层架构Kernel → Native → Framework → App每一层都有独立的异常检测机制但又通过进程父子关系、Binder 通信等相互关联。牢记六大异常Kernel Panic、Watchdog、System Server Crash、ANR、App Crash、Native Crash每种异常有特定的触发条件、检测者和日志产物。牢记日志产物映射last_kmsg找内核问题tombstone找 native 崩溃traces.txt找 ANR/Watchdogdropbox找 Java 层崩溃logcat做时间线还原。牢记五步排障法识别类型 → 收集日志 → 定位关键信息 → 推断根因 → 验证修复循序渐进避免瞎猜式分析。有了这张全景图在手下一篇我们将深入到最底层——内核层面详细解析 Kernel Panic 的触发机制、现场保存原理以及如何从last_kmsg和ramoops中还原崩溃现场。本文基于 AOSP 7Android Nougat, API 24-25源码编写。后续版本的实现可能有所差异但核心架构和定位思路是通用的。