1. 概述
xxxxxx
2. Watchdog机制解析
2.1 Watchdog的初始化
Watchdog是在System Server中初始化的:
/frameworks/base/services/java/com/android/server/SystemServer.java
1 | public final class SystemServer { |
Watchdog在初始化时构造了很多HandlerChecker,大致可以分为两类:
- Monitor Checker:用于检查是Monitor对象可能发生的死锁, AMS, PKMS, WMS等核心的系统服务都是Monitor对象。在log中会有
watchdog: Blocked in monitor xxx foreground thread(android.fg)
,所以其实就是android.fg线程。 - Looper Checker:用于检查线程的消息队列是否长时间处于工作状态。Watchdog自身的消息队列,UI, IO, Display这些全局的消息队列都是被检查的对象。此外,一些重要的线程的消息队列,也会加入到Looper Checker中,譬如AMS, PKMS,这些是在对应的对象初始化时加入的。
/frameworks/base/services/core/java/com/android/server/Watchdog.java
1 | /** This class calls its monitor every minute. Killing this process if they don't return **/ |
Monitor Checker和Looper Checker的侧重点不一样,前者预警我们不能长时间持有核心系统服务的对象锁,否则会阻塞很多函数的运行;后者预警我们不能长时间的霸占消息队列,否则其他消息将得不到处理。这两类都会导致系统卡住(System Not Responding)。
init注册了一个广播接收器用来接收重启系统的广播:
1 | final class RebootRequestReceiver extends BroadcastReceiver { |
2.2 触发Watchdog
初始化Watchdog后,在SystemServer中start,作为SystemServer进程中的一个单独的线程运行,但是想要触发Watchdog的运行还需要AMS、PMS等系统服务加入到Watchdog的监测集,也就是需要Watchdog关注的对象,Watchdog只关注一些核心的系统服务。
需要Watchdog检测的对象,需要将自己添加到Watchdog的监测集中,以AMS为例:
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
1 | public ActivityManagerService(Context systemContext) { |
/frameworks/base/services/core/java/com/android/server/Watchdog.java
1 | public class Watchdog extends Thread { |
1 | public class Watchdog extends Thread { |
AMS在构造函数中分别通过addMonitor和 addThread方法把自己添加到Monitor Checker对象中,把自己的Handler添加到Looper Checker对象中。
2.3 Watchdog监测机制
Watchdog继承了Thread,也就是说本身就是一个线程,来看一下它的run()方法实现:
1 |
|
2.3.1 scheduleCheckLocked()方法
Watchdog运行后开始循环,调用每一个HandlerChecker的scheduleCheckLocked()方法:
1 | public final class HandlerChecker implements Runnable { |
HandlerChecker对象既要监控服务,也要监控某个线程,所以代码中要先判断mMonitors.size是否为0,如果为0则说明这个HandlerChecker没有监控服务,这时如果被监控线程的消息队列处于空闲状态(调用isIdling()检查),则说明线程运行良好,把mCompleted设为true后就可以返回了。否则先把mCompleted设为false,然后记录消息开始发送的时间到变量mStartTime中,最后调用postAtFrontOfQueue()方法给被监控的线程发送一个消息。
2.3.2 定期检查
调度完HandlerChecker给受监控的线程发送完消息后,开始定期检查是否超时,每一次的检查的间隔由常量CHECK_INTERVAL设定,为30s,调用wait()方法(线程休眠且释放锁)让WatchDog线程睡眠一段时间。
2.3.3 检查线程或服务是否有问题
调用evaluateCheckerCompletionLocked()方法来检查是否有问题:
1 | private int evaluateCheckerCompletionLocked() { |
1 | public int getCompletionStateLocked() { |
根据等待时间来确认返回HandlerChecker对象的状态,
COMPLETED表示已经完成
WAITING和WAITED_HALF表示还在等待,但未超时
OVERDUE表示已经超时,默认情况下timeout是1分钟,但监测对象可以通过传参自行设定,譬如PKMS的Handler Checker的超时是10分钟:
1
2private static final long WATCHDOG_TIMEOUT = 1000*60*10; // ten minutes
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
2.3.4 getBlockedCheckersLocked
1 | private ArrayList<HandlerChecker> getBlockedCheckersLocked() { |
如果超时时间到了,还有HandlerChecker处于未完成的状态(OVERDUE),则通过getBlockedCheckersLocked()方法,获取阻塞的HandlerChecker,生成一些描述信息
2.3.5 保存日志
保存日志,包括一些运行时的堆栈信息,这些日志是我们解决Watchdog问题的重要依据。如果判断需要杀掉system_server进程,则给当前进程(system_server)发送signal。