01 | 崩溃优化(上)——学习总结

Android 崩溃分为 Java 崩溃和 Native 崩溃

 

1.Native 崩溃的捕获流程

https://mp.weixin.qq.com/s/g-WzYF3wWAljok1XjPoo7w?

完整的Native崩溃从补货到解析需要经历哪些流程:

编译端。需要将带符号信息的文件保留下来。

客户端。捕获到崩溃时,收集尽可能多的有用信息,然后选择合适的时机上传到服务器。

服务端。读取上报的日志文件,寻找合适的符号文件,生成可读的 C/C++调用栈。

 

2、Native崩溃捕获的难点

Chromium 的Breakpad是目前 Native 最成熟的捕获崩溃方案。

最核心的是怎么样保证客户端在各种极端情况下依然可以生成崩溃日志。因为在崩溃时,程序会处于一个不安全的状态,如果处理不当,非常容易发生二次崩溃。

生成崩溃日志时会有哪些比较棘手的情况?

情况一:文件句柄泄漏,导致创建日志文件失败,怎么办?应对方式:

我们需要提前申请文件句柄 fd 预留,防止出现这种情况。

情况二:因为栈溢出了,导致日志生成失败,怎么办?,替换当前栈,或者在堆里预留空间。

情况三:整个堆的内存都耗尽了,导致日志生成失败,怎么办?

Breakpad 做的比较彻底,重新封装了Linux Syscall Support,来避免直接调用 libc。

https://time.geekbang.org/column/article/70602

情况四:堆破坏或二次崩溃导致日志生成失败,怎么办?

Breakpad 会从原进程 fork 出子进程去收集崩溃现场。即使出现二次崩溃,只是这部分的信息丢失部分信息。

 

3. 选择合适的崩溃服务

Bugly、阿里的啄木鸟平台、网易云捕、Google 的 Firebase 等等。

当然,在平台的选择方面,我认为,从产品化跟社区维护来说,Bugly 在国内做的最好;从技术深度跟捕获能力来说,阿里 UC 浏览器内核团队打造的啄木鸟平台最佳。

 

如何客观地衡量崩溃

UV 崩溃率 = 发生崩溃的 UV / 登录 UV

PV 崩溃率、启动崩溃率、重复崩溃率这些指标,计算方法都大同小异。

启动崩溃对用户带来的伤害最大,应用无法启动往往通过热修复也无法拯救。闪屏广告、运营活动,很多应用启动过程异常复杂,又涉及各种资源、配置下发,极其容易出现问题。微信读书、蘑菇街、淘宝、天猫这些“重运营”的应用都有使用一种叫作“安全模式”的技术来保障客户端的启动流程,在监控到客户端启动失败后,给用户自救的机会。

 

如何客观地衡量稳定性

处理了崩溃,我们还会经常遇到 ANR .

我们怎么去发现应用中的 ANR 异常呢?

1. 使用 FileObserver 监听 /data/anr/traces.txt 的变化。

非常不幸的是,很多高版本的 ROM,已经没有读取这个文件的权限了。

海外可以使用 Google Play 服务,而国内微信利用Hardcoder框架(HC 框架是一套独立于安卓系统实现的通信框架,它让 App 和厂商 ROM 能够实时“对话”了)向厂商获取了更大的权限

 

2. 监控消息队列的运行时间。

这个方案无法准确地判断是否真正出现了 ANR 异常,也无法得到完整的 ANR 日志。在我看来,更应该放到卡顿的性能范畴。

Tinker 在补丁的加载流程也设计了简单的“安全模式”,在启动时会检查上次应用的退出类型,如果检查连续三次异常退出的情况。

都有哪些应用退出的情形

  • 主动自杀。Process.killProcess()、exit() 等。
  • 崩溃。出现了 Java 或 Native 崩溃。
  • 系统重启;系统出现异常、断电、用户主动重启等,我们可以通过比较应用开机运行时间是否比之前记录的值更小。
  • 被系统杀死。被 low memory killer 杀掉、从系统的任务管理器中划掉等。
  • ANR。

在应用启动的时候设定一个标志,在主动自杀或崩溃后更新标志,这样下次启动时通过检测这个标志就能确认运行期间是否发生过异常退出。

对应上面的五种退出场景,我们排除掉主动自杀和崩溃(崩溃会单独的统计)这两种场景,希望可以监控到剩下三种的异常退出,理论上这个异常捕获机制是可以达到 100% 覆盖的。

衡量应用的稳定性:异常率

UV 异常率 = 发生异常退出或崩溃的 UV / 登录 UV

我们不应该盲目追求崩溃率这一个数字,应该以用户体验为先,我们不应该随意使用 try catch 去隐藏真正的问题。了解崩溃的本质原因,保证后面的运行流程。

 

Breakpad是一个跨平台的开源项目,今天的课后作业是使用 Breakpad 来捕获一个 Native崩溃。

https://github.com/AndroidAdvanceWithGeektime/Chapter01

 

windows 下解析 breakpad 产生的dump

分析dump参考:https://www.jianshu.com/p/0bfe7800bdef0

利用了androidstudio 自带的 工具

 


 

 好,从.dump文件解析出来的信息中,根据文章Android 平台 Native 代码的崩溃捕获机制及实现的介绍,我们可知Crash reason: SIGSEGV代表哪种类型的错误:

SIGSEGV 是当一个进程执行了一个无效的内存引用,或发生段错误时发送给它的信号。
Thread 0 (crashed) // crash 发生时候的线程
 0  libcrash-lib.so + 0x526 // 发生 crash 的位置和寄存器信息 

有了具体的寄存器信息,我们进行符号解析,可以使用Android NDK中提供的addr2line来根据地址进行一个符号反解的过程,该工具在Android SDK目录下可以找到。
  工具链的选择要根据.so的类型来决定,看解析后的文件,有显示CPU信息。下面是NDK 18的工具链目录:


  如果是arm-64位的so,解析是需要使用aarch64-linux-android-4.9下的工具链。
  如果是arm-32位的so,解析是需要使用arm-linux-androideabi-4.9下的工具链。
  如果是x86-64位的so,解析是需要使用x86_64-4.9下的工具链。
  如果是x86-32位的so,解析是需要使用x86-4.9下的工具链。
  这里,因为CPU信息是arm,所以选择 arm-linux-androideabi-4.9下的工具链。我们将项目中build目录下对应的

libcrash-lib.so 地址:

(app\build\intermediates\transforms\mergeJniLibs\debug\0\lib\x86\libcrash-lib.so)

拷贝到x86-4.9下的工具链目录(D:\Android\sdk\ndk-bundle\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin)中,然后执行如下命令:

具体得到 哪个类,哪一行报错。

总结:

可能由于环境不同,无法启动,建议同学自行编译来获取工具,具体教程可见 https://github.com/google/breakpad

回过头来看Google Breakpad在Github上的说明,是针对没有minidump_stackwalk执行文件的开发者而言的,打个比方(可能不恰当,假设做Java后台的没有minidump_stackwalk):做Java Web的,利用JNI实现了一个需求,想捕获异常并分析,那么他就必须在他开发的平台上(Windows、Mac或Linux下)利用Google Breakpad源码生成一个minidump_stackwalk文件。只是,Android已经提供这个文件,只是有些人不知道而已。
  另外,我推测:在Linux、Mac下,只要安装了Android Studio应该都不需要编译Google Breakpad源码。

 

极客时间版权所有: https://time.geekbang.org/column/article/70602

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值