Watchdog监控
SystemServer 的 Watchdog 不是一个简单的“线程超过 N 秒就 kill”。它为主线程、foreground/UI/IO/display/animation 等 Handler 建立 HandlerChecker,把检查 Runnable 放到目标队列头部;同时 monitor checker 执行 BinderThreadMonitor 等同步检查。Watchdog 线程按半超时和全超时评估状态,先采集日志/线程栈,再根据 debugger、activity controller、restart policy 和 crash loop 决定是否终止 system_server。
1. Checker对象
源码文件:frameworks/base/services/core/java/com/android/server/Watchdog.java
public static class HandlerChecker implements Runnable {
private final Handler mHandler;
private final String mName;
private final ArrayList<Monitor> mMonitors = new ArrayList<>();
private boolean mCompleted;
private Monitor mCurrentMonitor;
private long mStartTimeMillis;
private long mWaitMaxMillis;
HandlerChecker(Handler handler, String name,
Object lock, Clock clock) {
mHandler = handler;
mName = name;
mCompleted = true;
mClock = clock;
mLock = lock;
}
}每个 checker 的 owner 是一个 Handler/Looper;mCompleted 表示本轮 Runnable 是否执行完,mStartTimeMillis 和 mWaitMaxMillis 计算延迟,mCurrentMonitor 标识卡在哪个 monitor。Monitor 列表和 Handler 检查共用一个 Runnable,但两种状态都由同一个 checker 保存。
2. Watchdog注册目标
mMonitorChecker = new HandlerChecker(
new Handler(t.getLooper()),
"monitor thread", mLock);
mHandlerCheckers.add(
withDefaultTimeout(mMonitorChecker));
mHandlerCheckers.add(withDefaultTimeout(
new HandlerChecker(FgThread.getHandler(),
"foreground thread", mLock)));
mHandlerCheckers.add(withDefaultTimeout(
new HandlerChecker(
new Handler(Looper.getMainLooper()),
"main thread", mLock)));
mHandlerCheckers.add(withDefaultTimeout(
new HandlerChecker(UiThread.getHandler(),
"ui thread", mLock)));
mHandlerCheckers.add(withDefaultTimeout(
new HandlerChecker(IoThread.getHandler(),
"i/o thread", mLock)));
addMonitor(new BinderThreadMonitor());Watchdog constructor登记多个线程,并把 BinderThreadMonitor 加入专用 monitor checker。主线程注释明确“只做快速检查”,因为主线程可能执行 UI;不是所有 Handler 都拥有相同耗时容忍度,部分 checker 可配置 custom timeout。
3. 检查入队
public void scheduleCheckLocked(
long handlerCheckerTimeoutMillis) {
mWaitMaxMillis = handlerCheckerTimeoutMillis;
if (mCompleted && !mMonitorQueue.isEmpty()) {
mMonitors.addAll(mMonitorQueue);
mMonitorQueue.clear();
}
long nowMillis = mClock.millis();
if ((mMonitors.size() == 0 && isHandlerPolling())
|| isPaused()) {
mCompleted = true;
return;
}
if (!mCompleted) return;
mCompleted = false;
mCurrentMonitor = null;
mStartTimeMillis = nowMillis;
mHandler.postAtFrontOfQueue(this);
}若目标 Looper 正在 polling 且没有 monitor,源码认为无需额外 context switch;paused checker 也不入队。否则 Runnable 放到队列头,尽快验证 Handler 是否能消费消息。mMonitorQueue 延迟合并,避免在当前 monitor 遍历中修改 mMonitors。
4. Monitor执行
@Override
public void run() {
final int size = mMonitors.size();
for (int i = 0; i < size; i++) {
synchronized (mLock) {
mCurrentMonitor = mMonitors.get(i);
}
mCurrentMonitor.monitor();
}
synchronized (mLock) {
mCompleted = true;
mCurrentMonitor = null;
}
}目标 Handler 执行 Runnable 后逐个运行 monitor,最后才将 mCompleted=true。如果线程卡在 monitor,mCurrentMonitor 会保留具体类型;如果连 Runnable 都没执行,描述状态会显示“Blocked in handler”。
5. 三段完成状态
public int getCompletionStateLocked() {
if (mCompleted) return COMPLETED;
long latency = mClock.millis() - mStartTimeMillis;
if (latency < mWaitMaxMillis / PRE_WATCHDOG_TIMEOUT_RATIO) {
return WAITING;
} else if (latency < mWaitMaxMillis) {
return WAITED_UNTIL_PRE_WATCHDOG;
}
return OVERDUE;
}状态依次是正常完成、仍在允许时间内、达到半超时、超过完整 timeout。半超时不是立即 kill,而是触发一次预警和线程栈采集;只有 OVERDUE 才进入终止决策。
6. Watchdog主循环
源码文件:frameworks/base/services/core/java/com/android/server/Watchdog.java
final long watchdogTimeoutMillis = mWatchdogTimeoutMillis;
final long checkIntervalMillis =
watchdogTimeoutMillis / PRE_WATCHDOG_TIMEOUT_RATIO;
synchronized (mLock) {
for (HandlerCheckerAndTimeout hc : mHandlerCheckers) {
hc.checker().scheduleCheckLocked(
hc.customTimeoutMillis().orElse(
watchdogTimeoutMillis
* Build.HW_TIMEOUT_MULTIPLIER));
}
long start = SystemClock.uptimeMillis();
while (timeout > 0) {
mLock.wait(timeout);
timeout = checkIntervalMillis
- (SystemClock.uptimeMillis() - start);
}
int waitState = evaluateCheckerCompletionLocked();
}Watchdog 在锁内统一调度所有 checker,并使用 uptimeMillis(),避免设备睡眠时间造成误杀。每轮 snapshot timeout,防止配置在中途变化导致同一轮 checker 使用不一致的阈值。
7. 暂停与恢复
源码文件:frameworks/base/services/core/java/com/android/server/Watchdog.java
public void pauseWatchingCurrentThread(String reason) {
synchronized (mLock) {
for (HandlerCheckerAndTimeout hc : mHandlerCheckers) {
if (hc.checker().getThread() == Thread.currentThread()) {
hc.checker().pauseLocked(reason);
return;
}
}
}
}PMS 等合法长任务可暂停当前线程 checker;恢复必须匹配同一线程和暂停次数。暂停会把 mCompleted 置 true,避免 Watchdog 在已经知道的长任务期间继续报告旧检查。暂停不是关闭整个 Watchdog,也不影响其他线程 checker。
8. 终止决策
if (Debug.isDebuggerConnected()) {
debuggerWasConnected = 2;
}
if (debuggerWasConnected >= 2) {
Slog.w(TAG,
"Debugger connected: Watchdog is *not* killing...");
} else if (!allowRestart) {
Slog.w(TAG,
"Restart not allowed: Watchdog is *not* killing...");
} else {
WatchdogDiagnostics.diagnoseCheckers(blockedCheckers);
Process.killProcess(Process.myPid());
System.exit(10);
}完整超时后仍可能不 kill:debugger 连接会抑制终止,ActivityController 可以返回继续等待,mAllowRestart=false 也会禁止重启。真正 kill 前先记录 blocked checker、诊断线程栈和 crash-loop 状态。
9. 失败定位与导航
WAITING持续:检查目标 Handler 是否只是短时忙;WAITED_UNTIL_PRE_WATCHDOG:先读半超时栈,不要立即判死锁;OVERDUE且卡在 handler:查主线程消息、同步 Binder reply 和用户锁;OVERDUE且卡在 monitor:查 monitor 实现和它持有的锁/下游调用;- 未 kill:检查 debugger、ActivityController 和 restart policy;
- 误报:检查 pause/resume 是否成对,以及是否使用 uptime 语义。
# 输入 Watchdog 构造和线程登记,输出 checker/monitor 目标。
rg -n "HandlerChecker|mHandlerCheckers|addMonitor|main thread|foreground thread|BinderThreadMonitor" \
frameworks/base/services/core/java/com/android/server/Watchdog.java
# 输入状态机和主循环,输出半超时/全超时、栈采集与终止决策。
rg -n "scheduleCheckLocked|getCompletionStateLocked|evaluateCheckerCompletionLocked|WAITED_UNTIL_PRE_WATCHDOG|OVERDUE|collectThreadDumps|killProcess|allowRestart" \
frameworks/base/services/core/java/com/android/server/Watchdog.java下一篇将进入 SystemServer 核心服务启动顺序与依赖链的反向诊断,不会重复 Watchdog checker 状态机。
