企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
本章我们没有对SystemServer做更进一步的分析,不过做为拓展内容,这里想介绍一下Watchdog。Watch Dog的中文意思是“看门狗”。我依稀记得,其最初存在的意义是因为早期嵌入式设备上的程序经常“跑飞”(比如说电磁干扰等),所以专门有个硬件看门狗,每隔一段时间,看门狗就去检查一下某个参数是不是被设置了,如果发现该参数没有被设置,则判断为系统出错,然后就会强制重启。 软件层面上Android对SystemServer对参数是否被设置也很谨慎,专门为它增加了一条看门狗,可它看的是哪个门呢?对了,就是看几个重要Service的门,一旦发现Service出了问题,就会杀掉system_server,这样就使zygote随其一起自杀,最后导致重启Java世界。 我们先把SystemServe使用Watchdog的调用流程总结一下,然后以这个为切入点来分析Watchdog。SS和Watchdog的交互流程可以总结为以下三个步骤: - Watchdog. getInstance().init() - Watchdog.getInstance().start() - Watchdog. getInstance().addMonitor() 这三个步骤都非常简单。先看第一步: 1. 创建和初始化Watchdog getInstance用于创建Watchdog,一起来看看,代码如下所示: **Watchdog.java** ~~~ public static Watchdog getInstance() { if(sWatchdog == null) { sWatchdog= new Watchdog(); //使用了单例模式。 } returnsWatchdog; } public class Watchdog extends Thread //Watchdog从线程类派生,所以它会在单独的一个线程中执行 private Watchdog() { super("watchdog"); //构造一个Handler,Handler的详细分析见第5章,读者可以简单地把它看做是消息处理的地方。 //它在handleMessage函数中处理消息 mHandler = new HeartbeatHandler(); //GlobalPssCollected和内存信息有关。 mGlobalPssCollected= new GlobalPssCollected(); } ~~~ 这条看门狗诞生后,再来看看init函数,代码如下所示: **Watchdog.java** ~~~ public void init(Context context, BatteryServicebattery, PowerManagerService power, AlarmManagerService alarm, ActivityManagerService activity) { mResolver = context.getContentResolver(); mBattery = battery; mPower = power; mAlarm = alarm; mActivity = activity; ...... mBootTime = System.currentTimeMillis();//得到当前时间 ...... } ~~~ 至此,看门狗诞生的知识就介绍完了,下面我们就让它动起来。 2. 看门狗跑起来 SystemServer调用Watchdog的start函数,这将导致Watchdog的run在另外一个线程中被执行。代码如下所示: **Watchdog.java** ~~~ public void run() { booleanwaitedHalf = false; while(true) {//外层while循环 mCompleted= false; //false表明各个服务的检查还没完成。 /* mHandler的消息处理是在另外一个线程上,这里将给那个线程的消息队列发条消息 请求Watchdog检查Service是否工作正常。 */ mHandler.sendEmptyMessage(MONITOR); synchronized (this) { long timeout = TIME_TO_WAIT; long start = SystemClock.uptimeMillis(); //注意这个小while循环的条件,mForceKillSystem为true也会导致退出循环 while (timeout > 0 && !mForceKillSystem) { try { wait(timeout); //等待检查的结果 } catch(InterruptedException e) { } timeout = TIME_TO_WAIT -(SystemClock.uptimeMillis() - start); } //mCompleted为true,表示service一切正常 if (mCompleted &&!mForceKillSystem) { waitedHalf = false; continue; } //如果mCompleted不为true,看门狗会比较尽责,再检查一次 if (!waitedHalf) { ...... waitedHalf = true; continue;//再检查一次 } } //已经检查过两次了,还是有问题,这回是真有问题了。所以SS需要把自己干掉。 if (!Debug.isDebuggerConnected()) { Process.killProcess(Process.myPid()); System.exit(10); //干掉自己 } ...... waitedHalf = false; } } ~~~ OK,这个run函数还是比较简单的,就是: · 隔一段时间给另外一个线程发送一条MONITOR消息,那个线程将检查各个Service的健康情况。而看门狗会等待检查结果,如果第二次还没有返回结果,那么它会杀掉SS。 好吧,来看看检查线程究竟是怎么检查Service的。 3. 列队检查 这么多Service,哪些是看门狗比较关注的呢?一共有三个Service是需要交给Watchdog检查的: - ActivityManagerService - PowerManagerService - WindowManagerService 要想支持看门狗的检查,就需要这些Service实现monitor接口,然后Watchdog就会调用它们的monitor函数进行检查了。检查的地方是在HeartbeatHandler类的handleMessage中,代码如下所示: **Watchdog.java::HeartbeatHandler** ~~~ final class HeartbeatHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { ...... case MONITOR: { ...... long now =SystemClock.uptimeMillis(); final int size =mMonitors.size(); //检查各个服务,并设置当前检查的对象为mCurrentMonitor for (int i = 0 ; i <size ; i++) { mCurrentMonitor =mMonitors.get(i); mCurrentMonitor.monitor();//检查这个对象 } //如果没问题,则设置mCompleted为真。 synchronized (Watchdog.this){ mCompleted = true; mCurrentMonitor = null; } } break; } } } ~~~ 那么,Service的健康是怎么判断的呢?我们以PowerManagerService为例,先看看它是怎么把自己交给看门狗检查的。 **PowerManagerService.java** ~~~ PowerManagerService() { ...... //在构造函数中把自己加入Watchdog的检查队列 Watchdog.getInstance().addMonitor(this); } ~~~ 而Watchdog调用各个monitor函数到底检查了些什么呢?再看看它实现的monitor函数吧。 **PowerManagerService.java** ~~~ public void monitor() { //monitor原来检查的就是这些Service是不是发生死锁了! synchronized (mLocks) { } } ~~~ 原来,Watchdog最怕系统服务死锁了,对于这种情况也只能采取杀系统的办法了。 >[info]**说明**:这种情况,我只碰到过一次,原因是有一个函数占着锁,但长时间没有返回。没返回的原因是这个函数需要和硬件交互,而硬件又没有及时返回。 关于Watchdog,我们就介绍到这里。另外,它还能检查内存的使用情况,这一部分内容读者可以自行研究。