Android 7系统异常问题排查(五)Framework层(下)—System Server崩溃

📅 2026/8/5 12:05:39
Android 7系统异常问题排查(五)Framework层(下)—System Server崩溃
系列目录第一篇异常机制全景图 | 第二篇Kernel Panic 与系统重启 | 第三篇Tombstone 机制 | 第四篇System Server Watchdog | 第五篇System Server 崩溃 | 第六篇ANR 机制 | 第七篇Java 层崩溃 | 第八篇Trace 机制 | 第九篇日志系统 | 第十篇实战方法论一、System Server 崩溃 vs Watchdog 超时在上一篇文章中我们探讨了 Watchdog 触发的自杀——系统卡死 → Watchdog 检测到 → 主动killProcess。本篇分析另一种形态System Server 因自身异常直接崩溃维度Watchdog 超时直接崩溃触发方式Watchdog 主动自杀未捕获异常或 Native 信号前置症状系统逐渐卡死可能无明显前兆日志特征system_server_watchdogsystem_server_crash或tombstone崩溃类型总是 Java 层自杀Java 异常 / Native crash / OOM二、崩溃类型分类2.1 Java 层未捕获异常System Server 是 Java 进程其中任何线程抛出的未捕获异常都会导致进程崩溃常见 Java 崩溃类型 ├─ NullPointerException — 空指针 ├─ ArrayIndexOutOfBounds — 数组越界 ├─ IllegalStateException — 非法状态 ├─ ClassCastException — 类型转换错误 └─ SecurityException — 权限问题2.2 Native 层崩溃System Server 通过 JNI 调用了大量 Native 代码libandroid_servers.so、libandroid_runtime.so等Native 层崩溃同样会生成 tombstone。2.3 OOM / LMK 杀掉当系统内存极度紧张时LMKLow Memory Killer可能会杀死 System Server。虽然 System Server 的oom_score_adj被设为较低值-800 左右但在极端情况下仍可能被选中。2.4 Watchdog 触发的自杀严格来说这也属于崩溃的一种但我们已经在上篇文章中详细分析过。三、崩溃处理链路源码分析3.1 System Server 的 UncaughtExceptionHandlerSystem Server 进程同样使用RuntimeInit.KillApplicationHandler作为默认的未捕获异常处理器源码路径frameworks/base/core/java/com/android/internal/os/RuntimeInit.javapublicclassRuntimeInit{// ...privatestaticIBindermApplicationObject;privatestaticvolatilebooleanmCrashingfalse;privatestaticfinalvoidcommonInit(){// 设置默认的未捕获异常处理器Thread.setDefaultUncaughtExceptionHandler(newKillApplicationHandler());}privatestaticclassKillApplicationHandlerimplementsThread.UncaughtExceptionHandler{publicvoiduncaughtException(Threadt,Throwablee){try{// 防止递归崩溃if(mCrashing)return;mCrashingtrue;// 1. 确保异常信息被记录到 logcatensureLogging(t,e);// 2. 尝试通过 AMS 记录崩溃信息if(mApplicationObjectnull){Slog.e(TAG,Attempted to log uncaught exception with null mApplicationObject.);}else{IActivityManageramActivityManagerNative.asInterface(mApplicationObject);am.handleApplicationCrash(mApplicationObject,newApplicationErrorReport.CrashInfo(e));}}catch(Throwablet2){// 连 AMS 都联系不上时直接记录日志Slog.e(TAG,Error reporting uncaught exception,t2);}finally{// 3. 终止进程Process.killProcess(Process.myPid());System.exit(10);}}}}关键设计ensureLogging()确保异常堆栈被写入 logcat即使 AMS 调用失败也能从日志中看到崩溃信息。mCrashing标志防止递归崩溃handler 自身异常时不会再次调用。3.2 System Server 与普通 App 崩溃处理的区别特性普通 AppSystem ServerFC 对话框弹出已停止运行不弹框系统进程无 UI进程影响仅该 App 被杀整个系统服务重启崩溃后用户可重新打开 AppZygote 自动重新 forkcrashCount限制连续崩溃后不再弹框N/A3.3 AMS.handleApplicationCrash() 的处理当 System Server 自身调用AMS.handleApplicationCrash()时实际上 System Server 自己就是 AMS 的宿主——这相当于自己通知自己即将崩溃。源码路径frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javapublicclassActivityManagerServiceextendsActivityManagerNativeimplementsWatchdog.Monitor,BatteryStatsImpl.BatteryCallback{// ...OverridepublicvoidhandleApplicationCrash(IBinderapp,ApplicationErrorReport.CrashInfocrashInfo){ProcessRecordrfindAppProcess(app,Crash);finalStringprocessNameappnull?system_server:rnull?unknown:r.processName;// 1. 添加 DropBox 条目addErrorToDropBox(system_server.equals(processName)?system_server_crash:crash,r,processName,null,null,null,null,null,crashInfo);// 2. 崩溃日志输出到 logcatSlog.e(TAG,*** FATAL EXCEPTION IN SYSTEM PROCESS: processName);// 3. 如果进程还存在尝试收集线程堆栈if(app!nullr!null){// dump stack traces// ...}}}关键设计System Server 崩溃时 DropBox tag 是system_server_crash而普通 App 是data_app_crash——这决定了后续日志分析时的过滤关键字。四、Zygote 重启机制4.1 Zygote 如何检测 System Server 死亡Zygote 进程在 fork System Server 之后会进入runSelectLoop()等待子进程退出源码路径frameworks/base/core/java/com/android/internal/os/ZygoteInit.javapublicclassZygoteInit{// ...publicstaticvoidmain(Stringargv[]){try{// ... 初始化 ...if(startSystemServer){pidZygote.forkSystemServer(...);if(pid0){// 子进程启动 System ServerhandleSystemServerProcess(parsedArgs);return;}}// 父进程Zygote进入主循环runSelectLoop(abiList);// ...}catch(MethodAndArgsCallercaller){caller.run();}}privatestaticvoidrunSelectLoop(StringabiList)throwsMethodAndArgsCaller{// ...while(true){// 使用 select/poll 等待子进程退出或新连接// 当 system_server 退出时Zygote 会检测到并退出}}}关键设计Zygote 通过runSelectLoop()中的select()系统调用监听子进程状态。当 system_server 退出时Zygote 会检测到 SIGCHLD 信号并退出自身进程。4.2 init 进程的编排作用源码路径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 service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin \ --zygote --socket-namezygote_secondary class main onrestart restart zygote注意onrestart配置的是重启 Zygote 依赖的 native 服务audioserver、cameraserver 等而非 system_server。当 Zygote 退出时init 会根据onrestart配置重新拉起 Zygote新 Zygote 启动时会通过--start-system-server参数自动重新 fork system_server。4.3 完整重启链路System Server 崩溃 ↓ Zygote 检测到子进程退出通过 runSelectLoop 中的 select ↓ Zygote 自身退出 ↓ init 进程检测到 Zygote 退出SIGCHLD ↓ init 根据 init.zygote*.rc 中 onrestart 配置 ├─ restart audioserver/cameraserver/media/netd └─ 重新拉起 Zygote因为 service 配置了 class main ↓ 新 Zygote 启动 → fork 出新的 System Server ↓ System Server 重新初始化所有服务AMS/WMS/PMS... ↓ 用户感知屏幕短暂黑屏/卡顿后恢复热重启五、Boot Loop 机制保护5.1 问题场景如果 System Server 在启动阶段就崩溃Zygote 会不断重启形成Boot Loop反复重启循环设备永远无法进入正常使用状态。5.2 RescuePartyAOSP 7 引入AOSP 7 引入了RescueParty机制来应对 Boot Loop源码路径frameworks/base/services/core/java/com/android/server/RescueParty.javapublicclassRescueParty{// ...publicstaticvoidnoteBoot(Contextcontext){// 系统启动成功后调用// 重置重启计数}publicstaticvoidnoteSystemServerRestart(Contextcontext){// System Server 每次重启时调用// 如果在短时间内重启次数过多 → 进入救援模式if(getRestartCount()THRESHOLD){executeRescueLevel(context,nextLevel());}}privatestaticvoidexecuteRescueLevel(Contextcontext,intlevel){switch(level){caseLEVEL_RESET_SETTINGS:// 1. 重置系统设置到出厂值resetGlobalSettings(context);break;caseLEVEL_RESET_TRUSTED_DEFAULTS:// 2. 恢复可信任的默认配置resetTrustedDefaults(context);break;caseLEVEL_FACTORY_RESET:// 3. 恢复出厂设置RecoverySystem.rebootWipeUserData(context,...);break;}}}关键设计RescueParty 通过持久化存储记录 System Server 重启次数。如果短时间内重启超过阈值会逐级执行恢复策略重置设置 → 恢复默认 → 恢复出厂。Rescue Level 递进频繁重启 Level 1 → 重置系统设置 仍然重启 Level 2 → 恢复可信任默认值 仍然重启 Level 3 → 提示用户恢复出厂设置六、日志产物分析6.1 logcat 中的关键日志// Java 层崩溃 AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: main AndroidRuntime: java.lang.NullPointerException: ... AndroidRuntime: at com.android.server.am.ActivityManagerService.xxx(AMS.java:1234) // Native 层崩溃 libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 1234 (system_server) // Zygote 重启 Zygote: Process 1234 exited due to signal 11 Zygote: Exit zygote because system server (1234) has terminated6.2 DropBox 条目dumpsys dropbox system_server_crash--print输出包含完整的 Java 异常堆栈Tag: system_server_crash Process: system_server Flags: 0x28... Package: android Subject: system_server ... java.lang.NullPointerException at com.android.server.am.ActivityManagerService.xxx(AMS.java:1234) at ...6.3 tombstoneNative Crash 时如果 System Server 是 Native 层崩溃/data/tombstones/中也会有墓碑文件按第三篇的方法还原即可。七、定位方法论区分 Watchdog 自杀 vs 直接崩溃判断依据Watchdog 自杀直接崩溃logcat 关键字WATCHDOG KILLING SYSTEM PROCESSFATAL EXCEPTION IN SYSTEM PROCESSDropBox tagsystem_server_watchdogsystem_server_crash堆栈特征线程多处于 Blocked/Waiting明确抛出java.lang.XXX异常tombstone一般没有Native crash 时有定位步骤1. 确认崩溃类型 → logcat 搜索 FATAL EXCEPTION IN SYSTEM PROCESS → 或 Fatal signal (Native crash) 2. 提取异常信息 → dumpsys dropbox system_server_crash --print → 或 /data/tombstones/tombstone_XX (Native crash) 3. 分析异常堆栈 → Java crash: 直接看异常类名 堆栈行号 → Native crash: ndk-stack 还原 4. 回溯崩溃前日志 → logcat -b all -d | grep -B 50 FATAL EXCEPTION → 寻找崩溃前的异常操作或错误日志 5. 确定根因 → 代码逻辑错误 → 修改代码 → 资源问题OOM → 优化内存 → 驱动问题Native crash → 排查驱动八、总结System Server 崩溃有四种形态Java 异常、Native crash、OOM/LMK、Watchdog 自杀。KillApplicationHandler 是所有 Java 崩溃的统一入口System Server 与普通 App 共用但处理不同不弹 FC 框。Zygote runSelectLoop init onrestart 自动恢复机制System Server 死亡后 Zygote 退出 → init 重新拉起 → 系统热重启。RescueParty 防止 Boot Loop多次启动失败后逐级执行恢复策略最终可能触发恢复出厂设置。日志产物区分 Watchdog vs Crashsystem_server_watchdogvssystem_server_crash。下一篇将进入应用层异常——ANR 机制全解。本文基于 AOSP 7Android Nougat源码编写。