Adnroid Watchdog实现详解

本文基于Android4.4,

最近查了下watchdog打印错误log的问题。头都大。。。也查看了下android framework 下watchdog的实现代码,做个记录以备后边温习,以及新入行后辈们能够快速上手

以PowerManagerservice为例做简单流程分析

Watchdog功能:

1.      监视reboot广播

2.      监视加到check list 的service是否死锁

功能介绍:

功能1非常简单,就是注册一个broadcastreceiver,收到关机的Action就去走关机或reboot流程

主要说下功能2

PowerManagerService.java:

先说一下构造函数:

private Watchdog() {

super("watchdog");

// Initialize handler checkers for each common thread we want tocheck.  Note

// that we are not currently checking the background thread, since itcan

// potentially hold longer running operations with no guarantees aboutthe timeliness

// of operations there.

// The shared foreground thread is the main checker.  It is where we

// will also dispatch monitor checks and do other work.

mMonitorChecker = newHandlerChecker(FgThread.getHandler(),

"foreground thread",DEFAULT_TIMEOUT);

mHandlerCheckers.add(mMonitorChecker);

// Add checker for main thread. We only do a quick check since there

// can be UI running on the thread.

mHandlerCheckers.add(new HandlerChecker(newHandler(Looper.getMainLooper()),

"main thread",DEFAULT_TIMEOUT));

// Add checker for shared UI thread.

mHandlerCheckers.add(newHandlerChecker(UiThread.getHandler(),

"ui thread", DEFAULT_TIMEOUT));

// And also check IO thread.

mHandlerCheckers.add(newHandlerChecker(IoThread.getHandler(),

"i/o thread",DEFAULT_TIMEOUT));

}

红色部分很重要,添加UIThread,FgThread,IoThread,还有当前new
Watchdog时候的主线程,其实就是System_server主线程

接下来说下init:

public void init(Context context, LightsService ls,

ActivityManagerService am, BatteryService bs, IBatteryStats bss,

IAppOpsService appOps, DisplayManagerService dm) {

。。。。。。

mHandlerThread = new HandlerThread(TAG);

mHandlerThread.start();

mHandler = new PowerManagerHandler(mHandlerThread.getLooper());

Watchdog.getInstance().addMonitor(this); 
//添加本对象到monitor列表里

Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName());

。。。。。。

}

public void addMonitor(Monitor monitor) {

synchronized (this) {

if (isAlive()) {

throw newRuntimeException("Monitors can‘t be added once the Watchdog isrunning");

}

mMonitorChecker.addMonitor(monitor);//

}

}

Watchdog构造函数里

mMonitorChecker = newHandlerChecker(FgThread.getHandler(),

"foreground thread",DEFAULT_TIMEOUT);

public void addMonitor(Monitor monitor){

//mMonitors是一个数组list  ArrayList<Monitor> mMonitors = newArrayList<Monitor>();

//添加powermanagerservice对象到此list

mMonitors.add(monitor);

}

接着说下Watchdog.getInstance().addThread(mHandler,mHandlerThread.getName());

public void addThread(Handler thread,String name) {

addThread(thread, name, DEFAULT_TIMEOUT);

}

public void addThread(Handler thread,String name, long timeoutMillis) {

synchronized (this) {

if (isAlive()) {

throw newRuntimeException("Threads can‘t be added once the Watchdog isrunning");

}

//把PowerManagerHandler
对象添加到mHandlerCheckers列表

mHandlerCheckers.add(newHandlerChecker(thread, name, timeoutMillis));

}

}

准备工作到此已经做完,接下来就是watchdog不停监视每个service是否死锁

代码主要在Watchdog.java

System_server会启动watchdog会跑到run函数:

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

public void run() {

booleanwaitedHalf= false;

while(true){

finalArrayListblockedCheckers;

finalStringsubject;

finalbooleanallowRestart;

synchronized(this){

longtimeout= CHECK_INTERVAL;

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

for (inti=0; i<mHandlerCheckers.size(); i++) {

HandlerChecker hc =mHandlerCheckers.get(i);

hc.scheduleCheckLocked();

}

//睡眠一段时间

longstart= SystemClock.uptimeMillis();

while(timeout> 0) {

try{

wait(timeout);

}catch(InterruptedException e) {

Log.wtf(TAG,e);

}

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

}

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

finalintwaitState =evaluateCheckerCompletionLocked();

if(waitState== COMPLETED) {

waitedHalf=false;

continue;

}elseif (waitState == WAITING) {

continue;

}elseif (waitState == WAITED_HALF) {

if(!waitedHalf){

ArrayListpids= new ArrayList();

pids.add(Process.myPid());

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

NATIVE_STACKS_OF_INTEREST);

waitedHalf=true;

}

continue;

}

......

{

//杀死SystemServer

Process.killProcess(Process.myPid());

System.exit(10);

}

waitedHalf=false;

}

}

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

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

publicvoidscheduleCheckLocked() {

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

mCompleted= true;

return;

}

if(!mCompleted) {

return;

}

mCompleted= false;

mCurrentMonitor= null;

mStartTime= SystemClock.uptimeMillis();

mHandler.postAtFrontOfQueue(this);//给监视的线程发送消息

}

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

public voiddispatchMessage(Message msg) {

if (msg.callback != null) {

handleCallback(msg);

} else {

if (mCallback != null) {

if(mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);

}

}

private static void handleCallback(Message message) {

message.callback.run();

}

这个消息的处理方法是HandlerChecker类的方法run(),代码如下:

publicvoidrun() {

finalint 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()方法的实现通常如下:

publicvoidmonitor() {

synchronized(mLock) {

}

}

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

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

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

privateintevaluateCheckerCompletionLocked() {

intstate = COMPLETED;

for(int i=0; i

HandlerCheckerhc =mHandlerCheckers.get(i);

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

}

returnstate;

}

!waitedHalf, pids, null, null,NATIVE_STACKS_OF_INTEREST);

getCompletionStateLocked()函数根据等待时间来确认返回HandlerChecker对象的状态,代码如下:

publicintgetCompletionStateLocked() {

if(mCompleted) {

returnCOMPLETED;

}else {

longlatency = SystemClock.uptimeMillis() -mStartTime;

if(latency < mWaitMax/2) {

returnWAITING;

}else if (latency < mWaitMax) {

returnWAITED_HALF;

}

}

returnOVERDUE;

}

到此就已经分析完毕,如果对发送消息不明白可以看我博文里handler,looper的那篇文章。中间网上找了些博文,借鉴。如果有什么不足之处,请指正。。

时间: 2025-01-11 23:40:00

Adnroid Watchdog实现详解的相关文章

keepalived的配置详解(非常详细)

keepalived的配置详解(非常详细) 2017-01-22 15:24 2997人阅读 评论(0) 收藏 举报  分类: 运维学习(25)  转载自:http://blog.csdn.net/u010391029/article/details/48311699 1. 前言 VRRP(Virtual Router Redundancy Protocol)协议是用于实现路由器冗余的协议,最新协议在RFC3768中定义,原来的定义RFC2338被废除,新协议相对还简化了一些功能. 2. 协议说

红帽Linux故障定位技术详解与实例(2)

红帽Linux故障定位技术详解与实例(2) 2011-09-28 14:26 圈儿 BEAREYES.COM 我要评论(0) 字号:T | T 在线故障定位就是在故障发生时, 故障所处的操作系统环境仍然可以访问,故障处理人员可通过console, ssh等方式登录到操作系统上,在shell上执行各种操作命令或测试程序的方式对故障环境进行观察,分析,测试,以定位出故障发生的原因. AD:2014WOT全球软件技术峰会北京站 课程视频发布 3.内核故障情形及处理 (1)内核panic panic是内

红帽Linux故障定位技术详解与实例(3)

红帽Linux故障定位技术详解与实例(3) 在线故障定位就是在故障发生时, 故障所处的操作系统环境仍然可以访问,故障处理人员可通过console, ssh等方式登录到操作系统上,在shell上执行各种操作命令或测试程序的方式对故障环境进行观察,分析,测试,以定位出故障发生的原因. AD:2014WOT全球软件技术峰会北京站 课程视频发布 5.用kdump工具内核故障定位实例 A) 部署Kdump 部署 kdump 收集故障信息的步骤如下: (1)设置好相关的内核启动参数 在 /boot/grub

keepalived基础配置详解(一)

一.简介 keepalived是一个基于VRRP协议来实现的WEB服务高可用方案,可以利用其来避免单点故障,用于web服务器的健康状态检测,如果有一台web服务器工作出现故障,keepalived将检测到,并将有故障的web服务器从系统中下线,等待服务器故障排除之后,将服务器重新添加至系统中. 要想学习keepalived,必须先了解VRRP协议,keepalived就是在VRRP协议的基础之上实现的. 二.VRRP协议简介 1.VRRP协议 虚拟路由冗余协议 VRRP(Virtual Rout

linux移植u-boot(一)——U-Boot详解+自定义命令实战

linux移植u-boot(一)--U-Boot详解+自定义命令实战 2015-02-07 一.Bootloader ????简单地说:Bootloader主要功能就是 在系统上电时开始执行,初始化硬件和设备,准备好软件环境,最后调用操作系统. ????具体的包含:关闭你看门狗WATCHDOG,改变系统时钟,初始化存储控制器 ,将操作系统内核代码复制到内存中去运行. ????为了开发方便,可以增加网络功能,从PC上通过串口或者网络下载文件,烧写文件,将flash上的内核代码解压后运行等. Boo

【嵌入式开发】 Bootloader 详解 ( 代码环境 | ARM 启动流程 | uboot 工作流程 | 架构设计)

作者 : 韩曙亮 博客地址 : http://blog.csdn.net/shulianghan/article/details/42462795 转载请著名出处 相关资源下载 :  -- u-boot 源码 : http://download.csdn.net/detail/han1202012/8342761 -- S3C2440 文档 : http://download.csdn.net/detail/han1202012/8342701 -- S5PV210_iROM_Applicati

keepalived详解 结合lvs

Keepalived原理与实战精讲 什么是Keepalived呢,keepalived观其名可知,保持存活,在网络里面就是保持在线了,也就是所谓的高可用或热备,用来防止单点故障(单点故障是指一旦某一点出现故障就会导致整个系统架构的不可用)的发生,那说到keepalived时不得不说的一个协议就是VRRP协议,可以说这个协议就是keepalived实现的基础,那么首先我们来看看VRRP协议 注:搞运维的要有足够的耐心哦,不理解协议就很难透彻的掌握keepalived的了 一,VRRP协议 VRRP

HA架构之heartbeat安装配置详解

一.主备相互解析 设置多个ip # vim /etc/hosts 192.168.7.2    css01 192.168.7.3    css02 二.配置扩展yum源 wget www.lishiming.net/data/attachment/forum/epel-release-6-8_64.noarch.rpm rpm -ivh epel-release-6-8_64.noarch.rpm 三.上传安装包 yum -y install lrzsz cd /usr/local/src r

轻量级高可用实现工具--keepalived详解

一 .keepalived简介 keepalived:它的诞生最初是为ipvs(一些服务,内核中的一些规则)提供高可用性的,最初最主要目的是能够自主调用ipvsadm来生成规则,并且能够自动实现将用户访问的地址转移到其他节点上进行实现的. keepalived:核心包含两个ckechers和VRRP协议. ckeckers #检查服务检查reserved的健康状况的,基于脚本也可以服务本身的健康状况.这里是实现ipvs后端健康状况的检测的. VRRP # Virtual Router Redun