Watchdog机制源码分析

移动开发 Android
Android设计了一个软件层面Watchdog,用于保护一些重要的系统服务,当出现故障时,通常会让Android系统重启,由于这种机制的存在,就经常会出现一些system_server进程被Watchdog杀掉而发生手机重启的问题.

[[434595]]

前言

Linux引入Watchdog,在Linux内核下,当Watchdog启动后,便设定了一个定时器,如果在超时时间内没有对/dev/Watchdog进行写操作,则会导致系统重启。通过定时器实现的Watchdog属于软件层面;

Android设计了一个软件层面Watchdog,用于保护一些重要的系统服务,当出现故障时,通常会让Android系统重启,由于这种机制的存在,就经常会出现一些system_server进程被Watchdog杀掉而发生手机重启的问题;

今天我们就来分析下原理;

一、WatchDog启动机制详解

ANR机制是针对应用的,对于系统进程来说,如果长时间“无响应”,Android系统设计了WatchDog机制来管控。如果超过了“无响应”的延时,那么系统WatchDog会触发自杀机制;

Watchdog是一个线程,继承于Thread,在SystemServer.java里面通过getInstance获取watchdog的对象;

1、在SystemServer.java中启动

  1. private void startOtherServices() { 
  2.     ······ 
  3.     traceBeginAndSlog("InitWatchdog"); 
  4.     final Watchdog watchdog = Watchdog.getInstance(); 
  5.     watchdog.init(context, mActivityManagerService); 
  6.     traceEnd(); 
  7.     ······ 
  8.     traceBeginAndSlog("StartWatchdog"); 
  9.     Watchdog.getInstance().start(); 
  10.    traceEnd(); 

因为是线程,所以,只要start即可;

2、查看WatchDog的构造方法

  1. private Watchdog() { 
  2.         super("watchdog"); 
  3.         // Initialize handler checkers for each common thread we want to check.  Note 
  4.         // that we are not currently checking the background thread, since it can 
  5.         // potentially hold longer running operations with no guarantees about the timeliness 
  6.         // of operations there. 
  7.         // The shared foreground thread is the main checker.  It is where we 
  8.         // will also dispatch monitor checks and do other work
  9.         mMonitorChecker = new HandlerChecker(FgThread.getHandler(), 
  10.                 "foreground thread", DEFAULT_TIMEOUT); 
  11.         mHandlerCheckers.add(mMonitorChecker); 
  12.         // Add checker for main thread.  We only do a quick check since there 
  13.         // can be UI running on the thread. 
  14.         mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()), 
  15.                 "main thread", DEFAULT_TIMEOUT)); 
  16.         // Add checker for shared UI thread. 
  17.         mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), 
  18.                 "ui thread", DEFAULT_TIMEOUT)); 
  19.         // And also check IO thread. 
  20.         mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), 
  21.                 "i/o thread", DEFAULT_TIMEOUT)); 
  22.         // And the display thread. 
  23.         mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(), 
  24.                 "display thread", DEFAULT_TIMEOUT)); 
  25.         // Initialize monitor for Binder threads. 
  26.         addMonitor(new BinderThreadMonitor()); 
  27.         mOpenFdMonitor = OpenFdMonitor.create(); 
  28.         // See the notes on DEFAULT_TIMEOUT. 
  29.         assert DB || 
  30.                 DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS; 
  31.         // mtk enhance 
  32.         exceptionHWT = new ExceptionLog(); 
  33.     } 

重点关注两个对象:mMonitorChecker和mHandlerCheckers

mHandlerCheckers列表元素的来源:

构造对象的导入:UiThread、IoThread、DisplatyThread、FgThread加入

外部导入:Watchdog.getInstance().addThread(handler);

mMonitorChecker列表元素的来源:

外部导入:Watchdog.getInstance().addMonitor(monitor);

特别说明:addMonitor(new BinderThreadMonitor());

3、查看WatchDog的run方法

  1. public void run() { 
  2.         boolean waitedHalf = false
  3.         boolean mSFHang = false
  4.         while (true) { 
  5.             ······ 
  6.             synchronized (this) { 
  7.                 ······ 
  8.                 for (int i=0; i<mHandlerCheckers.size(); i++) { 
  9.                     HandlerChecker hc = mHandlerCheckers.get(i); 
  10.                     hc.scheduleCheckLocked(); 
  11.                 } 
  12.                 ······ 
  13.             } 
  14.             ······ 

对mHandlerCheckers列表元素进行检测;

4、查看HandlerChecker的scheduleCheckLocked

  1. public void scheduleCheckLocked() { 
  2.         if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) { 
  3.                 // If the target looper has recently been polling, then 
  4.                 // there is no reason to enqueue our checker on it since that 
  5.                 // is as good as it not being deadlocked.  This avoid having 
  6.                 // to do a context switch to check the thread.  Note that we 
  7.                 // only do this if mCheckReboot is false and we have no 
  8.                 // monitors, since those would need to be executed at this point. 
  9.                 mCompleted = true
  10.                 return
  11.         } 
  12.         if (!mCompleted) { 
  13.                 // we already have a check in flight, so no need 
  14.                 return
  15.         } 
  16.         mCompleted = false
  17.         mCurrentMonitor = null
  18.         mStartTime = SystemClock.uptimeMillis(); 
  19.         mHandler.postAtFrontOfQueue(this); 

mMonitors.size() == 0的情況:主要为了检查mHandlerCheckers中的元素是否超时,运用的手段:mHandler.getLooper().getQueue().isPolling();

mMonitorChecker对象的列表元素一定是大于0,此时,关注点在mHandler.postAtFrontOfQueue(this);

  1. public void run() { 
  2.        final int size = mMonitors.size(); 
  3.        for (int i = 0 ; i < size ; i++) { 
  4.             synchronized (Watchdog.this) { 
  5.                 mCurrentMonitor = mMonitors.get(i); 
  6.             } 
  7.             mCurrentMonitor.monitor(); 
  8.        } 
  9.        synchronized (Watchdog.this) { 
  10.             mCompleted = true
  11.             mCurrentMonitor = null
  12.        } 

监听monitor方法,这里是对mMonitors进行monitor,而能够满足条件的只有:mMonitorChecker,例如:各种服务通过addMonitor加入列表;

  1. ActivityManagerService.java 
  2.     Watchdog.getInstance().addMonitor(this);  
  3. InputManagerService.java 
  4.     Watchdog.getInstance().addMonitor(this);  
  5. PowerManagerService.java 
  6.     Watchdog.getInstance().addMonitor(this);  
  7. ActivityManagerService.java 
  8.     Watchdog.getInstance().addMonitor(this);  
  9. WindowManagerService.java 
  10.     Watchdog.getInstance().addMonitor(this); 

而被执行的monitor方法很简单,例如ActivityManagerService:

  1. public void monitor() { 
  2.      synchronized (this) { } 

这里仅仅是检查系统服务是否被锁住;

Watchdog的内部类;

  1. private static final class BinderThreadMonitor implements Watchdog.Monitor { 
  2.         @Override 
  3.         public void monitor() { 
  4.             Binder.blockUntilThreadAvailable(); 
  5.         } 
  6. android.os.Binder.java 
  7. public static final native void blockUntilThreadAvailable(); 
  8. android_util_Binder.cpp 
  9. static void android_os_Binder_blockUntilThreadAvailable(JNIEnv* env, jobject clazz) 
  10.     return IPCThreadState::self()->blockUntilThreadAvailable(); 
  11. IPCThreadState.cpp 
  12. void IPCThreadState::blockUntilThreadAvailable() 
  13.     pthread_mutex_lock(&mProcess->mThreadCountLock); 
  14.     while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) { 
  15.         ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%lu mMaxThreads=%lu\n"
  16.                 static_cast<unsigned long>(mProcess->mExecutingThreadsCount), 
  17.                 static_cast<unsigned long>(mProcess->mMaxThreads)); 
  18.         pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock); 
  19.     } 
  20.     pthread_mutex_unlock(&mProcess->mThreadCountLock); 

这里仅仅是检查进程中包含的可执行线程的数量不能超过mMaxThreads,如果超过了最大值(31个),就需要等待;

  1. ProcessState.cpp 
  2. #define DEFAULT_MAX_BINDER_THREADS 15 
  3. 但是systemserver.java进行了设置 
  4. // maximum number of binder threads used for system_server 
  5. // will be higher than the system default 
  6. private static final int sMaxBinderThreads = 31; 
  7. private void run() { 
  8.     ······ 
  9.     BinderInternal.setMaxThreads(sMaxBinderThreads); 
  10.     ······ 

5、发生超时后退出

  1. public void run() { 
  2.     ······ 
  3.     Process.killProcess(Process.myPid()); 
  4.     System.exit(10); 
  5.     ······ 

kill自己所在进程(system_server),并退出;

二、原理解释

1、系统中所有需要监控的服务都调用Watchdog的addMonitor添加Monitor Checker到mMonitors这个List中或者addThread方法添加Looper Checker到mHandlerCheckers这个List中;

2、当Watchdog线程启动后,便开始无限循环,它的run方法就开始执行;

  • 第一步调用HandlerChecker#scheduleCheckLocked处理所有的mHandlerCheckers
  • 第二步定期检查是否超时,每一次检查的间隔时间由CHECK_INTERVAL常量设定,为30秒,每一次检查都会调用evaluateCheckerCompletionLocked()方法来评估一下HandlerChecker的完成状态:
  • COMPLETED表示已经完成;
  • WAITING和WAITED_HALF表示还在等待,但未超时,WAITED_HALF时候会dump一次trace.
  • OVERDUE表示已经超时。默认情况下,timeout是1分钟;

3、如果超时时间到了,还有HandlerChecker处于未完成的状态(OVERDUE),则通过getBlockedCheckersLocked()方法,获取阻塞的HandlerChecker,生成一些描述信息,保存日志,包括一些运行时的堆栈信息。

4、最后杀死SystemServer进程;

总结

Watchdog是一个线程,用来监听系统各项服务是否正常运行,没有发生死锁;

HandlerChecker用来检查Handler以及monitor;

monitor通过锁来判断是否死锁;

超时30秒会输出log,超时60秒会重启;

Watchdog会杀掉自己的进程,也就是此时system_server进程id会变化;

本文转载自微信公众号「Android开发编程」

 

责任编辑:姜华 来源: Android开发编程
相关推荐

2012-05-31 02:54:07

HadoopJava

2023-08-28 07:49:24

Redisson锁机制源码

2021-12-06 14:52:08

动画Android补间动画

2020-05-26 18:50:46

JVMAttachJava

2021-03-16 21:45:59

Python Resize机制

2023-06-15 14:09:00

解析器Servlet容器

2011-06-23 13:10:39

Python 对象机制

2011-03-15 11:33:18

iptables

2014-08-26 11:11:57

AsyncHttpCl源码分析

2011-08-24 16:59:59

LuaModule

2023-10-31 16:00:51

类加载机制Java

2014-07-18 11:11:16

SEAndroid

2011-05-26 10:05:48

MongoDB

2021-08-12 16:28:10

AndroidHandleLooper

2011-06-23 14:40:13

Qt 信号

2021-06-28 10:51:55

Redisson分布式锁Watchdog

2011-05-26 16:18:51

Mongodb

2021-01-04 08:09:07

Linux内核Watchdog

2010-04-16 11:17:33

hints调整

2017-08-16 16:20:01

Linux内核态抢占用户态抢占
点赞
收藏

51CTO技术栈公众号