Android---App 崩溃

崩溃问题是衡量 App 质量的决定性考核标准。Android 系统会输出各种相应的 log 日志,很大程度上降低了工程师 debug 崩溃问题的难度。如果要给 crash 日志进行分类,可以分为2大类:JVM 异常(Exception)堆栈信息native 代码崩溃日志

JVM 异常堆栈信息

Java 中异常(Exception)分两种:检查异常(checked Exception)和非检查异常(unchecked Exception)

\bullet 检查异常是在代码编译时期,Android Studio 就会提示代码有错误,无法通过编译。比如 IOException。如果没有在代码中将这些异常 catch,而是直接抛出,最终也有可能导致程序崩溃。

\bullet 非检查异常包括 error 和运行时异常(RuntimeException)。AS 并不会在编译时期提示这些异常信息,而是在程序运行时期因为代码错误而直接导致程序崩溃。比如 OOM 或者空指针异常(NPE)

Java 异常

对于上述两种异常,我们都可以使用 UncaughtExceptionHandler 来进行捕获操作。它是 Thread 的一个内部接口,定义如下

对于传入的 Thread,如果因为未捕获异常而导致被终止,uncaughtException 则会被调用。我们可以通过它来间接捕获程序异常,并进行异常信息的记录工作,或者给出更友好的异常提示信息。 

自定义异常处理类

自定义类实现 UncaughtExceptionHandler 接口,并实现 uncaughtException() 方法。如下代码所示

需要注意的几点,自定义异常处理类中,需要持有线程默认异常处理类,如图中红框处所示。这样做的目的是在自定义异常处理类无法处理或者处理异常失败时,还可以将异常交给系统做默认处理。如果自定义异常处理类成功处理异常,需要进行页面跳转或者将程序进程杀死,否则程序会一直卡死在崩溃界面,并弹出无响应对话框。在上面代码中通过 CrashDisplayActivity 页面来展示所捕获的异常详细信息。

一般情况下,在 handleException() 方法中需要做以下几件事情:

1)收集 crash 的现场相关信息。如下面方法获取当前 App 的版本信息,以及所有手机设备的相关信息

2)日志的记录工作,将收集到的信息保存在本地。比如以文件的方式保存。从下图中可以看出,除了我们自己收集的日志,还需要将系统抛出的异常信息也保持到文件中,方便后续开发人员分析问题原因。

使用自定义异常处理类

上面我们提到的 LagouExceptionHandler 自定义异常处理类定义好之后,就可以将其初始化。并将主线程注册到 LagouExceptionHandler 中。如下

最终,报错的 crash 日志信息格式如下图所示

需要注意的是,因为使用了文件写操作,所以需要动态申请文件操作的权限。

native 异常

当程序中的 native 代码发生崩溃时,系统会在 /data/tombstones/ 目录下保存一份详细的崩溃日志信息。如果一个 native crash 是必现的,不妨在模拟器上重现 bug。并将 /data/tombstones 中的崩溃日志拉到本地电脑中加以分析。

比如,创建一个模拟 native crash 的项目 LagouNativeCrash。项目结构如下

MainActivity 中有一个点击按钮 Button,当点击此按钮时,会调用 crash() 方法触发 native 代码崩溃。

native crash 在 native-lib.cpp 文件中声明,如下

当点击 Button 触发 native 崩溃之后,系统会在 /data/tombstones 目录下生成 tombstones 日志文件。可以在此日志文件中查看详细的保存信息。如下所示

但是,如果 native crash 是偶发现象,并且在模拟器上一时难以复现。那么就需要将工作交给测试工程师,在真机上尝试复现。

这种情况下就需要一种机制,将 native crash 现场的日志信息保存到可以访问的手机目录中。目前比较成熟,使用也比较广泛的是谷歌的 Breakpad。Breadpad 是一个跨平台的开源库,也可以在其 Breakpad Github 上下载自己编译,并通过 JNI 的方式引入到项目中。

NDK 导入 Breakpad

在 Breakpad GitHub 官网上,有一个 README Android 的介绍文件,这个文件专门介绍了如何在 Android 项目中导入 Breakpad。我们可以直接使用 cmake 方式将其编译为一个静态库。

在捕获 native crash 之前,需要初始化 Breakpad。主要是设置 Breakpad 保存 crash 日志的路径,如下所示

图中传入的 path 就是 Breakpad 保存日志的文件目录,一般情况下保存在外置 SDK 目录。

初始化好之后,就可以在我们自己的 native 业务层模拟一个崩溃现场。Breakpad 会自动捕获这次 crash,并将生成的 crash 信息保存在所设置的目录中。

breadpad 生成的文件是 .dmp 文件,需要将其进行转换,如下所示

线上崩溃日志捕获

上面介绍了 java 和 native 崩溃的捕获都是基于现场能够复现 bug 的前提。但是,对于线上用户,这种操作方式是不太现实的。首先,不可能将一个 debug 版本的 APK 安装到终端用户的手机上;其次,不太可能要求用户操作一遍手机并将某一目录下的文件发送给开发人员。

对于大多数公式来说,针对线上版本没有必要自己实现一个抓取 log 的平台系统。最快速的实现方式就是集成第三方 SDK。目前比较成熟,采用也比较多的就是腾讯的 Bugly。Bugly 能够满足线上版本捕获 crash 的所有需求,包括 java 层和 native 层的 crash 都可以获取相应的日志。并且每天 Bugly 都会邮件通知上一天的崩溃日志,方便测试和开发统计 bug 的分布以及崩溃率。

其它的 crash 上报工具,比如 XCrashSentry

这两者比 Bugly 好的地方就是除了自动拦截界面崩溃事件,还可以主动上报错误信息。以 XCrash 为例,基本使用如下所示

可以看出 XCrash 的使用更加灵活,工程师的掌控性更高。可以通过设置不同的过滤方式针对性的上报相应的 crash 日志。并且在捕获到 crash 之后可以加入自定义的操作,比如本地保存日志或者直接进行网络上传。

Sentry 还有一个好处就是可以通过设置过滤,来判断是否上报 crash 日志。这对于 SDK 的开发人员是很有用的,比如一些 SDK 的开发商只是想收集自身 SDK 引入的 crash,对于用户的其他操作导致的 crash 进行过滤。这种情况就可以考虑集成 Sentry。

总结

本次主要介绍了 Android 崩溃的相关知识。对于 Android 工程师来说,crash 可以分为2类:Java 层和 Native 层

\bullet Java 层一般通过自定义 UncaughtExceptionHandler 进行异常拦截

\bullet Native 层可以考虑集成谷歌的 breakpad 进行捕获,并保存日志在本地

最后介绍了几个线上捕获 crash 的工具:Bugly、XCrash 和 Sentry。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux内核密码模块

目录 密码算法介绍 Hash摘要算法 Cipher加解密算法 块密码算法 认证算法 MAC和HMAC AEAD算法 Linux内核密码模块的基本构件 Linux内核密码模块介绍 如何使用Linux密码模块 用户层调用Linux内核密码模块的方法 cryptodev AF_ALG 如何开发一个密码引擎驱动 开发一个…

数据的备份和恢复

数据的备份和恢复 备份:完全备份 增量备份 完全备份:将整个数据库完整的进行备份 增量备份:在完全备份的基础之上,对后续新增的内容进行备份 备份的需求 1、在生产环境中,数据的安全至关重要、任何数据的丢失都可…

【MySQL进阶之路丨第十六篇】一文带你精通MySQL函数

引言 在上一篇中我们介绍了MySQL数据的导入与导出;在开发中,对MySQL函数的运用是十分重要的。这一篇我们使用命令行方式来帮助读者掌握MySQL中函数的操作。 上一篇链接:【MySQL进阶之路丨第十五篇】一文带你精通MySQL数据的导入与导出 MySQ…

vue3使用element plus时遇到的问题

1.el-form中input无法输入 问题描述:在el-form中的el-input中输入数字或字母时出现卡顿,输入不进去的现象 问题原因:el-form的ref和model的名称写成了一样的单词 问题解决:两个不能一样 2.input去除边框 问题描述:…

2、鸿蒙开发工具首次运行时开发环境配置

请务必在第一次运行时配置好开发环境,如果取消了配置,后续再配置会比较麻烦 1、点击工具图标运行 2、在欢迎页中点击“Agree” 3、默认“Do not import setting”,点击“OK” 3、此片设置Nodejs和Ohpm的安装,其中, …

基于springboot实现高校党务平台管理系统【项目源码】

基于springboot实现高校党务平台管理系统演示 Java技术 Java是由Sun公司推出的一门跨平台的面向对象的程序设计语言。因为Java 技术具有卓越的通用性、高效性、健壮的安全性和平台移植性的特点,而且Java是开源的,拥有全世界最大的开发者专业社群&#x…

Python类的定义和使用:什么是类?实在不知道啥叫累!

文章目录 前言1.基础概念2.定义一个 Person 类3.类定义4.类方法定义5.类的继承6.类的公有,私有7.子类调用父类的方法关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例…

【紫光同创国产FPGA教程】——【PGL22G第十一章】以太网传输实验例程

本原创教程由深圳市小眼睛科技有限公司创作,版权归本公司所有,如需转载,需授权并注www.meyesemi.com) 适用于板卡型号: 紫光同创PGL22G开发平台(盘古22K) 一:盘古22K开发板(紫光…

VEX —— Intrinsic attribute

目录 查看 使用 PackedGeometry Intrinsic attribute 内在属性是已经被计算的值(从几何体派生出来的),可像属性一样访问; 查看 ginfo -I,打印所有内在属性;geometry spreadsheet,查看内在属性…

08.Diffusion Model数学原理分析(下)

文章目录 denoising matching term σ t z \sigma_tz σt​z的猜想Diffusion Model for SpeechDiffusion Model for TextMask-Predict 部分截图来自原课程视频《2023李宏毅最新生成式AI教程》,B站自行搜索。 书接上文。 denoising matching term E q ( x t ∣ x 0 …

第四章:人工智能深度学习教程-激活函数(第一节-激活函数)

简单来说,人工神经元计算其输入的“加权和”并添加偏差,如下图所示的净输入。 从数学上来说, 现在净输入的值可以是从 -inf 到 inf 之间的任何值。神经元并不真正知道如何绑定到值,因此无法决定激发模式。因此激活函数是人工神经网…

【Proteus仿真】【STM32单片机】汽车尾灯控制设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器,使用按键、LED模块等。 主要功能: 系统运行后,系统运行后,系统开始运行,K1键控制左转向灯&#xff…

【PHP函数封装】分分钟帮你实现数据脱敏处理, 支持手机号码、邮箱、身份证号 中文字符串!

🚀 个人主页 极客小俊 ✍🏻 作者简介:web开发者、设计师、技术分享博主 🐋 希望大家多多支持一下, 我们一起进步!😄 🏅 如果文章对你有帮助的话,欢迎评论 💬点赞&#x1…

一篇文章教会你写一个贪吃蛇小游戏(纯C语言)

一篇文章教会你写一个贪吃蛇小游戏 1、游戏展示2、游戏功能3、Win32 API3.1 控制台程序3.2 控制台屏幕上的坐标COORD3.3 GetStdHandle函数3.4 GetConsoleCursorInfo函数3.4.1 CONSOLE_CURSOR_INFO结构体 3.5 SetConsoleCursorInfo函数3.6 SetConsoleCursorPosition函数3.7 GetA…

C++智能指针的使用:shared_ptr、weak_ptr、unique_ptr的使用,使用案例说明。

系列文章目录 本章内容: (1)shared_ptr、weak_ptr、unique_ptr的介绍 (2)单独使用share_ptr造成的内存泄漏 (3)shared_ptr和weak_ptr的配合使用 文章目录 系列文章目录前言一、shared_ptr、wea…

openEuler 系统使用 Docker Compose 容器化部署 Redis Cluster 集群

openEuler 系统使用 Docker Compose 容器化部署 Redis Cluster 集群 Redis 的多种模式Redis-Alone 单机模式Redis 单机模式的优缺点 Redis 高可用集群模式Redis-Master/Slaver 主从模式Redis-Master/Slaver 哨兵模式哨兵模式监控的原理Redis 节点主客观下线标记Redis 节点主客观…

如何避免手动修改文件名,批量重命名文件的方法

在我们的日常生活和工作中,经常需要处理大量的文件,其中一些文件可能需要进行重命名。如果只是少数几个文件,我们可以手动重命名,但是当面对成百上千的文件时,手动重命名就变得非常繁琐和低效。那么,有没有…

低代码技术这么香,如何把它的开发特点发挥到极致?

前言 什么是低代码技术? 低代码是一种可视化软件开发方法,通过最少的编码更快地交付应用程序。图形用户界面和拖放功能使开发过程的各个方面自动化,消除了对传统计算机编程方法的依赖。 文章目录 前言低代码平台怎么选?用友Yonbu…

C语言中一维指针、二维指针和三维指针

指针可以指向一份普通类型的数据,例如 int、double、char 等,也可以指向一份指针类型的数据,例如 int *、double *、char * 等。 如果一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针。 假设…

github遇到想要强制拉取远程仓库内容

进行项目的时候,遇到了我的远程仓库 Sync fork 更新以后,这时候我的本地就和远程不同步,如果使用 git pull 的时候,如果出现 conficts 过多的情况怎么办,如果我们想要直接把远程仓库拉下来应该怎么办? git…
最新文章