Breakpad 简单使用

在Android日常开发中,我们肯定会遇到Crash,当Crash发生时我们应该尽可能详细的收集Crash信息,这样才会对我们定位问题时提供准确的信息。

对于Android开发中遇到的Crash,基本可以分为两类:Java Crash和Native Crash。

下面我们针对这两种Crash如何捕获进行简单的介绍。

1.Java Crash捕获
        相比于native crash,我们对于Java crash更为熟悉,在其发生时我们也相对容易对其信息进行捕获。
        在Java中发生crash,Java使用defaultUncaughtExceptionHandler对未进行try- catch的crash进行相应处理,利用AMS弹框提示用户应用发生崩溃异常,接着kill应用进程。Java同时也提供接口给开发者设置自定义UncaughtExceptionHandler来对崩溃时Crash信息,当前用户信息和设备信息的采集上报。

a.系统默认defaultUncaughtExceptionHandler

defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Log.e(TAG, "init defaultUncaughtExceptionHandler name " + defaultUncaughtExceptionHandler.getClass().getName());

通过上面代码以及日志我们可以知道系统默认采用的defaultUncaughtExceptionHandler是RuntimeInit$KillApplicationHandler。

 b.自定义CustomJavaCrashHandler

通过Java接口提供的API我们实现自己自定义的崩溃处理器。

Thread.setDefaultUncaughtExceptionHandler(new CustomJavaCrashHandler());

 

在回调方法中uncaughtException我们可以拿到崩溃发生的线程以及crash的堆栈信息,更近一步我们可以在本地目录保存错误堆栈调试或者收集更多崩溃信息上报服务器做进一步的分析。

2.Breakpad

a.breakpad简介
Breakpad是Google公司开发的开源多平台C++崩溃检测库。Breakpad可以捕获发布给用户的应用程序的崩溃,并记录软件崩溃的调试信息到“minidump”文件中。调试信息包括错误行号,报错详情,堆栈错误(stack traces)。软件崩溃时候把生成的“minidump”上传到自己的服务器上就可已方便的获取足够细致崩溃详情。

b.支持平台:
windows、linux、mac、ios、solaris、android ndk

c.breakpad实现原理简单了解
在不同平台下使用平台特有的函数以及方式实现异常捕获:
Windows:通过SetUnhandledExceptionFilter()设置崩溃回掉函数
Max OS:监听 Mach Exception Port 获取崩溃事件
Linux:监听 SIGILL SIGSEGV 等异常信号 获取崩溃事件

d.MiniDump文件格式
minidump是由微软开发的崩溃记录文件格式。minidump为二进制文件,体积小。为了保持统一,breakpad在其他系统下也选择生成minidump文件。

e.breakpad工作原理示意图

示意图要表达的意思如下:
a. 包含了breakpad客户端(静态库)的应用程序在发布Release版本的时候。在编译的时候选择保留调试信息。
b. 使用Breakpad提供的dump_syms工具根据release版本程序生成“symbols文件”。“symbols文件”包括程序之前保留的调试信息。
c. 发布给用户的release版本程序发生崩溃后包含在程序内“breakpad客户端”会捕捉崩溃并生成“minidump文件”。
d. “minidump文件”被应用程序发送到你指定的服务器,或通过其他方式收到用户软件崩溃产生的“minidump文件”。
e. 收到“minidump文件”后,结合发布应用的所对应的 “symbols文件”,通过“minidump_stackwalk” 工具来转换生成文本格式的“stack trace 文件”。这个文件内的信息就是程序员可以直接阅读的崩溃堆栈详情。从而准确的找到触发崩溃的bug。

3.模拟普通native crash

针对native crash的捕获,我们本次使用谷歌开源的breakpad来进行native crash的捕获。

a.因为实现是C++,在Android中使用,必须集成NDK开发工具

 b.创建Android native library

 系统会为我们自动创建cpp文件,Java类(通过JNI与cpp进行交互)以及CMakeLists.txt文件。

CMakeLists.txt类似于cpp文件的编译脚本,包括将当前cpp文件编译library的类型,以及当前cpp文件对第三方库的依赖等等。

在CMakeLists中定义library的name以及类型

 在Java代码中加载cpp编译生成的library,就可以完成Java调用cpp中定义的方法。

c.模拟native crash

extern "C"
JNIEXPORT void JNICALL
Java_com_example_nativelib_NativeLib_createNativeCrash(JNIEnv *env, jobject thiz) {
    //制造崩溃了
    int* p = NULL;
    *p = 7;
}

在Java代码中调用会产生native crash的方法

4.移植Breakpad到客户端程序

为了监控native crash我们需要集成breakpad,需要把breakpad源码导入nativelib module下,编译成本地库提供给nativelib使用,然后在nativelib内部调用breakpad监控crash方法传入生成dump文件路径。

将Breakpad 源文件src目录导入自己程序

breakpad编译脚本编写


cmake_minimum_required(VERSION 3.18.1)

# 源文件目录
include_directories(src src/common/android/include)

# 支持汇编语言编译
enable_language(ASM)

# 生成静态库
add_library( # Sets the name of the library.
        breakpad

             # Sets the library as a shared library.
        STATIC

             # Provides a relative path to your source file(s).
        src/client/linux/crash_generation/crash_generation_client.cc
        src/client/linux/dump_writer_common/thread_info.cc
        src/client/linux/dump_writer_common/ucontext_reader.cc
        src/client/linux/handler/exception_handler.cc
        src/client/linux/handler/minidump_descriptor.cc
        src/client/linux/log/log.cc
        src/client/linux/microdump_writer/microdump_writer.cc
        src/client/linux/minidump_writer/linux_dumper.cc
        src/client/linux/minidump_writer/linux_ptrace_dumper.cc
        src/client/linux/minidump_writer/minidump_writer.cc
        src/client/minidump_file_writer.cc
        src/common/convert_UTF.cc
        src/common/md5.cc
        src/common/string_conversion.cc
        src/common/linux/breakpad_getcontext.S
        src/common/linux/elfutils.cc
        src/common/linux/file_id.cc
        src/common/linux/guid_creator.cc
        src/common/linux/linux_libc_support.cc
        src/common/linux/memory_mapped_file.cc
        src/common/linux/safe_readlink.cc)


find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# 引入Android Log库
target_link_libraries( # Specifies the target library.
        breakpad

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

从breakpad Android sample中复制初始化监控native crash方法

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

    __android_log_print(ANDROID_LOG_INFO, "native", "===> %s", path);
    
    # 关键代码 监控奔溃信号
    google_breakpad::MinidumpDescriptor descriptor(path);
    static google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback,
                                         NULL, true, -1);
    env->ReleaseStringUTFChars(path_, path);
}

   # 信号处理回调
   bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
                      void* context,
                      bool succeeded) {
        __android_log_print(ANDROID_LOG_INFO, "DumpCallback", "===> %s", descriptor.path());

        printf("Dump path: %s\n", descriptor.path());
        return false;
    }

 最终调用Java层方法完成启动监控与制造native crash

public class NativeLib {

    // Used to load the 'nativelib' library on application startup.
    static {
        System.loadLibrary("nativelib");
    }

    /**
     * A native method that is implemented by the 'nativelib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

    # 模拟一个native崩溃
    public native void createNativeCrash();

    # 对应调用初始化Breakpad监控方法
    public native void initBreakPad(String path);

}

breakpad会在本地文件路径下生成dump文件

 使用minidump_stackwalk工具对dump文件进行转换成txt

minidump_stackwalk 67005dd4-18df-42ec-ca05f4a9-11f69fc9.dmp > crash.txt

 然后使用addr2line工具最终定位so库发生crash的位置(注意上面crash.txt上面记录的cpu架构,应该使用对应cpu架构的add2line工具来进行定位)

# 0x256f8 来自崩溃线程对应记录的寄存器地址
aarch64-linux-android-addr2line -f -C -e  libnativelib.so 0x256f8

nativelib.cpp:35

后续

1.Linux信号机制

2.Breakpad原理

参考文章系列
​​​​​​12.5-使用Qt实现跨平台C++崩溃捕获,看这一篇就足够了(Breakpad)_robert_cysy的博客-CSDN博客_qt崩溃捕获

Breakpad(跨平台crash工具)_奇小葩的博客-CSDN博客_breakpad

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值