扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
有Java层面,和Native层面。
成都创新互联公司服务项目包括循化网站建设、循化网站制作、循化网页制作以及循化网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,循化网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到循化省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!在我们平常操作中,如果有未捕获的异常,会导致系统崩溃,这个崩溃本质上是人为操作的,人为去操作系统主动退出(后面讲源码的地方可以看到)。
ANR系统因为线程阻塞问题,导致的无响应。
WTF(What a Terrible Failure)一般指,系统中自己编码没有按照android要求进行,例如发送未受保护的广播、启动的Activity未在注册文件里注册等等;
这个一般不用太关注,主要写代码按标准来就行。
首先我们先明确一个目的,我们的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()方法里设置的。
小总结在上面的源码分析步骤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()函数去处理。
addErrorToDropBox()函数和DropBoxManager有关,Android Dropbox 是 Android 在 Froyo(API level 8) 引入的用来持续化存储系统数据的机制。主要用于记录 Android 运行过程中, 内核, 系统进程, 用户进程等出现严重问题时的 log, 可以认为这是一个可持续存储的系统级别的 logcat。
记录位置:在data/system/dropbox中:
也就是说,我们想要看系统的崩溃日志,可以在这个文件路径下找。
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流