android程序员Android知识

Google Breakpad 学习笔记

2017-03-30  本文已影响5811人  骆驼骑士

作者:lds(lds2012@gmail.com)

日期:2017-03-24

一. BreakPad简介

Google breakpad是一个跨平台的崩溃转储和分析框架和工具集合。

Breakpad由三个主要组件:

简单来说就是一个生成 minidump,一个生成symbol file,然后将其合并处理成可读的Stack trace。

二. MiniDump文件格式

minidump文件格式是由微软开发的用于崩溃上传,它包括:

breakpad在所有平台上(windows/linux等)都统一使用minidump文件格式,而不使用core files,原因是因为:

什么是core files?core files是unit系统上程序崩溃时生成的文件。

参见:http://www.jianshu.com/p/8e1352a9638f

三. Symbols文件格式

symbols文件是基于纯文本的,每一行一条记录,每条记录中的字段以一个空格作为分隔符,每条记录的第一个字段表示这一行是什么类型的记录。

记录类型:

参见:https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md

四. 不同平台的实现原理

默认情况下,当崩溃时breakpad会生成一个minidump文件,在不同平台上的实现机制不一样:

当minidump被生成后,在不同平台上也使用不同的机制来上传crash dump文件。

参见:Windows SetUnhandledExceptionFilter
参见:Mac OS X Exception handling
参见:Catching Exceptions and Printing Stack Traces for C on Windows, Linux, & Mac

五. 异常处理机制

提供两种不同的异常处理机制:

  1. 同进程(in-process)
  2. 跨进程(out-precess)

因为在崩溃的进程写minidump文件是不安全的,所以三个平台(windows、linux、mac os)都提供跨进程的异常处理机制。

六. 在Linux平台使用breakpad

这里因为要研究Android上使用breakpad,所有主要研究linux平台,windows和mac平台的使用方法请自行参考文档。

6.1 构建Breakpad库

breakpad提供自动构建工具来构建linux client库和processor库。

在breakpad源码目录下通过运行命令:

./configure
make

将自动生成 src/client/linux/libbreakpad_client.a 文件, 其包含了在你的应用中生成minidumps文件的必要代码。

6.2 在你的应用中使用Breakpad

首先配置build precess来link刚生成的 libbreakpad_client.a 文件。

然后设置 include paths 来 包含 google-breakpad 目录下的 src 目录。

接下来include头文件:

#include "client/linux/handler/exception_handler.h"

现在你就可以初始化 ExceptionHandler 对象,初始化的时候需要提供一个用于写minidump文件的目录,以及一个回调函数用于在minidump文件写完以后调用。


int main(int argc, char* argv[]) {
  // 初始化ExceptionHandler
  google_breakpad::MinidumpDescriptor descriptor("/tmp"); // minidump文件写入到的目录
  google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL, true, -1);
  
  crash();
  return 0;
}

// 写完minidump后的回调函数
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
                         void* context, bool succeeded) {
  printf("Dump path: %s\n", descriptor.path());
  return succeeded;
}

// 触发crash来测试
void crash() {
  volatile int* a = (int*)(NULL);
  *a = 1;
}

编译并运行这个实例应该会在 /tmp 目录下生成 minidump 文件,并且终端下会输入minidump文件的路径。

关于初始化ExceptionHandler可以接受的参数需要参见源码

  ExceptionHandler(const MinidumpDescriptor& descriptor,
                   FilterCallback filter,
                   MinidumpCallback callback,
                   void* callback_context,
                   bool install_handler,
                   const int server_fd);

具体参数:

参见:exception_handler.h源码

需要注意的是,你必须在callback回调函数中做尽量少的工作,因为你的程序处于一个不安全的状态,它需要无法安全的去分配内存,或调用其他共享库中的函数。安全的方式是 forkexec 一个新进程去做想要做的事情。如果你需要在回调中做一些工作,breakpad源码提供一些简单的重新实现的libc库里的方法,来避免直接调用libc, 并提供一个a header file for making linux system calls,来避免直接调用其他共享库的方法。

6.3 发送minidump文件

在真实环境中,你通常需要以某种方式来处理minidump文件,例如把它发送给服务器来进行分析,Breakpad源码提供了一些HTTP上传的代码,并提供一个minidump上传工具( 详见minidump_upload.cc)。

6.4 生成symbols文件

为了生成可读的stack trace, breakpad需要你将binaries里的调试符号(debugging symbols)转换成基于文本格式的symbol files。

首先确保你在编译代码的时候加上 -g 参数来生成带调试符号的。

然后使用 configure && make breakpad源码来生成 dump_syms 工具。

接着运行 dump_syms 命令来生成 symbol files,如下:

$ google-breakpad/src/tools/linux/dump_syms/dump_syms ./test > test.sym

为了可以使用 ``minidump_stackwalk` 工具来生成stack trace,你需要将文件放置在一定的目录结构,symbol file的第一行说明了需要放置的目录结构,可以使用命令,或使用 Mozilla 提供的 symbolstore.py 工具来新建这样的目录结构。

$ head -n1 test.sym 
// MODULE Linux x86_64 6EDC6ACDB282125843FD59DA9C81BD830 test
$ mkdir -p ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830
$ mv test.sym ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830

6.5 生成Stack Trace

breakpad包含一个叫做 minidump_stackwalk 的工具来将 minidump 文件,外加symbol files来生成一个人可读的stack trace。在编译breakpad后,这个工具一般在 google-breakpad/src/processor 目录下, 通过将 minidump 和 symbol files 传入给它即可:

$ google-breakpad/src/processor/minidump_stackwalk minidump.dmp ./symbols

它会生成verbose output到stderr, stacktrace到stdout。

参见:How To Add Breakpad To Your Linux Application

七. 在Android平台使用Breakpad

Breakpad支持 ARM x86 和 MIPS 架构的Android系统。需要Android NDK r11c及以上版本。

7.1 构建client库

Android版本的Client库设计为一个静态库(static library)来使得你可以链接到你的Android native代码里。

一共有两种方法来build。

7.1.1 方法1:使用ndk-build构建(推荐)

使用ndk-build来构建,需要如下几个步骤:

  1. 在你的项目中的 Android.mk 中 include google-breakpad的 Android.mk
include $(LOCAL_PATH)/breakpad/android/google_breakpad/Android.mk
  1. 链接break-client未你的静态库模块
LOCAL_STATIC_LIBRARIES += breakpad_client
  1. 因为需要c++ STL,所以还需要在 Application.mk 文件中加入 STL 支持:
APP_STL := stlport_static

7.1.2 方法2:使用Android toolchain构建

  $GOOGLE_BREAKPAD_PATH/configure --host=arm-linux-androideabi \
                                  --disable-processor \
                                  --disable-tools
  make -j4

将会build到 src/client/linux/libbreakpad_client.a 文件。

可使用 make check 来在Android设备上运行测试。

7.2 在Android上使用Breakpad

在Android平台上使用breakpad,基本和在linux平台上是基本类似的。

需要如下几个步骤:

  1. 在cpp文件中include exception_handler头文件
#include "client/linux/handler/exception_handler.h"
  1. 如果使用ndk-build,需要配置include path(在Android.mk文件中)
LOCAL_C_INCLUDES        := $(GOOGLE_BREAKPAD_PATH)/src/common/android/include \
                           $(GOOGLE_BREAKPAD_PATH)/src

并且加上 -llog flag

LOCAL_LDLIBS := -llog
  1. 时刻记住在Android系统上没有 /tmp 目录,需要指定一个其他目录,可以是 application 专有目录(/data/data/packageName/files),或者存储到SDCard上面去(需要写入权限)

7.3 生成stack trace

这个操作和其他平台一样。

  1. 从设备上获取minidumps文件
  2. 使用dump_syms工具生成so的symbol files
dump_symc $PROJECT_PATH/obj/local/$ABI/libfoo.so > libfoo.so.sym
  1. 创建symbol files专有目录结构
// MODULE Linux x86_64 6EDC6ACDB282125843FD59DA9C81BD830 test

$PROJECT_PATH/symbols/libfoo.so/6EDC6ACDB282125843FD59DA9C81BD830/libfoo.sym
  1. 使用 minidump_stackwalk 来生成stack trace:
minidump_stackwalk $MINIDUMP_FILE $PROJECT_PATH/symbols

参见:breakpad for android 官方文档

八. 参考资料

上一篇 下一篇

猜你喜欢

热点阅读