android timer后函数继续执行_Android内存异常机制(用户空间)_JE

常见的Android稳定性异常,有内核异常和Android层异常。内核异常也就是常说的“kernel panic”,简称KE异常;Android层异常又分为java层crash和Native层crash,简称JE、NE异常。此外,Android层异常还有应用ANR和system_Server watchdog异常,这两种异常是应用或者系统长时间无响应时触发的。

本文主要介绍android层Java Exception异常的抓取机制和处理方式。下期文章里会再介绍NE异常。

Java Exception

1.简介  

我们知道java有try-catch的异常捕获机制,一份健壮的代码应该在设计和实现时考虑到各种可能遇到的exception异常,捕获并做相应的处理。

但并非所有的异常都是可被预知的,没有捕获到的异常,会被一层层的往上抛,最终由虚拟机的默认异常处理机制来处理。这里会打印出异常的堆栈信息,同时程序将停止运行,也就是我们常见的程序崩溃。

Debug版本上,程序崩溃会弹框提示“xx程序停止运行”。正式用户版本上,各厂商通常都修改为直接退出应用,移除了弹框提示。

2.异常抓取机制

Java的Thread类提供了一份Java的Thread类中有一个UncaughtExceptionHandler接口,该接口的作用主要是为了当Thread因未捕获的异常而突然终止时,调用处理程序处理异常。

//UncaughtExceptionHandler接口唯一的回调函数

void uncaughtException(Thread t, Throwable e);


//设置当前线程的异常处理器
Thread.setUncaughtExceptionHandler

//设置所有线程的默认异常处理器
Thread.setDefaultUncaughtExceptionHandler

//设置所有线程的默认异常预处理器
Thread.setUncaughtExceptionPreHandler

Android中也同样利用了这种机制。虚拟机在遇到线程没有捕获的异常时,会调用thread的dispatchUncaughtException分发到当前线程中。

38b2469cf7730b3df4f7625440a63a25.png

这里的java_lang_Thread_dispatchUncaughtException就是反射的java thread类的dispatchUnCaughtException方法。

e2f8a35aed68f7ee07b96e009a7aaf4d.png7576b4bb5c15d1c52accb4d5bccb375f.png

这里面会有两个uncaughtExceptionHandler参与处理,分别是preHandler和Handler,分别执行各自的unCaughtException()方法。

这里,preHandler可以不设置。事实上,Android平台在N之前只有一个Handler,并没有设置preHandler。

我们知道,Android系统中,System_server进程和各种应用进程都是从zygote进程孵化而来,zygoteInit的时候会调用Runntime.commonInit(),这里就会设置进程默认的uncaughtExceptionHandler,代码实现如下:

f8ed6890c26e5e709e05d231713478d3.png

这里,RunntimeInit初始化了两个handler,一个是preHandler(LoggingHandler),一个是defaultHangler(KillApplicationHandler)。

两个类都继承于Thread.UncaughtExceptionHandler,实现其中的uncaughtException方法。其中:

(1)LoggingHandler:

主要用来打印异常信息,包括是否是SYSTEM_SERVER进程异常,异常进程名、pid信息、异常堆栈等。

我们分析问题常见的“FATAL EXCEPTION:”的打印就是来自于这里。如果是SYSTEM_SERVER进程发生的JE异常,打印的头部会变成”*** FATAL EXCEPTION IN SYSTEM PROCESS:”.

(2)KillApplicationHandler:

主要用来检查和确保LoggingHandler的日志打印被调用到,然后通知AMS,杀掉应用进程。

2bbb742e7e109766ecfc489b3980d5b6.png531a99f4e9c769e290f045691ffd3e03.png

Android N之前,只有一个defaultHandler,日志打印和通知AMS杀进程都是在这个Handler中完成的。

需要注意的是,preHandler的设置并非对外公开api,应用无法使用。但是Thread的setDefaultUncaughtExceptionHandler是公开的api,应用进程可以通过重设它来实现自己捕获uncaughtException。这种情况下,系统日志中虽然打印了FATAL EXCEPTION,但是应用并没有死掉。应用可以通过这种方式自己捕获异常的堆栈,但是通常情况下,捕捉完信息后,建议还是杀掉或者重启进程,这种如果处理不好的话,容易出现应用假死(无法运行也不会自动退出) 的情况。

在log中打印完日志之后,uncaughtException还会调用AMS的handleApplicationCrash对本次异常进行处理,将抛出的异常throwable通过ApplicationErrorReport类转换为序列化变量再通过binder传递到AMS服务端。

5793415febd18f1a479af8a2ef33a6d0.pngbba8749ca636cb4730c4d8186e11f56d.png

HandleApplicationCrash会先去获取进程名称,进程名(processName)获取方式:

①当远程Ibinder对象为空,则进程名为“system_server”

②远程对象不为空时。如果processRecord能查到符合该binder对象的app记录,则打印processRecord对象中相应的进程名;如果processRecord为空,现场可能已经不完整,进程名复制为“unknown”。

88c33d3c674acaf28dd2e82868613c39.pngc016a82b0a35900aa146f5630dff223a.png

有了crashInfo,又拿到了processRecord信息和进程名,接下来继续执行crashInner处理方法。HandleApplicationCrashInner主要完成两件事情,一是调用addErrorToDropBox,将crashInfo的关键信息输出到dropbox文件中,目录位于data/system/dropbox,根据异常的进程名,一般名为system_server_crash@***.txt,system_app_crash***,data_app_crash***。

写入的内容包括进程名、pid、uid、时间、flag、包名、前后台信息、fingerprint版本信息、crashInfo堆栈信息等,厂商定制可能会再加入一些其他的打印。

到这里,日志已经保存完,接下来AppError.crashApplication用来完成最后的收尾工作,主要用来处理应用退出后带来的状态切换变化,以及呈现crash弹窗给用户。该函数中主要的两段:

df90883ef0158b66919094769079d807.png

① makeAppCrashingLocked。处理应用退出后的逻辑,主要完成的工作:

  • 处理屏幕旋转以及旋转动作相关逻辑;

  • 移除屏幕冻结的超时消息;

  • 使能输入事件分发;

  • 发送configuration改变的消息;

  • 恢复顶部的Activity;

② SHOW_ERROR_UI_MSG。主要用来处理crash之后的弹框提醒,阻塞并等待用户选择是否退出,用户不做选择超过5min或者手机休眠的话,会自动退出。

至此,JAVA Exception的抓取处理逻辑完成。

3.抓到的日志

JE异常产生后,会先在logcat buffer中产生一系列打印,包含刚才提到的“FATAL EXCEPTION”和“***FATAL EXCEPTION IN SYSTEM PROCESS”, 通常可以以FATAL关键字搜索定位。

LOG中的JE异常格式如下:

0ac2d650e3dd2a91becaea239907f40f.png

另外,在data/system/dropbox目录下,会同步生成一份txt的日志文件,需要root权限才能导出。通常根据crash的进程的不同,前缀可能是“system_app_crash”、“data_app_crash”、“system_server_crash”中的一种。

导出后的内容如下图:

b039465da870376c040245ca62e96b98.png

4.异常堆栈由来

Java exception的产生,主要有两种原因:

 (1) 编写的程序代码内部错误产生的异常,如调用对象为空(空指针异常)、数组越界异常、除0异常等。这种通常称为未检查的异常,在虚拟机中执行时会集中处理这些异常。

(2) 其他运行中异常,通过throw语句主动抛出的异常。这类异常称为检查异常,一般是程序认为自己遇到了严重的问题,后续再运行可能会出问题,主动告知方法调用者一些必要的信息。

未检查的异常是如何让线程退出循环,执行到uncaughtExceptionHandler的?我们以除0异常来举例。

8c36f32367f2b94039a1d7dd07195b0f.png

经过编译,这个触发操作最后会转化为一条div-int/lint8指令,当art虚拟机需要执行这条语句时,会去先解释这条语句,通过字符串匹配的方式找到对应的指令代码,这条语句对应的是DIV_INT_LIT8.

7a0b473b7f83c63222054088c2d93fbf.png

DIV_INT_LIT8会继续调用DoIntDivide方法。DoIntDivide方法定义如下,这里我们可以看到,当除数divisor为0的时候,虚拟机会通过hrowArithmeticExceptionDivideByZero方法抛出除零异常。

a6b9cd544d799898fcfe2a99ae5a16d6.png

接下来的调用顺序:

5dcdc4ee0a8e1c5bca05243e161be770.pngf63deeef94d647c55844620dfb6b9d46.png

Art虚拟机对该throw异常,遍历线程方法栈寄存器和PC指针寄存器, 得到函数方法调用栈等信息,最终用setException方法保存在tlsPtr变量中,等thread.destory调用dispatch uncaughtException的时候,将exception信息传递给之前RuntimeInit中注册的handler去处理。

其他的未检查的异常也是类似的逻辑。

对于检查类的异常,这一块逻辑会简单很多。通常检查类的异常都会由某段程序主动调用throw去抛出一个runntimeException,exception可以是原生的类型,例如SecurityException、NullPointerException、IllegalStateException,也可以是自己定义的某个集成于exception的类。

无论是哪种exception还是error,最终都是继承于Throwable类,throwable类在构造的时候就会调用fillInStackTrace方法。

68807de99b513617ed064a7d0cdd729a.png

这个jni方法最终会调用到art虚拟机的Thread:: CreateInternalStackTrace方法中。这就和刚才未检查异常里面获取stackTrace用到了同样的方法。这里会把exception(throwable)的堆栈环境记录下来。

等需要打印的时候,再通过jni方法来获取。前面提到的AMS调用handleApplicationCrash这里getStackTrace获取的就是throwable初始化时记录下来的函数运行堆栈。

a5e605e87f48cc7e91df476a9638a35a.png

5.分析方法

Java Exception的分析方法相对要简单很多,java堆栈会保留出错的调用栈,能精确到代码指定的行号。如果问题容易复现,可以直接用logcat命令复现并保存日志。如果是已经发生的低概率问题,机器现场还在的话,可以通过导出data/system/dropbox目录下的日志文件。通常是data_app_crash、system_app_crash、system_server_crash开头,以txt为后缀。通过分析日志堆栈可以快速定位到出错的代码。

5fc207aae7712dd2d523d635c012d444.png

例如上图的异常,堆栈可以明显看到指定的行号上存在代码运行空指针异常,并且准确的打印了空指针的变量名称,开发人员可以检查相关代码逻辑,处理即可。

16e243fb199601ca1424b32bf187fd00.gif

长按关注

内核工匠微信

Linux 内核黑科技 | 技术文章 | 精选教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/355523.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle10 数据库审计,Oracle数据库审计用法实例

本节是从ORACLE METALINK的DOC:167293.1翻译整理而来的。通过举例的方式来说明ORACLE审计的用法。ORACLE的审计可以从语句级、对象本节是从Oracle METALINK的DOC:167293.1翻译整理而来的。通过举例的方式来说明ORACLE审计的用法。ORACLE的审计可以从语句级、对象级和权限级几个…

cefsharp 发送请求服务器_超高性能管线式HTTP请求(实践·原理·实现)

来源:https://www.cnblogs.com/lulianqi/p/8167526.html这里的高性能指的就是网卡有多快请求发送就能有多快,基本上一般的服务器在一台客户端的压力下就会出现明显延时。该篇实际是介绍pipe管线的原理,下面主要通过其高性能的测试实践,解析背…

oracle 启用闪回数据库,如何启用Oracle10g闪回数据库特性

为什么80%的码农都做不了架构师?>>>1.确认当前模式SYS AS SYSDBA on 29-MAR-05 >select flashback_on from v$database;FLA---NO2.检查/修改恢复区设置SYS AS SYSDBA on 29-MAR-05 >show parameter db_recovery_file_destNAME TYPE VALUE-----------…

nvme通用驱动_对领域驱动设计的理解与实践

领域驱动设计(Domain-Driven-Design)是一种针对大型复杂系统的领域建模与分析方法论。2003 年,Eric Evans 发布《Domain-Driven Design: Tackling Complexity in the Heart of Software》(领域驱动设计:软件核心复杂性应对之道),其中定义了DD…

为什么不应该用Stream forEach替换for循环的3个原因

太棒了! 我们正在将代码库迁移到Java8。我们将用函数替换所有内容。 扔掉设计模式。 删除面向对象。 对! 我们走吧! 等一下 Java 8已经问世了一年多,而这种兴奋又回到了日常业务中。 baeldung.com从2015年5月开始执行的一项非代…

使用NPOI库导入导出EXCEL

一、EXCEL 导入&#xff08;Excel 导入导出实际项目中会被封装成**Helper 本示例只对简单功能做演示&#xff09; NPOI 包引用 视图view {ViewBag.Title "NPOIExcel"; }<h2>NPOIExcel</h2> <form action"Url.Action("NPOIInport", &…

oracle12c ora 12547,Oracle 12c DBCA出现PRCR-1079 ORA-12547 CRS-5017

Oracle 12c用dbca创建数据库时出现了PRCR-1079 ORA-12547 CRS-5017不能启动数据库。因为这里安装了Oracle Restart&#xff0c;所以尝试使用srvctl start database命令来手动启动数据库&#xff0c;但是结果还是一样不能启动。[gridoracle12c 12.1]$ srvctl start database -db…

kmeans鸢尾花分类python代码_python实现鸢尾花三种聚类算法(K-means,AGNES,DBScan)

一.分散性聚类(kmeans) 算法流程: 1.选择聚类的个数k. 2.任意产生k个聚类&#xff0c;然后确定聚类中心&#xff0c;或者直接生成k个中心。 3.对每个点确定其聚类中心点。 4.再计算其聚类新中心。 5.重复以上步骤直到满足收敛要求。&#xff08;通常就是确定的中心点不再改变。…

akka_Akka的字数统计MapReduce

akka在我与Akka的日常工作中&#xff0c;我最近写了一个字数映射减少示例。 本示例实现了Map Reduce模型&#xff0c;该模型非常适合横向扩展设计方法。 流 客户端系统&#xff08;FileReadActor&#xff09;读取文本文件&#xff0c;并将每一行文本作为消息发送给ClientActor…

Log4j 2配置与IntelliJ IDEA控制台颜色

Log4j是Java平台上最好的日志组件了&#xff0c;Log4j 2升级了不少API&#xff0c;拓展性更好。使用的话只需要直接引入就可以了. <dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version> &…

用c3p0连接oracle怎么分页,JSP分页(MySql+c3p0+dbutils)

JSP分页(MySqlc3p0dbutils)来源&#xff1a;互联网作者&#xff1a;佚名时间&#xff1a;2015-02-16 17:27为什么要对数据进行分页&#xff1f;当数据较多时&#xff0c;页面就会变的很庞大&#xff0c;不仅会影响到用户的使用&#xff0c;而且还有加重服务器的负担。下面简单的…

Apache Storm的实时情绪分析示例

实时情感分析是指处理自然语言文本&#xff08;或语音&#xff09;流以提取主观信息。 琐碎的用例用于构建推荐引擎或查找社交媒体趋势。 我选择了Apache Storm作为实时处理引擎。 Storm非常强大&#xff08;我们正在生产中使用它&#xff09;&#xff0c;并且非常容易在其之上…

flink sql设置并行度_《从0到1学习Flink》—— Flink parallelism 和 Slot 介绍

前言之所以写这个是因为前段时间自己的项目出现过这样的一个问题&#xff1a;Caused by: akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://flink/user/taskmanager_0#15608456]] after [10000 ms]. Sender[null] sent message of type "org.apache.f…

zabbix3.2监控

自动化运维框架 运维标准流程监控管理容量管理、关联关系、任务管理、自动部署、分布式集群、传统集群、机器管理安全控制灾难管理 自动化监控 监控评估数据采集主动式数据采集: client、公共插件、自定义脚本被动式服务状态: 服务状态、程序状态、用户访问质量第三方信息 公…

fasttext 文本分类_一文综述经典的深度文本分类方法

作者 | 何从庆转载自AI算法之心(ID:AIHeartForYou)笔者整理最近几年比较经典的深度文本分类方法&#xff0c;希望帮助小伙伴们了解深度学习在文本分类中的应用。Convolutional Neural Networks for Sentence Classification (EMNLP 2014)Kim在EMNLP2014提出的TextCNN方法&…

vi/vim 编辑器详解

vi/vim &#xff1a; 强大的编辑器 进入vi的命令 vi filename :打开或新建文件&#xff0c;并将光标置于第一行首 vi n filename &#xff1a;打开文件&#xff0c;并将光标置于第n行首 vi filename &#xff1a;打开文件&#xff0c;并将光标置于最后一行首 vi /pattern …

实验三+067+冯艳芳

一、实验目的 掌握黑盒测试用例设计方法 二、实验要求 &#xff08;1&#xff09;对被测程序进行黑盒测试用例设计 &#xff08;2&#xff09;运用等价类、边界值、决策表、状态图法等进行测试用例设计。 &#xff08;3&#xff09;对手机上任意一款音乐软件进行黑盒测试实践。…

python越来越慢_为什么Python中的串联速度越来越慢?

为什么在某些情况下,Python 3中的连接似乎比Python 2中的连接慢&#xff1f; 影响最大的串联方法似乎是字节对象的连续串联,从O(n)到O(n?)操作. 我的分析代码大部分在这里&#xff1a; #!/usr/bin/env python from operator import concat from sys import version, version_i…

jvm gc策略_IBM JVM调整– gencon GC策略

jvm gc策略本文将向您详细介绍从Java虚拟机&#xff08;例如HotSpot或JRockit&#xff09;迁移到IBM JVM时重要的Java堆空间调整注意事项。 此调整建议基于我为我的一个IT客户端执行的最新故障排除和调整任务。 IBM JVM概述 正如您可能从其他文章中看到的那样&#xff0c;IBM …

芬兰高性能图表控件-免费试用并提供技术支持

图表控件对于很多技术研发人员、工程设计师来说肯定不陌生&#xff0c;但市面上已有的图表控件产品大多功能单一、性能也不稳定&#xff0c;很难满足不同人群在不同场合的使用需求。为此&#xff0c;专注于开发高性能和最先进的数据可视化工具公司Arction则给出了完美的解决方案…