SW watchdog 分析

来源:互联网 发布:linux 安装javac 编辑:程序博客网 时间:2024/04/29 14:01

1. android framework层中的watchdog,它属于一种软件Watchdog实现。
    a.接收系统内部reboot请求,重启系统。
    b.监护SystemServer进程,防止系统死锁, 确保ActivityManagerService、WindowManagerService和 PowerManageService发生死锁后,退出SystemServer进程,让init进程重启它,让系统回到可用状态。
2. 分析framework/base/services/java/com/android/server/watchdog.java, watchdog实际上是一个thread
3. WatchDog如何启动, run@Frameworks/base/services/java/com/android/server/SystemServer.java
    WatchDog是在SystemServer进程中被初始化和启动的。在SystemServer 被Start时,各种Android服务被注册和启动,其中也包括了WatchDog的初始化和启动。代码如下:
        Watchdog.getInstance().init(context, battery, power, alarm,ActivityManagerService.self());
    在SystemServer Run函数的后半段,将检查系统是否已经准备好运行第三方代码,并通过SystemReady接口通知系统已经就绪。在ActivityManagerService的SystemReady接口的CallBack函数中实现WatchDog的启动,代码如下
        Watchdog.getInstance().start();

 


4. 在WatchDog启动之后,开始跑run函数。该函数内部为一个无限循环。
    public void run() {
            boolean waitedHalf = false;
            while (true) {
                mCompleted = false;
                mHandler.sendEmptyMessage(MONITOR);
                ...
                while (timeout > 0 && !mForceKillSystem) {
                        try {
                            wait(timeout);
                           } catch (InterruptedException e) {
                        }
                        timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
                        //TIME_TO_WAIT的默认时间为30s。此为第一次等待时间,WatchDog判断对象是否死锁的最长处理时间为1Min。
                    }
                ...
            }
    }

    一开始就会发送一个MONITOR的Message,由HeartbeatHandler负责接收并处理。同时会等待30秒,等待HeartbeatHandler的处理结果。然后才会进行下一步动作。
    在HeartbeatHandler中将会作如下处理:
    public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MONITOR: {
                    ...
                    final int size = mMonitors.size();
                        for (int i = 0 ; i < size ; i++) {
                            mCurrentMonitor = mMonitors.get(i);
                            mCurrentMonitor.monitor();
                        }//依次去调用监护对象的monitor接口,实现对其的监护。如果monitor中的synchronized(..)不能及时返回,则表明该监护对象被lock了
                     synchronized (Watchdog.this) {
                            mCompleted = true;
                            mCurrentMonitor = null;
                        }//如果监护的对象都正常,则会很快运行到这里,并对mCompleted赋值为true,表示对象正常返回。mCompleted值初始为false。

    同时在run函数中:if (mCompleted && !mForceKillSystem) {
                        // The monitors have returned.
                        waitedHalf = false;
                        continue;
                       }//如果所有对象在30s内能够返回,则会得到mCompleted = true;则本次监护就结束,返回继续下一轮监护。
    如果在30s内,monitor对象未能返回,mCompleted 值即为false,则会运行到该语句:
                     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;
                    }//会调用ActivityManagerService.java中的dumpStackTraces接口函数。

     该动作发生在第一次等待的30s时间内,monitor对象未返回,由于在调用完ActivityManagerService.java的dumpStackTraces接口函数后,将waitedHalf赋值为true。并返回继续下一轮监护。若紧接着的下一轮监护,在30s内 monitor对象依旧未及时返回,此时
    if (mCompleted && !mForceKillSystem){
        ...
    }
    if (!waitedHalf){
    ...
    }//此时这两个语句都不会运行,则会直接运行到下面部分。这表示系统的监护对象有死锁现象发生,SystemServer进程需要kill并重启。
     // If we got here, that means that the system is most likely hung.
    ...
    // Pull our own kernel thread stacks as well if we're configured for that
    if (RECORD_KERNEL_THREADS) {
        dumpKernelStackTraces();//-->dumpKernelStacks@frameworks/base/core/jni/android_server_watchdog.cpp,后面会分析
    }    

    // Only kill/crash if the debugger is not attached.
    if (!Debug.isDebuggerConnected()) {
      if (Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug")) {
        Slog.w(TAG, "*** WATCHDOG KILLING THE SYSTEM: " + name);
        // Give some extra time to make sure CrashMonitorService reacts to
        // the dropbox entry before the crash
        SystemClock.sleep(2000);
        forceCrashDump();//通过写入"c"到"/proc/sysrq-trigger"产生kernel crash,启动kernel crash dump
    } else {
        Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name);
        Process.killProcess(Process.myPid());
        System.exit(10);//在剩下的30s内,做一些收尾工作,如重新初始化trace file。最后直接将SystemServer进程kill,并且退出系统。Init进程会重新启动SystemServer进程,让其回到可用状态。System.exit(?)应该是退出进程???会终止该java程序的JVM
    }
    } else {
        Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");
    }


5. 由以上分析可知,如果监控的所有service没有被lock, watchdog thread会30秒心跳一次[HeartbeatHandler.sendEmptyMessage(MONITOR);];如果30秒后所监控的service有被lock的,则进入half lock状态,并做一些前期工作,应对完全死锁full lock; 如果在接下来的30秒,service都被解除lock,则表示又活过来了,重新开始30秒一次的心跳;如果没有在接下来的30秒中解除lock,则认为系统死锁了,开始处理死锁过程。
6. 如何使用watchdog monitor service,在 ActivityManagerService.java,PowerManagerService.java,WindowManagerService.java中有
    a. Watchdog.getInstance().addMonitor(this);//增加该service 到wathdog中的monitor list中
    b. @PowerManagerService.java 中有
            public void monitor() {
                synchronized (mLocks) { }
            }
    c. @WindowManagerService.java 中有
            public void monitor() {
            synchronized (mWindowMap) { }
            synchronized (mKeyguardTokenWatcher) { }
            }    
    d. @ActivityManagerService.java 中有
            public void monitor() {
            synchronized (this) { }
            }    
    e. 从代码中可以看到,用于monitor中的synchronized对象,也是被service 其他关键处理函数用到的synchronized对象;
    f. 简而言之,android的watchdog 机制,是基于java 的synchronized 锁对象机制,很巧妙的应用!!!!
7. 如果被监控的service 中关键处理过程或函数,超过1分钟没有完成,则触发android watchdog.
8. 分析dumpKernelStackTraces@frameworks/base/services/java/com/android/server/watchdog.java --> native_dumpKernelStacks-->dumpKernelStacks@frameworks/base/core/jni/android_server_watchdog.cpp
    a. 主要从 proc/<process id>/task 下获取当前process所有的thread 的ID
    b. dumpOneStack函数获取 proc/<thread id>/stack 的dump 信息
9. 分析如果发生死锁后,非userdebug和eng版本,init 如何重启watchdog thread和 SystemServer thread???
    a. init.rc中有
        service servicemanager /system/bin/servicemanager //该源代码位于 frameworks/base/cmds/servicemanager/目录下
        user system
        critical
        onrestart restart zygote
        onrestart restart media
    b. main@system/core/init/init.c中有一死循环会不断执行restart_processes-->service_for_each_flags-->restart_service_if_needed-->service_start, 检查是否*.rc申明的所有 非ONESHOT的service,是否已经停止,如果停止则需要重新启动该service. 好像和死锁重启无关???
    b. init.rc中还有
        service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-s    erver
        socket zygote stream 660 root system
        onrestart write /proc/sysrq-trigger c
       在后面的分析中如何 关键的三个service发生dead lock, zygote将会exit,然后init process会重启zygote --> system_server        
    c. startSystemServer@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中有
             "--nice-name=system_server",
             "com.android.server.SystemServer",
        指明了线程system_server 就是com.android.server.SystemServer, 也就是zygote会启动运行com.android.server.SystemServer
    d. $adb shell ps 可以看到
        root      1483  1     97632  28912 c011e7ec afd0b944 S zygote
        system    1756  1483  196400 41324 ffffffff afd0b7fc S system_server
    e. #ls /proc/1756/task 可以看到process system_server 启动的所有thread ID,比如 1756,1757,...; 进入1757目录,#cat status可以看到该thread的具体信息。
    f. 执行sh脚本
          adb shell ls proc/1756/task > dirlist
          while read one; do
                   temp=`expr substr $one 1 4`
                   adb shell cat proc/1756/task/${temp}/status | grep -E "Name:|Tgid:|Pid:|PPid:"
                   echo "----------------------------------------------------------"
          done <dirlist
        有很多关键线程都是被system_server即com.android.server.SystemServer创建,如HeapWorker,GC,Binder,ProcessStats,PowerManagerService,WindowManager,ActivityManager,wathdog等等,具体信息如下
            Name:    watchdog
            Tgid:    1756        //线程组号=system_server PID
            Pid:    1856         //线程ID
            PPid:    1483        //父进程ID = zygote PID
            TracerPid:    0    //接收跟踪该进程信息的进程ID = 没有?
10. 如果kill -9 1856, 会导致svcinfo_death@frameworks/base/cmds/servicemanager/service_manager.c,也就是所有注册到svclist的service都将died. kill掉任何一个system_server启动的thread 会导致system_server也被kill? 并会最终有如下log,
     I/Zygote  ( 1483): Exit zygote because system server (1756) has terminated 是从哪来的???????? sigchldHandler@dalvik/vm/native/dalvik_system_zygote.c
另外需要分析 zygote是如何exit的?????System.exit(?)。 需要提前说明的一点是Zygote 与 SystemServer 关系非常紧密!!
首先要分析zygote如何启动?和如何重启? zygote是运行在JVM空间的
    a. init.rc 中有
        service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        socket zygote stream 666
        onrestart write /proc/sysrq-trigger c
    b. service zygote在frameworks/base/cmds/app_process/app_main.cpp--> main启动; runtime.start("com.android.internal.os.ZygoteInit",startSystemServer)@frameworks/base/core/jni/androidruntime.cpp 启动起来
    c. androidruntime 会启动main@@frameworks/base/core/java/com/android/internal/os/zygoteinit.java, -->startSystemServer();-->  pid = Zygote.forkSystemServer,其中forkSystemServer对应的jni函数是Dalvik_dalvik_system_Zygote_forkSystemServer@dalvik/vm/native/dalvik_system_zygote.c
    d. forkAndSpecializeCommon@dalvik/vm/native/dalvik_system_zygote.c 很关键,fork一个子进程用于systemserver,并且还通过setSignalHandler();监控子进程的状态,
        sa.sa_handler = sigchldHandler; //处理子进程终止的callback函数
        err = sigaction (SIGCHLD, &sa, NULL); //注册 监听该子进程,如果子进程终止,将报告该信息给其父进程
    e. 当子进程终止时,sigchldHandler会被触发 pid = waitpid(-1, &status, WNOHANG) 会读取当前终止的子进程的信息,并把其彻底销毁,然乎返回其PID;另外提一句,如果还发现其他的僵尸进程还一并把它给处理了。
    f. 在sigchldHandler还有如下内容
           if (pid == gDvm.systemServerPid) { //判断被终止的Process ID 是否是system server ID(即system_server 进程)
           LOG(LOG_INFO, ZYGOTE_LOG_TAG,
               "Exit zygote because system server (%d) has terminated\n",
               (int) pid);
           kill(getpid(), SIGKILL); //如果是,则把其父进程(即,zygote)也kill掉,如此可见system_server和zygote关系之紧密,誓死共存亡!!!
           }
    g. zygote 被kill掉后,会被init demon进程马上发现,并重启zygote进程,由此android系统就通过重启,解除了死锁。


13. 所有在init.rc中的service process的父进程ID=1 (init process), 并且这些process都只是运行在native世界中,还不是JVM.
14. 小结:SW watchdog实现机制很有意思,首先是通过java的synchronized 机制,来监控关键的三个service; system_server进程会启动所有的java services,当然包含那三个关键服务,还有watchdog thread 等线程;一旦watchdog发现死锁,会通过System.exit(10) kill掉自己的父进程(system_server);而一旦system_server被kill,它的的父进程zygote会监控到,马上把自己也干掉了,system_server不活zygote活着也就没有意义了;最后zygote把自己干掉了,会被init demon进程发现,重新启动android的所有java process,到此为止android系统又活过来了;但是init.rc中 在重启servie zygote 时还会执行onrestart write /proc/sysrq-trigger c, 郁闷!难道又手动让kernel也crash? 启动ramdump机制?最后整个手机都重启了!!!SW watchdog的意义何在? 上网查了下,增加onrestart write /proc/sysrq-trigger c, 为本公司特色!!这样处理真是一了百了。

原创粉丝点击