第十板块:Android 系统稳定性与调试 | 第二十五篇:Watchdog 与 ANR 的系统级监控
所属板块:第十板块 --- Android 系统稳定性与调试
前置知识:第九板块中的多媒体架构(Camera/HAL3/AudioFlinger)、System Server 内部机制、Binder IPC 线程模型、Linux 信号机制(SIGQUIT)
本篇定位 :这是 Android 系统自我诊断与自我修复的最后一道防线 。如果说前面的组件是器官,那么 Watchdog 就是免疫系统 。本篇将彻底拆解 System Server Watchdog 的监测模型、ANR(Application Not Responding) 的触发与检测机制、Monitor 接口 的心跳检测、Native Crash 与 Java Crash 的区别、Tombstone 的生成与分析。我们将深入 Watchdog 线程 、ActivityManagerService 的 ANR 逻辑 、Signal Catcher 线程,揭示 Android 如何在系统即将死锁或应用无响应时,优雅地收集证据并重启。全程无抓 Crash 技巧、无 ANR 排查指南,仅保留 Android 稳定性系统的底层定义与监控规范。
1. 核心结论先行(Thesis Statement)
Android 的稳定性监控是一个基于超时与死锁检测的双重保险系统。
- Watchdog 的本质 :系统服务的心跳监护仪 。它运行在 System Server 的独立线程中,定期向关键系统服务(AMS, WMS, PMS 等)发送 Monitor 检查 。如果服务在规定时间内没有响应,Watchdog 判定系统死锁,触发 Kernel Panic 或 System Server 重启。
- ANR 的本质 :应用主线程的超时陷阱 。当应用主线程在特定操作(Input, Broadcast, Service)上阻塞超过阈值(5秒/10秒/60秒),ActivityManagerService 判定应用无响应,弹出 ANR 对话框并生成 /data/anr/traces.txt。
- Monitor 的本质 :死锁探测接口 。系统服务实现
Watchdog.Monitor接口,在monitor()方法中尝试获取关键锁。如果获取不到,说明发生了死锁。 - Tombstone 的本质 :进程临终快照。当 Native 层发生严重错误(段错误、非法指令)时,系统生成一份包含寄存器、堆栈、内存映射的二进制墓碑文件。
2. 稳定性监控全景图
2.1 系统级监控架构
#mermaid-svg-aY0K5Garg6pnA34x{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-aY0K5Garg6pnA34x .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-aY0K5Garg6pnA34x .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-aY0K5Garg6pnA34x .error-icon{fill:#552222;}#mermaid-svg-aY0K5Garg6pnA34x .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aY0K5Garg6pnA34x .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-aY0K5Garg6pnA34x .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aY0K5Garg6pnA34x .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aY0K5Garg6pnA34x .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-aY0K5Garg6pnA34x .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aY0K5Garg6pnA34x .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aY0K5Garg6pnA34x .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aY0K5Garg6pnA34x .marker.cross{stroke:#333333;}#mermaid-svg-aY0K5Garg6pnA34x svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aY0K5Garg6pnA34x p{margin:0;}#mermaid-svg-aY0K5Garg6pnA34x .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-aY0K5Garg6pnA34x .cluster-label text{fill:#333;}#mermaid-svg-aY0K5Garg6pnA34x .cluster-label span{color:#333;}#mermaid-svg-aY0K5Garg6pnA34x .cluster-label span p{background-color:transparent;}#mermaid-svg-aY0K5Garg6pnA34x .label text,#mermaid-svg-aY0K5Garg6pnA34x span{fill:#333;color:#333;}#mermaid-svg-aY0K5Garg6pnA34x .node rect,#mermaid-svg-aY0K5Garg6pnA34x .node circle,#mermaid-svg-aY0K5Garg6pnA34x .node ellipse,#mermaid-svg-aY0K5Garg6pnA34x .node polygon,#mermaid-svg-aY0K5Garg6pnA34x .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aY0K5Garg6pnA34x .rough-node .label text,#mermaid-svg-aY0K5Garg6pnA34x .node .label text,#mermaid-svg-aY0K5Garg6pnA34x .image-shape .label,#mermaid-svg-aY0K5Garg6pnA34x .icon-shape .label{text-anchor:middle;}#mermaid-svg-aY0K5Garg6pnA34x .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-aY0K5Garg6pnA34x .rough-node .label,#mermaid-svg-aY0K5Garg6pnA34x .node .label,#mermaid-svg-aY0K5Garg6pnA34x .image-shape .label,#mermaid-svg-aY0K5Garg6pnA34x .icon-shape .label{text-align:center;}#mermaid-svg-aY0K5Garg6pnA34x .node.clickable{cursor:pointer;}#mermaid-svg-aY0K5Garg6pnA34x .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-aY0K5Garg6pnA34x .arrowheadPath{fill:#333333;}#mermaid-svg-aY0K5Garg6pnA34x .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-aY0K5Garg6pnA34x .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-aY0K5Garg6pnA34x .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aY0K5Garg6pnA34x .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-aY0K5Garg6pnA34x .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aY0K5Garg6pnA34x .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-aY0K5Garg6pnA34x .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-aY0K5Garg6pnA34x .cluster text{fill:#333;}#mermaid-svg-aY0K5Garg6pnA34x .cluster span{color:#333;}#mermaid-svg-aY0K5Garg6pnA34x div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-aY0K5Garg6pnA34x .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-aY0K5Garg6pnA34x rect.text{fill:none;stroke-width:0;}#mermaid-svg-aY0K5Garg6pnA34x .icon-shape,#mermaid-svg-aY0K5Garg6pnA34x .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aY0K5Garg6pnA34x .icon-shape p,#mermaid-svg-aY0K5Garg6pnA34x .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-aY0K5Garg6pnA34x .icon-shape .label rect,#mermaid-svg-aY0K5Garg6pnA34x .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aY0K5Garg6pnA34x .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-aY0K5Garg6pnA34x .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-aY0K5Garg6pnA34x :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Linux 内核
应用进程
System Server 进程
- 定时检测 (30s)
- 尝试获取锁
- 检查是否死锁
- 检查是否阻塞
- 检测应用主线程
- 超时 (5s/10s/60s)
- 触发 ANR
- 生成 traces.txt
- Native Crash
- 发送 SIGABRT
- 生成 tombstone_XX
- 发送 SIGQUIT
- dump 堆栈
Watchdog 线程
ActivityManagerService
WindowManagerService
PackageManagerService
Monitor 接口
主线程 (Main Looper)
Binder 线程
信号机制 (SIGQUIT/SIGABRT)
Tombstone 生成器
/data/anr/
2.2 核心监控组件职责表
| 组件 | 层级 | 职责 | 学术定义 |
|---|---|---|---|
| Watchdog | System Server | 系统监护 | 监测 System Server 内部死锁和阻塞。 |
| ActivityManagerService | System Server | 应用监护 | 监测应用主线程的响应时间。 |
| Monitor | Interface | 死锁探测 | 通过尝试获取锁来检测死锁。 |
| Signal Catcher | ART Runtime | 信号捕获 | 捕获 SIGQUIT 信号,dump Java 堆栈。 |
| Debuggerd | Native Daemon | 墓碑生成 | 捕获 Native Crash,生成 Tombstone。 |
3. Watchdog 的死锁检测机制
3.1 Watchdog 的工作流程
Watchdog 是一个死循环线程,每隔一定时间(默认 30 秒)执行一次检测。
java
// frameworks/base/services/core/java/com/android/server/Watchdog.java
public class Watchdog extends Thread {
@Override
public void run() {
while (true) {
// 1. 检查全局锁
synchronized (mLock) {
// 2. 检查 Monitor
for (Monitor monitor : mMonitors) {
monitor.monitor(); // 尝试获取锁
}
}
// 3. 等待一段时间
wait(DEFAULT_TIMEOUT);
// 4. 如果超时,触发重启
if (isTimeout()) {
rebootSystem("Watchdog triggered");
}
}
}
}
3.2 Monitor 接口的实现
系统服务实现 Monitor 接口,在 monitor() 中尝试获取关键锁。
学术定义:
-
死锁检测 :如果
monitor()方法阻塞,说明该服务的关键锁被其他线程持有,可能发生死锁。 -
示例(ActivityManagerService) :
java// ActivityManagerService.java public void monitor() { synchronized (this) { } // 尝试获取 AMS 的主锁 }
3.3 重启策略
当 Watchdog 触发时,系统会采取不同级别的行动:
| 级别 | 行为 | 触发条件 |
|---|---|---|
| Level 1 | 重启 System Server | 单个服务死锁。 |
| Level 2 | 重启 Zygote | System Server 无法重启。 |
| Level 3 | 重启 Android Runtime | 严重 Native Crash。 |
| Level 4 | 重启设备 | Kernel Panic。 |
4. ANR 的检测与触发机制
4.1 ANR 的超时阈值
不同类型的组件有不同的超时时间。
| 组件类型 | 超时阈值 | 学术定义 |
|---|---|---|
| Input Dispatch | 5 秒 | 按键或触摸事件在 5 秒内未被分发。 |
| BroadcastReceiver | 10 秒 (前台) / 60 秒 (后台) | onReceive() 执行超时。 |
| Service | 20 秒 (前台) / 200 秒 (后台) | onCreate() / onStartCommand() 执行超时。 |
| ContentProvider | 10 秒 | query() / insert() 执行超时。 |
4.2 ANR 的检测逻辑
ActivityManagerService 使用 Handler 和 Message 检测超时。
java
// ActivityManagerService.java
void appNotResponding(ProcessRecord app) {
// 1. 获取应用主线程的 Looper
final Looper looper = app.thread.getLooper();
// 2. 发送一个 Message 到主线程
Message msg = Message.obtain();
msg.what = ANR_MSG;
looper.sendMessage(msg);
// 3. 设置一个定时器 (5秒)
mHandler.sendMessageDelayed(mAnrTimeoutMsg, 5000);
// 4. 如果 5 秒内主线程处理了 Message,取消定时器
// 5. 如果 5 秒内未处理,定时器触发,执行 ANR 逻辑
}
4.3 ANR 时的信息收集
当 ANR 发生时,系统会收集大量信息:
- Java 堆栈 :通过发送
SIGQUIT信号给应用进程,Signal Catcher 线程 dump 主线程堆栈。 - Native 堆栈:如果有 Native 代码,Debuggerd 会 dump Native 堆栈。
- 系统状态:CPU 使用率、内存状态、进程列表。
- Binder 状态:当前 Binder 调用栈,检测是否阻塞在 Binder 调用。
5. Native Crash 与 Tombstone
5.1 Native Crash 的信号处理
当 Native 层发生严重错误时,内核发送信号。
| 信号 | 含义 | 常见原因 |
|---|---|---|
| SIGSEGV | 段错误 | 空指针解引用、内存越界。 |
| SIGABRT | 异常终止 | abort() 调用、assert() 失败。 |
| SIGBUS | 总线错误 | 内存对齐错误。 |
| SIGILL | 非法指令 | 执行了非法机器码。 |
5.2 Tombstone 文件结构
Tombstone 是一个文本文件,包含丰富的调试信息。
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/crosshatch/crosshatch:11/RQ3A.210705.001/7475110:user/release-keys'
Revision: 'MP1.0'
ABI: 'arm64'
Timestamp: 2023-10-27 10:00:00+0800
pid: 12345, tid: 12347, name: Thread-2 >>> com.example.app <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
x0 0000000000000000 x1 0000007b3c001234 x2 0000000000000000 x3 0000007b3c001234
x4 0000000000000000 x5 0000000000000000 x6 0000000000000000 x7 0000000000000000
x8 0000000000000000 x9 0000007b3c001234 x10 0000000000000000 x11 0000000000000000
x12 0000000000000000 x13 0000000000000000 x14 0000000000000000 x15 0000000000000000
x16 0000007b3c001234 x17 0000007b3c001234 x18 0000000000000000 x19 0000000000000000
x20 0000000000000000 x21 0000000000000000 x22 0000000000000000 x23 0000000000000000
x24 0000000000000000 x25 0000000000000000 x26 0000000000000000 x27 0000000000000000
x28 0000000000000000 x29 0000000000000000 x30 0000007b3c001234
sp 0000007b3c001000 pc 0000007b3c001234 pstate 0000000000000000
backtrace:
#00 pc 0000000000001234 /apex/com.android.runtime/lib64/libart.so (art::Runtime::Abort(char const*)+123)
#01 pc 0000000000005678 /apex/com.android.runtime/lib64/libart.so (art::LogAbort(char const*, ...)+456)
#02 pc 0000000000009abc /data/app/com.example.app/lib/arm64/libnative-lib.so (crash_function+12)
学术定义:
- Registers: CPU 寄存器状态,用于定位崩溃指令。
- Backtrace: 调用栈回溯,用于定位代码位置。
- Maps: 内存映射,显示代码段、数据段、堆、栈的位置。
6. 关键源码深度解析
6.1 Watchdog 的 Monitor 检测
cpp
// frameworks/base/services/core/java/com/android/server/Watchdog.java
private final ArrayList<Monitor> mMonitors = new ArrayList<>();
public void addMonitor(Monitor monitor) {
synchronized (mLock) {
mMonitors.add(monitor);
}
}
void run() {
while (true) {
synchronized (mLock) {
for (Monitor m : mMonitors) {
// 关键:这里只是调用 monitor(),如果阻塞,整个 Watchdog 线程就卡住了
m.monitor();
}
}
// ... 等待和检查
}
}
6.2 ANR 的 Signal 处理
java
// frameworks/base/core/jni/android_os_Process.cpp
void signalCatcherThread() {
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGQUIT);
sigwait(&mask, &sig); // 等待 SIGQUIT 信号
// 收到信号,dump 堆栈
dumpJavaStacks();
dumpNativeStacks();
}
7. 稳定性系统的常见误区
| 误区 | 学术解释 |
|---|---|
| ANR 一定是主线程死循环 | 不一定。可能是主线程阻塞在 I/O、Binder 调用或锁竞争。 |
| Watchdog 重启能解决一切 | 不能。如果死锁发生在 Native 层或 Kernel 层,重启 System Server 无效。 |
| Tombstone 只能分析 Native Crash | 是的。Java Crash 由 logcat 记录,Tombstone 只记录 Native 层致命错误。 |
| 关闭 ANR 对话框就不会重启 | 错误。ANR 发生后,系统可能已经处于不稳定状态,关闭对话框只是掩盖问题。 |
8. 本篇总结(Knowledge Closure)
| 关键点 | 纯学术定义 |
|---|---|
| Watchdog 的本质 | 系统服务的心跳监护仪,通过 Monitor 接口检测死锁。 |
| ANR 的本质 | 应用主线程的超时陷阱,由 ActivityManagerService 检测并触发。 |
| Monitor 机制 | 死锁探测接口,通过尝试获取关键锁来判断是否死锁。 |
| Tombstone 的本质 | 进程临终快照,包含寄存器、堆栈和内存映射,用于事后分析。 |
| Signal 机制 | 内核与用户空间的通信方式,用于触发堆栈 dump 和进程终止。 |
9. 第十板块结语
至此,第十板块:Android 系统稳定性与调试 的第一篇已完成。
我们从 Watchdog 的死锁检测 出发,深入 ANR 的超时监控 ,探索 Monitor 接口的心跳机制 ,最终抵达 Tombstone 的临终快照。
我们揭示了 Android 稳定性系统的核心逻辑:用超时检测响应,用死锁检测阻塞,用信号触发诊断,用重启恢复服务。
下一篇预告 :第十板块:Android 系统稳定性与调试 | 第二十六篇:Systrace 与 Perfetto 的系统级性能分析