android -- WatchDog看门狗分析

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

在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);

}

原文:http://blog.csdn.net/andyhuabing/article/details/7395391

Android system server之WatchDog看门狗分析相关推荐

  1. java实现看门狗_Watchdog看门狗分析

    看门狗最初的意义是因为早期嵌入式设备上的程序经常跑飞(比如说电磁干扰等),所以专门设置了一个硬件看门狗,每隔一段时间,看门狗就去检查某个参数是不是被设置了,如果发现该参数被设置了,则判断为系统出错,然 ...

  2. Android System Server大纲之VibratorService

    Android System Server大纲之VibratorService vibrator Android System Server大纲之VibratorService 前言 Vibrator ...

  3. 什么是看门狗(watchdog)?看门狗有什么作用?

    什么是看门狗(watchdog) 看门狗,又叫 watchdog timer,是一个定时器电路, 一般有一个输入,叫喂狗,一个输出到MCU的RST端,MCU正常工作的时候,每隔一端时间输出一个信号到喂 ...

  4. Linux内核4.14版本——watchdog看门狗框架分析

    目录 0 简介 1. 设备的注册 1.1 dw_wdt_drv_probe 1.2 watchdog_register_device 1.3 __watchdog_register_device 1. ...

  5. AURIX TC397 SCU 之 Watchdog 看门狗

    目录 看门狗基础 TC397 Watchdog 微信公众号 看门狗基础 文档参阅 TC3XX User Manual 的9.4节, 看门狗Watchdog Timers (WDT)是System Co ...

  6. linux服务器看门狗服务,服务器watchdog看门狗的理解

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

  7. ESP32学习笔记(40)——Watchdog看门狗使用

    一.简介 看门狗其实就是一个定时器,从功能上说它可以让微控制器在程序发生意外(程序进入死循环或跑飞)的时候,能重新回复到系统刚上电状态,以保障系统出问题的时候可以重启一次.说的复杂一点,看门狗就是能让 ...

  8. arm linux下看门狗应用,arm linux watchdog 看门狗

    目前手上有个项目需要设计看门狗,是arm+CPLD 方式.由于对看门狗要求很高,打算做一个双看门狗,arm CPLD互相为 对方的看门狗.理论上CPLD是不需要看门狗的,还是这么去设计了.接下来对看门 ...

  9. [RK3568 Android11] 教程之watchdog看门狗应用

    目录 一.watchdogd服务应用 二.开启watchdogd服务 一.watchdogd服务应用 1.rk3568 android11系统中自身带有个watchdogd服务,默认是没有开启,此wa ...

最新文章

  1. Exchange2003-2010迁移系列之四,配置第一台Exchange CAS/HUB服务器
  2. 22个案例详解Pandas数据分析/预处理时的实用技巧,超简单
  3. svn 不支持http 客户端_Xversion for mac(SVN客户端)
  4. Cocos2d 游戏状态机
  5. RocketMQ集成SpringBoot
  6. 将Ehcache添加到Openxava应用程序
  7. Mac SecureCRT解决中文乱码
  8. datatables ajax错误,ajax datatable - DataTables警告:table id = example - 无法重新初始化DataTable(示例代码)...
  9. 一个年轻人为什么毫无欲望?
  10. Android Studio IDE Out of Memory
  11. vs2017可以写python_『vs python 使用教程』怎么用VS2017写一个最简单的Python程序,比如hello world?...
  12. 微信和qq默认表情代码对照表及表情文件下载
  13. pdf怎么设置密码?
  14. goeasy服务器发送(发布)消息,python服务端使用GoEasy实现websocket消息推送
  15. COMSOL随机裂缝生成
  16. 使用低代码开发的图书管理系统如何使用扫条形码实现图书的录入?
  17. ML-Agents命令及配置大全
  18. java实现 洛谷 P1427 小鱼的数字游戏
  19. mysql数据库data没有新创建_如何从pandas datafram在MySQL数据库中创建新表
  20. Mono.Cecil ReaderParameters

热门文章

  1. Java递归算法——二分查找
  2. MyEclipse + Maven开发Web工程的详细配置过程
  3. 生成和验证注册码的基本思路
  4. 隐马尔科夫模型HMM自学 (3)
  5. UA OPTI501 电磁波 求解麦克斯韦方程组的Fourier方法3 Coulomb Gauge下讨论Maxwell方程
  6. UA MATH564 概率论 计算至少有一个发生的概率:容斥原理与庞加莱公式
  7. 使用emu8086学习汇编 int 21h 指令
  8. Wireshark 跟踪TCP流
  9. 图解SQL子查询实例
  10. 学习旧岛小程序 (1) flex 布局