SystemServer中的WatchDog

来源:互联网 发布:java工程师培训有用吗 编辑:程序博客网 时间:2024/06/06 19:44

新书上市《深入解析Android 5.0系统》

 以下内容节选自本书


对手机系统而言,因为肩负着接听电话和接收短信的重任,所以被寄予7x24小时正常工作的希望。但是基于成本,普通的手机系统很难做到完全不出故障。但是大部分的故障都会做重启后消失,不会影响继续使用。所以简单的办法是,如果检测到系统不正常了,将设备重新启动,这样用户就能继续使用了。那么如何才能判断系统是否正常呢。通常的做法是在设备中增加一个硬件看门狗,软件系统必须定时的向看门狗硬件中写值来表示自己没出故障(俗称“喂狗”),否则超过了规定的时间看门狗就会重新启动设备。在Init进程一章中我们介绍了watchdogd守护进程,这个守护进程就是用来喂硬件看门狗的。

硬件看门狗的问题是它的功能比较单一,只能监控整个系统。早期的手机操作系统大多是单任务的,硬件看门狗勉强能胜任。AndroidSystemServer是一个非常复杂的进程,里面运行的服务超过五十种,是最可能出问题的进程,因此有必要对SystemServer中运行的各种线程实施监控。但是如果使用硬件看门狗的工作方式,每个线程隔一段时间去喂狗,不但非常浪费CPU,而且会导致程序设计更加复杂。因此Android开发了WatchDog类作为软件看门狗来监控SystemServer中的线程。一旦发现问题,WatchDog会杀死SystemServer进程。

SystemServer的父进程Zygote接收到SystemServer的死亡信号后,会杀死自己。Zygote进程死亡的信号传递到Init进程后,Init进程会杀死Zygote进程所有的子进程并重启Zygote。这样整个手机相当于重启一遍。通常SystemServer出现问题和kernel并没有关系,所以这种软重启大部分时候都能够解决问题。而且这种软重启的速度更快,对用户的影响也更小。

 

运行在Binder线程中的方法如果需要使用了全局的资源,就必须建立临界区来实施保护。通常的做法是使用synchronized关键字。例如:

synchronized (mLock) {

......

}

这样,我们可以通过锁mLock被持有的时间来判断服务是否正常。

而判断一个线程是否正常的方法是给这个线程发送消息,如果消息不能在规定的时间内得到处理就表明线程出问题了。

WatchDog运行在一个单独的线程中,它的线程执行方法run()的代码如下:

1.  public void run() {

2.      booleanwaitedHalf = false;

3.      while(true) {

4.          finalArrayList blockedCheckers;

5.          finalString subject;

6.          finalboolean allowRestart;

7.          synchronized(this) {

8.              longtimeout = CHECK_INTERVAL;

9.              //给监控的线程发送消息

10.             for(int i=0; i

11.                 HandlerCheckerhc = mHandlerCheckers.get(i);

12.                 hc.scheduleCheckLocked();

13.             }

14.             //睡眠一段时间

15.             longstart = SystemClock.uptimeMillis();

16.             while(timeout > 0) {

17.                 try{

18.                     wait(timeout);

19.                 }catch (InterruptedException e) {

20.                     Log.wtf(TAG,e);

21.                 }

22.                 timeout= CHECK_INTERVAL - (SystemClock.uptimeMillis() -start);

23.             }

24.             //检查是否有线程或服务出问题了

25.             finalint waitState =evaluateCheckerCompletionLocked();

26.             if(waitState == COMPLETED) {

27.                 waitedHalf= false;

28.                 continue;

29.             }else if (waitState == WAITING) {

30.                 continue;

31.             }else if (waitState == WAITED_HALF) {

32.                 if(!waitedHalf) {

33.                     ArrayListpids = new ArrayList();

34.                     pids.add(Process.myPid());

35.                     ActivityManagerService.dumpStackTraces(true,pids, null, null,

36.                             NATIVE_STACKS_OF_INTEREST);

37.                     waitedHalf= true;

38.                 }

39.                 continue;

40.             }

41.        ......

42.        {

43.             //杀死SystemServer

44.             Process.killProcess(Process.myPid());

45.             System.exit(10);

46.         }

47.         waitedHalf= false;

48.     }

49. }

代码清单10.2 WatchDog的线程执行函数run

run()方法中有一个无限循环,每次循环中主要做三件事:

1.       调用scheduleCheckLocked()方法给所有受监控的线程发送消息。scheduleCheckLocked()方法的代码如下

publicvoid scheduleCheckLocked() {

   if (mMonitors.size() == 0 &&mHandler.getLooper().isIdling()) {

       mCompleted = true;

       return;

   }

   if (!mCompleted) {

      return;

   }

   mCompleted = false;

   mCurrentMonitor = null;

   mStartTime = SystemClock.uptimeMillis();

   mHandler.postAtFrontOfQueue(this);

}

HandlerChecker对象即要监控服务,也要监控某个线程。所以上面的代码先判断mMonitorssize是否为0。如果为0,说明这个HandlerChecker没有监控服务,这时如果被监控线程的消息队列处于空闲状态(调用isIdling()检查),则说明线程运行良好,把mCompleted设为true后就可以返回了。否则先把mCompleted设为false,然后记录消息开始发送的时间到变量mStartTime中,最后调用postAtFrontOfQueue()方法给被监控的线程发送一个消息。这个消息的处理方法是HandlerChecker类的方法run(),代码如下:

publicvoid run() {

   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;

   }

}

如果消息处理方法run()能够被执行,说明受监控的线程本身没有问题。但是还需要检查被监控服务的状态。检查是通过调用服务中实现的monitor()方法来完成的。通常monitor()方法的实现是获取服务中的锁,如果不能得到,线程就会被挂起,这样mCompleted的值就不能被置成true了。

mCompleted的值为true,表明HandlerChecker对象监控的线程或服务正常。否则就可能有问题。是否真有问题还要通过等待的时间是否超过规定时间来判断。

moninor()方法的实现通常如下:

publicvoid monitor() {

   synchronized (mLock) {

   }

}

2.       给受监控的线程发送完消息后,调用wait()方法让WatchDog线程睡眠一段时间。

3.       逐个检查是否有线程或服务出问题了,一旦发现问题,马上杀死进程。

前面的代码清单10.225行调用了方法evaluateCheckerCompletionLocked()来检查线程或服务是否有问题。evaluateCheckerCompletionLocked()方法的代码如下:

privateint evaluateCheckerCompletionLocked() {

   int state = COMPLETED;

   for (int i=0; i

       HandlerChecker hc =mHandlerCheckers.get(i);

       state = Math.max(state,hc.getCompletionStateLocked());

   }

   return state;

}

evaluateCheckerCompletionLocked()调用每个检查对象的getCompletionStateLocked()方法来得到对象的状态值。状态值有四种:

1)       COMPLETED:值为0,表示状态良好。

2)       WAITING:值为1,表示正在等待消息处理的结果。

3)       WAITED_HALF:值为2,表示正在等待并且等待的时间超过了规定时间的一半了。

4)       OVERDUE:值为3表示等待时间已经超过规定的时间。

evaluateCheckerCompletionLocked()方法希望知道的是最坏的情况,所以上面的代码中使用Math.max来计算出所有监控对象的最坏情况。

前面的代码清单10.2中的第2640行在对返回的状态值做判断,只要不是OVERDUE状态都可以继续执行。否则就会杀死SystemServer进程。

其实这里使用三种状态就足够了:COMPLETEDWAITINGOVERDUEWAITED_HALF这种状态是为了调试性能用的。如果某个线程或服务的执行时间超过了规定时间的一半,表明可能会出问题,系统就会把它的信息输出到Log中。这样开发人员通过查看Log就能看到潜在的问题,方便进行改善。参见代码清单10.2中的第35行。

getCompletionStateLocked()函数用来返回HandlerChecker对象的状态,代码如下:

public intgetCompletionStateLocked() {

   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;

}

getCompletionStateLocked()函数正是通过时间来判断被监控对象的状况。前面已经介绍的很清楚了,这里就不再分析了。


2 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孩子被教官打了怎么办 三岁宝宝叛逆期怎么办 三岁宝宝很叛逆怎么办 孩子不听话怎么办有什么方法呢 打了三岁的宝宝怎么办 2岁半宝宝不听话怎么办 心里素质不好容易紧张怎么办 孩子二年级成绩差怎么办 遇到素质低的人怎么办 孩子上课注意力不集中怎么办 素质报告册丢了怎么办 潞城镇剩下5个村怎么办 高三复读生学籍怎么办 被检精子总数少怎么办 前向运动精子17%怎么办 精子形态正常率1怎么办 精子形态正常率2怎么办 精子头部畸形率高怎么办 椎底动脉供血不足怎么办 颈椎动脉供血不足怎么办 颈椎病引起头晕脑供血不足怎么办 淘宝店被释放了怎么办 被枣蝎子蛰了怎么办 六角螺丝拧花了怎么办 苹果螺丝滑丝了怎么办 六角螺帽拧花了怎么办 六角螺母拧花了怎么办 内六角螺丝滑丝怎么办 十字螺丝拧花了怎么办 梅花螺丝滑丝了怎么办 螺丝孔道滑丝了,怎么办 锅把铆钉松啦怎么办 膨胀螺丝孔大了怎么办 戒指不圆了怎么办妙招 眼镜框的腿断了怎么办 弹簧腿眼镜坏了怎么办 vps搭建ss被墙怎么办 注塑机螺杆黏料怎么办 分解师耐久度0了怎么办 有鼻涕擤不出来怎么办 擤鼻涕耳朵堵了怎么办