美文网首页Android开发经验谈Android技术知识Android开发
面试官:为什么应用出现异常会崩溃?

面试官:为什么应用出现异常会崩溃?

作者: 躲得过初一躲不过十五 | 来源:发表于2022-08-19 16:48 被阅读0次

    异常?崩溃?不是应该的吗?这....

    看到这个问题是不是这样 ->


    1、为什么发生Exception后应用会发生奔溃?

    当我们的应用发生未捕获异常后程序会回调到ThreaddispatchUncaughtException方法,如下:

    //Thread.java
    public final void dispatchUncaughtException(Throwable e) {
            ...省略部分代码
            // END Android-added: uncaughtExceptionPreHandler for use by platform.
            getUncaughtExceptionHandler().uncaughtException(this, e);
    }
    

    然后通过getUncaughtExceptionHandler去获取UncaughtExceptionHandler对象

    
    //Thread.java
    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
        return uncaughtExceptionHandler != null ? uncaughtExceptionHandler : group;
    }
    

    正常我们都没有设置UncaughtExceptionHandler,所有最后会将异常交给group(ThreadGroup)uncaughtException进行处理,如下:

    
    //ThreadGroup.java
    public void uncaughtException(Thread t, Throwable e) {
        if (parent != null) {
            parent.uncaughtException(t, e);
        } else {
            Thread.UncaughtExceptionHandler ueh = Thread.getDefaultUncaughtExceptionHandler();
            ...省略部分代码
        }
    }
    

    uncaughtException中,父类不等于null,则交由父类处理,否则会通过Thread.getDefaultUncaughtExceptionHandler();获取一个默认的UncaughtExceptionHandler来处理这个异常。

    
    //Thread.java
    public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
        return defaultUncaughtExceptionHandler;
    }
    

    那么Thread类的defaultUncaughtExceptionHandler是什么时候被赋值的呢?

    是在RuntimeInit类的入口函数main函数中的commonInit方法:

    
    //RuntimeInit.java
    public static final void main(String[] argv) {
       ...
        commonInit();
       ...
    }
    
    
    //RuntimeInit.java
    protected static final void commonInit() {
        ...
        Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
        ...
    }
    

    这个给ThreadsetDefaultUncaughtExceptionHandler设置了一个KillApplicationHandlerhandlerKillApplicationHandleruncaughtException方法如下:

    //KillApplicationHandler.java
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        try {
            // Bring up crash dialog, wait for it to be dismissed
            ActivityManager.getService().handleApplicationCrash(
                    mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
        } catch (Throwable t2) {
           ...
        } finally {
            // Try everything to make sure this process goes away.
            Process.killProcess(Process.myPid());
            System.exit(10);
        }
    }
    

    在try代码块中调用了ActivityManagerServicehandleApplicationCrash方法,在这里去写本地日志和弹出异常dialog

    最后在finally代码块中调用了Process.killProcess(Process.myPid())System.exit(10)杀掉进程。

    至此,当应用发生未捕获异常崩溃时的流程就结束了。

    上文中提到我们没有设置UncaughtExceptionHandler,其实现在很多应用也会设置通过setUncaughtExceptionHandler来设置UncaughtExceptionHandler。用于捕获异常,在回调里可以将异常日志进行整理,然后在合适的时机回传到服务器。

    那么setUncaughtExceptionHandlersetDefaultUncaughtExceptionHandler有什么区别呢?

    setUncaughtExceptionHandler:设置上文中的UncaughtExceptionHandler,只有当前线程生效。

    setDefaultUncaughtExceptionHandler,设置defaultUncaughtExceptionHandler,对所有线程生效。

    2、native_crash 奔溃怎么监控?

    这里简单提下native的崩溃。

    通过NativeCrashListener线程去监控。NativeCrashListener继承了Thread

    那么NativeCrashListener是什么时候开启监控的?

    通过ActivityManagerService中的startObservingNativeCrashes方法开启监控。

    具体逻辑:通过socket去监听文件描述符,之后进入阻塞状态,直到发生native异常,会向文件描述符中写入数据,此时,被唤醒,然后通过consumeNativeCrashData方法通过IO流去读取奔溃信息。在通过NativeCrashReport方法进行数据包装,包装为CrashInfo,然后又跳转到了ActivityManagerService中的handleApplicationCrashInner函数中进行处理。和上文中逻辑一样。

    转载自:公众号Android开发之旅

    相关文章

      网友评论

        本文标题:面试官:为什么应用出现异常会崩溃?

        本文链接:https://www.haomeiwen.com/subject/taeugrtx.html