Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android ANR在线监控原理

Android ANR在线监控原理

作者头像
大大大大大先生
发布于 2018-09-04 07:23:43
发布于 2018-09-04 07:23:43
2.9K00
代码可运行
举报
运行总次数:0
代码可运行

Android中的Watchdog

  • Android中,Watchdog是用来监测关键服务是否发生了死锁,如果发生了死锁就kill进程,重启SystemServer
  • Android的Watchdog是在SystemServer中进行初始化的,所以Watchdog是运行在SystemServer进程中
  • Watchdog是运行一个单独的线程中的,每次wait 30s之后就会发起一个监测行为,如果系统休眠了,那Watchdog的wait行为也会休眠,此时需要等待系统唤醒之后才会重新恢复监测
  • 想要被Watchdog监测的对象需要实现Watchdog.Monitor接口的monitor()方法,然后调用addMonitor()方法
  • 其实framework里面的Watchdog实现除了能监控线程死锁以外还能够监控线程卡顿,addMonitor()方法是监控线程死锁的,而addThread()方法是监控线程卡顿的
Watchdog线程死锁监控实现
  • Watchdog监控线程死锁需要被监控的对象实现Watchdog.Monitor接口的monitor()方法,然后再调用addMonitor()方法,例如ActivityManagerService:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final class ActivityManagerService extends ActivityManagerNative
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

  public ActivityManagerService(Context systemContext) {
    Watchdog.getInstance().addMonitor(this);
  }

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

如上是从ActivityManagerService提取出来关于Watchdog监控ActivityManagerService这个对象锁的相关代码,而监控的实现如下,Watchdog是一个线程对象,start这个线程之后就会每次wait 30s后检查一次,如此不断的循环检查:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void addMonitor(Monitor monitor) {
        synchronized (this) {
            if (isAlive()) {
                throw new RuntimeException("Monitors can't be added once the Watchdog is running");
            }
            mMonitorChecker.addMonitor(monitor);
        }
    }

@Override
    public void run() {
        boolean waitedHalf = false;
        while (true) {
            final ArrayList<HandlerChecker> blockedCheckers;
            final String subject;
            final boolean allowRestart;
            int debuggerWasConnected = 0;
            synchronized (this) {
                long timeout = CHECK_INTERVAL;
                // Make sure we (re)spin the checkers that have become idle within
                // this wait-and-check interval
                for (int i=0; i<mHandlerCheckers.size(); i++) {
                    HandlerChecker hc = mHandlerCheckers.get(i);
                    hc.scheduleCheckLocked();
                }

                if (debuggerWasConnected > 0) {
                    debuggerWasConnected--;
                }

                // 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) {
                    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);
                }

                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) {
                        // 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,
                                NATIVE_STACKS_OF_INTEREST);
                        waitedHalf = true;
                    }
                    continue;
                }

                // something is overdue!
                blockedCheckers = getBlockedCheckersLocked();
                subject = describeCheckersLocked(blockedCheckers);
                allowRestart = mAllowRestart;
            }

            // If we got here, that means that the system is most likely hung.
            // First collect stack traces from all threads of the system process.
            // Then kill this process so that the system will restart.
            EventLog.writeEvent(EventLogTags.WATCHDOG, subject);

            ArrayList<Integer> pids = new ArrayList<Integer>();
            pids.add(Process.myPid());
            if (mPhonePid > 0) pids.add(mPhonePid);
            // Pass !waitedHalf so that just in case we somehow wind up here without having
            // dumped the halfway stacks, we properly re-initialize the trace file.
            final File stack = ActivityManagerService.dumpStackTraces(
                    !waitedHalf, pids, null, null, NATIVE_STACKS_OF_INTEREST);

            // Give some extra time to make sure the stack traces get written.
            // The system's been hanging for a minute, another second or two won't hurt much.
            SystemClock.sleep(2000);

            // Pull our own kernel thread stacks as well if we're configured for that
            if (RECORD_KERNEL_THREADS) {
                dumpKernelStackTraces();
            }

            String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
            String traceFileNameAmendment = "_SystemServer_WDT" + mTraceDateFormat.format(new Date());

            if (tracesPath != null && tracesPath.length() != 0) {
                File traceRenameFile = new File(tracesPath);
                String newTracesPath;
                int lpos = tracesPath.lastIndexOf (".");
                if (-1 != lpos)
                    newTracesPath = tracesPath.substring (0, lpos) + traceFileNameAmendment + tracesPath.substring (lpos);
                else
                    newTracesPath = tracesPath + traceFileNameAmendment;
                traceRenameFile.renameTo(new File(newTracesPath));
                tracesPath = newTracesPath;
            }

            final File newFd = new File(tracesPath);

            // Try to add the error to the dropbox, but assuming that the ActivityManager
            // itself may be deadlocked.  (which has happened, causing this statement to
            // deadlock and the watchdog as a whole to be ineffective)
            Thread dropboxThread = new Thread("watchdogWriteToDropbox") {
                    public void run() {
                        mActivity.addErrorToDropBox(
                                "watchdog", null, "system_server", null, null,
                                subject, null, newFd, null);
                    }
                };
            dropboxThread.start();
            try {
                dropboxThread.join(2000);  // wait up to 2 seconds for it to return.
            } catch (InterruptedException ignored) {}


            // At times, when user space watchdog traces don't give an indication on
            // which component held a lock, because of which other threads are blocked,
            // (thereby causing Watchdog), crash the device to analyze RAM dumps
            boolean crashOnWatchdog = SystemProperties
                                        .getBoolean("persist.sys.crashOnWatchdog", false);
            if (crashOnWatchdog) {
                // Trigger the kernel to dump all blocked threads, and backtraces
                // on all CPUs to the kernel log
                Slog.e(TAG, "Triggering SysRq for system_server watchdog");
                doSysRq('w');
                doSysRq('l');

                // wait until the above blocked threads be dumped into kernel log
                SystemClock.sleep(3000);

                // now try to crash the target
                doSysRq('c');
            }

            IActivityController controller;
            synchronized (this) {
                controller = mController;
            }
            if (controller != null) {
                Slog.i(TAG, "Reporting stuck state to activity controller");
                try {
                    Binder.setDumpDisabled("Service dumps disabled due to hung system process.");
                    // 1 = keep waiting, -1 = kill system
                    int res = controller.systemNotResponding(subject);
                    if (res >= 0) {
                        Slog.i(TAG, "Activity controller requested to coninue to wait");
                        waitedHalf = false;
                        continue;
                    }
                } catch (RemoteException e) {
                }
            }

            // Only kill the process if the debugger is not attached.
            if (Debug.isDebuggerConnected()) {
                debuggerWasConnected = 2;
            }
            if (debuggerWasConnected >= 2) {
                Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");
            } else if (debuggerWasConnected > 0) {
                Slog.w(TAG, "Debugger was connected: Watchdog is *not* killing the system process");
            } else if (!allowRestart) {
                Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process");
            } else {
                Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject);
                for (int i=0; i<blockedCheckers.size(); i++) {
                    Slog.w(TAG, blockedCheckers.get(i).getName() + " stack trace:");
                    StackTraceElement[] stackTrace
                            = blockedCheckers.get(i).getThread().getStackTrace();
                    for (StackTraceElement element: stackTrace) {
                        Slog.w(TAG, "    at " + element);
                    }
                }
                Slog.w(TAG, "*** GOODBYE!");
                Process.killProcess(Process.myPid());
                System.exit(10);
            }

            waitedHalf = false;
        }
    }

首先,ActivityManagerService调用addMonitor()方法把自己添加到了Watchdog的mMonitorChecker对象中,这是Watchdog的一个全局变量,这个全部变量在Watchdog的构造方法中已经事先初始化好并添加到mHandlerCheckers:ArrayList<HandlerChecker>这个监控对象列表中了,mMonitorChecker是一个HandlerChecker类的实例对象,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final class HandlerChecker implements Runnable {
        private final Handler mHandler;
        private final String mName;
        private final long mWaitMax;
        private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
        private boolean mCompleted;
        private Monitor mCurrentMonitor;
        private long mStartTime;

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

        public void addMonitor(Monitor monitor) {
            mMonitors.add(monitor);
        }

        public void scheduleCheckLocked() {
            if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) {
                // If the target looper has recently been polling, then
                // there is no reason to enqueue our checker on it since that
                // is as good as it not being deadlocked.  This avoid having
                // to do a context switch to check the thread.  Note that we
                // only do this if mCheckReboot is false and we have no
                // monitors, since those would need to be executed at this point.
                mCompleted = true;
                return;
            }

            if (!mCompleted) {
                // we already have a check in flight, so no need
                return;
            }

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

        public boolean isOverdueLocked() {
            return (!mCompleted) && (SystemClock.uptimeMillis() > mStartTime + mWaitMax);
        }

        public int getCompletionStateLocked() {
            if (mCompleted) {
                return COMPLETED;
            } else {
                long latency = SystemClock.uptimeMillis() - mStartTime;
                if (latency < mWaitMax/2) {
                    return WAITING;
                } else if (latency < mWaitMax) {
                    return WAITED_HALF;
                }
            }
            return OVERDUE;
        }

        public Thread getThread() {
            return mHandler.getLooper().getThread();
        }

        public String getName() {
            return mName;
        }

        public String describeBlockedStateLocked() {
            if (mCurrentMonitor == null) {
                return "Blocked in handler on " + mName + " (" + getThread().getName() + ")";
            } else {
                return "Blocked in monitor " + mCurrentMonitor.getClass().getName()
                        + " on " + mName + " (" + getThread().getName() + ")";
            }
        }

        @Override
        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;
            }
        }
    }

HandlerChecker类中的mMonitors也是监控对象列表,这里是监控所有实现了Watchdog.Monitor接口的监控对象,而那些没有实现Watchdog.Monitor接口的对象则会单独创建一个HandlerChecker类并add到Watchdog的mHandlerCheckers监控列表中,当Watchdog线程开始健康那个的时候就回去遍历mHandlerCheckers列表,并逐一的调用HandlerChecker的scheduleCheckLocked方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void scheduleCheckLocked() {
            if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) {
                // If the target looper has recently been polling, then
                // there is no reason to enqueue our checker on it since that
                // is as good as it not being deadlocked.  This avoid having
                // to do a context switch to check the thread.  Note that we
                // only do this if mCheckReboot is false and we have no
                // monitors, since those would need to be executed at this point.
                mCompleted = true;
                return;
            }

            if (!mCompleted) {
                // we already have a check in flight, so no need
                return;
            }

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

HandlerChecker这个类中有几个比较重要的标志,一个是mCompleted,标识着本次监控扫描是否在指定时间内完成,mStartTime标识本次开始扫描的时间mHandler,则是被监控的线程的handler,scheduleCheckLocked是开启本次对与改线程的监控,里面理所当然的会把mCompleted置为false并设置开始时间,可以看到,监控原理就是向被监控的线程的Handler的消息队列中post一个任务,也就是HandlerChecker本身,然后HandlerChecker这个任务就会在被监控的线程对应Handler维护的消息队列中被执行,如果消息队列因为某一个任务卡住,那么HandlerChecker这个任务就无法及时的执行到,超过了指定的时间后就会被认为当前被监控的这个线程发生了卡死(死锁造成的卡死或者执行耗时任务造成的卡死),在HandlerChecker这个任务中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
        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;
            }
        }

首先遍历mMonitors列表中的监控对象并调用monitor()方法来开启监控,通常在被监控对象实现的monitor()方法都是按照如下实现的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void monitor() {
        synchronized (this) { }
    }

即监控某一个死锁,然后就是本次监控完成,mCompleted设置为true,而当所有的scheduleCheckLocked都执行完了之后,Watchdog就开始wait,而且一定要wait for 30s,这里有一个实现细节:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
long start = SystemClock.uptimeMillis();
                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);
                }

原先,我看到这段代码的时候,首先关注到SystemClock.uptimeMillis()在设备休眠的时候是不计时的,因此猜测会不会是因为设备休眠了,wait也停止了,Watchdog在wait到15s的时候设备休眠了,并且连续休眠30分钟后才又被唤醒,那么这时候wait会不会马上被唤醒,答案是:正常情况下wait会继续,知道直到剩下的15s也wait完成后才会唤醒,所以我疑惑了,于是查看下下Thread的wait()方法的接口文档,终于找到如下解释:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
A thread can also wake up without being notified, interrupted, or
     * timing out, a so-called <i>spurious wakeup</i>.  While this will rarely
     * occur in practice, applications must guard against it by testing for
     * the condition that should have caused the thread to be awakened, and
     * continuing to wait if the condition is not satisfied.  In other words,
     * waits should always occur in loops, like this one:
     * <pre>
     *     synchronized (obj) {
     *         while (&lt;condition does not hold&gt;)
     *             obj.wait(timeout);
     *         ... // Perform action appropriate to condition
     *     }
     * </pre>

大致意思是说当Thread在wait的时候除了会被主动唤醒(notify或者notifyAll),中断(interrupt),或者wait的时间到期而唤醒,还有可能被假唤醒,而这种假唤醒在实践中发生的几率非常低,不过针对这种假唤醒,程序需要通过验证唤醒条件来区分线程是真的唤醒还是假的唤醒,如果是假的唤醒那么就继续wait直到真唤醒,事实上,在我们实际的开发过程中确实要注意这种微小的细节,可能99%的情况下不会发生,但是要是遇到1%的情况发生之后,那么这个问题将会是非常隐晦的,而且在查找问题的时候也会变得很困难,很奇怪,为什么线程好好的wait过程中突然被唤醒了呢,甚至可能怀疑我们以前对于线程wait在设备休眠状态下的执行情况?,废话就扯到这里,继续来研究Watchdog机制,在Watchdog等待30s之后会调用evaluateCheckerCompletionLocked()方法来检测被监控对象的运行情况:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private int evaluateCheckerCompletionLocked() {
        int state = COMPLETED;
        for (int i=0; i<mHandlerCheckers.size(); i++) {
            HandlerChecker hc = mHandlerCheckers.get(i);
            state = Math.max(state, hc.getCompletionStateLocked());
        }
        return state;
    }

通过调用HandlerChecker的getCompletionStateLocked来获取每一个HandlerChecker的监控状态:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public int getCompletionStateLocked() {
            if (mCompleted) {
                return COMPLETED;
            } else {
                long latency = SystemClock.uptimeMillis() - mStartTime;
                if (latency < mWaitMax/2) {
                    return WAITING;
                } else if (latency < mWaitMax) {
                    return WAITED_HALF;
                }
            }
            return OVERDUE;
        }

从这里,我们就看到了其实是通过mCompleted这个标志来区分30s之前和30s之后的不通状态,因为30s之前对被监控的线程对应的Handler的消息对了中post了一个HandlerChecker任务,然后mCompleted = false,等待了30s后,如果HandlerChecker被及时的执行了,那么mCompleted = true表示任务及时执行完毕,而如果发现mCompleted = false那就说明HandlerChecker依然未被执行,当mCompleted = false的时候,会继续检测HandlerChecker任务的执行时间,如果在唤醒状态下的执行时间小于30秒,那重新post监控等待,如果在30秒到60秒之间,那就会dump出一些堆栈信息,然后重新post监控等待,当等待时间已经超过60秒了,那就认为这是异常情况了(要么死锁,要么耗时任务太久),这时候就会搜集各种相关信息,例如代码堆栈信息,kernel信息,cpu信息等,生成trace文件,保存相关信息到dropbox文件夹下,然后杀死该进程,到这里监控就结束了

Watchdog线程卡顿监控实现

之前我们提到Watchdog监控的实现是通过post一个HandlerChecker到线程对应的Handler对的消息对了中的,而死锁的监控对象都是保存在HandlerChecker的mMonitors列表中的,所以外部调用addMonitor()方法,最终都会add到Watchdog的全局变量mMonitorChecker中的监控列表,一次所有线程的死锁监控都由mMonitorChecker来负责实现,那么对于线程耗时任务的监控,Watchdog是通过addThread()方法来实现的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void addThread(Handler thread) {
        addThread(thread, DEFAULT_TIMEOUT);
    }

    public void addThread(Handler thread, long timeoutMillis) {
        synchronized (this) {
            if (isAlive()) {
                throw new RuntimeException("Threads can't be added once the Watchdog is running");
            }
            final String name = thread.getLooper().getThread().getName();
            mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis));
        }
    }

addThread()方法实际上是创建了一个新的HandlerChecker对象,通过该对象来实现耗时任务的监控,而该HandlerChecker对象的mMonitors列表实际上是空的,因此在执行任务的时候并不会执行monitor()方法了,而是直接设置mCompleted标志位,所以可以这么解释:Watchdog监控者是HandlerChecker,而HandlerChecker实现了线程死锁监控和耗时任务监控,当有Monitor对象的时候就会同时监控线程死锁和耗时任务,而没有Monitor的时候就只是监控线程的耗时任务造成的卡顿

Watchdog监控流程

watchdog.jpg

  • 理解了Watchdog的监控流程,我们可以考虑是否把Watchdog机制运用到我们实际的项目中去实现监控在多线程场景中重要线程的死锁,以及实时监控主线程的anr的发生?当然是可以的,事实上,Watchdog的在framework中的重要作用就是监控主要的系统服务器是否发生死锁或者发生卡顿,例如监控ActivityManagerService,如果发生异常情况,那么Watchdog将会杀死进程重启,这样可以保证重要的系统服务遇到类似问题的时候可以通过重启来恢复,Watchdog实际上相当于一个最后的保障,及时的dump出异常信息,异常恢复进程运行环境
  • 对于应用程序中,健康那个重要线程的死锁问题实现原理可以和Watchdog保持一致
  • 对于监控应用的anr卡顿的实现原理可以从Watchdog中借鉴,具体实现稍微有点不一样,Activity是5秒发生anr,Broadcast是10秒,Service是20秒,但是实际四大组件都是运行在主线程中的,所以可以用像Watchdog一样,wait 30秒发起一次监控,通过设置mCompleted标志位来检测post到MessageQueue的任务是否被卡住并未及时的执行,通过mStartTime来计算出任务的执行时间,然后通过任务执行的时间来检测MessageQueue中其他的任务执行是否存在耗时操作,如果发现执行时间超过5秒,那么可以说明消息队列中存在耗时任务,这时候可能就有anr的风险,应该及时dump线程栈信息保存,然后通过大数据上报后台分析,记住这里一定是计算设备活跃的状态下的时间,如果是设备休眠,MessageQueue本来就会暂停运行,这时候其实并不是死锁或者卡顿

anr1.jpg

WatchDog机制的anr在线监控实现与demo

https://github.com/liuhongda/anrmonitor/tree/master/anrmonitor

Watchdog机制总结
  • 每一个线程都可以对应一个Looper,一个Looper对应一个MessageQueue,所以可以通过向MessageQueue中post检测任务来预测该检测任务是否被及时的执行,以此达到检测线程任务卡顿的效果,但是前提是该线程要先创建一个Looper
  • Watchdog必须独自运行在一个单独的线程中,这样才可以监控其他线程而不互相影响
  • 使用Watchdog机制来实现在线的anr监控可能并不能百分百准确,比如5秒发生anr,在快到5秒的临界值的时候耗时任务正好执行完成了,这时候执行anr检测任务,在检测任务执行过程中,有可能Watchdog线程wait的时间也到了,这时候发现检测任务还没执行完于是就报了一个anr,这是不准确的;另一种情况可能是5秒anr已经发生了,但是Watchdog线程检测还没还是wait,也就是anr发生的时间和Watchdog线程wait的时间错开了,等到下一次Watchdog线程开始wait的时候,anr已经发生完了,主线程可能已经恢复正常,这时候就会漏掉这次发生的anr信息搜集,所以当anr卡顿的时间是Watchdog线程wait时间的两倍的时候,才能完整的扫描到anr并记录,也就是说Watchdog的wait时间为2.5秒,这个在实际应用中有点过于频繁了,如果设备不休眠,Watchdog相当于每间隔2.5秒就会运行一下,可能会有耗电风险
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017.12.02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android系统层Watchdog机制源码分析
一:为什么需要看门狗? Watchdog,初次见到这个词语是在大学的单片机书上, 谈到了看门狗定时器. 在很早以前那个单片机刚发展的时候, 单片机容易受到外界工作影响, 导致自己的程序跑飞, 因此有了
用户1269200
2018/02/01
1.5K0
Android系统层Watchdog机制源码分析
Android中SystemServer的Watchdog
SystemServer中通过Watchdog来检测UI、IO、Fg等线程是否会阻塞 , 也可以检测是否发生死锁.
None_Ling
2021/02/22
9210
android进阶之Watchdog检查系统异常机制
Watchdog是Android系统提供的以后总检查系统异常的机制,正如其名,“看门狗”,它看的是Android框架层的几个核心服务。Watchdog一旦发现的AMS、WMS和PMS等核心服务的主线程阻塞,就清除systemserver进程,我们知道,一单SystemServer进程停止,Zygote进程就会自杀,系统就会重启。
见得乐
2022/09/08
2K0
java watchdog_Watchdog实现分析
Framework层所有的Service都是运行在SystemServer进程中;SystemServer进程是由Zygote进程创建。
全栈程序员站长
2022/11/15
7940
java watchdog_Watchdog实现分析
02.Android崩溃Crash库之App崩溃分析
目录总结 01.抛出异常导致崩溃分析 02.RuntimeInit类分析 03.Looper停止App就退出吗 04.handleApplicationCrash 05.native_crash如何监控 06.ANR是如何监控的 07.回过头看addErrorToDropBox 前沿 上一篇整体介绍了crash崩溃库崩溃重启,崩溃记录记录,查看以及分享日志等功能。 项目地址:https://github.com/yangchong211/YCAndroidTool 欢迎star,哈哈哈 01.抛出异常导致崩
杨充
2020/09/07
3.4K0
微信Android客户端的ANR监控方案
ANR监控是一个非常有年代感的话题了,但是市面上的ANR监控工具,或者并非真正意义上的ANR的监控(而是5秒卡顿监控);或者并不完善,监控不到到所有的ANR。而想要得到一个完善的ANR监控工具,必须要先了解系统整个ANR的流程。本文分析了ANR的主要流程,给出了一个完善的ANR监控方案。该方案已经在Android微信客户端上经过全量验证,稳定地运行了一年多的时间。 我们知道ANR流程基本都是在system_server系统进程完成的,系统进程的行为我们很难监控和改变,想要监控ANR就必须找到系统进程跟
微信终端开发团队
2021/07/19
5.2K0
Android性能优化(七)之你真的理解ANR吗?
在上一篇文章《Android性能优化(六)之卡顿那些事》中,我们提到了卡顿的成因、检测卡顿的途径以及避免卡顿的方法。卡顿再扩大就会产生大名鼎鼎的ANR(Application Not Responding),然后告诉用户你的App无响应,继续等待或者强制关闭,很大的概率用户可能会顺手卸载如此卡的App。
用户2898788
2018/08/21
1.1K0
Android性能优化(七)之你真的理解ANR吗?
ActivityManagerService启动过程分析
之前讲Android的View的绘制原理和流程的时候,讲到过在Android调用setContentView之后,Android调用了一个prepreTravle的方法,这里面就提到了ActivityManagerService。 ActivityManagerService提供的主要功能:        (1)统一调度各应用程序的Activity        (2)内存管理        (3)进程管理 上一篇我们分析Android启动过程的文章中我们分析到了SystemServer,当时我们只是简单的
xiangzhihong
2018/02/05
9910
ActivityManagerService启动过程分析
Android PMS的创建过程
PMS的创建过程分为两个部分进行讲解,分别是SyetemServer处理部分和PMS构造方法。其中SyetemServer处理部分和AMS和WMS的创建过程是类似的,可以将它们进行对比,这样可以更好的理解和记忆这一知识点。
用户1269200
2018/08/14
1.4K0
Android PMS的创建过程
Android ANR问题解析(一)
ANR,是“Application Not Responding”的缩写,即“应用程序无响应”。直观地说就是:“又卡了?” 与Java Crash或者Native Crash不同,ANR并不会导致程序崩溃,如果用户愿意等待,大多数ANR在一段时间后都是可以恢复的。但对于用户而言,打开一个窗口就要黑屏8秒,或者按下一个按钮后10秒程序没有任何响应显然是不可接受的。为了便于开发者Debug自己程序中响应迟缓的部分,Android提供了ANR机制。ActivityManagerService(简称 AMS)和 WindowManagerService(简称 WMS)会监测应用程序的响应时间,如果应用程序主线程(即 UI 线程)在超时时间内对输入事件没有处理完毕,或者对特定操作没有执行完毕,就会出现 ANR。
用户7557625
2020/07/15
2.7K0
[Android][Framework]关于Activity回收你要知道的事情
之前分析过一篇:ActivityThread流程wossoneri.github.io,简单了解了从ActivityThread创建到Application的启动流程。
wOw
2020/01/20
9980
ActivityManagerService 启动初探
在之前的Android SystemServer启动(二)中,分析到在SystemServer中会启动大量的Service,其中就有一个比较特殊的Service,它就是ActivityManagerService。
Rouse
2021/01/12
9840
Android中使用Contentprovider导致进程被杀死
Contentprovider也是四大组件之一,支持跨进程调用,因此肯定会用到IPC的Binder机制来实现跨进程调用,在应用层就是AIDL
大大大大大先生
2018/09/04
2.8K0
Android SystemServer启动(二)
在之前已经分析到,通过SystemServer的run方法进入到SystemServer内部逻辑。
Rouse
2021/01/12
1K0
APK安装流程详解7——PackageManagerService的启动流程(上)
我们看到在SystemServer无参构造函数里面就是初始化mFactoryTestMode
隔壁老李头
2018/08/30
2.5K0
APK安装流程详解7——PackageManagerService的启动流程(上)
PackageManagerService启动流程源码解析
PackageManagerService,是Android系统中核心服务之一,管理着所有跟package相关的工作,常见的比如安装、卸载应用。 PKMS服务也是通过binder进行通信,IPackageManager.aidl由工具转换后自动生成binder的服务端IPackageManager.Stub和客户端IPackageManager.Stub.Proxy,具体关系如下:
老马的编程之旅
2022/06/22
1.3K0
PackageManagerService启动流程源码解析
Android全面解析之由浅及深Handler消息机制
关于Handler的博客可谓是俯拾皆是,而这也是一个老生常谈的话题,可见的他非常基础,也非常重要。但很多的博客,却很少有从入门开始介绍,这在我一开始学习的时候就直接给我讲Looper讲阻塞,非常难以理解。同时,也很少有系统地讲解关于Handler的一切,知识比较零散。我希望写一篇从入门到深入,系统地全面地讲解Handler的文章,帮助大家认识Handler。
huofo
2022/03/18
8740
Android全面解析之由浅及深Handler消息机制
Android 线程与消息机制源码分析
messagequeue是用来存储消息的载体,而lopper是无限循环查找这个载体中是否有消息, handler是创建消息并使用lopper来构建消息循环。 handler主要任务是将任务切换到指定线程中执行
Yif
2019/12/26
4280
Android高频面试专题 - 进阶篇(一)ANR
ANR:Application Not Responding,即应用无响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过长,都会造成ANR。一般地,这时往往会弹出一个提示框,告知用户当前xxx未响应,用户可选择继续等待或者Force Close。
Android扫地僧
2020/03/19
1.9K0
Android高频面试专题 - 进阶篇(一)ANR
(七十)Android O Service启动流程梳理——bindService
前言:最近在处理anr问题的时候迫切需要搞清楚service的启动流程,抽时间梳理一下。
全栈程序员站长
2022/09/05
8720
相关推荐
Android系统层Watchdog机制源码分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验