专栏名称: 安卓开发精选
伯乐在线旗下账号,分享安卓应用相关内容,包括:安卓应用开发、设计和动态等。
目录
相关文章推荐
stormzhang  ·  维权成功! ·  昨天  
stormzhang  ·  国庆前,2 件大事 ·  2 天前  
鸿洋  ·  Jetpack ... ·  2 天前  
stormzhang  ·  打工人维权的正确姿势 ·  3 天前  
鸿洋  ·  深入学习 Android ... ·  5 天前  
51好读  ›  专栏  ›  安卓开发精选

WatchDog 工作原理(上)

安卓开发精选  · 公众号  · android  · 2016-10-07 10:27

正文

(点击上方公众号,可快速关注)


来源:伯乐在线专栏作者 - gityuan

链接:http://android.jobbole.com/84881/

点击 → 了解如何加入专栏作者


一、概述


Android系统中,有硬件WatchDog用于定时检测关键硬件是否正常工作,类似地,在framework层有一个软件WatchDog用于定期检测关键系统服务是否发生死锁事件。WatchDog功能主要是分析系统核心服务和重要线程是否处于Blocked状态。


  • 监视reboot广播;

  • 监视mMonitors关键系统服务是否死锁。


二、启动流程


2.1 startOtherServices


[-> SystemServer.java]


private void startOtherServices() {

    ...

    //创建watchdog【见小节2.2】

    final Watchdog watchdog = Watchdog.getInstance();

    //注册reboot广播【见小节2.3】

    watchdog.init(context, mActivityManagerService);

    ...

    mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);

    ...

    mActivityManagerService.systemReady(new Runnable() {

       @Override

       public void run() {

           mSystemServiceManager.startBootPhase(

                   SystemService.PHASE_ACTIVITY_MANAGER_READY);

           ...

           // watchdog启动【见小节3.1】

           Watchdog.getInstance().start();

           mSystemServiceManager.startBootPhase(

                   SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);

        }

    }

}


2.2 getInstance


[-> Watchdog.java]


public static Watchdog getInstance() {

    if (sWatchdog == null) {

        //单例模式,创建实例对象【见小节2.2.1 】

        sWatchdog = new Watchdog();

    }

    return sWatchdog;

}


2.2.1 创建Watchdog


[-> Watchdog.java]


public class Watchdog extends Thread {

    ...

 

    private Watchdog() {

        super("watchdog");

        //【见小节2.2.2 】

        mMonitorChecker = new HandlerChecker(FgThread.getHandler(),

                "foreground thread", DEFAULT_TIMEOUT);

        mHandlerCheckers.add(mMonitorChecker);

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

                "main thread", DEFAULT_TIMEOUT));

        mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),

                "ui thread", DEFAULT_TIMEOUT));

        mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),

                "i/o thread", DEFAULT_TIMEOUT));

        mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),

                "display thread", DEFAULT_TIMEOUT));

        //【见小节2.2.3】

        addMonitor(new BinderThreadMonitor());

    }

 

}


Watchdog继承于Thread,创建的线程名为”watchdog”。mHandlerCheckers是记录着所有的HandlerChecker对象的列表。


Watchdog监控的线程有:


线程名对应handler含义
main threadnew Handler(MainLooper)当前主线程
android.fgFgThread.getHandler前台线程
android.uiUiThread.getHandlerUI线程
android.ioIoThread.getHandlerI/O线程
android.displayDisplayThread.getHandlerDisplay线程


DEFAULT_TIMEOUT默认为60s,调试时才为10s方便找出潜在的ANR问题。


2.2.2 HandlerChecker


[-> Watchdog.java]


public final class HandlerChecker implements Runnable {

    ...

    HandlerChecker(Handler handler, String name, long waitMaxMillis) {

        mHandler = handler;

        mName = name;

        mWaitMax = waitMaxMillis;

        mCompleted = true;

    }

}


mMonitors记录所有Watchdog目前正在监控的服务。


2.2.3 监控Binder线程


在小节【2.2.1】创建Watchdog时,通过addMonitor(new BinderThreadMonitor())来监控Binder线程, 这里拆分两步骤:


  • addMonitor

  • new BinderThreadMonitor


2.2.3.1 addMonitor


public class Watchdog extends Thread {

    public void addMonitor(Monitor monitor) {

        synchronized (this) {

            if (isAlive()) {

                throw new RuntimeException("Monitors can't be added once the Watchdog is running");

            }

            //此处mMonitorChecker数据类型为HandlerChecker

            mMonitorChecker.addMonitor(monitor);

        }

    }

 

    public final class HandlerChecker implements Runnable {

        private final ArrayList mMonitors = new ArrayList();

 

        public void addMonitor(Monitor monitor) {

            //将上面的BinderThreadMonitor添加到mMonitors队列

            mMonitors.add(monitor);

        }

        ...

    }

}


将monitor添加到HandlerChecker的成员变量mMonitors列表中。


2.2.3.2 BinderThreadMonitor


private static final class BinderThreadMonitor implements Watchdog.Monitor {

    public void monitor() {

        Binder.blockUntilThreadAvailable();

    }

}


blockUntilThreadAvailable最终调用的是IPCThreadState,等待有空闲的binder线程


void IPCThreadState::blockUntilThreadAvailable()

{

    pthread_mutex_lock(&mProcess->mThreadCountLock);

    while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) {

        //等待正在执行的binder线程小于进程最大binder线程上限(16个)

        pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock);

    }

    pthread_mutex_unlock(&mProcess->mThreadCountLock);

}


可见addMonitor(new BinderThreadMonitor())是将Binder线程添加到android.fg线程的handler(mMonitorChecker)来检查是否工作正常。


2.2.4 Monitor


public class Watchdog extends Thread {

    public interface Monitor {

        void monitor();

    }

}


能够被Watchdog监控的系统服务都实现了Watchdog.Monitor接口。 实现该接口类:


  • ActivityManagerService

  • PowerManagerService

  • WindowManagerService

  • InputManagerService

  • NetworkManagementService

  • MountService

  • NativeDaemonConnector

  • BinderThreadMonitor

  • MediaProjectionManagerService

  • MediaRouterService

  • MediaSessionService


2.3 init


[-> Watchdog.java]


public void init(Context context, ActivityManagerService activity) {

    mResolver = context.getContentResolver();

    mActivity = activity;

    //注册reboot广播接收者【见小节2.3.1】

    context.registerReceiver(new RebootRequestReceiver(),

            new IntentFilter(Intent.ACTION_REBOOT),

            android.Manifest.permission.REBOOT, null);

}


2.3.1 RebootRequestReceiver


[-> Watchdog.java]


final class RebootRequestReceiver extends BroadcastReceiver {

    @Override

    public void onReceive(Context c, Intent intent) {

        if (intent.getIntExtra("nowait", 0) != 0) {

            //【见小节2.3.2】

            rebootSystem("Received ACTION_REBOOT broadcast");

            return;

        }

        Slog.w(TAG, "Unsupported ACTION_REBOOT broadcast: " + intent);

    }

}


2.3.2 rebootSystem


[-> Watchdog.java]


void rebootSystem(String reason) {

    Slog.i(TAG, "Rebooting system because: " + reason);

    IPowerManager pms = (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE);

    try {

        //通过PowerManager执行reboot操作

        pms.reboot(false, reason, false);

    } catch (RemoteException ex) {

    }

}


最终是通过PowerManagerService来完成重启操作,具体的重启流程后续会单独讲述。


2.4 小节


获取watchdog实例对象,并注册reboot广播


  • mHandlerCheckers记录所有的HandlerChecker对象的列表,包括foreground, main, ui, i/o, display线程的handler;

  • mMonitors记录所有Watchdog目前正在监控Monitor,此处为BinderThreadMonitor;

  • 注册reboot广播,最终是通过PowerManagerService来完成;

  • 系统每间隔1分钟,执行一次monitor操作, 当系统hang时间超过1分钟则执行run()方法;


下面来看看当系统hang超过1分钟时,进入watchdog.run()的过程:


三、Watchdog


3.1 run


public void run() {

    boolean waitedHalf = false;

    while (true) {

        final ArrayList blockedCheckers;

        final String subject;

        final boolean allowRestart;

        int debuggerWasConnected = 0;

        synchronized (this) {

            //timeout=30s

            long timeout = CHECK_INTERVAL;

            for (int i=0; imHandlerCheckers.size(); i++) {

                HandlerChecker hc = mHandlerCheckers.get(i);

                //【见小节3.2】

                hc.scheduleCheckLocked();

            }

 

            if (debuggerWasConnected > 0) {

                debuggerWasConnected--;

            }

 

            long start = SystemClock.uptimeMillis();

            //等待30s

            while (timeout > 0) {

                if (Debug.isDebuggerConnected()) {

                    debuggerWasConnected = 2;

                }

                try {

                    wait(timeout);

                } catch (InterruptedException e) {

                    Log.wtf(TAG, e);

                }

                if (Debug.isDebuggerConnected()) {

                    debuggerWasConnected = 2;

                }

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

            }


接下文


专栏作者简介( 点击 → 加入专栏作者 


gityuan:Android全栈工程师:上至能写App,中间能改framework和Native代码,下至能调驱动,全栈能解决性能与稳定性。(新浪微博:@Gityuan)

打赏支持作者写出更多好文章,谢谢!



 关注「安卓开发精选

看更多精选安卓技术文章
↓↓↓ 

推荐文章
stormzhang  ·  维权成功!
昨天
stormzhang  ·  国庆前,2 件大事
2 天前
stormzhang  ·  打工人维权的正确姿势
3 天前
编剧帮  ·  是谁,杀死了情景喜剧?
7 年前
刘晓博说楼市  ·  讲真,你可能已变成自己讨厌的样子
7 年前