一、形成体系溃散(crash)的原因是什么?
(1)未捕获的反常
有Java
层面,和Native
层面 。
在咱们平常操作中,假如有未捕获的反常,会导致体系溃散,这个溃散本质上是人为操作的
,人为操作体系自动退出
(后面讲源码的当地能够看到)。
(2)ANR
体系由于线程堵塞问题,导致的无呼应。
(3)WTF(What a Terrible Failure)
一般指,体系中自己编码没有依照android要求进行,例如发送未受保护的广播、发动的Activity未在注册文件里注册等等;这个一般不用太关注,首要写代码按标准来
就行。
二、java层未捕获的反常是怎么导致溃散的
源码剖析过程1
首先咱们先明确一个意图,咱们的main
函数的启用本身作为主线程存在,那么在咱们想要探索体系究竟怎么处理反常,需要去关注到一个类Thread
;
在咱们的程序代码中,假如存在一个反常,任何当地都没有去捕获处理它的话,它就会一路往上抛,最终来到main
函数,假如main
函数也没有处理这个反常,就会给到JVM
来处理,JVM
会给到当前的线程Thread
来处理。
源码剖析过程2
在Thread
类中,看到一段这样的函数dispatchUncaughtException()
;
注释翻译为:向处理程序发送未捕获的反常。此办法旨在仅由JVM
调用; 能够理解为,未处理的反常
会走到这儿来:
在上图咱们能够看到官方明确奉告,JVM在处理未经捕获的反常时
,会调用当前dispatchUncaughtException
函数进行处理,这个里面咱们能看到一个类型为UncaughtExceptionHandler
的类。
在上图的逻辑中咱们能够看到假如没有设置uncaughtExceptionHandler
,将使用线程所在的线程组(ThreadGroup )
来处理这个未捕获反常。线程组ThreadGroup
实现了UncaughtExceptionHandler
,所以能够用来处理未捕获反常。
源码剖析过程3
所以,咱们重点来看ThreadGroup
中,是怎么来处理未捕获反常的:在Thread
类的dispatchUncaughtException
函数中,最终调用了getUncaughtExceptionHandler().uncaughtException(this, e);
咱们知道这个getUncaughtExceptionHandler()
回来的是ThreadGroup
,所以咱们来看ThreadGroup
中的uncaughtException
办法:
默许状况下,ThreadGroup
处理未捕获反常的逻辑是:
-
首先将反常音讯通知给
父线程组(假如parent不为空的话)
; -
然后尝试利用一个默许的
defaultUncaughtExceptionHandler
来处理反常; -
假如没有默许的反常处理器则将
错误信息输出打印到System.err
。
这儿能够考虑下,咱们能够自定义一个反常处理类,承继下 Thread.UncaughtExceptionHandler
,然后去处理未捕获的反常。记住需要手动去调用Thread.setUncaughtExceptionPreHandler()
办法设置下,有了这个自定义反常处理类,就能够做相应的溃散优化。
源码剖析过程4
回到Thread
中,考虑下:已然他是通过getDefaultUncaughtExceptionHandler
来处理,现在咱们并没有看到有相关的设置,但是在Thread
中咱们看到了他对外提供了对应的设置函数:Thread.setUncaughtExceptionPreHandler()
。
源码剖析过程5
考虑下:体系是否会有当地默许给咱们设置了uncaughtExceptionHandler
?
由于从上面的源码看来,咱们并没有看到有让体系直接溃散掉的状况,由于默许是ThreadGroup
去处理,他只不过是做了一个日志信息的记载,不会有退出的状况,那么肯定是有哪个当地默许设置了uncaughtExceptionHandler
,让体系退出的。
源码剖析过程6
来看下RuntimeInit
这个类,zygote
担任发动RuntimeInit
进程(作用:app运转时环境初始化,用来初始化运转时的一系列信息,其间包括反常处理),它里面有个main
办法:
这儿设置了默许的反常处理:KillApplicationHandler
。
源码剖析过程7
咱们来看下KillApplicationHandler
重点来看 uncaughtException(Thread t, Throwable e)
这个办法:
看到这儿就知道了,默许的反常处理(杀进程
)是在RuntimeInit
进程(作用:app运转时环境初始化,用来初始化运转时的一系列信息,其间包括反常处理)的main()
办法里设置的。
小总结
三、AMS怎么承接应用的反常信息上报?
在上面的源码剖析过程7咱们知道了,在KillApplicationHandler的uncaughtException()
办法里,最终反常信息有一个AMS
上报过程:
来看下ActivityManagerService.handleApplicationCrash()
办法:
从上面能够看出,若传入app
为null
时,processName
就设置为system_server
,意思是:假如没有来历默许判定是体系进程自己。接着看handleApplicationCrashInner(String eventType......)
办法:
参数eventType
是指事件类型,详细如下:
-
Java
层未捕捉的反常:crash
-
ANR
:anr
-
native
层的反常:native_crash
现在咱们看的是java
的反常,所以这个类型传的是crash
。
接着看handleApplicationCrashInner()
函数:
中心的能够先不论他们,这个能够理解为在进行体系日志输出,详细的处理是在addErrorToDropBox()
函数中。
重点注意:无论是java crash
、native_crash
、ANR
或是wtf
,最终都是来到这儿,交由addErrorToDropBox()
函数去处理。
四、DropBoxManager
addErrorToDropBox()
函数和DropBoxManager
有关,Android Dropbox
是 Android 在 Froyo(API level 8) 引入的用来继续化存储体系数据的机制。首要用于记载 Android 运转过程中, 内核, 体系进程, 用户进程等呈现严重问题时的 log, 能够以为这是一个可继续存储的体系级别的 logcat。
记载位置:在data/system/dropbox
中:
也就是说,咱们想要看体系的溃散日志,能够在这个文件路径下找。