美文网首页
Android TimeoutException闪退记录及解决

Android TimeoutException闪退记录及解决

作者: skyboyhp | 来源:发表于2019-07-23 15:08 被阅读0次

    此问题在oppo R9 系列的手机出现较多,而且主要集中在Android 5.1-6.0的手机系统。
    TimeoutException,在Android 系统里会出现下面这些,在释放资源时,因耗时导致的,可能不是10s,可能会是20s,30s,60s,120s。具体跟手机有关。

    android.database.CursorWindow.finalize() timed out after 10 seconds
    
    java.util.regex.Matcher.finalize() timed out after 10 seconds
    
    android.graphics.Bitmap$BitmapFinalizer.finalize() timed out after 10 seconds
    
    org.apache.http.impl.conn.SingleClientConnManager.finalize() timed out after 10 seconds
    
    java.util.concurrent.ThreadPoolExecutor.finalize() timed out after 10 seconds
    
    android.os.BinderProxy.finalize() timed out after 10 seconds
    
    android.graphics.Path.finalize() timed out after 10 seconds
    

    这些都 会导致此闪退出现。这个bug,在stackoverflow数量还是比较 多的。
    经过google查询,最终在
    具体的分析及解决可以详细阅读滴滴移动团队 分享的文章
    https://mp.weixin.qq.com/s/uFcFYO2GtWWiblotem2bGg

    我按滴滴的文章,还是会闪退,对于 app的异常监听,可参考之前的一篇文章 https://www.jianshu.com/p/2cb297395bd4

    由于我们App还集成了一些第三方 的SDK,这个SDK 里都有实现对 异常 的拦截处理,如jpush、umeng、神策打点。所以当我在自己的
    Thread.UncaughtExceptionHandler,处理完后,会再抛出一个java.lang.RuntimeException,最终还是会走异常的处理逻辑,造成App闪退。

    1 xxxxx.CrashHandler.uncaughtException()
    2 com.umeng.analytics.pro.j.uncaughtException()
    3 com.qiyukf.unicorn.j.d$1.uncaughtException()
    4 cn.jiguang.a.a.c.e.uncaughtException()
    5 com.tencent.bugly.crashreport.crash.e.b()
    6 com.tencent.bugly.crashreport.crash.e.uncaughtException()
    7 java.lang.Daemons$FinalizerWatchdogDaemon.finalizerTimedOut(Daemons.java:316)
    8 java.lang.Daemons$FinalizerWatchdogDaemon.run(Daemons.java:238)
    9 java.lang.Thread.run(Thread.java:833)
    
    2019-07-23 11:24:31.277 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():62 ]: ==thread==FinalizerWatchdogDaemon
    2019-07-23 11:24:31.278 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():67 ]: ===ex=java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
    2019-07-23 11:24:31.278 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():70 ]: ===ignore=
    2019-07-23 11:24:31.280 11406-11419/xxxx E/AndroidRuntime: FATAL EXCEPTION: FinalizerWatchdogDaemon
        Process: xxxx, PID: 11406
        java.lang.RuntimeException: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
            at cn.jiguang.a.a.c.e.uncaughtException(Unknown Source:69)
            at com.xiaomi.mipush.sdk.z.uncaughtException(Unknown Source:25)
            at com.loc.ai.uncaughtException(Unknown Source:21)
            at com.loc.ay.uncaughtException(Unknown Source:232)
            at java.lang.Daemons$FinalizerWatchdogDaemon.finalizerTimedOut(Daemons.java:424)
            at java.lang.Daemons$FinalizerWatchdogDaemon.runInternal(Daemons.java:285)
            at java.lang.Daemons$Daemon.run(Daemons.java:105)
            at java.lang.Thread.run(Thread.java:764)
         Caused by: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
            at java.lang.Thread.sleep(Native Method)
            at java.lang.Thread.sleep(Thread.java:373)
            at java.lang.Thread.sleep(Thread.java:314)
            at xxxx.ui.index.FinlaizeTimeoutObject.finalize(FinlaizeTimeoutObject.java:11)
            at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:252)
            at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:239)
            at java.lang.Daemons$Daemon.run(Daemons.java:105) 
            at java.lang.Thread.run(Thread.java:764) 
    2019-07-23 11:24:34.356 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():62 ]: ==thread==FinalizerWatchdogDaemon
    2019-07-23 11:24:34.356 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():67 ]: ===ex=java.lang.RuntimeException: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
    2019-07-23 11:24:34.356 11406-11419/xxxx E/[ FinalizerWatchdogDaemon:CrashHandler:uncaughtException():72 ]: ===ex=java.lang.RuntimeException: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
    2019-07-23 11:24:34.358 11406-11419/xxxx E/CrashReport: CrashReport has not been initialed! pls to call method 'initCrashReport' first!
    2019-07-23 11:24:37.359 11406-11419/xxxx E/Tinker.TinkerUncaughtExceptionHandler: uncaughtException:java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
    2019-07-23 11:24:37.359 11406-11419/xxxx W/Tinker.TinkerUncaughtExceptionHandler: tinker is not loaded
    2019-07-23 11:24:37.361 11406-11419/xxxx E/Tinker.UncaughtHandler: TinkerUncaughtHandler catch exception:java.lang.RuntimeException: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
            at cn.jiguang.a.a.c.e.uncaughtException(Unknown Source:69)
            at com.xiaomi.mipush.sdk.z.uncaughtException(Unknown Source:25)
            at com.loc.ai.uncaughtException(Unknown Source:21)
            at com.loc.ay.uncaughtException(Unknown Source:232)
            at java.lang.Daemons$FinalizerWatchdogDaemon.finalizerTimedOut(Daemons.java:424)
            at java.lang.Daemons$FinalizerWatchdogDaemon.runInternal(Daemons.java:285)
            at java.lang.Daemons$Daemon.run(Daemons.java:105)
            at java.lang.Thread.run(Thread.java:764)
         Caused by: java.util.concurrent.TimeoutException: xxxx.ui.index.FinlaizeTimeoutObject.finalize() timed out after 60 seconds
            at java.lang.Thread.sleep(Native Method)
            at java.lang.Thread.sleep(Thread.java:373)
            at java.lang.Thread.sleep(Thread.java:314)
            at xxxx.ui.index.FinlaizeTimeoutObject.finalize(FinlaizeTimeoutObject.java:11)
            at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:252)
            at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:239)
            at java.lang.Daemons$Daemon.run(Daemons.java:105) 
            at java.lang.Thread.run(Thread.java:764) 
    

    如何设计出一个TimeoutException。
    先自己随便写一下类,暂且叫,CustomTimeoutException吧。重写finalize()方法,在里面将线程sleep 100s,这个是测试出来的,上文有提到,不同的手机 、系统对应超时时间不一样,我用了一个魅族 5.1的手机 ,20s,在小米 note 2 8.0 系统 是60s.

    public class CustomTimeoutException {
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("====开始Timeout处理====");
            // 每个手机触发 Timeout 的时长不同,看情况修改
            Thread.sleep(100*1000);
            System.out.println("====结束Timeout处理====");
        }
    }
    

    然后在一个页面加一个点击事件,throwsTimeout()

    private void throwsTimeout(){
            new Thread(()->{
                new CustomTimeoutException();
                Runtime.getRuntime().gc();
                System.runFinalization();
            }).start();
        }
    

    点击按钮后,我们会看到打印 :
    \color{red}{====开始Timeout处理====}
    但迟迟不见:\color{red}{====结束Timeout处理====} 日志.
    注意,我在测试时,并不是每次出现,有时会打印“====结束Timeout处理====” 日志,猜测可能跟我 开启一下线程处理这个有关,因为我并没有阻塞 UI线程,App还是可以 继续使用。
    为什么要开启一个线程,不然很容易造成ANR(10s),无法复现此问题。

    经过这个,我最终并没有完全按滴滴提供的方法处理此异常。只要检测到是线程名是 FinalizerWatchdogDaemon,我就忽略此异常,这样,这样也就不会被其它的 异常处理 类强制 退出App。

    /**
         * 当UncaughtException发生时会转入该函数来处理
         */
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            System.out.println("==thread=="+thread.getName());
            System.out.println("===ex="+ex);
            System.out.println("===isTimeOut="+(ex instanceof TimeoutException)); 
            System.out.println("=isThread=="+
                   TextUtils.equals(thread.getName(),
                           "FinalizerWatchdogDaemon"));
            if(TextUtils.equals(thread.getName(),
                      "FinalizerWatchdogDaemon")) {
                //&&ex instanceof TimeoutException)
                System.out.println("===ignore=");
            }else {
               // 正常处理异常,该上抛的上抛,该交给系统 处理的交给系统处理。
            }
    

    虽然问题是解决了,但这并没有从根本上解决这个问题,真的要减少此异常的话,还是得规范开发的,尽量让App减少 GC的回收。

    相关文章

      网友评论

          本文标题:Android TimeoutException闪退记录及解决

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