一、形成体系溃散(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调用; 能够理解为,未处理的反常会走到这儿来: ​

造成Android Java层crash原理分析
在上图咱们能够看到官方明确奉告,JVM在处理未经捕获的反常时,会调用当前dispatchUncaughtException函数进行处理,这个里面咱们能看到一个类型为UncaughtExceptionHandler的类。 ​
造成Android Java层crash原理分析
在上图的逻辑中咱们能够看到假如没有设置uncaughtExceptionHandler,将使用线程所在的线程组(ThreadGroup ) 来处理这个未捕获反常。线程组ThreadGroup实现了UncaughtExceptionHandler,所以能够用来处理未捕获反常。

源码剖析过程3

所以,咱们重点来看ThreadGroup中,是怎么来处理未捕获反常的:在Thread类的dispatchUncaughtException函数中,最终调用了getUncaughtExceptionHandler().uncaughtException(this, e); 咱们知道这个getUncaughtExceptionHandler()回来的是ThreadGroup,所以咱们来看ThreadGroup中的uncaughtException办法: ​

造成Android Java层crash原理分析
默许状况下,ThreadGroup处理未捕获反常的逻辑是:

  1. 首先将反常音讯通知给父线程组(假如parent不为空的话)

  2. 然后尝试利用一个默许的defaultUncaughtExceptionHandler来处理反常;

  3. 假如没有默许的反常处理器则将错误信息输出打印到System.err

这儿能够考虑下,咱们能够自定义一个反常处理类,承继下 Thread.UncaughtExceptionHandler,然后去处理未捕获的反常。记住需要手动去调用Thread.setUncaughtExceptionPreHandler()办法设置下,有了这个自定义反常处理类,就能够做相应的溃散优化。

源码剖析过程4

回到Thread中,考虑下:已然他是通过getDefaultUncaughtExceptionHandler来处理,现在咱们并没有看到有相关的设置,但是在Thread中咱们看到了他对外提供了对应的设置函数:Thread.setUncaughtExceptionPreHandler()

源码剖析过程5

考虑下:体系是否会有当地默许给咱们设置了uncaughtExceptionHandler?

由于从上面的源码看来,咱们并没有看到有让体系直接溃散掉的状况,由于默许是ThreadGroup去处理,他只不过是做了一个日志信息的记载,不会有退出的状况,那么肯定是有哪个当地默许设置了uncaughtExceptionHandler,让体系退出的。

源码剖析过程6

来看下RuntimeInit这个类,zygote担任发动RuntimeInit进程(作用:app运转时环境初始化,用来初始化运转时的一系列信息,其间包括反常处理),它里面有个main办法: ​

造成Android Java层crash原理分析
造成Android Java层crash原理分析
这儿设置了默许的反常处理:KillApplicationHandler

源码剖析过程7

咱们来看下KillApplicationHandler

造成Android Java层crash原理分析
重点来看 uncaughtException(Thread t, Throwable e)这个办法: ​
造成Android Java层crash原理分析
看到这儿就知道了,默许的反常处理(杀进程)是在RuntimeInit进程(作用:app运转时环境初始化,用来初始化运转时的一系列信息,其间包括反常处理)的main()办法里设置的。

小总结

造成Android Java层crash原理分析

三、AMS怎么承接应用的反常信息上报?

在上面的源码剖析过程7咱们知道了,在KillApplicationHandler的uncaughtException()办法里,最终反常信息有一个AMS上报过程: ​

造成Android Java层crash原理分析
来看下ActivityManagerService.handleApplicationCrash()办法: ​
造成Android Java层crash原理分析
从上面能够看出,若传入appnull时,processName就设置为system_server,意思是:假如没有来历默许判定是体系进程自己。接着看handleApplicationCrashInner(String eventType......)办法:

参数eventType是指事件类型,详细如下:

  • Java层未捕捉的反常:crash
  • ANRanr
  • native层的反常:native_crash

现在咱们看的是java的反常,所以这个类型传的是crash

接着看handleApplicationCrashInner()函数: ​

造成Android Java层crash原理分析

中心的能够先不论他们,这个能够理解为在进行体系日志输出,详细的处理是在addErrorToDropBox()函数中。

重点注意:无论是java crashnative_crashANR或是wtf,最终都是来到这儿,交由addErrorToDropBox()函数去处理。

四、DropBoxManager

addErrorToDropBox()函数和DropBoxManager有关,Android Dropbox 是 Android 在 Froyo(API level 8) 引入的用来继续化存储体系数据的机制。首要用于记载 Android 运转过程中, 内核, 体系进程, 用户进程等呈现严重问题时的 log, 能够以为这是一个可继续存储的体系级别的 logcat。

记载位置:在data/system/dropbox中:

也就是说,咱们想要看体系的溃散日志,能够在这个文件路径下找。 ​

造成Android Java层crash原理分析