Android性能优化(1)-使用Breakpad捕获Android Native Crash

2,107 阅读3分钟

前言

最近学习 Android开发高手课学习到了Native Crash的定位技巧,秉着好记性不如烂笔头的原则写一篇文章记录一下Native Crash的定位流程。后续也会继续记录性能优化学习过程中的一些知识和技巧,希望能和各位大佬多多交流,一起进步。

开始之前先献上本文中使用到的的Android项目地址: github.com/AndroidAdva…

概述

本文的项目中集成了brekpad模块来生成崩溃文件用于后续的分析,集成进来的breakpad模块如图所示 定位大致步骤如下

  1. 点击crash按钮造成应用崩溃,生成崩溃信息,如果授予Sdcard权限会优先存放在/sdcard/crashDump下,反之会放到目录 /data/data/com.dodola.breakpad/files/crashDump。
  2. adb pull /sdcard/crashDump .
  3. 使用 minidump_stackwalk crashDump/***.dmp >crashLog.txt 生成崩溃文本信息文件
  4. 使用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这个工具。

  1. 安装depot_tools
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
#建议设置到~/.zprofile里面避免重复设置
export PATH=./depot_tools:$PATH
  1. 安装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
  1. 获取目标文件 我们需要的目标文件的路径为 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的步骤,以及一些常见坑点,希望能帮助到大家。

参考链接

Android开发高手课

github.com/AndroidAdva…

breakpad文档

depot_tools官网