前言
最近学习 Android开发高手课学习到了Native Crash的定位技巧,秉着好记性不如烂笔头的原则写一篇文章记录一下Native Crash的定位流程。后续也会继续记录性能优化学习过程中的一些知识和技巧,希望能和各位大佬多多交流,一起进步。
开始之前先献上本文中使用到的的Android项目地址: github.com/AndroidAdva…
概述
本文的项目中集成了brekpad模块来生成崩溃文件用于后续的分析,集成进来的breakpad模块如图所示
定位大致步骤如下
- 点击crash按钮造成应用崩溃,生成崩溃信息,如果授予Sdcard权限会优先存放在/sdcard/crashDump下,反之会放到目录 /data/data/com.dodola.breakpad/files/crashDump。
- adb pull /sdcard/crashDump .
- 使用
minidump_stackwalk crashDump/***.dmp >crashLog.txt生成崩溃文本信息文件 - 使用ndk包下的aarch64-linux-android-addr2line 捕获崩溃的具体位置
软件环境
本文的软件环境如下
- macOS 11.2
- Android Studio 4.1.1
- NDK-16b
- 红米K30Pro Android 11.0
- breakpad 上面列出的软件应该除了NDK之外,大家应该都有现成的吧,其实NDK各位大佬可能也是安装的,不过这个项目是需要这个版本的NDK工具来编译的,所以就下了这个版本的NDK,点击上面的超链接可以下载对应的macOS的NDK压缩包,如果是Windows,Linux的话可以自己去官网找一下。Windows不太推荐,因为上面的breakpad这个工具可能需要自己编译生成,Windows这方面确实不太友好,可以安装一个Linux虚拟机来实现。
编译,安装项目
下载项目
git clone https://github.com/AndroidAdvanceWithGeektime/Chapter01
下载项目完成之后通过Android Studio打开项目,编译失败报错
这是因为没有指定对应版本的NDK工具造成的,解决办法如下,在项目根目录的local.properties中加上对应的NDK-16b的路径,比如我的路径如下
sdk.dir=/Users/ray/Library/Android/sdk
#设置项目的ndk路径
ndk.dir=/Users/ray/Library/Android/sdk/android-ndk-r16b
设置完成之后重新编译项目通过,运行部署到手机上之后允许文件权限之后点击crash按钮之后应用就会崩溃。接下来就是我们分析定位nativa crash的操作了。
编译,生成分析工具
要得到minidump_stackwalk这个工具,需要我们下载breakpad的源码并且编译生成。获取breakpad的源码又需要先安装 depot_tools。breadpad的源码的文档点这里。下面我简单介绍一下depot_tools,breakpad的安装和如何生成minidump_stackwalk这个工具。
- 安装depot_tools
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
#建议设置到~/.zprofile里面避免重复设置
export PATH=./depot_tools:$PATH
- 安装breakpad
mkdir breakpad && cd breakpad
fetch breakpad
我们直接下载完成breakpad还不够,还需要一些第三方的文件,如果src目录下没有third_party文件夹的话需要
mkdir third_party && cd third_party
然后下载第三方的依赖
git clone https://chromium.googlesource.com/linux-syscall-support
第三方的依赖下载完成之后就可以在breakpad的src目录下进行编译生成目标文件了
./configure && make
make install
- 获取目标文件
我们需要的目标文件的路径为
src/processor/minidump_stackwalk
生成崩溃文本信息文件
使用我们上面编译生成的minidump_stackwalk程序可以把breakpad生成dmp文件转换为txt文件便于我们查看信息。具体使用如下(我的breakpad安装路径跟项目在同一目录上)
./breakpad/src/src/processor/minidump_stackwalk Chapter01/crashDump/***.dmp > crashLog.txt
查看crashLog.txt
Thread 0 (crashed) //crash 发生时候的线程
0 libcrash-lib.so + 0x5e0 //crash 发生的位置和寄存器信息
x0 = 0xb400007a972dd3c0 x1 = 0x0000007fef78ecd4
x2 = 0xb400007a00430000 x3 = 0x0000007fef78da28
x4 = 0x00000079fab18700 x5 = 0xa2685857527afd55
x6 = 0x0000007fef78d9b0 x7 = 0x0000007a06a721fc
x8 = 0x0000000000000001 x9 = 0x0000000000000000
x10 = 0x0000000000430000 x11 = 0x0000007a80000000
x12 = 0x000000007086f460 x13 = 0xb7ac8963bffc2d7d
x14 = 0x0000000000000006 x15 = 0xffffffffffffffff
x16 = 0x00000079f44a8fe8 x17 = 0x00000079f44985cc
x18 = 0x0000007a97e06000 x19 = 0xb400007a972f1c00
x20 = 0x0000000000000000 x21 = 0xb400007a972f1c00
x22 = 0x0000007a977e8000 x23 = 0xb400007a972f1cb8
x24 = 0x0000007a0681e268 x25 = 0x0000007a977e8000
x26 = 0x0000000000000037 x27 = 0x0000000000000001
x28 = 0x0000007fef78ece0 fp = 0x0000007fef78ecb0
lr = 0x00000079f4498604 sp = 0x0000007fef78ec90
pc = 0x00000079f44985e0
Found by: given as instruction pointer in context
请注意 ibcrash-lib.so, 0x5e0这两个信息非常重要,后续马上要用到。
定位崩溃代码位置
终于到了最关键的时候,我们可以通过上面的信息捕获crash的具体位置了。具体的操作如下
ray@RayYudeMacBook-Pro Chapter01 % $ANDROID_HOME/android-ndk-r16b/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line -f -C -e sample/build/intermediates/transforms/mergeJniLibs/debug/0/lib/arm64-v8a/libcrash-lib.so 0x5e0
Crash()
/Users/ray/AndroidPerformance/Chapter01/sample/src/main/cpp/crash.cpp:10
可以看到crash发生在crash.cpp第10行代码,终于找到了罪魁祸首,我们来看看到底是什么造成了崩溃。
crash.cpp
总结
本文简单介绍了怎么通过breakpad工具分析定位native crash的步骤,以及一些常见坑点,希望能帮助到大家。
参考链接