android2.2 watchdog分析
1 watchdog分析
Watchdog就是“看门狗”。其最初存在的意义是因为以前嵌入式设备上的程序经常跑飞(电磁干扰之类的),所以专门设置了一个硬件看门狗,每个一段时间,看门狗就去检查一下某个参数是否被设置了,如果发现该参数没有被设置,则判断为系统出错,然后就会强制重启。
在软件层面上,Android对Systemserver的参数是否被设置也很谨慎,所以专门为它增加了一条看门狗,它主要看几个重要service的门。一旦发现service出现问题,就会kill system_server进程,进而导致zygote进程自杀,最后导致java世界重启。
我们先把systemServer使用watchdog的调用流程总结一下,然后以此为切入点来分析watchdog。SS和watchdog的交互流程可以总结如下:
①watchdog.getInstance.Init()
②watchdog.getInstance.start()
③watchdog.getInstance.addMonitor()
1.1 创建和初始化watchdog
GetInstance用于创建watchdog,代码如下:
|
public static Watchdog getInstance() { if (sWatchdog == null) { sWatchdog = new Watchdog(); //使用了单实例模式。 } return sWatchdog; } //构造函数 private Watchdog() { super("watchdog"); /*为每一个我们想检查的普通线程初始化一个handler检测器。需要注意的是:我们并不马上检查后台线程,因为这样可能会执行更长的操作且无法保证这些操作的耗时是合适的。 我们大家共享的前台线程是主要的检查者,同时我们也会派遣监视器进行检查并做一些其他的工作。 Handler是系统消息处理的地方,会在后面进行详细的分析*/ mMonitorChecker = new HandlerChecker(FgThread.getHandler(), "foreground thread", DEFAULT_TIMEOUT); mHandlerCheckers.add(mMonitorChecker); //为主线程添加一个checker,鉴于可能会是一个UI正运行在主线程中,所以我们只在这里做一个快速的检查 mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()), "main thread", DEFAULT_TIMEOUT)); // 为共享的UI线程添加一个checker mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), "ui thread", DEFAULT_TIMEOUT)); // 同时为io线程添加一个checker mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread", DEFAULT_TIMEOUT)); } |
在看门狗诞生后,再来看看init函数:
|
public void init(Context context, BatteryService battery, PowerManagerService power, AlarmManagerService alarm, ActivityManagerService activity) { mResolver = context.getContentResolver(); mBattery = battery; mPower = power; mAlarm = alarm; mActivity = activity; /*注册一个广播接受者,这个接受者只接收ACTION标记为REBOOT的广播,并且这个接受者拥有重启系统的权限*/ context.registerReceiver(new RebootRequestReceiver(), new IntentFilter(Intent.ACTION_REBOOT), android.Manifest.permission.REBOOT, null); } |
1.2 watchdog跑起来
Systemserver调用watchdog的start函数,这将导致watchdog的run函数在另一个线程中被执行:
|
@Override public void run() { boolean waitedHalf = false; while (true) {//外层while循环 final ArrayList<HandlerChecker> blockedCheckers; final String subject; final boolean allowRestart; synchronized (this) { long timeout = CHECK_INTERVAL; // 检查的间隔时间,=2500 //对每一个checker进行轮询,scheduleCheckLocked会调用handler的postAtFrontOfQueue(Runnable r)函数,这个函数发送的消息会在另一个线程中得到处理,该线程触发 monitor去检查server的状态(是否死锁). for (int i=0; i<mHandlerCheckers.size(); i++) { HandlerChecker hc = mHandlerCheckers.get(i); hc.scheduleCheckLocked(); } long start = SystemClock.uptimeMillis(); //检查的开始时间 //在CHECK_INTERVAL时间内循环等待检查结果 while (timeout > 0) { try { wait(timeout); //等待检查的结果 } catch (InterruptedException e) { Log.wtf(TAG, e); } timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start); } /* waitState共有四种状态:COMPLETED = 0;WAITING = 1;WAITED_HALF = 2; OVERDUE = 3; evaluateCheckerCompletionLocked函数的作用是:遍历所有的checkers,返回这些checkers中最大的State值——值越大就说明该checker检查到的状态越严重*/ final int waitState = evaluateCheckerCompletionLocked(); if (waitState == COMPLETED) { // 表明经过所有检查后,发现一切service正常,本轮检查后,系统不处于waitedHalf状态 waitedHalf = false; continue; } else if (waitState == WAITING) { // 有某些checker还在它们的间隔时间内等待检查结果,那么就直接返回,重新检查,waitedHalf状态值不改变 continue; } else if (waitState == WAITED_HALF) {//已经有某些个checker处于WAITED_HALF状态了 if (!waitedHalf) { //如果当前总的检查状态并不处于waitedHalf状态,那么就pull一个栈跟踪到ActivityManagerService中,并将waitedHalf状态置为真,然后继续检查;否则直接继续检查 ArrayList<Integer> pids = new ArrayList<Integer>(); pids.add(Process.myPid()); ActivityManagerService.dumpStackTraces(true, pids, null, null, NATIVE_STACKS_OF_INTEREST); waitedHalf = true; } continue; } //说明watchdog已经处于OVERDUE状态了,就可能需要重启了 blockedCheckers = getBlockedCheckersLocked(); subject = describeCheckersLocked(blockedCheckers); allowRestart = mAllowRestart; } /*代码运行到这里就说明watchdog已经处于OVERDUE状态了(即系统极可能已经挂起了~),那么我们首先收集SS进程中所有线程的栈跟踪信息,然后杀掉SS进程,这样就会导致系统重启了~*/ EventLog.writeEvent(EventLogTags.WATCHDOG, subject); …….. if (controller != null) { //如果第一次检查的时候发现controller可以处理这种情况,那么就不需要重启,重新检查即可 Slog.i(TAG, "Reporting stuck state to activity controller"); try { Binder.setDumpDisabled("Service dumps disabled due to hung system process."); // 1 = keep waiting, -1 = kill system int res = controller.systemNotResponding(subject); if (res >= 0) { Slog.i(TAG, "Activity controller requested to coninue to wait"); waitedHalf = false; continue; } } catch (RemoteException e) { } } // 已经检查过两次了,还是有问题,那么说明这次是真的有问题了,所以SS就自杀 if (Debug.isDebuggerConnected()) { Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process"); } …….. Process.killProcess(Process.myPid()); System.exit(10); } //检查发现没有问题了,就将waitedHalf值置为假 waitedHalf = false; } } |
总结:watchdog隔一段时间就会向另一个线程的消息队列头发送一条消息,那个线程将检查各个service的状况。而watchdog会等待检查的结果,如果第二次还是没有正确的返回结果,那么就杀掉SS。
1.3 列队检查
这么多service,哪些是watchdog比较关注的呢?一共有3个:
①activityManagerService
②powerManagerService
③windowManagerService
要想支持watchdog的检查,就需要让这些service实现monitor接口,然后watchdog就会调用它们的monitor函数进行检查了。检查的地方是在watchdog::HandlerChecker类的run中:
|
public void run() { // mMonitors是所有monitor的集合 final int size = mMonitors.size(); //检查各个service for (int i = 0 ; i < size ; i++) { synchronized (Watchdog.this) { mCurrentMonitor = mMonitors.get(i); } mCurrentMonitor.monitor(); //调用该service的monitor函数 } synchronized (Watchdog.this) { //如果没有问题,就设置mCompleted为真 mCompleted = true; mCurrentMonitor = null; } } |
那么,service是如何判断自己的健康状况的呢?我们以ActivityManagerService为例,先看看它是如何把自己交给watchdog检查的:
|
①在其构造函数中有: Watchdog.getInstance().addMonitor(this); //把自己加入到watchdog的检查队列中 ②ActivityManagerService自己重载的monitoe函数: public void monitor() { //执行死锁检查 synchronized (this) { } } 原来,watchdog最怕系统服务死锁,对于这种情况也只能采取杀系统的方法了~ |
1.4总结
其实watchdog是周期性地调用需要进行状态检查的服务自己的monitor函数来判断该服务是否死锁。然后根据返回结果来判断系统是否需要重启。
android2.2 watchdog分析的更多相关文章
- OpenFaaS实战之五:大话watchdog
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- [深入理解Android卷一全文-第四章]深入理解zygote
由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该由于纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的所有内容. ...
- android -- WatchDog看门狗分析
在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生 ...
- Watchdog问题实例分析
1.日志获取 Watchdog相关的问题甚至需要以下所有的日志: logcat 通过adb logcat命令输出Android的一些当前运行日志,可以通过logcat的 -b 参数指定要输出的日志缓冲 ...
- Android2.2源码属性服务分析
属性服务property service 大家都知道,在windows中有个注册表,里面存储的是一些键值对.注册表的作用就是:系统或者应用程序将自己的一些属性存储在注册表中,即使系统或应用程序重启,它 ...
- Android2.2源码init机制分析
1 源码分析必备知识 1.1 linux内核链表 Linux内核链表的核心思想是:在用户自定义的结构A中声明list_head类型的成员p,这样每个结构类型为A的变量a中,都拥有同样的成员p,如下: ...
- android2.3 View视图框架源码分析之一:android是如何创建一个view的?
View是所有控件的一个基类,无论是布局(Layout),还是控件(Widget)都是继承自View类.只不过layout是一个特殊的view,它里面创建一个view的数组可以包含其他的view而已. ...
- 《深入理解Android2》读书笔记(四)
接上篇<深入理解Android2>读书笔记(三) ActivityManagerService(AMS) 1.AMS由ActivityManagerNative(AMN)类派生,并实现Wa ...
- [原] KVM虚拟机网络闪断分析
背景 公司云平台的机器时常会发生网络闪断,通常在10s-100s之间. 异常情况 VM出现问题时,表现出来的情况是外部监控系统无法访问,猜测可能是由于系统假死,OVS链路问题等等.但是在出现网络问题的 ...
随机推荐
- Java8函数之旅 (三) --几道关于流的练习题
为什么要有练习题? 所谓学而不思则罔,思而不学则殆,在系列第一篇就表明我认为写博客,既是分享,也是自己的巩固,我深信"纸上得来终觉浅,绝知此事要躬行"的道理,因此之后的几篇博 ...
- java算法面试题:递归算法题2 第1个人10,第2个比第1个人大2岁,依次递推,请用递归方式计算出第8个人多大?
package com.swift; public class Digui_Return { public static void main(String[] args) { /* * 递归算法题2 ...
- java 实现猜数字游戏 随机给定一个数字,猜大小直到正确
package com.swift; import java.util.Random; import java.util.Scanner; public class GuessBigSmall { p ...
- 防止sql注入方法 如何防止java中将MySQL的数据库验证密码加上 ' or '1'= '1 就可以出现万能密码 的PreparedStatement
package com.swift; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Prepar ...
- SummerVocation_Leaning--java动态绑定(多态)
概念: 动态绑定:在执行期间(非编译期间)判断所引用的对象的实际类型,根据实际类型调用其相应的方法.如下例程序中,根据person对象的成员变量pet所引用的不同的实际类型调用相应的方法. 具体实现好 ...
- 为什么90%的IT人员都不适合做老大?
什么是格局? 格局就是能够很好的平衡短期利益和长期利益. 过分注重短期利益的人必然会失去长期利益,到头来一定会很普通. 例如:跳槽不断,可能短期薪资会增长,但长期来看后劲可能会不足,未来发展空间会变窄 ...
- php扩展开发-实现一个简易的哈希表
从一个简易的哈希表入手,会让你更好的理解php的哈希表,他们的本质是一样的,只是php的哈希表做了更多的功能扩展,php的哈希表是php语言的一个重要核心,大量的内核代码使用到哈希表. #includ ...
- 虚拟主机的搭建(ubuntu+apache2)
搭建环境:windows+VMware(Ubuntu)+apache2.(同一IP,不同域名) 1:在VMware的虚拟机Ubuntu下安装apache2(怎么安装百度一下就能找到): 2: apac ...
- JZOJ 4307. 喝喝喝
Description
- JZOJ 1267. 路障
1267. 路障(block.pas/c/cpp) (File IO): input:block.in output:block.out Time Limits: 1000 ms Memory Li ...