在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的芯片,俗称"看门狗"。





在Android系统中也需要看好几个重要的Service门,用于发现出了问题的Service杀掉SystemServer进程,所以有必要了解并分析其系统问题。



那么被监控的有哪些Service呢?



ActivityManagerService.java :frameworks\base\services\java\com\android\server\am

PowerManagerService.java    :frameworks\base\services\java\com\android\server

WindowManagerService.java   :frameworks\base\services\java\com\android\server





下面就依次分析一下其整个处理流程:



1、初始化

run @ SysemServer.java

      Slog.i(TAG, "Init Watchdog");

      Watchdog.getInstance().init(context, battery, power, alarm,

              ActivityManagerService.self());





这里使用单例模式创建:

    public static Watchdog getInstance() {

        if (sWatchdog == null) {

            sWatchdog = new Watchdog();

        }

        return sWatchdog;

    }



    public void init(Context context, BatteryService battery,

            PowerManagerService power, AlarmManagerService alarm,

            ActivityManagerService activity) {

        // 上下文环境变量

        mResolver = context.getContentResolver();

        mBattery = battery;

        mPower = power;

        mAlarm = alarm;

        mActivity = activity;

// 登记 RebootReceiver() 接收,用于reboot广播接收使用

context.registerReceiver(new RebootReceiver(),

new IntentFilter(REBOOT_ACTION));

...

// 系统启动时间

mBootTime = System.currentTimeMillis();

    }





ok,调用init函数启动完毕



2、运行中

run @ SysemServer.java

调用 Watchdog.getInstance().start(); 启动看门狗



首先看下 Watchdog 类定义:

/** This class calls its monitor every minute. Killing this process if they don't return **/

public class Watchdog extends Thread {

}



从线程类中继承,即会在一个单独线程中运行,调用thrrad.start()即调用 Watchdog.java 中的 run() 函数



    public void run() {

        boolean waitedHalf = false;





        while (true) {

            mCompleted = false;

            

            // 1、给mHandler发送 MONITOR 消息,用于请求检查 Service是否工作正常

            mHandler.sendEmptyMessage(MONITOR);





            synchronized (this) {

// 2、进行 wait 等待 timeout 时间确认是否退出循环

long timeout = TIME_TO_WAIT;                

                // NOTE: We use uptimeMillis() here because we do not want to increment the time we

                // wait while asleep. If the device is asleep then the thing that we are waiting

                // to timeout on is asleep as well and won't have a chance to run, causing a false

                // positive on when to kill things.

                long start = SystemClock.uptimeMillis();

                while (timeout > 0 && !mForceKillSystem) {

                    try {

                        wait(timeout);  // notifyAll() is called when mForceKillSystem is set

                    } catch (InterruptedException e) {

                        Log.wtf(TAG, e);

                    }

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

                }

// 3、如果 mCompleted 为真表示service一切正常,后面会再讲到

if (mCompleted && !mForceKillSystem) {

                    // The monitors have returned.

                    waitedHalf = false;

                    continue;

                }

// 4、表明检测到了有 deadlock-detection 条件发生,利用 dumpStackTraces 打印堆栈依信息

if (!waitedHalf) {

                    // We've waited half the deadlock-detection interval.  Pull a stack

                    // trace and wait another half.

                    ArrayList<Integer> pids = new ArrayList<Integer>();

                    pids.add(Process.myPid());

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

                    waitedHalf = true;

                    continue; // 不过这里会再次检测一次

                }

}



SystemClock.sleep(2000);

            

            // 5、打印内核栈调用关系

            // Pull our own kernel thread stacks as well if we're configured for that

            if (RECORD_KERNEL_THREADS) {

                dumpKernelStackTraces();

            }

// 6、ok,系统出问题了,检测到某个 Service 出现死锁情况,杀死SystemServer进程

// Only kill the process if the debugger is not attached.

            if (!Debug.isDebuggerConnected()) {

                Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name);

                Process.killProcess(Process.myPid());

                System.exit(10);

            } else {

                Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");

            }





            waitedHalf = false;

        }

    }





主要工作逻辑:监控线程每隔一段时间发送一条 MONITOR 线另外一个线程,另个一个线程会检查各个 Service 是否正常运行,看门狗就不停的检查并等待结果,失败则杀死SystemServer.





3、Service 检查线程



    /**

     * Used for scheduling monitor callbacks and checking memory usage.

     */

    final class HeartbeatHandler extends Handler {

@Override
 

    public void handleMessage(Message msg) {  // Looper 消息处理函数

            switch (msg.what) {

            

                case MONITOR: {

// 依次检测各个服务,即调用 monitor() 函数

final int size = mMonitors.size();

for (int i = 0 ; i < size ; i++) {

                        mCurrentMonitor = mMonitors.get(i);

                        mCurrentMonitor.monitor();

                    }

// 检测成功则设置 mCompleted 变量为 true

synchronized (Watchdog.this) {

                        mCompleted = true;

                        mCurrentMonitor = null;

                    }



下面我们来看一下各个Service如何确定自已运行ok呢?以 ActivityManagerService 为例:



首先加入检查队列:

private ActivityManagerService() {

        // Add ourself to the Watchdog monitors.

        Watchdog.getInstance().addMonitor(this);

}





然后实现 monitor() 函数:

    /** In this method we try to acquire our lock to make sure that we have not deadlocked */

    public void monitor() {

        synchronized (this) { }

    }

明白了吧,其实就是检查这个 Service 是否发生了死锁,对于此情况就只能kill SystemServer系统了。对于死锁的产生原因非常多,但有个情况需要注意:java层死锁可能发生在调用native函数,而native函数可能与硬件交互导致时间过长而没有返回,从而导致长时间占用导致问题。



4、内存使用检测

消息发送

final class GlobalPssCollected implements Runnable {

public void run() {

            mHandler.sendEmptyMessage(GLOBAL_PSS);

        }

    }

    

    检测内存处理函数:

    final class HeartbeatHandler extends Handler {

        @Override

        public void handleMessage(Message msg) {

            switch (msg.what) {

                case GLOBAL_PSS: {

                    if (mHaveGlobalPss) {

                        // During the last pass we collected pss information, so

                        // now it is time to report it.

                        mHaveGlobalPss = false;

                        if (localLOGV) Slog.v(TAG, "Received global pss, logging.");

logGlobalMemory();

}

                } break;

                

        

        其主要功能如下,统计pSS状况及读取相关linux内核中内存信息:

        void logGlobalMemory() {        

        mActivity.collectPss(stats);

        

        Process.readProcLines("/proc/meminfo",
mMemInfoFields, mMemInfoSizes);

        

        Process.readProcLines("/proc/vmstat",
mVMStatFields, mVMStatSizes);

}

android -- WatchDog看门狗分析的更多相关文章

  1. 服务器watchdog看门狗的理解

    1.什么是watchdog?watchdog,中文名称叫做“看门狗”,全称watchdog timer,从字面上我们可以知道其实它属于一种定时器.然而它与我们平常所接触的定时器在作用上又有所不同.普通 ...

  2. Resin 的watchdog(看门狗)介绍和resin负载均衡实现

    为了稳定和安全,Resin使用一个独立的watchdog进程来启动和监视Resin服务器.watchdog连续你检测Resin服务器的状态,如果其没有反应或者迟钝,将会重启Resin服务器进程.大多数 ...

  3. 【分享】iTOP-iMX6UL开发板驱动看门狗 watchdog 以及 Linux-c 测试例程

    iTOP-iMX6UL开发板看门狗测试例程,iTOP-iMX6UL 开发板的看门狗驱动默认已经配置,可以直接使用测试例程. 版本 V1.1:1.格式修改:2.例程修改完善,其中增加喂狗代码.1 看门狗 ...

  4. RM-Linux驱动--Watch Dog Timer(看门狗)驱动分析

    from:http://blog.csdn.net/geekcome/article/details/6595265 硬件平台:FL2440 内核版本:2.6.28 主机平台:Ubuntu 11,04 ...

  5. 基于S3C2440的嵌入式Linux驱动——看门狗(watchdog)驱动解读

    本文将介绍看门狗驱动的实现. 目标平台:TQ2440 CPU:s3c2440 内核版本:2.6.30 1. 看门狗概述 看门狗其实就是一个定时器,当该定时器溢出前必须对看门狗进行"喂狗“,如 ...

  6. u-boot分析(五)----I/D cache失效|关闭MMU和cache|关闭看门狗

    u-boot分析(五) 上篇博文我们按照210的启动流程,对u-boot启动中的设置异常向量表,设置SVC模式进行了分析,今天我们继续按照u-boot的启动流程对以下内容进行分析. 今天我们会用到的文 ...

  7. shell 之 用linux定时任务crontab和watchdog.sh脚本做软件看门狗

    1.简介 看门狗的作用是定期检测服务正常运行,如果发现服务不在了,会重新拉起服务:linux中可以利用系统的定时任务功能crontab定期的去执行watchdog.sh脚本,而watchdog.sh脚 ...

  8. Linux 软件看门狗 watchdog 喂狗

    Linux 自带了一个 watchdog 的实现,用于监视系统的运行,包括一个内核 watchdog module 和一个用户空间的 watchdog程序.内核 watchdog 模块通过 /dev/ ...

  9. 用go写一个简单的看门狗程序(WatchDog)

    简述 因为公司的一些小程序只是临时使用一下(不再维护更新),有的有一些bug会导致崩溃,但又不是很严重,崩溃了重新启动一下就好. 所以写了一个看门狗程序来监控程序,挂了(因为我这里并不关心程序的其他状 ...

随机推荐

  1. LightOJ 1341 - Aladdin and the Flying Carpet (唯一分解定理 + 素数筛选)

    http://lightoj.com/volume_showproblem.php?problem=1341 Aladdin and the Flying Carpet Time Limit:3000 ...

  2. android开发中提示:requires permission android.permission write_settings解决方法

    一.在Manifest.xml 中添加: <uses-permission android:name="android.permission.WRITE_CONTACTS" ...

  3. 关于JAVA多线程的那些事__初心者

    前言 其实事情的经过也许会复杂了点,这事还得从两个月前开始说.那天,我果断不干IT支援.那天,我立志要做一个真正的程序猿.那天,我26岁11个月.那天,我开始看Android.那天,我一边叨念着有朋自 ...

  4. [转][IIS]发布网站,提示用户 'IIS APPPOOL\***' 登录失败。

    链接:http://www.cnblogs.com/tianguook/p/3881075.html 用户 'IIS APPPOOL\DefaultAppPool' 登录失败. 我在windows8中 ...

  5. 跨域iframe高度自适应(兼容IE/FF/OP/Chrome)

    采用JavaScript来控制iframe元素的高度是iframe高度自适应的关键,同时由于JavaScript对不同域名下权限的控制,引发出同域.跨域两种情况. 由于客户端js使用浏览器的同源安全策 ...

  6. uva 11324 The Largest Clique(强连通分量缩点+DAG动态规划)

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=25&page=sh ...

  7. C++学习笔记之由文本文件读取数据到vector模板建立的二维数组 并存储为新的文本文件

    阅读本文可首先参考: C++学习笔记之输入.输出和文件 测试数据: /*读取txt文件到二维数组*/ #include <iostream> #include <fstream> ...

  8. UVA 674 Coin Change (DP)

    Suppose there are 5 types of coins: 50-cent, 25-cent, 10-cent, 5-cent, and 1-cent. We want to make c ...

  9. VS 统计代码行数

    使用正则表达式 :    ^:b*[^:b#/]+.*$ 简单说明如下: ^:行头 $:行尾 +:一个或多个 *:0个或多个 :b:表示空白,匹配空格或者制表符 # 表示后面是include,/表示注 ...

  10. .Net连接到SAP【转载】

    刚开始接触SAP了,感觉很陌生,清一色的TCode,不过里面的功能确实强大,不得不佩服啊,之前我一直是搞WinForm和WebForm的,现在能够接触到SAP那我还是想多学习一下,看了一下ABAP的语 ...