作为开发同学,每天都在面临各种各种的崩溃问题。
我们都如果在Android应用中发生了未捕获的崩溃问题,不管是在主线程还是在子线程,应用都会直接退出。
但是Java程序,子线程抛出的异常,不会引起程序的退出。
那你们知道JVM是如何处理应用未捕获崩溃的吗?Android又是怎样在发生崩溃时让程序退出的呢?

崩溃处理机制

当一个线程抛出异常时,JVM会调用线程的dispatchUncaughtException方法,所有未被捕获的异常,最后都会交给UncaughtExceptionHandler处理。

对于一个线程来说,UncaughtExceptionHandler有多个,首先有针对单个线程的unCaughtExceptionHandler,然后还有静态的首先有一个静态的defaultUncaughtExceptionHandlerdefaultUncaughtPreExceptionHandler,这个是对每个线程都生效的。

处理顺序:未捕获的异常,先由线程处理,然后由线程的ThreadGroup处理,最后再由默认异常处理程序处理。

Android发生崩溃后

为什么Android发生异常后,不管是在主线程还是在子线程,都会引起程序crash退出呢?
其实是因为Android给所有线程都设置了一个defaultExceptionHandler,这个ExceptionHandler的处理逻辑就是让程序退出。
下面我们来看源码。

在应用程序被创建的时候,RuntimeInit会设置一个默认的异常处理Handler,这个异常处理Handler就是KillApplicationHandler。从名字就可以看出,这个Handler主要负责杀掉App进程。

// RuntimInit
protected static final void commonInit() {
    LoggingHandler loggingHandler = new LoggingHandler();
    // 设置preExceptionHandler
    Thread.setUncaughtExceptionPreHandler(loggingHandler);
    // KillApplicationHandler 作为全局 Handler
    Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
    //...
}

KillApplicationHandler会先调用loggingHandler打印日志,然后杀掉当前进程。

   private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
        private final LoggingHandler mLoggingHandler;

        public KillApplicationHandler(LoggingHandler loggingHandler) {
            // 传入loggingHandler用于打日志
            this.mLoggingHandler = Objects.requireNonNull(loggingHandler);
        }

        @Override
        public void uncaughtException(Thread t, Throwable e) {
            try {
                // 打日志
                ensureLogging(t, e);
                // 已经在crash中了,不处理了
                if (mCrashing) return;
                mCrashing = true;
                // ...
            } catch (Throwable t2) {
                // ...
            } finally {
                // 通知内核杀掉进程
                Process.killProcess(Process.myPid());
                // 停止VM
                System.exit(10);
            }
        }

所以,当出现未捕获的异常时,会交给KillApplicationHandler中的uncaughtException,从而直接让程序退出。与此同时,我们也可以从adb日志中看到崩溃的具体堆栈。

声明:本站所有文章均来源于网络,仅供学习技术交流。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。另请遵守法律法规,禁止利用本站资源修改调整后从事任何商业活动。