APP崩溃之BreakPad捕获异常
一、简介
在开发APP时一定会遇到程序异常退出的情况,有时相对于解决问题,发现定位问题更加的困难和重要。这里就需要一个功能强大的异常捕获框架——BreakPad
Android的崩溃大体可分为以下三种:
- java层异常
- Native层异常
- ANR程序无响应:I/O、CPU或者大量GC导致的
对于以上三种情况,Native的异常捕获定位比较困难。需要对操作系统等底层有很深入的了解,以及一些极端情况的考虑(如日志生成失败导致的破坏了原来的崩溃现场)。才能制定一个优秀的异常捕获框架,但这也让BreakPad的代码量增加了。
二、window下使用BreakPad
1)、下载BreakPad源码
1、利用git等方式下载BreakPad源码,需要使用该编译源码生成工具,以及用到以上的JNI文件。
2、下载的头文件中会缺少一个文件夹,会导致配置编译的时候出现错误,这个需要手动的下载。这个可以在GitHub中下载

2)、配置编译源码
1、环境准备
需要准备Linux系统和Make,我这里用的是ubantu-16-04-3版本、Make-4.1、XShell、共享工具
2、编译
-
1、将下载的文件放置到Linux共享文件中(或用git下载到一个目录中)
image.png
-
2、配置编译
利用XShell配置breakpad文件夹下面中的configure文件,并make编译。命令:./configure && make
minidump_stackwalk
完成后在processor目录下会有个minidump_stackwalk文件,之后会使用。
3)、使用Breakpad
下载的BreakPad源码会有JNI文件,利用该文件单独放置一个模块中,官方的例子中使用的是makefile,这里改用的是make编译。可以直接将GitHub中的breakpad下载使用。
public class BreakpadInit {
static {
System.loadLibrary("breakpad-core");
}
public static void initBreakpad(String path){
initBreakpadNative(path);
}
private static native void initBreakpadNative(String path);
}
接下来使用breakpad就很简单了,直接在初始化BreakPad库的时候配置一个文件夹,该文件夹是存放之后生成的日志文件。
三、定位问题
- 1、官方给出的Native奔溃例子如下:
#include <stdio.h>
#include <jni.h>
/**
* 引起 crash
*/
void Crash() {
volatile int *a = (int *) (NULL);
*a = 1;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_dodola_breakpad_MainActivity_crash(JNIEnv *env, jobject obj) {
Crash();
}
奔溃后,取出生成的奔溃日志。我这里的日志名改成了t.dmp
- 2、使用minidump_stackwalk
在processor目录下,执行./minidump_stackwalk t.dmp > crash.txt
之后会生成一个crash.txt的日志文件。
Operating system: Android
0.0.0 Linux 4.4.21-perf-g6679372 #1 SMP PREEMPT Tue Jan 23 00:40:47 CST 2018 aarch64
CPU: arm64
8 CPUs
GPU: UNKNOWN
Crash reason: SIGSEGV /SEGV_MAPERR
Crash address: 0x0
Process uptime: not available
Thread 0 (crashed)
0 libcrash-lib.so + 0x5e0
x0 = 0x0000007f7463e180 x1 = 0x0000007ffe09eb34
x2 = 0x0000000000000000 x3 = 0x0000007f74696a00
x4 = 0x0000007ffe09efa8 x5 = 0x0000007f58bbf506
x6 = 0x00000000001b9ded x7 = 0x0000000012c7cce8
x8 = 0x0000000000000001 x9 = 0x0000000000000000
x10 = 0x375abb98f10f9542 x11 = 0x0000000000000000
x12 = 0x0000000000000000 x13 = 0x0000000000430000
x14 = 0x0000000000000000 x15 = 0x0000007f745fc7d0
x16 = 0x0000007f73024fe8 x17 = 0x0000007f730145cc
x18 = 0x00000000000000af x19 = 0x0000007f74696a00
x20 = 0x0000007f7404d350 x21 = 0x0000007f74696a00
x22 = 0x0000007ffe09eddc x23 = 0x0000007f58bbf506
x24 = 0x0000000000000004 x25 = 0x375abb98f10f9542
x26 = 0x0000007f74696a98 x27 = 0x0000007f74690600
x28 = 0x375abb98f10f9542 fp = 0x0000007ffe09eb10
lr = 0x0000007f73014604 sp = 0x0000007ffe09eaf0
pc = 0x0000007f730145e0
Found by: given as instruction pointer in context
1 libcrash-lib.so + 0x600
fp = 0x0000007ffe09ebf8 lr = 0x0000007f58cfda94
sp = 0x0000007ffe09eb20 pc = 0x0000007f73014604
Found by: previous frame's frame pointer
2 base.odex + 0x2f9a90
fp = 0x0000007ffe09ecf0 lr = 0x0000007f7405af54
sp = 0x0000007ffe09ec08 pc = 0x0000007f58cfda94
Found by: previous frame's frame pointer
这里面有奔溃的位置:libcrash-lib.so + 0x5e0
使用的CPU架构:arm64
对于Crash Reason可以参考如下对应表:

对应上面的Native崩溃,可以看出崩溃的原因是“地址无效”导致的。
- 3、使用addr2line
在SDK中toolchain交叉编译工具链中,有个 aarch64-linux-android-addr2line.exe可执行文件进行符号解析,这样就可以将之前生成的crash.txt文件定位到哪一行的问题。
这里执行的命令:
aarch64-linux-android-addr2line.exe -f -C -e
D:\F\project\self\github\AndroidAdvanceWithGeektime\Chapter01\sample\build\intermediates\transforms\mergeJniLibs\debug\0\lib\arm64-v8a\libcrash-lib.so 0x5e0
这里需要错误的so文件和crash.txt中报错对的偏移地址 0x5e0和addr2line.exe

这里就可以定位到是这个so库中的Crash方法、第十行出现的问题。