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链路问题等等.但是在出现网络问题的 ...
随机推荐
- 在Drupal7中创建web接口
Services 模块允许您从一个主要模块后端配置和管理区域启用您 Drupal 站点上自定义构建的内容服务器和服务.该模块中包含的服务允许您调用内容,从 Drupal 的默认和分配的 File.Co ...
- DOTA自走棋卡牌及搭配阵容
这个游戏其实就根炉石jjc和A牌轮抽一样,前期要找着质量牌抓,保证你至少不漏.根据你的需求补一些你不会上场的阵容组件,最后根据你的组件和核心紫卡来哪张来决定打什么.另外也要考虑场上另外几家,如果有一家 ...
- 架构图(拓扑图)画图工具分析整理(静态,动态,可交互图.层级tu)
最近要画架构图. 一方面有图片洁癖,另外一方面又不想不停的挪动图片. 一开始想用脑图软件. 发现脑图是树状的,架构模块依赖图是网状的.(也可以简化为层级图,不画交互关系.类似 dubbo 的架构图. ...
- c++question 005 c++中转义字符有哪些?
(1)'\a' 注意,这里不再是两个字符\ 和 a 而是表达了一个具体的含义是,蜂鸣一声 (2)'\n' 换行,这里不再是两个字符\ 和 n 而是表达了一个具体的含义是,相当于 endl (3)'\ ...
- .NET下寄宿于控制台的HTTPS监听
附上原文链接:https://blogs.msdn.microsoft.com/jpsanders/2009/09/29/how-to-walkthrough-using-httplistener-o ...
- CentOS---JDK安装与配置
1.先查看一下CentOS中存在的jdk安装包信息 # rpm -qa | grep java 查看CentOS安装的jdk版本 #java -version 2.分别执行以下命令将所有相关包都删除 ...
- 5- vue django restful framework 打造生鲜超市 -完成商品列表页(上)
使用Python3.6与Django2.0.2(Django-rest-framework)以及前端vue开发的前后端分离的商城网站 项目支持支付宝支付(暂不支持微信支付),支持手机短信验证码注册, ...
- 传智 杨中科老师 ASP.NET 笔记
- JZOJ 5344. 摘果子
Description Input Output Sample Input 7 9 39 6 13 2 22 6 7 4 -19 5 28 6 -17 1 2 1 3 2 4 1 5 4 6 2 7 ...
- vue之小小动态按钮
Vue是前台框架,可以独立完成前后端分离式web项目渐进式的javascript框架 ,今天我们来设计一个简单的动态按钮 具体效果图如下: 点击后会变成这样: 首先我们需要下载vue.js:htt ...