Google BreakPad在Android 平台上的应用

    崩溃是Android开发经常会碰到的问题,我们都知道,Android崩溃分为Java崩溃和Native崩溃。简单来说Java崩溃就是在Java代码中出现了未捕获异常,导致程序异常退出。那Native崩溃又是如何产生的?一般是因为Native代码中访问非法地址,也可能是地址对齐出现了问题,或者发生了程序主动abort,这些都会产生相应的signal信号,导致程序异常退出。
    相比于Java崩溃,Native崩溃更难捕获和定位。事实上针对我们目前的项目,几乎大部分的崩溃都是Native 崩溃。分析项目的崩溃日志我们可以发现,有些崩溃是可以从backtrace中获得一些有用的信息。但是有些崩溃甚至连backtrace都不会出现,开发人员只能单步调试,无法快速定位。所以有没有一个系统的框架来收集和处理这些Native崩溃呢?当然有,Google开源的BreakPad就是其中之一。

1 BreakPad

1.1常见信号类型

    在介绍BreakPad之前,我们首先要对信号机制有一个大概的了解。这里只是希望能对常见的信号类型有一个认识,因为一旦发生崩溃,信号类型能让我们对崩溃有一个初步的判断。

信号量 value 描述 例子
SIGABRT 6 程序发生错误或者调用了abort 很多C的库函数,如果发现异常会调用abort,如strlen
SIGBUS 10,7,10 不存在的物理地址硬件错误 更多的是因为硬件或者系统引起的
SIGFPE 8 浮点数运算错误 如除0,余0,整型溢出
SIGILL 4 非法指令 损坏的可执行文件或者代码区损坏
SIGSEGV 11 段地址错误 空指针,访问不存在的地址空间,访问内核区,写只读空间,栈溢出,数组越界,野指针
SIGSTKFLT 16 //未使用
SIGPIPE 13 管道错误,往没有reader的管道中写 Linux中的socket,如果断掉了继续写,signal(SIGPIPE,SIG_IGN)
1.2BreakPad简介

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


1.png

BreakPad由三个主要组件组成:

  • client,以library的形式内置在你的应用中,当崩溃发生时写 minidump文件
  • symbol dumper, 读取由编译器生成的调试信息(debugging information),并生成 symbol file
  • processor, 读取 minidump文件 和 symbol file ,生成可读的c/c++ Stack trace.
    简单来说就是一个生成 minidump,一个生成symbol file,然后将其合并处理成可读的Stack trace。

2 BreakPad Android集成

2.1BreakPad源码下载

    既然是BreakPad在Android平台上的应用,就把具体的应用过程写的更详细一点。BreakPad的源码下载其实是一件挺让人头大的事情,你想直接去下载国外的一些优秀开源项目的源码基本上都需要翻墙,而且翻墙了你也不一定能下载得到。参考了网上获取BreakPad源码的几种方法,虽然我已经确定自己翻墙了,无一例外全部以失败告终。后来摸索中发现,其实要获取源码,可以直接通过谷歌浏览器下载。
进入这个网页https://chromium.googlesource.com/breakpad/breakpad

2.png

然后选择master分支
3.png

然后点击tgz,源码算是下载下来了。不过还没完,源码下载到本地解压以后,你会发现是这么一个文件目录
4.png

其实我们关心的主要是src这个文件夹,因为BreakPad的源码是在这个目录下面。这里提醒一下踩过的坑。在src/third_party这个路径下面,其实是少了一个文件夹的。文件夹名是lss,文件夹内部包含了一个文件linux_syscall_support.h,少了他BreakPad就编译不通过了,好在这个文件比较好下载,具体流程就不细说了。

2.2 BreakPad动态库编译

    源码下载完以后,我们就可以开始把BreakPad集成到App中了。这个过程主要分三步。编写JNI层mapping文件;编译Android各个平台的.so文件;将.so文件导入到实际的开发项目中。
    动态库的编译需要使用ndk,本文没有采用传统的Android.mk脚本进行编译,而是使用了cmake,直接把BreakPad源码编译成了.so文件。实际上,在下载完BreakPad源码以后,进入src目录,执行./configure 和 make 命令,就能得到libbreakpad.a静态库,通过libbreakpad.a也能编译得到对应的动态库。对应的JNI层目录如下:


5.png

include文件夹下面的文件是BreakPad源码中src目录下的文件,包含Breakpad的实现源码以及所有的头文件。breakpad.cpp对应JNI mapping文件,用来注册信号处理接口,监听崩溃时系统抛出的信号。对应的代码如下:


6.png

对应的native接口为
public static native void BreakPadInit(String path)
其中参数path是发生崩溃时,dump文件的生成路径。通过编写CMakeLists.txt来生成对应的libbreakpad.so。关于Cmake的语法规则可以查阅相关资料。CMakeLists.txt文件对应如下:
7.png

至此已经可以得到我们想要的libbreakpad.so,把生成的动态库文件导入到项目中,就算完成任务了。

3 Native Crash分析

    通过得到的libbreakpad.so我们已经可以进行native crash的监测了。我们试着利用Breakpad进行native crash的定位和分析。

3.1 捕获native崩溃

    首先我们在JNI层的Native代码中人为的制造一个崩溃。这里制造了一个空指针的崩溃


8.png

我们把libbreakpad.so集成到案例项目中,运行程序,调用BreakPadTest接口,果然程序崩溃了。而且崩的很彻底,Logcat上并没有发现有用的日志信息,提示信息如下:


9.png

Error只是上报了一个SIGSEGV的信号,我们通过这个信号,只能知道是native层发生了段地址错误,有可能是数组越界或者空指针之类的常见问题,除此之外具体是哪里出现了错误,我们无从得知。
3.2 Dmp文件分析

    分析Dmp文件是我们通过Breakpad定位崩溃问题的重要手段。我们在进行Breakpad回调函数注册的时候会设置一个路径,这个路径就是发生崩溃时,dmp文件的生成路径。4.1节中,dmp文件的生成路径为/storage/emulated/0/,对应的dmp文件名为72a7ac3f-8cbe-482a-28339c98-ef9d8eb2.dmp。
    进入Breakpad源码目录,在/breakpad-master/目录下执行configure命令,执行完该命令以后,会在/breakpad-master/src/processor目录下生成minidump_stackwalk工具,用于导出崩溃日志。同时在/breakpad-master/src/tools/linux/dump_syms目录下生成dump_syms工具,用于导出符号文件。把dmp文件和minidump_stackwalk,dump_syms以及debug版本的对应so文件拷贝到同一个目录下。首先执行生成符号文件命令:


10.png

这部分的实现需要在linux环境下执行。得到libbreakpad.so.sym文件以后,查看文件,我们能够得到文件头部的一个字符串:


11.png

继续执行命令
12.png

导出崩溃堆栈信息文件(确保dmp文件和symbols目录是同级的):
13.png

这里面的native_dmp.dmp文件对应的就是上面的72a7ac3f-8cbe-482a-28339c98-ef9d8eb2.dmp,文件名太长,我在导出的时候进行了重命名。可以看到此时我们的test目录下生成了我们所需要的crashed日志,如下图:


14.png

我们打开日志可以发现崩溃位置:
15.png

定位到我们的breakpad.cpp的第46行,从左到右第二个字符。我们可以回顾一下之前制造崩溃的位置:
16.png

4 总结

    在Android平台上使用Breakpad进行native崩溃定位的整个流程就结束了,显然Breakpad优点很明显,首先它具有跨平台的特性,其次它也是google颇为得意的一款开源工具集,权威性不言而喻。缺点也很明显,从集成目标项目,到最后的崩溃日志分析,整个过程的步骤比较复杂,而且Breakpad的代码体量也比较大。如果把Breakpad集成到我们自己的项目中又会出现一些新的问题,比如目前我们软终端Android项目中的so库大大小小将近二十个,发生崩溃时,如果我们无法定位究竟是哪一个so引发的问题,那就比较头大了。最坏情况下,要对所有的so进行一番分析,所以对待native崩溃还是要结合其他手段一起定位,分析native crash并不是一件容易的事情。作者水平有限,难免会有疏漏和错误,欢迎大家批评指正。

引用

https://blog.csdn.net/elsdnwn/article/details/48651815
https://blog.csdn.net/Tencent_Bugly/article/details/75006423
对应Demo的github https://github.com/zhoutianjie/BreakPadTest

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容