系列目录 :第一篇:异常机制全景图 | [第二篇:Kernel Panic 与系统重启](#第二篇:Kernel Panic 与系统重启) | [第三篇:Tombstone 机制](#第三篇:Tombstone 机制) | [第四篇:System Server Watchdog](#第四篇:System Server Watchdog) | [第五篇:System Server 崩溃](#第五篇:System Server 崩溃) | [第六篇:ANR 机制](#第六篇:ANR 机制) | [第七篇:Java 层崩溃](#第七篇:Java 层崩溃) | [第八篇:Trace 机制](#第八篇:Trace 机制) | 第九篇:日志系统 | 第十篇:实战方法论
一、System Server 崩溃 vs Watchdog 超时
在上一篇文章中我们探讨了 Watchdog 触发的"自杀"------系统卡死 → Watchdog 检测到 → 主动 killProcess。本篇分析另一种形态:System Server 因自身异常直接崩溃:
| 维度 | Watchdog 超时 | 直接崩溃 |
|---|---|---|
| 触发方式 | Watchdog 主动自杀 | 未捕获异常或 Native 信号 |
| 前置症状 | 系统逐渐卡死 | 可能无明显前兆 |
| 日志特征 | system_server_watchdog |
system_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 杀掉
当系统内存极度紧张时,LMK(Low Memory Killer)可能会杀死 System Server。虽然 System Server 的 oom_score_adj 被设为较低值(-800 左右),但在极端情况下仍可能被选中。
2.4 Watchdog 触发的自杀
严格来说这也属于崩溃的一种,但我们已经在上篇文章中详细分析过。
三、崩溃处理链路源码分析
3.1 System Server 的 UncaughtExceptionHandler
System Server 进程同样使用 RuntimeInit.KillApplicationHandler 作为默认的未捕获异常处理器:
源码路径 :frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
java
public class RuntimeInit {
// ...
private static IBinder mApplicationObject;
private static volatile boolean mCrashing = false;
private static final void commonInit() {
// 设置默认的未捕获异常处理器
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler());
}
private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
try {
// 防止递归崩溃
if (mCrashing) return;
mCrashing = true;
// 1. 确保异常信息被记录到 logcat
ensureLogging(t, e);
// 2. 尝试通过 AMS 记录崩溃信息
if (mApplicationObject == null) {
Slog.e(TAG, "Attempted to log uncaught exception "
+ "with null mApplicationObject.");
} else {
IActivityManager am = ActivityManagerNative.asInterface(
mApplicationObject);
am.handleApplicationCrash(mApplicationObject,
new ApplicationErrorReport.CrashInfo(e));
}
} catch (Throwable t2) {
// 连 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 崩溃处理的区别
| 特性 | 普通 App | System Server |
|---|---|---|
| FC 对话框 | 弹出"已停止运行" | 不弹框(系统进程无 UI) |
| 进程影响 | 仅该 App 被杀 | 整个系统服务重启 |
| 崩溃后 | 用户可重新打开 App | Zygote 自动重新 fork |
crashCount 限制 |
连续崩溃后不再弹框 | N/A |
3.3 AMS.handleApplicationCrash() 的处理
当 System Server 自身调用 AMS.handleApplicationCrash() 时,实际上 System Server 自己就是 AMS 的宿主------这相当于"自己通知自己即将崩溃"。
源码路径 :frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
java
public class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
// ...
@Override
public void handleApplicationCrash(IBinder app,
ApplicationErrorReport.CrashInfo crashInfo) {
ProcessRecord r = findAppProcess(app, "Crash");
final String processName = app == null ? "system_server"
: r == null ? "unknown" : r.processName;
// 1. 添加 DropBox 条目
addErrorToDropBox(
"system_server".equals(processName) ? "system_server_crash"
: "crash",
r, processName, null, null, null, null, null, crashInfo);
// 2. 崩溃日志输出到 logcat
Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + processName);
// 3. 如果进程还存在,尝试收集线程堆栈
if (app != null && r != 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.java
java
public class ZygoteInit {
// ...
public static void main(String argv[]) {
try {
// ... 初始化 ...
if (startSystemServer) {
pid = Zygote.forkSystemServer(...);
if (pid == 0) {
// 子进程:启动 System Server
handleSystemServerProcess(parsedArgs);
return;
}
}
// 父进程(Zygote):进入主循环
runSelectLoop(abiList);
// ...
} catch (MethodAndArgsCaller caller) {
caller.run();
}
}
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
// ...
while (true) {
// 使用 select/poll 等待子进程退出或新连接
// 当 system_server 退出时,Zygote 会检测到并退出
}
}
}
关键设计 :Zygote 通过
runSelectLoop()中的select()系统调用监听子进程状态。当 system_server 退出时,Zygote 会检测到 SIGCHLD 信号并退出自身进程。
4.2 init 进程的编排作用
源码路径 :system/core/rootdir/init.zygote32_64.rc
ini
service zygote /system/bin/app_process32 -Xzygote /system/bin \
--zygote --start-system-server --socket-name=zygote
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-name=zygote_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 RescueParty(AOSP 7 引入)
AOSP 7 引入了 RescueParty 机制来应对 Boot Loop:
源码路径 :frameworks/base/services/core/java/com/android/server/RescueParty.java
java
public class RescueParty {
// ...
public static void noteBoot(Context context) {
// 系统启动成功后调用
// 重置重启计数
}
public static void noteSystemServerRestart(Context context) {
// System Server 每次重启时调用
// 如果在短时间内重启次数过多 → 进入救援模式
if (getRestartCount() > THRESHOLD) {
executeRescueLevel(context, nextLevel());
}
}
private static void executeRescueLevel(Context context, int level) {
switch (level) {
case LEVEL_RESET_SETTINGS:
// 1. 重置系统设置到出厂值
resetGlobalSettings(context);
break;
case LEVEL_RESET_TRUSTED_DEFAULTS:
// 2. 恢复可信任的默认配置
resetTrustedDefaults(context);
break;
case LEVEL_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 terminated
6.2 DropBox 条目
bash
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 tombstone(Native Crash 时)
如果 System Server 是 Native 层崩溃,/data/tombstones/ 中也会有墓碑文件,按第三篇的方法还原即可。
七、定位方法论
区分 Watchdog 自杀 vs 直接崩溃
| 判断依据 | Watchdog 自杀 | 直接崩溃 |
|---|---|---|
| logcat 关键字 | WATCHDOG KILLING SYSTEM PROCESS |
FATAL EXCEPTION IN SYSTEM PROCESS |
| DropBox tag | system_server_watchdog |
system_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 Crash :
system_server_watchdogvssystem_server_crash。
下一篇将进入应用层异常------ANR 机制全解。
本文基于 AOSP 7(Android Nougat)源码编写。