Android 系统中的 WatchDog 详解

文章来源:https://justinwei.blog.csdn.net/article/details/81021257

请转载朋友标明出处,请支持原创~~~

源码基于:Android R

 

 

0. 前言

Watchdog字面上是“看门狗”的意思,有做过嵌入式低层的朋友应该知道,为了防止嵌入式系统MCU里的程序因为干扰而跑飞,专门在MCU里设计了一个定时器电路,叫做看门狗。当MCU正常工作的,每隔一段时间会输出一个信号给看门狗,也就是所谓的喂狗。如果程序跑飞,MCU在规定的时间内没法喂狗,这时看门狗就会直接触发一个reset信号,让CPU重新启动。

在Android系统的framework中,设计了一个系统服务Watchdog,它类似于一个软件看门狗,用来保护重要的系统服务。它的源代码位于:

frameworks/base/services/core/java/com/android/server/Watchdog.java

流程图:

1. 获取WatchDog 对象

public class Watchdog extends Thread { }

想要分析一个功能代码,可能先从本身的源头找起,对于Java 类首先看的就是类的定义以及构造构造函数啦!

从这里看 WatchDog 其实一个Thread,这个Thread 可能比较特殊而已,至于怎么特殊,下面会在SystemServer 分析的时候说明。那对于一个Thread,核心的操作部分就是run() 函数了,这个最重要的部分会放在最后解析。

再来看下WatchDog 的构造函数:

private Watchdog() { }

WatchDog 构造函数是private,对于外界获取对象的接口为:

    public static Watchdog getInstance() {
        if (sWatchdog == null) {
            sWatchdog = new Watchdog();
        }

        return sWatchdog;
    }

外界获取WatchDog 就是通过getInstance(),至于这个“外界”后面会补充。

2. WatchDog 的启动

/frameworks/base/services/java/com/android/server/SystemServer.java

    private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
        t.traceBegin("startBootstrapServices");

        // Start the watchdog as early as possible so we can crash the system server
        // if we deadlock during early boot
        t.traceBegin("StartWatchdog");
        final Watchdog watchdog = Watchdog.getInstance();
        watchdog.start();
        t.traceEnd();

        ...

        t.traceBegin("InitWatchdog");
        watchdog.init(mSystemContext, mActivityManagerService);
        t.traceEnd();

        ...
    }

从第一节得知 WatchDog 实际是一个 thread,而且是以单例的形式存在,则需要确定其启动的地方。

这部分代码主要作用:

  • 创建WatchDog 实例;
  • 运行WatchDog thread;
  • 在AMS 启动后,执行init() 函数,传入mSystemContext 和 AMS 实例;

由此,WatchDog 线程是在 system_server 进程中启动,专门用来给 system_server 中的其他线程喂狗。

3. 构造函数

private Watchdog() {
    //线程名为watchdog
	super("watchdog");


	//将fg thread 单独提出作为主要的checker
	mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
			"foreground thread", DEFAULT_TIMEOUT);
	mHandlerCheckers.add(mMonitorChecker);
	
    //创建主线程的checker
	mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
			"main thread", DEFAULT_TIMEOUT));
	//创建UI thread 的checker
	mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
			"ui thread", DEFAULT_TIMEOUT));
	//创建Io thread 的checker
	mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
			"i/o thread", DEFAULT_TIMEOUT));
	//创建display thread 的checker
	mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
			"display thread", DEFAULT_TIMEOUT));
	//创建animation thread 的checker
	mHandlerCheckers.add(new HandlerChecker(AnimationThread.getHandler(),
			"animation thread", DEFAULT_TIMEOUT));
	//创建surface animation thread 的checker
	mHandlerCheckers.add(new HandlerChecker(SurfaceAnimationThread.getHandler(),
			"surface animation thread", DEFAULT_TIMEOUT));

	//fg thread的checker 中添加对binder 的checker
	addMonitor(new BinderThreadMonitor());

    // 添加对watchdog 相关目录的监控
	mOpenFdMonitor = OpenFdMonitor.create();

	mInterestingJavaPids.add(Process.myPid());

	// See the notes on DEFAULT_TIMEOUT.
	assert DB ||
			DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
}

3.1 设定线程名

设WatchDog 的线程名为 watchdog

3.2 创建 HandlerChecker

WatchDog 中靠 HandlerChecker 来完成check 工作,每个 HandlerChecker 伴随一个Handler,即一个独立的 Looper 和 Thread。

WatchDog 在创建的时候指定对 FgThread、MainThread、UIThread、IoThread、DisplayThread、AnimationThread、SurfaceAnimationThread 等thread 的监控,当然后期可以通过接口动态添加到 check list(mHandlerCheckers) 中,例如通过接口 addThread(),该函数后面会详细剖析,可以查看第 5.2 节。

  • MainThread 是在 SystemServer 运行的时候创建的
frameworks/base/services/java/com/android/server/SystemServer.java
private void run() {
    ...
    Looper.prepareMainLooper();
    ...
}

HandlerChecker 有3 个参数分别是Handler 对象、name、以及触发watchdog 的最大时间间隔,详细的HandlerChecker 看下面第6节

  • 重要的几个 thread 在这里都有监听,它们都有专门的名字:
    • android.fg
    • android.ui
    • android.io
    • android.display
    • android.anim
    • android.anim.lf

3.3 添加对binder 的监控

    private static final class BinderThreadMonitor implements Watchdog.Monitor {
        @Override
        public void monitor() {
            Binder.blockUntilThreadAvailable();
        }
    }

monitor() 会调用到 native 层 IPCThreadState:

frameworks/native/libs/binder/IPCThreadState.cpp

void IPCThreadState::blockUntilThreadAvailable()
{
    pthread_mutex_lock(&mProcess->mThreadCountLock);
    while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) {
        ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%lu mMaxThreads=%lu\n",
                static_cast<unsigned long>(mProcess->mExecutingThreadsCount),
                static_cast<unsigned long>(mProcess->mMaxThreads));
        pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock);
    }
    pthread_mutex_unlock(&mProcess->mThreadCountLock);
}

BinderThreadMonitor 会被添加到 fg thread 中,主要是用于确认binder 是否有出现不够用的情况,例如,假设 binder 的max thread 为15个,超过15后就需要 check 是否存在 binder 阻塞。

3.4 创建OpenFdMonitor

public static OpenFdMonitor create() {
	// Only run the FD monitor on debuggable builds (such as userdebug and eng builds).
	if (!Build.IS_DEBUGGABLE) {
		return null;
	}

	final StructRlimit rlimit;
	try {
		rlimit = android.system.Os.getrlimit(OsConstants.RLIMIT_NOFILE);
	} catch (ErrnoException errno) {
		Slog.w(TAG, "Error thrown from getrlimit(RLIMIT_NOFILE)", errno);
		return null;
	}


	final File fdThreshold = new File("/proc/self/fd/" + (rlimit.rlim_cur - FD_HIGH_WATER_MARK));
	return new OpenFdMonitor(new File("/data/anr"), fdThreshold);
}
  • 只有 debug 版本才做 fd monitor,例如 userdebug 或 eng;
  • 主要是确认 /data/anr 路径的正常性;

3.5 mInterestingJavaPids

主要是触发WatchDog 或者 HALF time 的时候,将这里存的 pid 所对应的堆栈dump 出来。AMS 中每次启动一个进程时,都会调用 handleProcessStartedLocked() 最终调用 WatchDog.processStarted() 添加到 WatchDog 中,而process 也是有限定的,如下:

    private static boolean isInterestingJavaProcess(String processName) {
        return processName.equals(StorageManagerService.sMediaStoreAuthorityProcessName)
                || processName.equals("com.android.phone");
    }


    public void processStarted(String processName, int pid) {
        if (isInterestingJavaProcess(processName)) {
            Slog.i(TAG, "Interesting Java process " + processName + " started. Pid " + pid);
            synchronized (this) {
                mInterestingJavaPids.add(pid);
            }
        }
    }

4. init 函数

    public void init(Context context, ActivityManagerService activity) {
        mResolver = context.getContentResolver();
        mActivity = activity;

        context.registerReceiver(new RebootRequestReceiver(),
                new IntentFilter(Intent.ACTION_REBOOT),
                android.Manifest.permission.REBOOT, null);
    }

注册了reboot 的广播,软重启的操作是在这里进行的:

    final class RebootRequestReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context c, Intent intent) {
            if (intent.getIntExtra("nowait", 0) != 0) {
                rebootSystem("Received ACTION_REBOOT broadcast");
                return;
            }
            Slog.w(TAG, "Unsupported ACTION_REBOOT broadcast: " + intent);
        }
    }

    void rebootSystem(String reason) {
        Slog.i(TAG, "Rebooting system because: " + reason);
        IPowerManager pms = (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE);
        try {
            pms.reboot(false, reason, false);
        } catch (RemoteException ex) {
        }
    }

该软重启的 intent 中需要设定一个参数 nowait,且不为0.

5. 其他几个重要函数

5.1 addMonitor()

    public void addMonitor(Monitor monitor) {
        synchronized (this) {
            mMonitorChecker.addMonitorLocked(monitor);//通过此接口会将monitor添加到fg thread中
        }
    }

本函数是将 monitor 添加到 mMonitorChecker 中监控;

    public interface Monitor {
        void monitor();
    }

例如AMS 构造函数中:

Watchdog.getInstance().addMonitor(this);

5.2 addThread()

    public void addThread(Handler thread) {
        addThread(thread, DEFAULT_TIMEOUT);
    }

    public void addThread(Handler thread, long timeoutMillis) {//通过此接口新建HandlerChecker
        synchronized (this) {
            final String name = thread.getLooper().getThread().getName();
            mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis));
        }
    }

通过本函数新建 HandlerChecker 并添加到 mHandlerCheckers 中,然后进行 check 该线程是否阻塞,默认timeout 为 60s;

例如 AMS 构造函数中:

Watchdog.getInstance().addThread(mHandler);

6. HandlerChecker类

在分析WatchDog 核心函数 run 之前,先来分析下核心处理类 HandlerChecker,所有 thread 的监听、处理都是在这个类中。

6.1 HandlerChecker 是一个Runnable

public final class HandlerChecker implements Runnable {

 

6.2  HandlerChecker的构造

HandlerChecker(Handler handler, String name, long waitMaxMillis) {
	mHandler = handler;
	mName = name;
	mWaitMax = waitMaxMillis;
	mCompleted = true;
}

构造参数有三个:

  • handler 用来发消息,通过handler 可以确定 thread;
  • name 为 HandlerChecker 对应thread 的描述时使用,除了构造中的特殊的checker 有特殊的name,其他通过 addThread() 接口创建的 checker,都是使用线程名;
  • waitMaxMillis 为监控时最大时长,默认为60s;

6.3 核心变量

private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
private final ArrayList<Monitor> mMonitorQueue = new ArrayList<Monitor>();

一个HandlerChecker 中可以添加多个monitor,为了安全考虑,防止在monitor check 过程中添加新的monitor,将过程分两部分:

  • 每次HandlerChecker 在schedule check的时候,只检查 mMonitors;
  • schedule check 过程中,新添加的monitor 都临时存放在 mMonitorQueue 中;

详细看scheduleCheckLocked() 函数,即第 6.4 节。

6.4 scheduleCheckLocked

public void scheduleCheckLocked() {
	if (mCompleted) { //step 1
		// Safe to update monitors in queue, Handler is not in the middle of work
		mMonitors.addAll(mMonitorQueue);
		mMonitorQueue.clear();
	}
	if ((mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling())
			|| (mPauseCount > 0)) { //step 2
		mCompleted = true;
		return;
	}
	if (!mCompleted) { //step 3
		// we already have a check in flight, so no need
		return;
	}

	mCompleted = false; //step 4
	mCurrentMonitor = null;
	mStartTime = SystemClock.uptimeMillis();
	mHandler.postAtFrontOfQueue(this);
}

逻辑比较简单,见代码中注释,将逻辑分为4个部分:

  • step1: 新的 schedule 时 mCompleted 为 true,会将 mMonitorQueue 中的 monitor copy到mMonitor 中,用以在 run() 函数中 check;
  • step2:如果 handle 的 Looper 处于 polling 状态,且没有 monitor 添加进来,或者是HandlerChecker 处于pause 状态,不做 schedule check,直接指定 schedule 完成状态;
  • step3:如果 HandlerChecker 中有 monitor 或者是 Looper 中有消息在处理,会跳过 step2, 如果是第一次执行 step3 的 case 是不会处理,如果 mCompleted 此时为false,那肯定是schedule 已经执行过一次,但是30s 的时候并没有执行完成,于是这里直接return,为了再给一次机会,再等 30s 等待 monitor 或者 msg 处理完成;
  • step4:能进入 step4,是因为上一次的 schedule 顺利执行完成,通过mHandler.post() 函数准备执行 run() 函数,run() 如果顺利执行完成则会将mCompleted 置为true,不会进入 step3

6.5 run() 函数

public void run() {
	final int 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;
	}
}

通过一个循环分别调用每一个 monitor 的 monitor() 函数,如果其中一个阻塞了,则无法退出该循环,mCompleted 状态也不会变成 true,如果 mCompleted 为false,WatchDog 只能通过时间来进一步确认状态,在下面一节中会详细说明。

用 AMS 中的 monitor 来举例:

frameworks/base/services/core/java/com/android/server/am/AMS.java

    public void monitor() {
        synchronized (this) { }
    }

AMS 的 monitor 就是为了 check AMS 是否死锁了。

7. WatchDog 的run() 函数

上面的基本函数都大概解析完了,对于一个Thread 那最重要的肯定还是run() 函数,这里也是WatchDog 的监测机制所在,因为代码比较多,这里裁剪分析。

step 1:建立死循环

WatchDog 在整个系统运行过程中都需要存在的,除非了进程或是系统重启了,不然WatchDog 需要长期运行。

    public void run() {
        boolean waitedHalf = false;
        while (true) {
            ...
        }
    }

step2:创建schedule

            synchronized (this) {
                long timeout = CHECK_INTERVAL;

                for (int i=0; i<mHandlerCheckers.size(); i++) {
                    HandlerChecker hc = mHandlerCheckers.get(i);
                    hc.scheduleCheckLocked();
                }

读取所有的 mHandlerCheckers,执行每一个 checker 中的 scheduleCheckLocked() 函数,下面会等待 30 s 的时间,然后在收集这些 checker 的状态。

注意两点:

  • timeout 默认为30s(DEFAULT_TIMEOUT / 2),所有的 schedule 启动完会 wait 30s 等待所有的 schedule 都能顺利执行完;
  • 启动schedule 会加上锁,与 HandlerChecker 的run() 函数互斥,这就要求,在wait 之前,HandlerChecker 的runnable 是无法运行的,下文在 wait() 的时候会释放this 对象的锁,runnable 才可以顺利执行(wait/synchronized 使用);

step3: 等待30s

                long start = SystemClock.uptimeMillis();
                while (timeout > 0) {
                    if (Debug.isDebuggerConnected()) {
                        debuggerWasConnected = 2;
                    }
                    try {
                        wait(timeout);
                        // Note: mHandlerCheckers and mMonitorChecker may have changed after waiting
                    } catch (InterruptedException e) {
                        Log.wtf(TAG, e);
                    }
                    if (Debug.isDebuggerConnected()) {
                        debuggerWasConnected = 2;
                    }
                    timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
                }

这里等待30s,直到时间完全用完。此处调用 wait() 会临时释放 this 这把锁,这样所有的 checker 就会进入下一步处理,即 runnable() 处理。 

step4:收集check 完成状态

                    final int waitState = evaluateCheckerCompletionLocked();
                    if (waitState == COMPLETED) {
                        // The monitors have returned; reset
                        waitedHalf = false;
                        continue;
                    } else if (waitState == WAITING) {
                        // still waiting but within their configured intervals; back off and recheck
                        continue;
                    } else if (waitState == WAITED_HALF) {
                        if (!waitedHalf) {
                            Slog.i(TAG, "WAITED_HALF");
                            // We've waited half the deadlock-detection interval.  Pull a stack
                            // trace and wait another half.
                            ArrayList<Integer> pids = new ArrayList<>(mInterestingJavaPids);
                            ActivityManagerService.dumpStackTraces(pids, null, null,
                                    getInterestingNativePids(), null);
                            waitedHalf = true;
                        }
                        continue;
                    }

在 30s 时间等待完成后,通过 evaluateCheckerCompletionLocked() 函数来收集所有 checkers 的状态。

状态分:

  • COMPLETED顺利完成
  • WAITING有可能 HandlerChecker 中的 monitor 比较多,而部分 monitor 占用时间比较长,这就导致有些 monitor 执行不到30s时,wait 就结束了,这时候会返回WAITING 状态,继续等待下一个schedule;
  • WATIED_HALF同WAITING,会继续等待下一个schedule,不同于 WAITING,WAITED_HALF 会通过AMS 去 dump 一次 stack;
  • OVERDUE有 monitor 执行超过了60s,这个是不允许的,step5 会处理OVERDUE的情况

step5:处理OVERDUE 情况

                    blockedCheckers = getBlockedCheckersLocked();
                    subject = describeCheckersLocked(blockedCheckers);

最开始是统计出OVERDUE 的HandlerChecker,存入blockedCheckers 中,并统计这些HandlerChecker 的描述。

    private ArrayList<HandlerChecker> getBlockedCheckersLocked() {
        ArrayList<HandlerChecker> checkers = new ArrayList<HandlerChecker>();
        for (int i=0; i<mHandlerCheckers.size(); i++) {
            HandlerChecker hc = mHandlerCheckers.get(i);
            if (hc.isOverdueLocked()) {
                checkers.add(hc);
            }
        }
        return checkers;
    }

统计所有状态OVERDUE 的HandlerChecker。

    private String describeCheckersLocked(List<HandlerChecker> checkers) {
        StringBuilder builder = new StringBuilder(128);
        for (int i=0; i<checkers.size(); i++) {
            if (builder.length() > 0) {
                builder.append(", ");
            }
            builder.append(checkers.get(i).describeBlockedStateLocked());
        }
        return builder.toString();
    }

统计所有符合条件的OVERDUE 的HandlerChecker 的描述,以逗号分割。

例如:

11-06 00:05:28.603  2197  2441 W Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: Blocked in monitor com.android.server.am.ActivityManagerService on foreground thread (android.fg), Blocked in handler on ActivityManager (ActivityManager)

接着就是保存日志,包括一些运行时的堆栈信息,这些日志是我们解决Watchdog问题的重要依据。如果判断需要杀掉system_server进程,则给当前进程(system_server)发送signal 9,详细信息看 Android 系统中WatchDog 日志分析

8. 通过AMS引入WatchDog 监控的根本形式

    Watchdog.getInstance().addMonitor(this);
    Watchdog.getInstance().addThread(mHandler);

来看下一直说的monitor 是什么东西:

    public void monitor() {
        synchronized (this) { }
    }

这里其实就是确认AMS 中是否存在死锁,30秒后还是没有放出来这个锁,WatchDog 会在给一次机会,如果还是没有释放的话,会打印堆栈信息并且结束AMS 所在进程。

需要注意的是WatchDog 的监控,除了WatchDog 构造函数中的默认Thread,外界若需要添加监控,需要通过两种途径:

  • addMonitor(Monitor monitor);
  • addThread(Handler thread);

两个接口区别在于参数,一个传入的是monitor,例如WatchDog 内部的 BinderThreadMonitor 或AMS 的monitor,monitor() 的处理是在  fg thread 中;另一个传入的是Handler,通过第 5 节得知,addThread() 会创建一个HandlerChecker 对象单独监控;

那么,结合 HandlerChecker 的 scheduleCheckLocked() 函数,可以认定,WatchDog 可以监控的形式有两种:

  • monitor:HandlerChecker专门用来维护monitor,run() 中逐个确认monitor是否正常运行
  • handler - msg:HandlerChecker 专门用来维护消息的监控,run() 中不会确认 monitor 的状态,而是直接将 mCompleted 置为 true,但是前提是Handler 中的 Looper 此时如果正在处理消息,这个消息不能阻塞此次 schedule 的 post,如果 Looper 中的消息处理超过 30s,那么HandlerChecker 中的 run() 只能等下一次 30s 时候才能有机会执行;

9. WatchDog 针对系统的 monitor 监控

  • ActivityManagerService
  • InputManagerService
  • MediaProjectionManagerService
  • MediaRouterService
  • MediaSessionService
  • PowerManagerService
  • StorageManagerService
  • TvRemoteService
  • WindowManagerService

都是通过addMonitor() 添加到 fg thread 的 HandlerChecker 中。

10. WatchDog 中Handler msg监控

都是通过 Handler 的方式添加到各自的 HandlerChecker 中,有的是在 WatchDog 的构造的时候添加,有的是后期通过 addThread() 方式添加。

11. AMS WD 举例

8 节中列出了AMS 代码中 addMonitor()addThread() 两种方式都使用了,所以在dump trace 的时候会列举 fg thread 的 stack trace 和 ActivityManager stack trace:

11-06 00:05:28.603  2197  2441 W Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: Blocked in monitor com.android.server.am.ActivityManagerService on foreground thread (android.fg), Blocked in handler on ActivityManager (ActivityManager)
11-06 00:05:28.603  2197  2441 W Watchdog: foreground thread stack trace:
11-06 00:05:28.603  2197  2441 W Watchdog:     at com.android.server.am.ActivityManagerService.monitor(ActivityManagerService.java:23862)
11-06 00:05:28.604  2197  2441 W Watchdog:     at com.android.server.Watchdog$HandlerChecker.run(Watchdog.java:211)
11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.Handler.handleCallback(Handler.java:790)
11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.Handler.dispatchMessage(Handler.java:99)
11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.Looper.loop(Looper.java:164)
11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.HandlerThread.run(HandlerThread.java:65)
11-06 00:05:28.604  2197  2441 W Watchdog:     at com.android.server.ServiceThread.run(ServiceThread.java:46)
11-06 00:05:28.604  2197  2441 W Watchdog: ActivityManager stack trace:
11-06 00:05:28.604  2197  2441 W Watchdog:     at com.android.server.am.ActivityManagerService.idleUids(ActivityManagerService.java:23305)
11-06 00:05:28.604  2197  2441 W Watchdog:     at com.android.server.am.ActivityManagerService$MainHandler.handleMessage(ActivityManagerService.java:2428)
11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.Handler.dispatchMessage(Handler.java:106)
11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.Looper.loop(Looper.java:164)
11-06 00:05:28.604  2197  2441 W Watchdog:     at android.os.HandlerThread.run(HandlerThread.java:65)
11-06 00:05:28.604  2197  2441 W Watchdog:     at com.android.server.ServiceThread.run(ServiceThread.java:46)
11-06 00:05:28.604  2197  2441 W Watchdog: *** GOODBYE

具体的可以看 Android 系统中WatchDog 日志分析

总结:

Android 中的WatchDog 主要是监测系统中重要服务,例如AMS、WMS 等,当注册的monitor 无法通过检测,或者是消息处理超时的时候就会触发WatchDog,最后可能会引起系统的重启。

下一篇博文 Android 系统中WatchDog 日志分析 中会结合实例详解run() 第 4 步保存日志。

附加:WatchDog 类图

  • 12
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

私房菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值