Breakpad Native异常捕获

906 阅读2分钟

Breakpad工具下载,make

  1. 下载breakpad 源码,下载ssl包到 breakpad源码的third_party中去。需要翻墙

    git clone https://chromium.googlesource.com/linux-syscall-support 
    
  2. 到源码下面编译,然后生成工具 dump_sys, minidump_stackwalk.(在src/processor下面)

./configure && make
make install

项目引用Breakpad工程

  1. 搭建module,导入breakpad源码,配置CMakeLists.txt

    cmake_minimum_required(VERSION 3.4.1)
    
    set(BREAKPAD_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
    
    include_directories(${BREAKPAD_ROOT}/src ${BREAKPAD_ROOT}/src/common/android/include)
    
    file(GLOB BREAKPAD_SOURCES_COMMON
            ${BREAKPAD_ROOT}/src/client/linux/crash_generation/crash_generation_client.cc
            ${BREAKPAD_ROOT}/src/client/linux/dump_writer_common/thread_info.cc
            ${BREAKPAD_ROOT}/src/client/linux/dump_writer_common/ucontext_reader.cc
            ${BREAKPAD_ROOT}/src/client/linux/handler/exception_handler.cc
            ${BREAKPAD_ROOT}/src/client/linux/handler/minidump_descriptor.cc
            ${BREAKPAD_ROOT}/src/client/linux/log/log.cc
            ${BREAKPAD_ROOT}/src/client/linux/microdump_writer/microdump_writer.cc
            ${BREAKPAD_ROOT}/src/client/linux/minidump_writer/linux_dumper.cc
            ${BREAKPAD_ROOT}/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
            ${BREAKPAD_ROOT}/src/client/linux/minidump_writer/minidump_writer.cc
            ${BREAKPAD_ROOT}/src/client/minidump_file_writer.cc
            ${BREAKPAD_ROOT}/src/common/convert_UTF.c
            ${BREAKPAD_ROOT}/src/common/md5.cc
            ${BREAKPAD_ROOT}/src/common/string_conversion.cc
            ${BREAKPAD_ROOT}/src/common/linux/elfutils.cc
            ${BREAKPAD_ROOT}/src/common/linux/file_id.cc
            ${BREAKPAD_ROOT}/src/common/linux/guid_creator.cc
            ${BREAKPAD_ROOT}/src/common/linux/linux_libc_support.cc
            ${BREAKPAD_ROOT}/src/common/linux/memory_mapped_file.cc
            ${BREAKPAD_ROOT}/src/common/linux/safe_readlink.cc
    
            )
    
    file(GLOB BREAKPAD_ASM_SOURCE ${BREAKPAD_ROOT}/src/common/android/breakpad_getcontext.S
            )
    
    set_source_files_properties(${BREAKPAD_ASM_SOURCE} PROPERTIES LANGUAGE C)
    
    add_library(breakpad STATIC ${BREAKPAD_SOURCES_COMMON} ${BREAKPAD_ASM_SOURCE})
    
    target_link_libraries(breakpad log)
    
  2. 初始化 Breakpad库

    public class BreakpadInit {
        static {
            System.loadLibrary("breakpad-core");
        }
    
        public static void initBreakpad(String path){
            initBreakpadNative(path);
        }
    
        private static native void initBreakpadNative(String path);
    }
    

native:

bool DumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
                  void *context,
                  bool succeeded) {
    ALOGD("===============crrrrash================");
    ALOGD("Dump path: %s\n", descriptor.path());
    return succeeded;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_sample_breakpad_BreakpadInit_initBreakpadNative(JNIEnv *env, jclass type, jstring path_) {
    const char *path = env->GetStringUTFChars(path_, 0);

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

    env->ReleaseStringUTFChars(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;
}
  1. 项目工程中,把奔溃写入到sdcard里:

     /**
         * 一般来说,crash捕获初始化都会放到Application中,这里主要是为了大家有机会可以把崩溃文件输   		*出到sdcard中做进一步的分析
         */
        private void initBreakPad() {
            if (externalReportPath == null) {
                externalReportPath = new File(getFilesDir(), "crashDump");
                if (!externalReportPath.exists()) {
                    externalReportPath.mkdirs();
                }
            }
            BreakpadInit.initBreakpad(externalReportPath.getAbsolutePath());
        }
    
        @Override
        public void onRequestPermissionsResult(
                int requestCode, String[] permissions, int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            initExternalReportPath();
        }
    
        private void initExternalReportPath() {
            externalReportPath = new File(Environment.getExternalStorageDirectory(), "crashDump");
            if (!externalReportPath.exists()) {
                externalReportPath.mkdirs();
            }
        }
    

分析

1.将sdcard中保存下来的crashDump的文件保存到本地:

$:> adb pull /sdcard/crashDump  /Users/***/Desktop
  1. 首先把dump文件转化成text文件,采用的工具是Breakpad中的minidump工具。
./tools/mac/minidump_stackwalk crashDump/***.dmp >crashLog.txt 
  1. 打开text文件看到详细的crash日志,如下

    Operating system: Android
                      0.0.0 Linux 3.4.0-g7717f76 #1 SMP PREEMPT Wed Nov 4 21:42:24 UTC 2015 armv7l
    CPU: arm
         ARMv7 Qualcomm Krait features: swp,half,thumb,fastmult,vfpv2,edsp,neon,vfpv3,tls,vfpv4,idiva,idivt
         4 CPUs
    
    GPU: UNKNOWN
    Crash reason:  SIGSEGV /SEGV_MAPERR
    Crash address: 0x0
    Process uptime: not available
    
    Thread 0 (crashed)//crash 发生时候的线程
     0  libcrash-lib.so + 0x76e//发生 crash 的位置和寄存器信息
         r0 = 0x00000000    r1 = 0x00000001    r2 = 0xbea9b1fc    r3 = 0xb4d96a80
         r4 = 0x6f94d378    r5 = 0x12c0ec00    r6 = 0x12dca6a0    r7 = 0xbea9b1e8
         r8 = 0x12d63680    r9 = 0xb4db6500   r10 = 0x12d0bf20   r12 = 0xb3b1afd8
         fp = 0x00000000    sp = 0xbea9b1d4    lr = 0xb3b1778b    pc = 0xb3b1776e
        Found by: given as instruction pointer in context
     1  dalvik-main space (deleted) + 0x1cf0de
         sp = 0xbea9b1ec    pc = 0x12dcf0e0
        Found by: stack scanning
     2  base.odex + 0x441137
         sp = 0xbea9b1f0    pc = 0xa2159139
        Found by: stack scanning
     3  dalvik-LinearAlloc (deleted) + 0x8bae
         sp = 0xbea9b1f4    pc = 0xb0732bb0
        Found by: stack scanning
     4  dalvik-main space (deleted) + 0x5397e
         sp = 0xbea9b200    pc = 0x12c53980
        Found by: stack scanning
     5  dalvik-main space (deleted) + 0xebfe
         sp = 0xbea9b248    pc = 0x12c0ec00
        Found by: stack scanning
     6  dalvik-main space (deleted) + 0x1ca69e
         sp = 0xbea9b24c    pc = 0x12dca6a0
        Found by: stack scanning
     7  dalvik-main space (deleted) + 0x1cf0de
         sp = 0xbea9b250    pc = 0x12dcf0e0
        Found by: stack scanning
     8  dalvik-main space (deleted) + 0x16367e
         sp = 0xbea9b254    pc = 0x12d63680
        Found by: stack scanning
     9  dalvik-main space (deleted) + 0x10bf1e
         sp = 0xbea9b258    pc = 0x12d0bf20
        Found by: stack scanning
    10  base.odex + 0x440cb5
         sp = 0xbea9b260    pc = 0xa2158cb7
        Found by: stack scanning
    
  2. 符号解析,可以使用 ndk 中提供的addr2line来根据地址进行一个符号反解的过程,该工具在$NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line

注意:此处要注意一下平台,如果是 arm64位的 so,解析是需要使用 aarch64-linux-android-4.9下的工具链

xiuchengdeMBP:crashDump xiuchengyin$ /Users/xiuchengyin/Library/Android/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line -f -C -e libcrash-lib.so 0x76e
Crash()
/Users/xiuchengyin/Documents/AndroidJK/Chapter01/sample/src/main/cpp/crash.cpp:10
xiuchengdeMBP:crashDump xiuchengyin$

这样就可以看到 具体奔溃的代码行数了。

我只是做个笔记,文章参考:time.geekbang.org/column/arti…