美文网首页
Android Fk:【Stability】应用FC弹窗流程

Android Fk:【Stability】应用FC弹窗流程

作者: 马小藤 | 来源:发表于2018-11-02 14:32 被阅读24次

    Android Fk:【Stability】应用FC弹窗流程

    一.概述

    在Android手机里,用户可见的应用crash有两种情况:

    1. 出错后弹出出错提示框
    2. 应用直接闪退

    二.应用FC退出流程

    应用进程FC异常分为Java异常FC,Native异常FC

    2.1 Java FC Crash弹窗流程

    image.png

    这里注意到调用AMS方法时是同步binder call,因此会在dialog show出来处理完毕后才会走回来kill 自己.

    //frameworks/base/services/core/java/com/android/server/am/AppErrors.java
    void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
                int callingPid, int callingUid) {
        synchronized (mService) {
           final Message msg = Message.obtain();
                msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
                task = data.task;
                msg.obj = data;
                mService.mUiHandler.sendMessage(msg);
         }
        int res = result.get();//这里会等待dialog处理,主动wait()
        ...
    }
    
    
    //frameworks/base/services/core/java/com/android/server/am/AppErrorResult.java
    final class AppErrorResult {
        public void set(int res) {
            synchronized (this) {
                mHasResult = true;
                mResult = res;
                notifyAll();
            }
        }
    
        public int get() {
            synchronized (this) {
                while (!mHasResult) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
            return mResult;
        }
    
        boolean mHasResult = false;
        int mResult;
    }
    

    2.2 Native FC Crash弹窗流程

    image.png

    弹窗退出方式即便进程是在后台,还是会show出dialog,用户是可以察觉的.

    2.3 应用闪退

    看下RuntimeInit.java中的code,在commitInit()中设置了两个UncaughtExceptionHandler,其中setUncaughtExceptionPreHandler()不是公开的接口,setDefaultUncaughtExceptionHandler()是公开的接口.

    //frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
    protected static final void commonInit() {
            if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
    
            /*
             * set handlers; these apply to all threads in the VM. Apps can replace
             * the default handler, but not the pre handler.
             */
            Thread.setUncaughtExceptionPreHandler(new LoggingHandler());
            Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler());
    }
    

    这里设置了Thread默认的UncaughtExceptionHandler为KillApplicationHandler:

        /**
         * Handle application death from an uncaught exception.  The framework
         * catches these for the main threads, so this should only matter for
         * threads created by applications.  Before this method runs,
         * {@link LoggingHandler} will already have logged details.
         */
        private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
            public void uncaughtException(Thread t, Throwable e) {
                try {
                    ...
                    //这里跨进程去通知AMS show dialog,同步binder call,会等待dialog处理结束(即dismiss掉)再回来
                    ActivityManager.getService().handleApplicationCrash(
                            mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
                } catch (Throwable t2) {
                   ...
                } finally {
                    // 最后kill掉自己并退出
                    Process.killProcess(Process.myPid());
                    System.exit(10);
                }
            }
        }
    

    可以看出KillApplicationHandler在kill自己退出之前会去先同步binder调用show error dialog;
    而setDefaultUncaughtExceptionHandler是公开的接口,应用可以自己重写UncaughtExceptionHandler,然后调用Thread.setDefaultUncaughtExceptionHandler()来设置default为重写的handler,从而实现异常时自己需要处理的操作,比如抓取特定的log保存待上传等.

    一般良心应用的操作,在application初始化的时候先获取保存默认的UncaughtExceptionHandler,再设置default为重写的UncaughtExceptionHandler,等异常时先调用重写的UncaughtExceptionHandler,等自己的逻辑走完后再调用保存的原来的UncaughtExceptionHandler走系统默认的处理方式.

    比如讯飞语音的操作:

    public class d implements UncaughtExceptionHandler {
        private static d c;
        private UncaughtExceptionHandler a;
        private Context b;
    
        private d(Context context) {
            if (Thread.getDefaultUncaughtExceptionHandler() != this) {
                //将默认的UncaughtExceptionHandler保存在a中
                this.a = Thread.getDefaultUncaughtExceptionHandler();
                //设置默认的为复写后的
                Thread.setDefaultUncaughtExceptionHandler(this);
                this.b = context.getApplicationContext();
            }
        }
    
        private String a(Throwable th) {
            String str = null;
            if (th != null) {
                try {
                    Writer stringWriter = new StringWriter();
                    PrintWriter printWriter = new PrintWriter(stringWriter);
                    th.printStackTrace(printWriter);
                    printWriter.close();
                    str = stringWriter.toString();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return str;
        }
        //该方法猜测应该是在讯飞应用application中进行实例化
        public static void a(Context context) {
            if (c == null) {
                c = new d(context);
            }
        }
    
        public void uncaughtException(Thread thread, Throwable th) {
            //先处理自己的逻辑
            if (a.h.booleanValue()) {
                String a = a(th);
                c cVar = new c();
                cVar.a = a.d;
                cVar.b = e.a(a);
                cVar.c = System.currentTimeMillis();
                f.a(cVar);
            }
            new com.iflytek.sunflower.d.d(this.b).a();
            if (this.a != null) {
                //再调用系统原来默认的,如果前面没有kill掉自己,在这里会走系统原生的killApplicationHandler
                //从而会弹出FC dialog.
                this.a.uncaughtException(thread, th);
            }
        }
    }
    

    如果进程在后台不可见,该退出方式用户是察觉不到的.
    http://blog.csdn.net/TaylorPotter/article/details/79305155

    三. 应用进程启动

    应用进程会在启动时去设置DefaultUncaughtExceptionHandler,而DefaultUncaughtExceptionHandler是可以复写重新设置的.
    简单图:

    image.png

    四. 总结

    1. Java FC 弹窗详细流程


      image.png
    2. Native FC 弹窗详细流程


      image.png
    3. 应用启动详细流程


      image.png
    4. 以上流程图的uml代码
      百度云下载上面图中的uml代码

    相关文章

      网友评论

          本文标题:Android Fk:【Stability】应用FC弹窗流程

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