Android&iOS崩潰堆棧上報
原文地址:http://www.cnblogs.com/songcf/p/4885468.html
通過崩潰捕獲和收集,可以收集到已發布應用(游戲)的異常,以便開發人員發現和修改bug,對於提高軟件質量有着極大的幫助。在這里總結一下這幾天做崩潰捕獲的收獲。
我們項目使用的是cocos2dx-js,那么要捕獲的信息就有以下三點:
- js腳本語法錯誤、js調用為定義的native對象(程序不會崩潰)
- iOS(obj-c)/Android(java)端的未捕獲異常導致的crash
- c++操作時導致的crash
1. js端錯誤
js端的錯誤,都會調用2dx的ScriptingCore::reportError方法打印日志,在該方法內獲取錯誤並上報即可。
2. iOS(obj-c)/Android(java)的未捕獲異常
iOS/Android都可以在程序的入口處設置未捕獲異常的捕獲
- iOS :
NSSetUncaughtExceptionHandler(&HandleException); - Android :
Thread.setDefaultUncaughtExceptionHandler(handler);
在回調中獲取堆棧信息上報即可。
3. c++層操作時導致crash
c++操作錯誤導致crash時,無論是iOS還是android系統,其底層都是unix或者是類unix系統,可以通過信號機制來捕獲(signal或者是sigaction),即任何系統錯誤都會拋出一個錯誤信號,我們可以通過設定一個回調函數,然后在回調函數里面打印並發送錯誤日志,而我在接入時,主要的難點在Android平台。
下面列舉一些我嘗試過的,獲取c/c++函數調用堆棧的方法
1)使用CallStack工具類
頭文件位於frameworks/native/include/utils/CallStack.h,在Android的C++中,已經集成了工具類CallStack,在libutils.so中。此方法不適用NDK,對於2dx來說,如果想要使用該工具類需要下載android源碼,然后在ndk的工程中添加依賴;或者使用dlopen/dlsym動態獲得函數句柄實現調用(該方法不知可行否,還沒來得及測試)
2)使用execinfo.h
glibc頭文件"execinfo.h"中的backtrace、backtrace_symbols接口是linux下常用的獲取堆棧的方式,但是該方法不適用於android,因為android適用的是bionic,而非glibc。
3)使用unwind_backtrace
使用unwind在百度上能查出很多總不同的實現,這里貼出一篇我用過並成功編譯運行的實現方式的帖子:http://stackoverflow.com/questions/8115192/android-ndk-getting-the-backtrace
但是該方式如果是在收到signal的回調函數中使用,是不能還原崩潰堆棧的,只能得到signal發出后到調用unwind之間的函數堆棧,而我們需要的是signal發出前的崩潰堆棧
4)通過函數調用原理,自己實現獲取函數棧的方法
這里有篇不錯的博客:http://hutaow.com/blog/2013/10/15/dump-stack/ 不過我在測試時,匯編代碼ndk編譯不過,一直沒解決,所以並沒有采用該方法。
后來又找到了一篇不錯的文章,可以結合着看:http://blog.chinaunix.net/uid-24774106-id-3457205.html
5)android平台通過logcat獲取崩潰堆棧
在收到信號時通過jni回調java端,通過新開一個進程獲取logcat來得到崩潰堆棧,但此時並未得到c++的崩潰堆棧,該方法源自:
http://stackoverflow.com/questions/8115192/android-ndk-getting-the-backtrace#
http://www.cnblogs.com/lancidie/archive/2013/04/13/3019349.html
6)使用第三發sdk
使用第三方sdk很方便,而且在后台瀏覽crash信息也很清晰,這里推薦一下我用的tencent-bugly,如果你在使用之前不清楚獲取崩潰堆棧的原理,看看前面幾點提到的文章和方法會收益頗多
關於符號表的原理推薦看這本書:
《Linkers and Loaders》——John Levine
