【2013-12-10】Android应用开发笔记:JNI的崩溃捕获及google-breakpad的使用 [历史归档]本文原发布于 cstriker1407.info 个人博客内容为历史存档仅供参考。发布时间2013-12-10 标题Android应用开发笔记JNI的崩溃捕获及google-breakpad的使用分类编程 / android 标签android·java·jni·google-breakpadAndroid应用开发笔记JNI的崩溃捕获及google-breakpad的使用备注google-breakpad的下载google-breakpad的使用crash文件的处理进行 Android NDK 开发时C 代码不好调试一旦 crash 很难直接定位。这里分享开源工具google-breakpad的使用可以生成 minidump 文件并还原崩溃堆栈。备注由于google-breakpad的分析对平台有兼容性要求作者在ubuntu13.10 x64上进行google-breakpad的学习。后续源代码工程放到github上面。google-breakpad的下载直接访问官方网站下载代码svn checkout http://google-breakpad.googlecode.com/svn/trunk/ google-breakpad-read-only如下图下载完成后进入下载的目录可以发现里面有几个介绍文件如下图非常重要我们就按照这个来一步一步的整合。这里我把【 README.ANDROID 】文件贴出来我们后续的学习都是根据这个文件的介绍一步步来的。README.ANDROIDGoogle BreakpadforAndroidThis document explains how to use the Google Breakpad client library on Android, and later generate valid stack traces from the minidumps it generates. This release supports ARM, x86 and MIPS based Android systems. I. Building the client library:The Android client is built as a static library that you canlinkinto your own Android native code. There are two ways to build it: I.1. Building with ndk-build: ----------------------------- If youre using the ndk-build build system, you can follow these simple steps: 1/ Include android/google_breakpad/Android.mk from your own projects Android.mk This can bedoneeither directly, or using ndk-builds import-module feature. 2/ Link the library to one of your modules by using: LOCAL_STATIC_LIBRARIES breakpad_client NOTE: The client library requires a C STL implementation, which you can select with APP_STL in your Application.mk It has been tested succesfully with both STLport and GNU libstdc II.1. Building with a standalone Android toolchain: --------------------------------------------------- All you need to do is configure your build with the right host value, and disable the processor and tools, as in: $GOOGLE_BREAKPAD_PATH/configure --hostarm-linux-androideabi \ --disable-processor \ --disable-tools make -j4 The library will be under src/client/linux/libbreakpad_client.a You can also use makecheck to run the test suite on a connected Android device. This requires the Android adb tool to be in your path. II. Using the client library in Android: The usage instructions are very similar to the Linux ones that are found at http://code.google.com/p/google-breakpad/wiki/LinuxStarterGuide 1/ You need to include client/linux/handler/exception_handler.h from a C source file. 2/ If youre not using ndk-build, you also need to: -addthe following to your compiler include search paths:$GOOGLE_BREAKPAD_PATH/src$GOOGLE_BREAKPAD_PATH/src/common/android/include -add-llogto your linker flags Note that ndk-build does thatforyour automatically.3/ Keepinmind that there is no /tmp directory on Android. If you use the library from a regular Android applications, specify a path under your app-specific storage directory. An alternative is to store them on the SDCard, but this requires a specific permission. For a concrete example, see the sampletestapplication under android/sample_app. See its READMEformoreinformation. III. Getting a stack trace on the host:This process is similar to other platforms, but heres a quick example: 1/ Retrieve the minidumps on your development machine. 2/ Dump the symbols for your native libraries with the dump_syms tool. This first requires building the host version of Google Breakpad, then calling: dump_syms $PROJECT_PATH/obj/local/$ABI/libfoo.so libfoo.so.sym 3/ Create the symbol directory hierarchy. The first line of the generated libfoo.so.sym will have a MODULE entry that carries a hexadecimal version number, e.g.: MODULE Linux arm D51B4A5504974FA6ECC1869CAEE3603B0 test_google_breakpad Note: The second field could be either Linux or Android. Extract the version number, and a symbol directory,forexample:$PROJECT_PATH/symbols/libfoo.so/$VERSION/ Copy/Move your libfoo.symfilethere.4/ Invoke minidump_stackwalk to create the stack trace: minidump_stackwalk$MINIDUMP_FILE$PROJECT_PATH/symbols Note that various helper scripts can be found on the web to automate these steps. IV. Verifying the Android build library:If you modify Google Breakpad and want to check that it still works correctly on Android, please run the android/run-checks.sh scriptwhichwilldoall necessary verificationsforyou. This includes: - Rebuilding the fullhostbinaries. - Rebuilding the full Android binaries with configure/make. - Rebuilding the client library unit tests, and running them on a device. - Rebuilding the client library with ndk-build. - Building, installing and running atestcrasher program on a device. - Extracting the corresponding minidump, dumping thetestprogram symbols and generating a stack trace. - Checking the generated stack traceforvalidsourcelocations. Formoredetails, please run: android/run-checks.sh –help-allgoogle-breakpad的使用为了简单起见我们先建立一个最简单的Android的JNI工程【 HelloBreakPad 】如下图所示核心代码如下MainActivity.javapublicclassMainActivityextendsActivity{static{try{System.loadLibrary(HelloBreakPad);}catch(Errore){e.printStackTrace();}}privateButtonbutton1;privatenativeintnative_call();OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);button1(Button)findViewById(R.id.button1);button1.setOnClickListener(newOnClickListener(){publicvoidonClick(Viewv){Toast.makeText(MainActivity.this,native_call(),Toast.LENGTH_SHORT).show();}});}}net_yeah_cstriker1407_hellobreakpad_MainActivity.h/* DO NOT EDIT THIS FILE - it is machine generated */#includejni.h/* Header for class net_yeah_cstriker1407_hellobreakpad_MainActivity */#ifndef_Included_net_yeah_cstriker1407_hellobreakpad_MainActivity#define_Included_net_yeah_cstriker1407_hellobreakpad_MainActivity#ifdef__cplusplusexternC{#endif/* * Class: net_yeah_cstriker1407_hellobreakpad_MainActivity * Method: native_call * Signature: ()I */JNIEXPORT jint JNICALLJava_net_yeah_cstriker1407_hellobreakpad_MainActivity_native_1call(JNIEnv*,jobject);#ifdef__cplusplus}#endif#endifHelloBreakPad.cpp#includejni.h#includestring.h#includenet_yeah_cstriker1407_hellobreakpad_MainActivity.hJNIEXPORT jint JNICALLJava_net_yeah_cstriker1407_hellobreakpad_MainActivity_native_1call(JNIEnv*env,jobject obj){return1;}Android.mkLOCAL_PATH : $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE : HelloBreakPad LOCAL_SRC_FILES : HelloBreakPad.cpp include $(BUILD_SHARED_LIBRARY)一切正常的话这个工程就可以运行起来。此时我们在这个工程上加入google-breakpad将 google-breakpad 源代码里面的src文件夹拷贝到 HelloBreakPad 的jni目录下将 google-breakpad-read-only/android/google_breakpad 下的【 android.mk 】文件拷贝到相同目录下需要注意的是里面有些代码是冗余的可以删除这里为了简单起见作者简单的全部拷贝过来。修改 HelloBreakPad 的 jni/andorid.mk 按照要求增加代码最后如下MY_ROOT_PATH:$(call my-dir)################# 编译breakpad #################### include $(MY_ROOT_PATH)/googlebreakpad/Android.mk LOCAL_PATH:$(MY_ROOT_PATH)include $(CLEAR_VARS)LOCAL_MODULE:HelloBreakPad LOCAL_SRC_FILES:HelloBreakPad.cpp ################# 链接breakpad #################### LOCAL_STATIC_LIBRARIESbreakpad_client include $(BUILD_SHARED_LIBRARY)3增加一个Application.mk 文件,内容如下APP_STL:stlport_static修改后的工程目录如下图所示请注意googlebreakpad文件夹和HelloBreakPad.cppApplication.mk同一级别目录src文件夹和Android.mk同一级别目录。编译工程如果正常的话会出现此时google-breakpad的代码就合入了我们的工程我们需要在自己的业务代码里使用它。修改HelloBreakPad.cpp,增加文件处理改后文件如下#includejni.h#includestring.h#includenet_yeah_cstriker1407_hellobreakpad_MainActivity.h/* added to support googlebreakpad */#includegooglebreakpad/src/client/linux/handler/exception_handler.h#includegooglebreakpad/src/client/linux/handler/minidump_descriptor.hJNIEXPORT jint JNICALLJava_net_yeah_cstriker1407_hellobreakpad_MainActivity_native_1call(JNIEnv*env,jobject obj){google_breakpad::MinidumpDescriptordescriptor(/mnt/sdcard/hellobreakpad);google_breakpad::ExceptionHandlereh(descriptor,NULL,NULL,NULL,true,-1);int*p0;*p1;//bug!!return1;}注意这里为了简单起见将crash文件直接写到sd卡里面。而且代码里面有明显的bug。修改AndroidManifest.xml增加 SD 卡写权限uses-permissionandroid:nameandroid.permission.MOUNT_UNMOUNT_FILESYSTEMS/uses-permissionandroid:nameandroid.permission.WRITE_EXTERNAL_STORAGE/在sd卡里面手动增加一个文件夹hellobreakpad编译运行程序点击按钮会发现程序crash然后sd卡里面出现了crash文件如下图将文件取出保存好如下图crash文件的处理crash文件的处理有点麻烦需要使用一些工具。因此这里我们还需要在ubuntu上编译google-breakpad。最简单的google-breakpad的编译命令是进入/google-breakpad-read-only目录编译先 ./configure 然后 make 即可。但是作者在编译时遇到了automake1.14找不到的问题作者的系统是 ubuntu14.10 x64在作者系统里面没有这个工具apt-get也获取不到最后下载了automake1.14源码进行编译安装下载地址【 https://launchpad.net/ubuntu/trusty/source/automake-1.14/1:1.14-2ubuntu1/files/automake-1.14_1.14.orig.tar.xz 】。编译安装方法也很简单./configure 然后 make 然后make install 即可。里面可能会需要root权限sudo即可。当我们对 google-breakpad-read-only make成功之后我们会在/google-breakpad-read-only/src/tools/linux/dump_syms下面找到可执行文件【 dump_syms 】根据README.ANDROID文件的指导我们把 HelloBreakPad工程/obj/local/armabi/下的libHelloBreakPad.so 取出来执行命令./dump_syms libHelloBreakPad.solibHelloBreakPad.so.sym注意so 文件务必取obj目录下的不是libs目录下的。使用head命令获取版本号headlibHelloBreakPad.so.sym输出示例MODULE Linux arm 37FD215018996EE5DCEA7C51DB89D1570 libHelloBreakPad.so根据 README.ANDROID 的指引我们将生成的 libHelloBreakPad.so.sym 文件放入文件夹【 /HelloBreakPad/symbols/libHelloBreakPad.so/37FD215018996EE5DCEA7C51DB89D1570/ 】里面。sym文件放好之后进入google-breakpad-read-only/src/processor/目录找到可执行文件minidump_stackwalk。为了简单我将这个可执行文件和sd卡下面的crash文件全部放入symbols文件夹下面如下图执行命令./minidump_stackwalk 089db057-1c2c-94d0-68f468a8-02dfa8d2.dmp ./result.txt我们打开result.txt文件就可以发现异常出现在HelloBreakad.cpp的第19行。如下图