Skip to content

Watchdog监控

深入 Watchdog HandlerChecker、monitor、半超时/全超时、栈采集、调试器抑制和系统重启路径。

基于android-17.0.0_r1
AndroidSystemServerWatchdog源码阅读

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

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注册目标 ​

java
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. 检查入队 ​

java
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执行 ​

java
@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. 三段完成状态 ​

java
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

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

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. 终止决策 ​

java
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 语义。
bash
# 输入 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 状态机。