使用Breakpad捕获分析native层报错

248 阅读2分钟

Android项目集成breakpad及使用

集成

breakpad项目的github地址:github.com/google/brea…

把项目clone或者download下来,然后本地编译成so库或者通过项目集成进去;

初始化

在jni/breakpad/ 下添加 breakpad.cpp 文件,内容:

extern "C" JNIEXPORT void JNICALL
Java_com_example_breakpaddemo_MainActivity_breakpadInit(
        JNIEnv *env,
        jobject /* this */, jstring dump_path) {
    const char *path = env->GetStringUTFChars(dump_path, 0);

    google_breakpad::MinidumpDescriptor descriptor(path);
    static google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback, NULL, true, -1);

    env->ReleaseStringUTFChars(dump_path, path);
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    return JNI_VERSION_1_6;
}

在java层通过jni调用Java_com_example_breakpaddemo_MainActivity_breakpadInit方法,path为log存放的路径

    public static void initBreakpad(String path){
        initBreakpadNative(path);
    }

    private static native void initBreakpadNative(String path);

写一段native报错代码 crash.cpp

/**
 * 引起 crash
 */
void Crash() {
    volatile int *a = (int *) (NULL);
    *a = 1;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_breakpaddemo_MainActivity_crash(JNIEnv *env, jobject obj) {
    Crash();
}

添加一个按钮,点击后通过jni调用crash方法

findViewById(R.id.crash_btn)
                .setOnClickListener(
                        new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                crash();
                            }
                        });

public native void crash();

分析dmp文件

使用 minidump_stackwalk 工具把 dmp 文件生成堆栈的 log 信息

./minidump_stackwalk ***.dmp > crash.txt

如果不想自己编译生成 minidump_stackwalk 工具,可以使用 Android Studio 自带的 minidump_stackwalk 工具,路径在AS的安装路径下的 bin/lldb/bin 下

再来看看生成的 crash.txt

Thread 0 (crashed)//出现crash的线程
 0  libcrash-lib.so + 0x650//发生crash的so文件和寄存器信息
     x0 = 0x00000072b8a41300    x1 = 0x0000007fcb3ed354
     x2 = 0x0000000000000000    x3 = 0x00000072b8ac7a00
     x4 = 0x0000007fcb3ed7c8    x5 = 0x00000072b75e4f91

使用 ndk 中提供的 addr2line 来根据地址进行符号反解,addr2line 的路径:android-ndk-r16b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/ 目录下,请根据操作系统找对应的目录。

arm-linux-androideabi-addr2line -f -C -e
//发生crash的so库路径
../build/intermediates/transforms/mergeJniLibs/debug/0/lib/arm64-v8a/libcrash-lib.so 0x650
//打印结果
Crash();

总结

对于native崩溃报错的异常捕获,显然会比较麻烦,所以得付出一些耐心。本人也是第一次尝试,所以记录一下,有什么不对的地方,还望谅解,希望共勉。 对于NDK开发,还不是很熟悉,希望以后能够积累,学习完善对于NDK开发的一些知识。