从源码角度看 WatchDog 机制

简介

Android系统中,普通开发者最常见的还是ANR,即AMS中的四大组件没有响应,这个问题常常是由于APP自身质量问题,在主线程中做耗时的操作导致。那么不知道大家有没有想过,ANR是Android Framework对普通应用的约束,不允许应用为所欲为的随意在重要的线程做耗时的任务,以免导致用户体验过差,那么运行在system_server进程中的服务呢,也可以无拘无束么?

看过我先前写过的文章的读者应该都知道,四大组件中的大部分操作是需要应用和system_server进程的服务交互来完成的,比方说启动一个Activity,那么不仅仅需要应用端调用onCreate, onStart这些方法,同时也需要在AMS服务端完成创建ActivityRecord、管理Stack和Task的操作。如果说此时类似AMS这类重要的服务或者线程出现了因为异常导致的耗时与阻塞,用户不是也会有糟糕的体验么?这时系统会作出什么样的回应来应对这种情况呢?Android Framework当然考虑到了这一点,引入了WatchDog机制,用来监测所有的系统服务和各种重要的系统线程,如果这些中的任何一个出现超时导致系统hang机,WatchDog线程将会重启手机系统

本篇文章,我将从先列出WatchDog机制涉及的主要类并对每个类进行大概的解释,随后再列举出主要的被监测服务与线程,方便大家参考用;最后带大家走入细节分析源码,每个重要步骤的源码最后都会放出一张逻辑图,不想看源码的读者可以直接参考这些图

整体类图

查看大图

  • WatchDog: 本身是一个线程,在SystemServer.startOtherServices中被启动,启动之后直接进入一个无限循环,监测系统的重要服务和线程的状态;这个类是WatchDog机制的大管家,以单例的形式存在在系统
  • HandlerChecker: 在WatchDog被实例化时,会初始化几个重要线程的监测对象,它是以线程和Handler一一对应存在的,WatchDog维护着多个HandlerChecker, 当触发监测操作时,实际上是HandlerChecker实例进行实际操作的
  • Monitor: 被各种需要监测的服务实现的接口,当monitor方法迟迟不返回时,就会判定这个服务已经超时

WatchDog监控职责

WatchDog主要监测着系统中的重要服务和重要线程,如果其中的服务没有回应或者说线程被阻塞,那么就会触发WatchDog重启

系统Service

系统Service 职务 判断是否超时方法
ActivityManagerService 四大组件与进程的管理 ActivityManagerService.class类锁是否有被释放
InputManagerService 输入管理 mInputFilerLock是否有被释放
WindowManagerService 窗口管理 mWindowMap是否有被释放
PowerManagerService 电源管理 mLock是否有被释放
MountService 设备存储连接与管理服务 内部两个连接器的mDaemonLock锁是否被都被释放
NetworkmanagermentService 网络服务 内部连接器的mDaemonLock锁是否被释放

以上只列举出比较常见的服务,还有一些没有列举出来,判断服务是否有做超时的方式其实很简单,就是判断这个服务中的重要锁是否一直在阻塞状态,如果长时间没有拿到这个锁的持有权,那么也就意味着这个服务一直在做某项耗时的操作,迟迟没有返回。

WatchDog采用这样的方式来监听系统服务中的超时现象,也是因为Android系统中的确定义了很多重要的锁,列如AMS,PMS这两把类锁。这种方式即方便但却又是致命的。例如系统常用的四大组件,每个运行中的APP都是有可能掺和一脚进来的,如果某个APP做了恶意的耗时操作并且频繁请求,那么系统只要稍微考虑不周,就可能会对这几把系统服务的大锁造成影响,进而牵一发而动全身,导致系统卡顿频繁

值得一提的是,WatchDog监控者几个重要系统服务之外,也监控着system_server Binder线程池的情况。WatchDog的内部类通过调用native方法blockUntilThreadAvailable来进行实现,如果所有Binder线程始终不能被访问到,那么也会导致系统出现WatchDog异常

系统重要线程

线程 优先级 作用
android.fg THREAD\_PRIORITY\_DEFAULT 系统专用的线程,可以用来做比较耗时的任务
system_server 主线程 THREAD\_PRIORITY\_FOREGROUND 用来做system_serverUI操作
android.ui THREAD\_PRIORITY\_FOREGROUND 适合用来做很快就能完成的操作
android.io THREAD\_PRIORITY\_DEFAULT 用来做IO操作的线程
android.display THREAD\_PRIORITY\_DISPLAY 用来做与显示有关的任务,常常被WindowManager, WindowManager等使用
PackageManager THREAD_PRIORITY_BACKGROUND 用来做PMS相关的操作
ActivityManagerService THREAD_PRIORITY_FOREGROUND 用来做AMS相关的操作
PowerManagerService THREAD_PRIORITY_DISPLAY 用来做PowerManagerService相关的操作

源码分析

初始化

[frameworks/base/services/core/java/com/android/server/Watchdog.java]

  • private Watchdog() {
  • super("watchdog");
  • mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
  • "foreground thread", DEFAULT_TIMEOUT);
  • mHandlerCheckers.add(mMonitorChecker);
  • mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
  • "main thread", DEFAULT_TIMEOUT));
  • mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
  • "ui thread", DEFAULT_TIMEOUT));
  • mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
  • "i/o thread", DEFAULT_TIMEOUT));
  • mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
  • "display thread", DEFAULT_TIMEOUT));
  • addMonitor(new BinderThreadMonitor());
  • }
  • public void addMonitor(Monitor monitor) {
  • synchronized (this) {
  • if (isAlive()) {
  • throw new RuntimeException("Monitors can't be added once the Watchdog is running");
  • }
  • mMonitorChecker.addMonitor(monitor);
  • }
  • }
  • public void addThread(Handler thread) {
  • addThread(thread, DEFAULT_TIMEOUT);
  • }

WatchDog在被初始化会创建多个HandlerChecker并保存在mHandlerCheckers这个队列中,通过调用addMonitor系统服务监测monitor都会被添加到mMonitorChecker这个成员变量中的列表中。通过调用addThread可以检测指定的线程是否长期不可用。

[frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java]

  • public ActivityManagerService(Context systemContext) {
  • ...
  • Watchdog.getInstance().addMonitor(this);
  • Watchdog.getInstance().addThread(mHandler);
  • }

以上代码为ActivityManagerService在初始化时,将自己添加到WatchDog监测之列,同时也监测着自己内部常用的线程情况

检查机制

[frameworks/base/services/core/java/com/android/server/Watchdog.java]

```java
@Override
public void run() {
boolean waitedHalf = false;
// 进入无限循环,监测系统状态
while (true) {
final ArrayList blockedCheckers;

  • synchronized (this) {
  • long timeout = CHECK_INTERVAL;
  • // 触发检查
  • for (int i=0; i<mHandlerCheckers.size(); i++) {
  • HandlerChecker hc = mHandlerCheckers.get(i);
  • hc.scheduleCheckLocked();
  • }
  • long start = SystemClock.uptimeMillis();
  • while (timeout > 0) {
  • try {
  • // 等待监测完成
  • wait(timeout);
  • } catch (InterruptedException e) {
  • Log.wtf(TAG, e);
  • }
  • timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
  • }
  • final int waitState = evaluateCheckerCompletionLocked();
  • if (waitState == COMPLETED) {
  • waitedHalf = false;
  • continue;
  • } else if (waitState == WAITING) {
  • continue;
  • } else if (waitState == WAITED_HALF) {
  • if (!waitedHalf) {
  • ArrayList<Integer> pids = new ArrayList<Integer>();
  • pids.add(Process.myPid());
  • // 如果已经超时了一半,那么会将system_server进程堆栈信息进行打印
  • ActivityManagerService.dumpStackTraces(true, pids, null, null,
  • NATIVE_STACKS_OF_INTEREST);
  • waitedHalf = true;
  • }
  • continue;
  • }
  • // 走到这里说明系统进入hang机状态了
  • blockedCheckers = getBlockedCheckersLocked();
  • subject = describeCheckersLocked(blockedCheckers);
  • allowRestart = mAllowRestart;
top Created with Sketch.