Android-JNI开发系列《四》Native-Crash定位_[erecovery]readevent: ereceventmanager readevent 0-程序员宅基地

技术标签: Android JNI  Android  

人间观察

你有多久没有十点之前睡过觉了。

假期ing~~~

在Android中进行JNI的开发的当然也会发生crash,而发生crash后比较难定位。
因为jni是使用C/C++来进行开发的,熟悉C/C++语言的同学都知道,指针和内存申请的使用时需要自己申请和释放的,它不像java那样有jvm有垃圾回收管理机制gc,稍微管理不当就会导致问题。比如:内存地址访问错误、堆栈溢出、指针使用错误等等,最后都会导致程序崩溃。

幸好Android NDK提供了一些工具来帮助精确定位到出问题的代码。
我们模拟一下crash,模拟一个指针未初始化访问的case。

#include "common.h"
#include <malloc.h>

extern "C"
JNIEXPORT void JNICALL
Java_com_bj_gxz_jniapp_crash_JNICrash_crash(JNIEnv *env, jobject thiz) {
//    int *p = static_cast<int *>(malloc(sizeof(int)));
    int *p;
    *p = 1;
    LOG_D("*P=%d", *p);
    free(p);
}

*p没有初始化
崩溃的日志如下:


2020-09-28 14:36:49.737 19047-19047/com.bj.gxz.jniapp A/libc: Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x6fcabb4d34 in tid 19047 (m.bj.gxz.jniapp), pid 19047 (m.bj.gxz.jniapp)
2020-09-28 14:36:49.856 19167-19167/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
2020-09-28 14:36:49.856 19167-19167/? A/DEBUG: Build fingerprint: 'HONOR/STF-AL00/HWSTF:9/HUAWEISTF-AL00/9.1.0.219C00:user/release-keys'
2020-09-28 14:36:49.856 19167-19167/? A/DEBUG: Revision: '0'
2020-09-28 14:36:49.856 19167-19167/? A/DEBUG: ABI: 'arm64'
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG: Happend: 'Mon Sep 28 14:36:49 2020
    '
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG: SYSVMTYPE: Art
    APPVMTYPE: Art
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG: pid: 19047, tid: 19047, name: m.bj.gxz.jniapp  >>> com.bj.gxz.jniapp <<<
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG: signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x6fcabb4d34
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG:     x0  0000006fcb0c5460  x1  0000007fdd935134  x2  0000006fac4b2b84  x3  0000000070cfc600
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG:     x4  0000000000000000  x5  0000000000000000  x6  0000000000000000  x7  0000000000000000
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG:     x8  0000000000000001  x9  0000000000000003  x10 0000006fac4b2b80  x11 0000006fcabb4d34
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG:     x12 0000007051586630  x13 0f2fce861ea823e3  x14 000000705118b000  x15 ffffffffffffffff
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG:     x16 0000006fac4990bc  x17 00000070507c5d48  x18 0000000000000001  x19 0000006fcb015c00
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG:     x20 0000000000000000  x21 0000006fcb015c00  x22 0000007fdd935400  x23 0000006faeae68f1
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG:     x24 0000000000000004  x25 00000070518f65e0  x26 0000006fcb015ca0  x27 0000000000000001
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG:     x28 0000007fdd935130  x29 0000007fdd935100
2020-09-28 14:36:49.857 19167-19167/? A/DEBUG:     sp  0000007fdd9350e0  lr  0000006fcaeb6fe4  pc  0000006fac4990ec
2020-09-28 14:36:49.891 744-2617/? E/LOGSERVER_UTILS: [Erecovery]readEvent: eRecEventManager readEvent 0
2020-09-28 14:36:49.998 19167-19167/? A/DEBUG: backtrace:
2020-09-28 14:36:49.998 19167-19167/? A/DEBUG:     #00 pc 000000000000e0ec  /data/app/com.bj.gxz.jniapp-wTViTmvyh8_za4_TB4rqtQ==/lib/arm64/libnative-lib.so (Java_com_bj_gxz_jniapp_crash_JNICrash_crash+48)
2020-09-28 14:36:49.998 19167-19167/? A/DEBUG:     #01 pc 0000000000588fe0  /system/lib64/libart.so (art_quick_generic_jni_trampoline+144)
2020-09-28 14:36:49.998 19167-19167/? A/DEBUG:     #02 pc 000000000057ff88  /system/lib64/libart.so (art_quick_invoke_stub+584)
2020-09-28 14:36:49.998 19167-19167/? A/DEBUG:     #03 pc 00000000000d8608  /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
2020-09-28 14:36:49.998 19167-19167/? A/DEBUG:     #04 pc 000000000028cec8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
2020-09-28 14:36:49.998 19167-19167/? A/DEBUG:     #05 pc 0000000000286ed0  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+968)
2020-09-28 14:36:49.998 19167-19167/? A/DEBUG:     #06 pc 000000000054747c  /system/lib64/libart.so (MterpInvokeVirtual+588)
2020-09-28 14:36:49.998 19167-19167/? A/DEBUG:     #07 pc 0000000000572514  /system/lib64/libart.so (ExecuteMterpImpl+14228)
2020-09-28 14:36:49.998 19167-19167/? A/DEBUG:     #08 pc 00000000001678da  /dev/ashmem/dalvik-classes.dex extracted in memory from /data/app/com.bj.gxz.jniapp-wTViTmvyh8_za4_TB4rqtQ==/base.apk (deleted) (com.bj.gxz.jniapp.MainActivity.onJniCrash+10)
2020-09-28 14:36:49.998 19167-19167/? A/DEBUG:     #09 pc 0000000000260bd4  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.2850692617+488)
2

//  ...省略其它日志不重要的日志

crash日志里 最有用的backtrace信息。 backtrace描述了crash发生时函数的调用关系及其它地址信息等。
在backtrace中,从#00到#04 共五行信息代表是crash时函数调用关系,从下往上倒着看,#04行的方法调用了#03行的方法;#03行的方法调用了#02行的方法;向上类推,最后就是#01行的方法调用了#00行的方法。而最终出现的crash就是在#00行中。

如何定位解决呢?

使用ndk提供的命令addr2line

addr2line命令在ndk版本的toolchains目录下,我的是在

/Users/guxiuzhong/Library/Android/sdk/ndk/21.0.6113669/toolchains
B000000073160:toolchains guxiuzhong$ ls
aarch64-linux-android-4.9	renderscript
arm-linux-androideabi-4.9	x86-4.9
llvm				x86_64-4.9

从上面可以看得出来NDK针对不同的CPU架构实现了多套相同的工具,所以你要根据目标机器的CPU架构来选择。如果不知道目标机器的CPU架构,把手机连上电脑,用adb shell cat /proc/cpuinfo可以查看手机的CPU信息。我的目标机器是Processor : AArch64 Processor rev 1 (aarch64)

addr2line的使用方式是

addr2line -e 000000000000e0ec

-e 指定带符号表的so文件路径,也需要对应目标机器的CPU架构的so文件的绝对路径

000000000000e0ec 崩溃的汇编指令地址

addr2line一下

/Users/guxiuzhong/Library/Android/sdk/ndk/21.0.6113669/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line  -e /Users/guxiuzhong/Desktop/JNIAPP/app/build/intermediates/cmake/debug/obj/arm64-v8a/libnative-lib.so  000000000000e0ec

结果如下

/Users/guxiuzhong/Desktop/JNIAPP/app/src/main/cpp/crash.cpp:9

回看下我们.cpp的源码,第9行由于int* p指针没有初始化导致了fault addr。

使用ndk提供的命令ndk-stack

这个命令可以简化上面的步骤。

使用adb获取logcat的日志,并通过管道输出给ndk-stack进行分析。

ndk-stack -sym使用方式是

ndk-stack -sym XXXX

-sym 指定带符号表的so文件路径,也需要对应目标机器的CPU架构的so文件的根目录即可

ndk-stack一下

adb logcat | /Users/guxiuzhong/Library/Android/sdk/ndk/21.0.6113669/ndk-stack -sym /Users/guxiuzhong/Desktop/JNIAPP/app/build/intermediates/cmake/debug/obj/arm64-v8a

这时候模拟一下crash,检测到crash,ndk-stack自动解析了,结果和上面的一样第9行:

********** Crash dump: **********
Build fingerprint: 'HONOR/STF-AL00/HWSTF:9/HUAWEISTF-AL00/9.1.0.219C00:user/release-keys'
#00 0x000000000000e0ec /data/app/com.bj.gxz.jniapp-wTViTmvyh8_za4_TB4rqtQ==/lib/arm64/libnative-lib.so (Java_com_bj_gxz_jniapp_crash_JNICrash_crash+48)
                                                                                                        Java_com_bj_gxz_jniapp_crash_JNICrash_crash
                                                                                                        /Users/guxiuzhong/Desktop/JNIAPP/app/src/main/cpp/crash.cpp:9:8
#01 0x0000000000588fe0 /system/lib64/libart.so (art_quick_generic_jni_trampoline+144)
#02 0x000000000057ff88 /system/lib64/libart.so (art_quick_invoke_stub+584)

这个命令也支持文件的解析(使用-dump参数),这个好,因为有些crash不是必须的。

ndk-stack -dump 使用方式是

ndk-stack -sym XXXX -dump XXXX

-sym 指定带符号表的so文件路径,也需要对应目标机器的CPU架构的so文件的根目录即可
-dump crash的堆栈信息的文件

B000000073160:bin guxiuzhong$ /Users/guxiuzhong/Library/Android/sdk/ndk/21.0.6113669/ndk-stack -sym /Users/guxiuzhong/Desktop/JNIAPP/app/build/intermediates/cmake/debug/obj/arm64-v8a -dump  ~/Desktop/crash.log 
********** Crash dump: **********
Build fingerprint: 'HONOR/STF-AL00/HWSTF:9/HUAWEISTF-AL00/9.1.0.219C00:user/release-keys'
#00 0x000000000000e0ec /data/app/com.bj.gxz.jniapp-wTViTmvyh8_za4_TB4rqtQ==/lib/arm64/libnative-lib.so (Java_com_bj_gxz_jniapp_crash_JNICrash_crash+48)
                                                                                                        Java_com_bj_gxz_jniapp_crash_JNICrash_crash
                                                                                                        /Users/guxiuzhong/Desktop/JNIAPP/app/src/main/cpp/crash.cpp:9:8
#01 0x0000000000588fe0 /system/lib64/libart.so (art_quick_generic_jni_trampoline+144)
#02 0x000000000057ff88 /system/lib64/libart.so (art_quick_invoke_stub+584)
#03 0x00000000000d8608 /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
#04 0x000000000028cec8 /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
#05 0x0000000000286ed0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+968)
#06 0x000000000054747c /system/lib64/libart.so (MterpInvokeVirtual+588)
#07 0x0000000000572514 /system/lib64/libart.so (ExecuteMterpImpl+14228)

总结:两种方法来定位crash。 addr2line -e xxxx 指定汇编指令地址。 adb logcat | ndk-stack -sym 指定对应目标机器的CPU架构的so文件的绝对路径; ndk-stack -dump 对应目标机器的CPU架构的so文件的根目录 -dump crash的堆栈信息的文件。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ta893115871/article/details/108991277

智能推荐

中国区域Modis行列号(附Shapefile文件下载)-程序员宅基地

文章浏览阅读2.1w次,点赞26次,收藏84次。中国区域Modis行列号,Landsat条带号对照图_modis行列号

windows命令 - 类似linux的less作用_windows less-程序员宅基地

文章浏览阅读1.4k次。more命令例如 ipconfig | more_windows less

深度剖析:利用Charles抓包工具进行iOS逆向分析_charles 监听ios-程序员宅基地

文章浏览阅读1k次。Charles是一款强大的代理工具,可用于拦截、监视和修改网络通信。您可以从Charles的官方网站下载并安装适用于您的操作系统版本。Charles提供了Mac、Windows和Linux平台三个客户端的版本,以及Firefox插件。今天我们主要讨论的是Mac版。_charles 监听ios

iOS 判断手机型号及系统版本(包括iPhone 11系列)_ios 系统型号对应 iphone 11,-程序员宅基地

文章浏览阅读4.9k次。iPhoneX推出已经有很长时间了,从最初的简单适配到前一段时间拿到真机开始做更优化的适配,我在部分地方用到了判断手机型号及系统版本的方法,下面分享一下。首先需要导入头文件#import <sys/utsname.h>之后进行判断struct utsname systemInfo;uname(&systemInfo);NSString*phoneType..._ios 系统型号对应 iphone 11,

Android烧录镜像文件介绍_devcfg.mbn-程序员宅基地

文章浏览阅读6.9k次,点赞2次,收藏44次。sbl1.mbn烧录命令:fastboot flash sbl1 sbl1.bin作用:second bootloader1的缩写,是在little kernel(lk)前启动,起到引导lk的作用,如果将该分区擦除,则设备表现为进入紧急下载模式,即,擦除该分区后,插入USB显示QDload端口。rpm.mbn烧录命令:fastboot flash rpm rpm.mbn作用:电源管理器,..._devcfg.mbn

大数据GIS及应用浅析_大数据gis特征-程序员宅基地

文章浏览阅读8k次,点赞18次,收藏69次。大数据GIS是在大数据浪潮下,GIS从传统迈向大数据时代的一次变革。大数据GIS能为空间大数据的存储、分析和可视化提供更先进的理论方法和软件平台,促进了传统GIS的产业升级,为地理信息产业发展提供新的渠道和原动力,服务于我国“十三五”期间的大数据产业发展和部署。本文将浅析大数据GIS的产生及其在相关行业中的应用方式。大数据GIS的产生• 大数据近几年,大数据(Big Data)一词越来越多地..._大数据gis特征

随便推点

DEV-C++调试时出现“项目没有调试信息,你想打开调试选项并重新生成吗”_项目没有调试信息,您想打开项目调试选项-程序员宅基地

文章浏览阅读5.8w次,点赞99次,收藏37次。在下载完DEV-C++以后进行第一次调试时,系统弹出以上窗口,点击Yes按钮后编译器出现秒退的情况。具体解决方案为:菜单栏&gt;&gt;工具&gt;&gt;编译器选项&gt;&gt;代码生成/优化&gt;&gt;连接器&gt;&gt;产生调试信息&gt;&gt;更改为Yes;附一张图:..._项目没有调试信息,您想打开项目调试选项

cuda+cudnn+anaconda+pycharm(安装pytorch)_anaconda cuda pycharm-程序员宅基地

文章浏览阅读2.5k次,点赞4次,收藏22次。1.安装cuda安装cuda之前应该查看自己电脑适合什么版本可以先将驱动升级(这一步很重要,比如驱动精灵之类的驱动更新软件)电脑右键→NVIDIA控制面板→系统信息→组件:可以看到下面的NVCUDA这里面显示是你可以装的最高版本在这里我们已经知道我们的驱动适应的最高版本的cuda,因此下一步就是去官网下载对应版本的cuda:https://developer.nvidia.com/cuda-toolkit-archive我们的最高版本是10.2,但在这里我选择安装cuda10.1,下载完成之后直_anaconda cuda pycharm

elasticsearch7外网访问与503错误解决方案_elasticsearch 503-程序员宅基地

文章浏览阅读1.2w次,点赞3次,收藏10次。笔者安装的是elasticsearch7版本的,安装环境为centos7,配置的java为jdk11。一、elasticsearch外网访问这个问题困扰笔者许久,查阅相关资料才发现那人正在灯火阑珊处解决方案如下:相关配置文件的修改 修改安装的elasticsearch文件下的config/elasticsearch.yml文件。添加:network.http: 0.0.0.0 ..._elasticsearch 503

URLEncode,URLEncode python实现,处理cookie加密,js逆向_python urlencode函数 base64字符串-程序员宅基地

文章浏览阅读966次。URL编码(URL encoding),也称作百分号编码(Percent-encoding), 是特定上下文的统一资源定位符 (URL)的编码机制。将需要转码的字符转为16进制,然后从右到左取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式。_python urlencode函数 base64字符串

SATA与PATA接口硬盘的区别_pata和sata接口区别-程序员宅基地

文章浏览阅读2k次。 一、PATA与SATA技术方面的区分 PATA的全称是Parallel ATA,就是并行ATA硬盘接口规范,也就是我们现在最常见的硬盘接口规范了。PATA硬盘接口规模已经具有相当的辉煌的历史了,而且从ATA33/66一直发展到ATA100/133,一直到目前最高的ATA150。SATA硬盘全称则是Serial ATA,即串行ATA硬盘接口规范。目前PATA100硬盘的一般写入速度为65MB/s,而第一代SATA硬盘的写入速度为150MB/s,第二代SATA硬盘的写入速度_pata和sata接口区别

实现mysql的sequence_mywseq-程序员宅基地

文章浏览阅读3.5k次。背景因为做oracle迁移mysql的工作,mysql并不具有sequence语法,所以需要自己想办法模拟实现一个sequence。步骤建一张表e_sys_sequence用来记录序列名称和值CREATE TABLE `e_sys_sequence` ( `sequence_name` varchar(64) NOT NULL COMMENT '序列名称' , `va..._mywseq