android2.2 watchdog分析

摘要:
1watchdog分析Watchdog就是“看门狗”。在软件层面上,Android对Systemserver的参数是否被设置也很谨慎,所以专门为它增加了一条看门狗,它主要看几个重要service的门。我们先把systemServer使用watchdog的调用流程总结一下,然后以此为切入点来分析watchdog。SS和watchdog的交互流程可以总结如下:①watchdog.getInstance.Init()②watchdog.getInstance.start()③watchdog.getInstance.addMonitor()1.1创建和初始化watchdogGetInstance用于创建watchdog,代码如下:publicstaticWatchdoggetInstance(){if{sWatchdog=newWatchdog();//使用了单实例模式。}returnsWatchdog;}//构造函数privateWatchdog(){super;/*为每一个我们想检查的普通线程初始化一个handler检测器。

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分析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【STM32H7教程】第5章 STM32H7下载和调试方法(MDK5)C++ 继承、派生、多态下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Redis分布式锁,看完不懂你打我

简易的redis分布式锁 加锁: set key my_random_value NX PX 30000 这个命令比setnx好,因为可以同时设置过期时间。不设置过期时间,应用挂了,解不了锁,就一直锁住了。 解锁: if redis.call("get",KEYS[1])==ARGV[1] then return redis.call("del",K...

Delphi线程的终止

当线程对象的Execute()执行完毕,我们就认为此线程终止了。这时候,它会调用Delphi的一个标准例程EndThread(),这个例程再调用API函数ExitThread()。由ExitThread()来清除线程所占用的栈。 当结束使用TThread对象时,应该确保已经把这个Delphi对象从内存中清除了。这才能确保所有内存占有都释放掉。尽管在进程终止...

java线程安全初窥探

知识点: 线程同步 线程并发 问题描述:在当处理全局变量的时候,当两个或者以上的线程处理同一个** 全局 **变量的时候,可能会出现冲突问题。 java 同步函数 首先看一下问题场景 package com.Thread.Test; /** * 抢票问题的一个案例分析 */ class ThreadTrain implements Runna...

Apsara Clouder基础技能认证:阿里巴巴编码规范 考试备考题库

考试网址: https://edu.aliyun.com/clouder/exam/intro/33 共50道题 限时90分钟 阿里云大学Apsara Clouder基础技能认证——阿里巴巴编码规范认证考试。成绩在80分以上可获得认证证书。本考试应用了防作弊系统,请遵守考试秩序。(Java代码在线检测及IDE插件下载:https://edu.aliyun...

.Net 调式案例—实验4 高CPU(High CPU)回顾

转载: https://www.cnblogs.com/softfair/archive/2008/03/03/dotnet-Debugging-Demos---Lab-4-HighCPU--Review.html   .Net 调式案例—实验4 高CPU(High CPU)回顾   现在开始第四个实验。 前面的案例和设置指导 请参看前面发布的文章。...

初识安卓之利用Handler进行线程间数据传递

背景:点击界面上一个按钮,使文本框中的数字加1,此过程中,如果按钮点击事件是开启了一个新的线程,让文本框中的文字加1,则运算后的结果无法返回到主线程中,主线程拿不到修改后的值,无法更新文本框的内容,这时,使用Handler来进行线程间的数据传递 以下为DEMO public class PostActivityActivity extends Activi...