Android(安卓)系统中的 WatchDog 详解
来源:
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 类图
更多相关文章
- 箭头函数的基础使用
- Python技巧匿名函数、回调函数和高阶函数
- 浅析android通过jni控制service服务程序的简易流程
- Android(安卓)Wifi模块分析(三)
- Android中dispatchDraw分析
- 浅析Android中的消息机制-解决:Only the original thread that cr
- Android四大基本组件介绍与生命周期
- Android异步消息机制之Handler
- Android(安卓)Service AIDL