Java层崩溃
崩溃产生的原因
-
当有异常没有在代码中捕获到时,JVM会帮我们调用
Thread.dispatchUncaughtException
方法 -
在这个方法中会判断有没有设置
UncaughtExceptionHandler
;如果有则让它调用uncaughtException
方法处理异常;如果没有则使用默认的异常处理器进行处理 -
在app进程刚创建的时候,(RuntimeInit.java)会给线程设置一个默认的异常处理器
KillApplicationhandler
,这个默认异常处理器会将异常信息上报AMS,然后杀死app进程
解决办法
-
给Thread设置一个全局的异常处理器,在里面收集崩溃信息并上报服务器
-
正常崩溃会杀死整个app进程,捕获异常后可以仅关闭当前显示的Activity,提升用户体验
-
一般崩溃都是发生在主线程Looper处理消息过程中,我们可以在Looper循环处理消息外面一层加上
try/catch
,从而避免应用被杀死;-
具体做法是通过Handler在主线程Looper发送一个消息,在这个消息中开启一个无限循环,循环里调用
Looper.loop()
并用try/catch
包裹起来,当异常发生时会被捕获,从而又重新开启一个循环去遍历消息,达到不崩溃目的 -
Handler(Looper.getMainLooper()).post { while (true) { try { Looper.loop()//开启新的循环 } catch (e: Throwable) { e.printStackTrace() } } }
-
Native层崩溃
系统native崩溃监测
- 在SystemServer启动系统服务时,会通过AMS创建一个NativeCrash监听,通过监听native层crash信号量,判断是崩溃后会将崩溃信息通过DropBoxManager保存到
/data/system/dropbox
目录下
应用内native层崩溃监测
-
通过JNI在native层监听crash有关的信号量,然后回调java层方法记录并保存起来
-
ndk提供addr2line工具可以根据内存地址定位代码行数
-
第三方框架:breakpad、腾讯Bugly
ANR
ANR的种类
Input事件和Service\广播、ContentProvider没有在规定时间内处理完事件
-
“Input event dispatching timed out” =》5秒内没有响应触摸事件
-
“Time out executing service” =》Serveice未在规定时间内启动完成,前台服务20秒,后台200秒
-
“Time out of broadcast BroadcastRecord” => 未在规定时间内处理完广播,前台广播10秒,后台广播60秒
-
“time out publish content provider” => ContentProvider没有在10秒内publish完
ANR产生的原因
-
系统在检测ANR时主要在处理事件之前通过Handler发送一个延迟消息,如果在规定时间内处理完则移除消息,否则执行ANR操作,将ANR信息保存起来并弹出ANR窗口提示;ANR信息被保存在在
/data/anr/traces.txt
文件中; -
在应用层主要是主线程做了耗时操作、或者频繁触发GC、死锁等问题造成的
ANR问题分析
-
通过系统log查看anr发生的时间、进程id、包名、ANR类型等信息
-
分析ANR发生时CPU占用情况,如果app占用率比较高,则认为是app的问题,如果是系统cpu占用率比较高,则可能是系统原因导致的
-
接着分析ANR的trace文件,主要看main主线程的状态,以及打印的堆栈信息定位发生ANR位置;比如当时主线程是不是在等待其他锁的释放,或者处理sleep、wait等状态等等
ANR监测
-
通过
FileObserver
监测data/anr/
目录下的文件变化,当ANR发生时会在该目录下生成trace文件;腾讯Bugly就是这种实现方式 -
开启一个单独的线程,通过Handler往主线程上修改一个变量,如果在设定的时间内没有修改成功,则认为发生了ANR,然后获取主线程调用栈信息;ANR-WatchDog的实现方式
-
在native层监听ANR发生时的信号量实现;微信实现方式
其他崩溃
- wtf(What a Terrible Failure):一般是值没有安装Android官方要求编码抛出的异常,比如发送了未受保护的广播,在后台服务启动Activity时没有添加
Intent.FLAG_ACTIVITY_NEW_TASK
标签等等