android 抓取native层奔溃

白日放歌须纵酒,青春作伴好还乡。这篇文章主要讲述android 抓取native层奔溃相关的知识,希望能为你提供帮助。
使用android的breakpad工具
使用这个工具需要下载Breakpad的源码,然后进行编译,编译之后会生成两个工具

android 抓取native层奔溃

文章图片

android 抓取native层奔溃

文章图片

我们使用这两个工具来解析奔溃的位置。这里我们可以下载已经编译好的工具
下载地址是:链接:http://pan.baidu.com/s/1jIiU5cq 密码:wy6f
你把对应的工具下载完成后需要上传到对应的linux环境下才能使用
二、生成转换工具
1、下载BreakPad源代码
命令行输入:svn checkout http://google-breakpad.googlecode.com/svn/trunk/ google-breakpad-read-only
2、编译工具
①进入代码路径
cd google-breakpad-read-only/

②配置环境
./configure

③编译工具
make

3、看看以下工具是否存在:
google-breakpad-read-only/src/tools/linux/dump_syms/dump_syms
google-breakpad-read-only/src/processor/minidump_stackwalk
  这两个工具可以直接到csdn中去下载编译成功的
这个过程你需要编译出几个工具:minidump_stackwalk  dump_syms等等
就是上面这两个工具
但是这里要注意不同的版本不一样,这里可以直接到csdn上去下载
集成到App中使用开源的:https://github.com/yinyinnie/breakpad-for-android,它已经将对应的抓取奔溃的so库已经生成好了你只需要将对应的breakpad moudle引入到你的工程中就可以了
android 抓取native层奔溃

文章图片

我们的工程依赖breakpad 这个模块
android 抓取native层奔溃

文章图片

 
 
  接下来我们来看看工程的代码:
调用的时候你只需要调用:  NativeBreakpad.init("/sdcard/Android/data/com.cetcs.ecmapplication/");
就可以,其中init中的参数就是奔溃日志存储的路径
当产生奔溃的时候会在该路径下面产生一个dmp的文件。有了dmp文件我们需要将dmp文件使用上面产生的两个工具来进行解析
得到奔溃的日志信息
我们新建了一个Dump文件夹
将上面的两个工具上传上去,必须保证上面的两个工具具有可以执行的权限
把奔溃的日志上传上去,保证奔溃的dmp文件具有可执行权限
把运行的si库文件上传上去,这里上传的so库必须需要具有调试信息:
对应android studio而言,这里需要上传的so库不是src/libs目录下的so库,而是必须具有调试信息的so库
具有调试信息的so 库在/local/目录下
android 抓取native层奔溃

文章图片

使用ndk-build编译出来的so 库需要具有调试信息,so库存在的目录如下所示:
android 抓取native层奔溃

文章图片

libs是正式提供给第三方使用的,obj目录下的so库才是具有调试信息的,所以具有调试信息的so库在发布版本的时候,我们需要进行备份
具体的操作步骤看博客:http://blog.csdn.net/brook0344/article/details/20126351
android 抓取native层奔溃

文章图片

   
这里我实验了好多天:解析出来的dmp文件好像都没有和符号文件关联起来,不能得到下面的信息:
12-14 14:24:18.36932813281 F DEBUG: backtrace:12-14 14:24:18.36932813281 F DEBUG:#00 pc 00000c98/data/app/logback.ecmapplication.cetcs.com.testbreakpad-2/lib/arm/libweiyuan.so (sb_crash+3)12-14 14:24:18.36932813281 F DEBUG:#01 pc 00000ca1/data/app/logback.ecmapplication.cetcs.com.testbreakpad-2/lib/arm/libweiyuan.so (java_logback_ecmapplication_cetcs_com_testbreakpad_MainActivity_getStringFromC+4)12-14 14:24:18.36932813281 F DEBUG:#02 pc 000ec389/system/lib/libart.so (art_quick_generic_jni_trampoline+40)

 
得到的文件内容如下:
Operating system: Android 0.0.0 Linux 3.10.86-g8b38b32 #1 SMP PREEMPT Thu Apr 14 14:24:52 CST 2016 armv7l CPU: arm ARMv1 ARM part(0x4100d080) features: half,thumb,fastmult,vfpv2,edsp,neon,vfpv3,vfpv4,idiva,idivt 8 CPUsGPU: UNKNOWNCrash reason:SIGSEGV Crash address: 0x0 Process uptime: not availableThread 0 (crashed) 0libweiyuan.so + 0xc98 r0 = 0xf43d6cc0r1 = 0xffcf371cr2 = 0x00000001r3 = 0x00000000 r4 = 0xf43d6cc0r5 = 0xffcf3cb0r6 = 0x0000004cr7 = 0xffcf37d0 r8 = 0xef5251c8r9 = 0xf43f6500r10 = 0xffcf3720r12 = 0xef50bc9d fp = 0xf43f6500sp = 0xffcf36f8lr = 0xef50bca5pc = 0xef50bc98 Found by: given as instruction pointer in context 1dalvik-LinearAlloc (deleted) + 0x151c6 sp = 0xffcf36fcpc = 0xef5251c8 Found by: stack scanning 2libart.so + 0xec389 sp = 0xffcf3700pc = 0xf3fb638b Found by: stack scanning 3dalvik-main space 1 (deleted) + 0x1e40e sp = 0xffcf3704pc = 0x32c1e410 Found by: stack scanning 4dalvik-main space 1 (deleted) + 0x1e3fe sp = 0xffcf3708pc = 0x32c1e400 Found by: stack scannin


只能得到一个c98,这个时候有啥办法可以直接定位出来没
这个时候可以使用arm-linux-androideabi-addr2line.exe这个工具来进行定位,具体不清楚的看博客http://blog.csdn.net/xyang81/article/details/42319789
我们首先进入到工程中具有调试信息so 库所在的目录:目录的路径如下所示:
C:\\TestGoogleBreakPad\\app\\build\\intermediates\\ndk\\debug\\obj\\local\\armeabi-v7a
我们使用下面的命令:
D:\\android_sdk_ndk\\android-ndk-r10e\\toolchains\\arm-linux-androideabi-4.8\\prebuilt\\windows-x86_64\\bin\\arm-linux-androideabi-addr2line.exe   -C -f -e ./libweiyuan.so 00000c98
其中:D:\\android_sdk_ndk\\android-ndk-r10e\\toolchains\\arm-linux-androideabi-4.8\\prebuilt\\windows-x86_64\\bin\\arm-linux-androideabi-addr2line.exe 是对应的arm-linux-androideabi-addr2line工具的路径
00000c98就是对应的so 库奔溃对应的堆栈位置
我们来看一下
android 抓取native层奔溃

文章图片

 
  我们可以看出对应的奔溃信息是在:Java_logback_ecmapplication_cetcs_com_testbreakpad_MainActivity_getStringFromC这个c文件的第12行发生了奔溃
android 抓取native层奔溃

文章图片

第12行就是*a =1,*a是一个无效的野指针,给野指针赋值就会导致内存奔溃
我们来看看这个c文件的代码:
// // Created by wei.yuan on 2017/11/13. // #include< jni.h> #include< logback_ecmapplication_cetcs_com_testbreakpad_MainActivity.h> #include < jni.h> #include < string.h> #include < pthread.h> void sb_crash(){ int *a = (int *) (NULL); *a = 1; } JNIEXPORT jstring JNICALL Java_logback_ecmapplication_cetcs_com_testbreakpad_MainActivity_getStringFromC (JNIEnv * env, jobject obj){ sb_crash(); return (*env)-> NewStringUTF(env,"I\'m comes from 444444to Native Function!"); }

 
 
  我们来看看整个工程的目录架构如下所示:
android 抓取native层奔溃

文章图片

 
特别需要注意的地方:
1、不同的breakpad版本的源码编译出来的上面的两个工具可能不一样,这样对dmp文件进行解析,解析出来的结果可能存在问题;
2、使用功能进行解析的时候,需要使用具有调试信息的so库文件,所以每次发版本的时候,需要将具有调试信息的so库文件进行备份;
3、如果解析dmp文件得不到具有的那个函数奔溃,没有和符号文件关联起来,可以使用\\arm-linux-androideabi-addr2line.exe对具体调试信息的so库文件进行定位,这样也可以得到具体的行数
4、对应android 6.0以上的操作系统,存储奔溃文件需要动态申请,一定要保存app的存储权限已经开启,否则在对应的目录下没有对应的奔溃文件
  整个android studio工程的代码如下:
http://pan.baidu.com/s/1ge9iKQf
相当的经典
  集成:
在ecms集成breakPad模块的时候报错:
android 抓取native层奔溃

文章图片

 
 

上面ecmcommon这个模块依赖breakpad模块
需要注意几点:
第一:breakpad模块中在gradle配置文件中

defaultConfig {
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

}
必须和ecmcommon模块中对应

minSdkVersion 16
targetSdkVersion 23
一一对应

第二:要在ecmmmon对应的minifimest清单文件中添加

tools:replace="android:allowBackup"
这句话

< manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.cetcs.ecmcommon">

< application android:allowBackup="false"
android:label="@string/app_name"
android:supportsRtl="true"
tools:replace="android:allowBackup"
>

< /application>
< uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
< uses-permission android:name="android.permission.INTERNET" />
< uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
< uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
< uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
< uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
< uses-permission android:name="android.permission.GET_TASKS"/>
< uses-permission android:name="android.permission.READ_LOGS"/>
< uses-permission android:name="android.permission.READ_PHONE_STATE"/>
< uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
< /manifest>


不清楚的参看博客:https://www.jianshu.com/p/a3c3532f4d30

集成方式二:

集成到App
  1. 拷贝.so文件到你项目的app/libs/
  2. 拷贝sample/breakpad/src/main/java/cn/onlinecache/breakpad/NativeBreakpad.java到你的工程目录下,注意:包名不能改哦!!
  3. 在你的Application类初始化:NativeBreakpad.init(Environment.getExternalStorageDirectory().getAbsolutePath());   注意:这个方法所传的参数你可以直接定义
你也可以无需编译,直接使用sample的breakpad module
如果集成好了有打印:

01-18 13:00:39.085 24480-24480/com.cetcs.ecmapplication D/cn.onlinecache.breakpad: nativeInit ===> breakpad initialized succeeded, dump file will be saved at /sdcard/Android/data/com.cetcs.ecmapplication/
01-18 13:00:39.628 24510-24510/? D/cn.onlinecache.breakpad: nativeInit ===> breakpad initialized succeeded, dump file will be saved at /sdcard/Android/data/com.cetcs.ecmapplication/
如何抓取到奔溃日志有打印:

-18 13:03:35.127 25292-25292/com.cetcs.ecmapplication E/cn.onlinecache.breakpad: native crash capture begin
01-18 13:03:35.246 25292-25292/com.cetcs.ecmapplication E/cn.onlinecache.breakpad: DumpCallback ===> succeeded 1
如果日志上出现
  DumpCallback ===> succeeded 0
【android 抓取native层奔溃】0表示native奔溃日志没有抓取成功




    推荐阅读