来源:

https://blog.csdn.net/shift_wwx/article/details/81021257

 

前言:

Watchdog字面上是“看门狗”的意思,有做过嵌入式低层的朋友应该知道,为了防止嵌入式系统MCU里的程序因为干扰而跑飞,专门在MCU里设计了一个定时器电路,叫做看门狗。当MCU正常工作的,每隔一段时间会输出一个信号给看门狗,也就是所谓的喂狗。如果程序跑飞,MCU在规定的时间内没法喂狗,这时看门狗就会直接触发一个reset信号,让CPU重新启动。

在Android系统的framework中,设计了一个系统服务Watchdog,它类似于一个软件看门狗,用来保护重要的系统服务。它的源代码位于:

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

 

流程图:

 

源码分析:(基于android O)

1、获取WatchDog 对象

public class Watchdog extends Thread { }

想要分析一个功能代码,可能先从本身的源头找起,对于Java 类首先看的就是类的定义以及构造构造函数啦!

从这里看 WatchDog 其实一个Thread,这个Thread 可能比较特殊而已,至于这么特殊,下面会在SystemServer 分析的时候说明。那对于一个Thread,核心的操作部分就是run() 函数了,这个最重要的部分会放在最后解析。

再来看下WatchDog 的构造函数:

private Watchdog() { }

WatchDog 构造函数是private,对于外界获取对象的接口为:

    public static Watchdog getInstance() {        if (sWatchdog == null) {            sWatchdog = new Watchdog();        }        return sWatchdog;    }

外界获取WatchDog 就是通过getInstance(),至于这个“外界”后面会补充。

 

2、构造函数

    private Watchdog() {        // 线程名为 watchdog        super("watchdog");        mMonitorChecker = new HandlerChecker(FgThread.getHandler(),                "foreground thread", DEFAULT_TIMEOUT);        mHandlerCheckers.add(mMonitorChecker);        // Add checker for main thread.  We only do a quick check since there        // can be UI running on the thread.        mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),                "main thread", DEFAULT_TIMEOUT));        // Add checker for shared UI thread.        mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),                "ui thread", DEFAULT_TIMEOUT));        // And also check IO thread.        mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),                "i/o thread", DEFAULT_TIMEOUT));        // And the display thread.        mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),                "display thread", DEFAULT_TIMEOUT));        // Initialize monitor for Binder threads.        addMonitor(new BinderThreadMonitor());        mOpenFdMonitor = OpenFdMonitor.create();        // See the notes on DEFAULT_TIMEOUT.        assert DB ||                DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;    }

(1)线程名为 watchdog

(2)前几个都是HandlerChedker 对象,分别代表的是FgThread、MainThread、UIThread、IoThread、DisplayThread。

  • MainThread 有自己的MainLooper
  • 其他的Thread 都是继承自HandlerThread(详细看  Android HandlerThread 详解

(3)HandlerChecker 有3 个参数分别是Handler 对象、name、以及触发watchdog 的最大时间间隔,详细的HandlerChecker 看下面。

(4)BinderThreadMonitor 和 OpenFdMonitor 创建

 

3、init() 函数

    public void init(Context context, ActivityManagerService activity) {        mResolver = context.getContentResolver();        mActivity = activity;        context.registerReceiver(new RebootRequestReceiver(),                new IntentFilter(Intent.ACTION_REBOOT),                android.Manifest.permission.REBOOT, null);    }

注册了reboot 的广播,软重启的操作时在这里进行的

 

4、HandlerChecker类

    public final class HandlerChecker implements Runnable { //Runnable 类型,核心就是run()        private final Handler mHandler;        private final String mName;        private final long mWaitMax;        private final ArrayList mMonitors = new ArrayList(); //这个是核心成员        private boolean mCompleted;        private Monitor mCurrentMonitor;        private long mStartTime;        HandlerChecker(Handler handler, String name, long waitMaxMillis) {            mHandler = handler;            mName = name;            mWaitMax = waitMaxMillis;            mCompleted = true;        }        public void addMonitor(Monitor monitor) { //注册的monitor 都在这里            mMonitors.add(monitor);        }        public void scheduleCheckLocked() {            if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) {                // If the target looper has recently been polling, then                // there is no reason to enqueue our checker on it since that                // is as good as it not being deadlocked.  This avoid having                // to do a context switch to check the thread.  Note that we                // only do this if mCheckReboot is false and we have no                // monitors, since those would need to be executed at this point.                mCompleted = true;                return;            }            if (!mCompleted) { //check 过了就不用再check                // we already have a check in flight, so no need                return;            }            mCompleted = false;            mCurrentMonitor = null;            mStartTime = SystemClock.uptimeMillis();            mHandler.postAtFrontOfQueue(this); //check 的时候往MessageQueue 中最前面添加,最终会调用run()        }        public boolean isOverdueLocked() {            return (!mCompleted) && (SystemClock.uptimeMillis() > mStartTime + mWaitMax);        }        public int getCompletionStateLocked() { //获取scheduleCheckLocked 最后的结果,如果没有从monitor() 出来就会出现WAIT            if (mCompleted) {                return COMPLETED;            } else {                long latency = SystemClock.uptimeMillis() - mStartTime;                if (latency < mWaitMax/2) {                    return WAITING;                } else if (latency < mWaitMax) {                    return WAITED_HALF;                }            }            return OVERDUE;        }        public Thread getThread() { //每个HandlerChecker 都是个单独的thread,mHandler 比较特殊            return mHandler.getLooper().getThread();        }        public String getName() {            return mName;        }        public String describeBlockedStateLocked() {            if (mCurrentMonitor == null) {                return "Blocked in handler on " + mName + " (" + getThread().getName() + ")";            } else {                return "Blocked in monitor " + mCurrentMonitor.getClass().getName()                        + " on " + mName + " (" + getThread().getName() + ")";            }        }        @Override        public void run() { //scheduleCheckLocked 函数会执行这里            final int size = mMonitors.size();            for (int i = 0 ; i < size ; i++) {                synchronized (Watchdog.this) {                    mCurrentMonitor = mMonitors.get(i);                }                mCurrentMonitor.monitor();            }            synchronized (Watchdog.this) {                mCompleted = true;                mCurrentMonitor = null;            }        }    }

需要注意的地方:

  • HandlerChecker 是Runnable 类型,那核心部分就是run() 函数
  • mHandler比较特殊,都是HandlerThread 中的Handler,都存在于单独的thread 中
  • 注册的monitor 都是通过成员函数addMonitor() 存放
  • scheduleCheckLocked() 是HandlerChecker 的触发点

既然HandlerCheker 是Runnable 类型,那核心就是run() 函数,run() 函数的目的就是分别调用注册进来的monitor 的monitor() 函数。在每过一个时间间隔(默认为30秒),WatchDog 会通过scheduleCheckLocked 函数轮询一下monitors 中的注册的monitor。

在scheduleCheckLocked 中,其实主要是处理mMonitorChecker 的情况,对于其他的没有monitor 注册进来的且处于polling 状态的 HandlerChecker 是不去检查的,例如,UiThread,肯定一直处于polling 状态。

 

5、其他几个重要函数

    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); //通过WatchDog 添加的monitor都在mMonitorChecker中的mMonitors里        }    }    public void addThread(Handler thread) { //除了构造中的几个Thread,也可以添加其他Thread 的monitor        addThread(thread, DEFAULT_TIMEOUT);    }    public void addThread(Handler thread, long timeoutMillis) {        synchronized (this) {            if (isAlive()) {                throw new RuntimeException("Threads can't be added once the Watchdog is running");            }            final String name = thread.getLooper().getThread().getName();            mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis)); //新添加的monitor 都在mHandlerChekers中        }    }    /**     * Perform a full reboot of the system.     */    void rebootSystem(String reason) { //收到reboot 广播后会调用到这里        Slog.i(TAG, "Rebooting system because: " + reason);        IPowerManager pms = (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE);        try {            pms.reboot(false, reason, false);        } catch (RemoteException ex) {        }    }

见code 中的注释部分

 

6、WatchDog 的run() 函数

上面的基本函数都大概解析完了,对于一个Thread 那最重要的肯定还是run() 函数,这里也是WatchDog 的监测机制所在,下面来详细分析。

    public void run() {        boolean waitedHalf = false;        File initialStack = null;        while (true) {            ...            ...            synchronized (this) {                long timeout = CHECK_INTERVAL; //30秒一次循环检查                                //第一步,30秒轮询系统中所有的monitor                for (int i=0; i 0) {                    if (Debug.isDebuggerConnected()) {                        debuggerWasConnected = 2;                    }                    try {                        wait(timeout);                    } catch (InterruptedException e) {                        Log.wtf(TAG, e);                    }                    if (Debug.isDebuggerConnected()) {                        debuggerWasConnected = 2;                    }                    timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);                }                ...                ...                if (!fdLimitTriggered) {                    //第三步,检查HandlerChecker 完成状态                    final int waitState = evaluateCheckerCompletionLocked();                    if (waitState == COMPLETED) { //monitor() 顺利返回                        // The monitors have returned; reset                        waitedHalf = false;                        continue;                    } else if (waitState == WAITING) { //不到30秒的等下个30秒                        // still waiting but within their configured intervals; back off and recheck                        continue;                    } else if (waitState == WAITED_HALF) { //过了30秒的,再给个机会                        if (!waitedHalf) {                            // We've waited half the deadlock-detection interval.  Pull a stack                            // trace and wait another half.                            ArrayList pids = new ArrayList();                            pids.add(Process.myPid());                            initialStack = ActivityManagerService.dumpStackTraces(true, pids,                                    null, null, getInterestingNativePids());                            waitedHalf = true;                        }                        continue;                    }                    //第四步,如果状态是 overdue!,也就是超过60秒                    blockedCheckers = getBlockedCheckersLocked();                    subject = describeCheckersLocked(blockedCheckers);                } else {                    blockedCheckers = Collections.emptyList();                    subject = "Open FD high water mark reached";                }                allowRestart = mAllowRestart;            }            // 第五步,保存日志,重启系统            ...            ...                Slog.w(TAG, "*** GOODBYE!");                Process.killProcess(Process.myPid());                System.exit(10);        }    }

流程梳理下:

(1)Watchdog运行后,便开始无限循环,依次调用每一个HandlerChecker的scheduleCheckLocked()方法
(2)调度完HandlerChecker之后,便开始定期检查是否超时,每一次检查的间隔时间由CHECK_INTERVAL常量设定,为30秒
(3)每一次检查都会调用evaluateCheckerCompletionLocked()方法来评估一下HandlerChecker的完成状态:

  • COMPLETED表示已经完成
  • WAITING和WAITED_HALF表示还在等待,但未超时
  • OVERDUE表示已经超时。默认情况下,timeout是1分钟,但监测对象可以通过传参自行设定,譬如PKMS的Handler Checker的超时是10分钟

(4)如果超时时间到了,还有HandlerChecker处于未完成的状态(OVERDUE),则通过getBlockedCheckersLocked()方法,获取阻塞的HandlerChecker,生成一些描述信息

(5)保存日志,包括一些运行时的堆栈信息,这些日志是我们解决Watchdog问题的重要依据。如果判断需要杀掉system_server进程,则给当前进程(system_server)发送signal 9,详细信息看 Android 系统中WatchDog 日志分析

 

总结watchdog 监控:

线程名 对应handler 说明 Timeout
main new Handler(Looper.getMainLooper()) 当前主线程 1min
android.fg FgThread.getHandler 前台线程 1min
android.ui UiThread.getHandler UI线程 1min
android.io IoThread.getHandler I/O线程 1min
android.display DisplayThread.getHandler display线程 1min
ActivityManager AMS.MainHandler AMS线程 1min
PowerManagerService PMS.PowerManagerHandler PMS线程 1min
PackageManager PKMS.PackageHandler PKMS线程 10min

 

至此,WatchDog 类的解析基本完成了,下面继续来看“外界”触发或调用的地方。

 

7、SystemServer 中初始化WatchDog

    final Watchdog watchdog = Watchdog.getInstance();    watchdog.init(context, mActivityManagerService);

WatchDog 是单例存在,所以系统中对象就一个,其实在AMS 初始化的时候就已经调用了getInstance(),详细看下面。

这里其实主要是调用init()

 

8、AMS 构造的时候添加monitor

    Watchdog.getInstance().addMonitor(this);    Watchdog.getInstance().addThread(mHandler);

来看下一直说的monitor 是什么东西:

    public void monitor() {        synchronized (this) { }    }

这里其实就是确认AMS 中是否存在死锁,30秒后还是没有放出来这个锁,WatchDog 会在给一次机会,如果还是没有释放的话,会打印堆栈信息并且结束AMS 所在进程。

这里还需要注意的是addThread() 函数,AMS 会在WatchDog 中创建一个单独的HandlerChecker,所以会有下面的log:

11-06 00:05:28.603  2197  2441 W Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: Blocked in monitor com.android.server.am.ActivityManagerService on foreground thread (android.fg), Blocked in handler on ActivityManager (ActivityManager)11-06 00:05:28.603  2197  2441 W Watchdog: foreground thread stack trace:11-06 00:05:28.603  2197  2441 W Watchdog:     at com.android.server.am.ActivityManagerService.monitor(ActivityManagerService.java:23862)11-06 00:05:28.604  2197  2441 W Watchdog:     at com.android.server.Watchdog$HandlerChecker.run(Watchdog.java:211)11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.Handler.handleCallback(Handler.java:790)11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.Handler.dispatchMessage(Handler.java:99)11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.Looper.loop(Looper.java:164)11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.HandlerThread.run(HandlerThread.java:65)11-06 00:05:28.604  2197  2441 W Watchdog:     at com.android.server.ServiceThread.run(ServiceThread.java:46)11-06 00:05:28.604  2197  2441 W Watchdog: ActivityManager stack trace:11-06 00:05:28.604  2197  2441 W Watchdog:     at com.android.server.am.ActivityManagerService.idleUids(ActivityManagerService.java:23305)11-06 00:05:28.604  2197  2441 W Watchdog:     at com.android.server.am.ActivityManagerService$MainHandler.handleMessage(ActivityManagerService.java:2428)11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.Handler.dispatchMessage(Handler.java:106)11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.Looper.loop(Looper.java:164)11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.HandlerThread.run(HandlerThread.java:65)11-06 00:05:28.604  2197  2441 W Watchdog:     at com.android.server.ServiceThread.run(ServiceThread.java:46)11-06 00:05:28.604  2197  2441 W Watchdog: *** GOODBYE

其中就有ActivityManager stack trace的打印,具体的可以看 Android 系统中WatchDog 日志分析

 

WMS 中的monitor:

    public void monitor() {        synchronized (mWindowMap) { }    }

能够被Watchdog监控的系统服务都实现了Watchdog.Monitor接口,并实现其中的monitor()方法。运行在android.fg线程, 系统中实现该接口类主要有:

  • ActivityManagerService
  • WindowManagerService
  • InputManagerService
  • PowerManagerService
  • NetworkManagementService
  • MountService
  • NativeDaemonConnector
  • BinderThreadMonitor
  • MediaProjectionManagerService
  • MediaRouterService
  • MediaSessionService
  • BinderThreadMonitor


9、WatchDog 的启动

   traceBeginAndSlog("StartWatchdog");   Watchdog.getInstance().start();   traceEnd();

在AMS ready 的时候会start watch dog,进而触发WatchDog 的run()函数。

 

总结:

Android 中的WatchDog 主要是监测系统中重要服务,例如AMS、WMS 等,当注册的monitor 无法通过检测,或者是超时的时候就会触发WatchDog,最后可能会引起系统的重启。

 

下一篇博文 Android 系统中WatchDog 日志分析 中会结合实例详解run() 第 5 步保存日志。

 

 

附加:WatchDog 类图

 

 

 

 

 

 

 

更多相关文章

  1. 箭头函数的基础使用
  2. Python技巧匿名函数、回调函数和高阶函数
  3. 浅析android通过jni控制service服务程序的简易流程
  4. Android(安卓)Wifi模块分析(三)
  5. Android中dispatchDraw分析
  6. 浅析Android中的消息机制-解决:Only the original thread that cr
  7. Android四大基本组件介绍与生命周期
  8. Android异步消息机制之Handler
  9. Android(安卓)Service AIDL

随机推荐

  1. centos7环境下创建mysql5.6多实例的方法
  2. centos7环境下二进制安装包安装 mysql5.6
  3. 分享MySql8.0.19 安装采坑记录
  4. centos7环境下源码安装mysql5.7.16的方法
  5. mysql非主键自增长用法实例分析
  6. win10安装zip版MySQL8.0.19的教程详解
  7. mysql中GROUP_CONCAT的使用方法实例分析
  8. Window下如何恢复被删除的Mysql8.0.17 Ro
  9. 安装mysql-8.0.19-winx64遇到的问题:Can&#
  10. Mysql中正则表达式Regexp常见用法