Google BreakPad在Android 平臺上的應用

????崩潰是Android開發(fā)經常會碰到的問題,我們都知道,Android崩潰分為Java崩潰和Native崩潰。簡單來說Java崩潰就是在Java代碼中出現(xiàn)了未捕獲異常,導致程序異常退出。那Native崩潰又是如何產生的?一般是因為Native代碼中訪問非法地址,也可能是地址對齊出現(xiàn)了問題,或者發(fā)生了程序主動abort,這些都會產生相應的signal信號,導致程序異常退出。
????相比于Java崩潰,Native崩潰更難捕獲和定位。事實上針對我們目前的項目,幾乎大部分的崩潰都是Native 崩潰。分析項目的崩潰日志我們可以發(fā)現(xiàn),有些崩潰是可以從backtrace中獲得一些有用的信息。但是有些崩潰甚至連backtrace都不會出現(xiàn),開發(fā)人員只能單步調試,無法快速定位。所以有沒有一個系統(tǒng)的框架來收集和處理這些Native崩潰呢?當然有,Google開源的BreakPad就是其中之一。

1 BreakPad

1.1常見信號類型

????在介紹BreakPad之前,我們首先要對信號機制有一個大概的了解。這里只是希望能對常見的信號類型有一個認識,因為一旦發(fā)生崩潰,信號類型能讓我們對崩潰有一個初步的判斷。

信號量 value 描述 例子
SIGABRT 6 程序發(fā)生錯誤或者調用了abort 很多C的庫函數(shù),如果發(fā)現(xiàn)異常會調用abort,如strlen
SIGBUS 10,7,10 不存在的物理地址硬件錯誤 更多的是因為硬件或者系統(tǒng)引起的
SIGFPE 8 浮點數(shù)運算錯誤 如除0,余0,整型溢出
SIGILL 4 非法指令 損壞的可執(zhí)行文件或者代碼區(qū)損壞
SIGSEGV 11 段地址錯誤 空指針,訪問不存在的地址空間,訪問內核區(qū),寫只讀空間,棧溢出,數(shù)組越界,野指針
SIGSTKFLT 16 //未使用
SIGPIPE 13 管道錯誤,往沒有reader的管道中寫 Linux中的socket,如果斷掉了繼續(xù)寫,signal(SIGPIPE,SIG_IGN)
1.2BreakPad簡介

????Google BreakPad是一個跨平臺的崩潰轉儲和分析框架,它是一個工具集合。


1.png

BreakPad由三個主要組件組成:

  • client,以library的形式內置在你的應用中,當崩潰發(fā)生時寫 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的源碼下載其實是一件挺讓人頭大的事情,你想直接去下載國外的一些優(yōu)秀開源項目的源碼基本上都需要翻墻,而且翻墻了你也不一定能下載得到。參考了網上獲取BreakPad源碼的幾種方法,雖然我已經確定自己翻墻了,無一例外全部以失敗告終。后來摸索中發(fā)現(xiàn),其實要獲取源碼,可以直接通過谷歌瀏覽器下載。
進入這個網頁https://chromium.googlesource.com/breakpad/breakpad

2.png

然后選擇master分支
3.png

然后點擊tgz,源碼算是下載下來了。不過還沒完,源碼下載到本地解壓以后,你會發(fā)現(xiàn)是這么一個文件目錄
4.png

其實我們關心的主要是src這個文件夾,因為BreakPad的源碼是在這個目錄下面。這里提醒一下踩過的坑。在src/third_party這個路徑下面,其實是少了一個文件夾的。文件夾名是lss,文件夾內部包含了一個文件linux_syscall_support.h,少了他BreakPad就編譯不通過了,好在這個文件比較好下載,具體流程就不細說了。

2.2 BreakPad動態(tài)庫編譯

????源碼下載完以后,我們就可以開始把BreakPad集成到App中了。這個過程主要分三步。編寫JNI層mapping文件;編譯Android各個平臺的.so文件;將.so文件導入到實際的開發(fā)項目中。
????動態(tài)庫的編譯需要使用ndk,本文沒有采用傳統(tǒng)的Android.mk腳本進行編譯,而是使用了cmake,直接把BreakPad源碼編譯成了.so文件。實際上,在下載完BreakPad源碼以后,進入src目錄,執(zhí)行./configure 和 make 命令,就能得到libbreakpad.a靜態(tài)庫,通過libbreakpad.a也能編譯得到對應的動態(tài)庫。對應的JNI層目錄如下:


5.png

include文件夾下面的文件是BreakPad源碼中src目錄下的文件,包含Breakpad的實現(xiàn)源碼以及所有的頭文件。breakpad.cpp對應JNI mapping文件,用來注冊信號處理接口,監(jiān)聽崩潰時系統(tǒng)拋出的信號。對應的代碼如下:


6.png

對應的native接口為
public static native void BreakPadInit(String path)
其中參數(shù)path是發(fā)生崩潰時,dump文件的生成路徑。通過編寫CMakeLists.txt來生成對應的libbreakpad.so。關于Cmake的語法規(guī)則可以查閱相關資料。CMakeLists.txt文件對應如下:
7.png

至此已經可以得到我們想要的libbreakpad.so,把生成的動態(tài)庫文件導入到項目中,就算完成任務了。

3 Native Crash分析

????通過得到的libbreakpad.so我們已經可以進行native crash的監(jiān)測了。我們試著利用Breakpad進行native crash的定位和分析。

3.1 捕獲native崩潰

????首先我們在JNI層的Native代碼中人為的制造一個崩潰。這里制造了一個空指針的崩潰


8.png

我們把libbreakpad.so集成到案例項目中,運行程序,調用BreakPadTest接口,果然程序崩潰了。而且崩的很徹底,Logcat上并沒有發(fā)現(xiàn)有用的日志信息,提示信息如下:


9.png

Error只是上報了一個SIGSEGV的信號,我們通過這個信號,只能知道是native層發(fā)生了段地址錯誤,有可能是數(shù)組越界或者空指針之類的常見問題,除此之外具體是哪里出現(xiàn)了錯誤,我們無從得知。
3.2 Dmp文件分析

????分析Dmp文件是我們通過Breakpad定位崩潰問題的重要手段。我們在進行Breakpad回調函數(shù)注冊的時候會設置一個路徑,這個路徑就是發(fā)生崩潰時,dmp文件的生成路徑。4.1節(jié)中,dmp文件的生成路徑為/storage/emulated/0/,對應的dmp文件名為72a7ac3f-8cbe-482a-28339c98-ef9d8eb2.dmp。
????進入Breakpad源碼目錄,在/breakpad-master/目錄下執(zhí)行configure命令,執(zhí)行完該命令以后,會在/breakpad-master/src/processor目錄下生成minidump_stackwalk工具,用于導出崩潰日志。同時在/breakpad-master/src/tools/linux/dump_syms目錄下生成dump_syms工具,用于導出符號文件。把dmp文件和minidump_stackwalk,dump_syms以及debug版本的對應so文件拷貝到同一個目錄下。首先執(zhí)行生成符號文件命令:


10.png

這部分的實現(xiàn)需要在linux環(huán)境下執(zhí)行。得到libbreakpad.so.sym文件以后,查看文件,我們能夠得到文件頭部的一個字符串:


11.png

繼續(xù)執(zhí)行命令
12.png

導出崩潰堆棧信息文件(確保dmp文件和symbols目錄是同級的):
13.png

這里面的native_dmp.dmp文件對應的就是上面的72a7ac3f-8cbe-482a-28339c98-ef9d8eb2.dmp,文件名太長,我在導出的時候進行了重命名。可以看到此時我們的test目錄下生成了我們所需要的crashed日志,如下圖:


14.png

我們打開日志可以發(fā)現(xiàn)崩潰位置:
15.png

定位到我們的breakpad.cpp的第46行,從左到右第二個字符。我們可以回顧一下之前制造崩潰的位置:
16.png

4 總結

????在Android平臺上使用Breakpad進行native崩潰定位的整個流程就結束了,顯然Breakpad優(yōu)點很明顯,首先它具有跨平臺的特性,其次它也是google頗為得意的一款開源工具集,權威性不言而喻。缺點也很明顯,從集成目標項目,到最后的崩潰日志分析,整個過程的步驟比較復雜,而且Breakpad的代碼體量也比較大。如果把Breakpad集成到我們自己的項目中又會出現(xiàn)一些新的問題,比如目前我們軟終端Android項目中的so庫大大小小將近二十個,發(fā)生崩潰時,如果我們無法定位究竟是哪一個so引發(fā)的問題,那就比較頭大了。最壞情況下,要對所有的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

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容