造成Android Java层crash原理分析

一、造成系统崩溃(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处理未捕获异常的逻辑是:

  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方法: ​ 这里设置了默认的异常处理: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中:

也就是说,我们想要看系统的崩溃日志,可以在这个文件路径下找。 ​

相关推荐
SRC_BLUE_171 小时前
SQLI LABS | Less-39 GET-Stacked Query Injection-Intiger Based
android·网络安全·adb·less
无尽的大道4 小时前
Android打包流程图
android
镭封6 小时前
android studio 配置过程
android·ide·android studio
夜雨星辰4876 小时前
Android Studio 学习——整体框架和概念
android·学习·android studio
邹阿涛涛涛涛涛涛6 小时前
月之暗面招 Android 开发,大家快来投简历呀
android·人工智能·aigc
IAM四十二6 小时前
Jetpack Compose State 你用对了吗?
android·android jetpack·composer
奶茶喵喵叫7 小时前
Android开发中的隐藏控件技巧
android
Winston Wood8 小时前
Android中Activity启动的模式
android
众乐认证9 小时前
Android Auto 不再用于旧手机
android·google·智能手机·android auto
三杯温开水9 小时前
新的服务器Centos7.6 安卓基础的环境配置(新服务器可直接粘贴使用配置)
android·运维·服务器