本文微信公众号「安卓小煜」首发
1. 背景
最近重读了 Android 开发高手课,记录一下阅读的一些笔记。
包括有些之前课后作业完成不了的,这次也都一并完成了。
如果想看课后作业的,可以直接定位到最后一节,前面的都是原文的一个汇总。
2. 崩溃的分类
- Java 崩溃:在 Java 代码中,出现了未捕获的异常,导致程序异常退出。
- Native 崩溃:一般都是因为在 Native 代码中访问非法地址,也可能是地址对齐出现了问题,或者发生了程序主动 abort,这些都会产生相应的 signal 信号,导致程序异常退出。
2.1 Native 崩溃的捕获流程
- 编译端。编译 C/C++ 代码时,需要将带符号信息的文件保留下来。
- 客户端。捕获到崩溃时候,将收集到尽可能多的有用信息写入日志文件,然后选择合适的时机上传到服务器。
- 服务端。读取客户端上报的日志文件,寻找合适的符号文件,生成可读的 C/C++ 调用栈。
2.2 Native 崩溃捕获的难点
最核心的是怎么样保证客户端在各种极端情况下依然可以生成崩溃日志
- 情况一:文件句柄泄漏,导致创建日志文件失败,怎么办?
提前申请文件句柄 fd 预留,防止出现这种情况 - 情况二:因为栈溢出了,导致日志生成失败,怎么办?
使用常见的 signalstack,预留部分堆空间 - 情况三:整个堆的内存都耗尽了,导致日志生成失败,怎么办?
Breadpad 做法是重新封装了 Linux Syscall Support,来避免直接调用 libc。 - 情况四:堆破坏或二次崩溃导致日志生成失败,怎么办?
从原进程 fork 出子进程。某些特殊情况下,还可能从子进程 fork 出孙进程。
2.3 选择合适的崩溃服务
对于很多中小型公司来说,可以选择一些第三方的服务。
从产品化和社区维护来说,推荐 Bugly。
从技术深度跟捕获能力来说,推荐啄木鸟平台。
3. 一些衡量指标
3.1 如何客观地衡量崩溃
如果想评估崩溃造成的用户影响范围,我们会先去看 UV 崩溃率。
UV 崩溃率 = 发生崩溃的 UV / 登录 UV
3.2 如何客观地衡量稳定性
-
怎么去发现应用中的 ANR 异常呢?
- 使用 FileObserver 监听 /data/anr/traces.txt 的变化
- 监控消息队列的运行时间
这两个方法都无法准确的发现 ANR
-
UV 异常率 = 发生异常退出或崩溃的 UV / 登录 UV
4. 课后作业
机器环境
OS version: macOS Monterey 12.5
AS version: Android Studio Electric Eel | 2022.1.1 Patch 2
仓库地址:Chapter01
重点说一下在按照 README 操作的过程中遇到的问题。
- 问题一
NDK is missing a "platforms" directory.
If you are using NDK, verify the ndk.dir is set to a valid NDK directory. It is currently set to /Users/zhanzengyu/Library/Android/sdk/ndk-bundle.
If you are not using NDK, unset the NDK variable from ANDROID_NDK_HOME or local.properties to remove this warning.
解法一(推荐):配置 NDK 版本,这边使用 16.1.4479499 是可以的
解法二:在 ndk-bundle 下面创建 platforms 空目录
- 问题二
ABIs [arm64-v8a] are not supported for platform. Supported ABIs are [armeabi-v7a, x86].
解法一(推荐):配置 NDK 版本,这边使用 16.1.4479499 是可以的
解法二:删除 breakpad-build 和 sample 下 abiFilters 里面的 "arm64-v8a"
- 问题三
x86 模拟器点击 crash 按钮确实闪退了,但是没有生成 dmp 文件
解法一:按照 GitHub 说的方式配置(PS:注意,如果 NDK 版本不对,会报错:GCC is no longer supported)
- 将 ndk 切换到 16b,下载地址: github.com/android/ndk...
- 在 Androidstudio 里设置 ndk 路径为ndk-16b的路径
- 在 sample 和 breakpad-build 的 build.gradle 配置里增加如下配置
javascript
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
arguments "-DANDROID_TOOLCHAIN=gcc"
}
}
解法二:使用真机
- 问题四
dyld[51346]: Symbol not found: (__ZTTNSt7__cxx1118basic_stringstreamIcSt11char_traitsIcESaIcEEE)
Referenced from: '/Users/zhanzengyu/Desktop/zengyu/project/github/Chapter01/tools/mac/minidump_stackwalk'
Expected in: '/usr/lib/libstdc++.6.dylib'
[1] 51346 abort ./098877a7-142f-4668-8784c3b0-fc8eaaef.dmp > crashLog.txt
解决方案:使用 AndroidStudio 里面自带的 minidump_stackwalk
位置在:/Applications/Android\ Studio.app/Contents/plugins/android-ndk/resources/lldb/bin/minidump_stackwalk
总结来说,最重要的是要配置正确的 NDK 版本