Android NDK入门教程之快速定位Crash问题
文章目录
- 首先制造一个 so crash问题
- addr2line
- addr2line工具位置
- addr2line命令如下:
- 分析crash log
- so strip
- 欢迎联系、指正、批评
首先制造一个 so crash问题
public class MainActivity extends AppCompatActivity {// Used to load the 'ndkcrashdemo' library on application startup.static {System.loadLibrary("ndkcrashdemo");}private ActivityMainBinding binding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());// Example of a call to a native methodTextView tv = binding.sampleText;tv.setText(stringFromJNI());}/*** A native method that is implemented by the 'ndkcrashdemo' native library,* which is packaged with this application.*/public native String stringFromJNI();
}
故意空指针
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_cy_ndkcrashdemo_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {std::string hello=NULL;//故意空指针hello.c_str();return env->NewStringUTF(hello.c_str());
}
运行到真机,发生crash,部分LOG如图:
发现并不能看出代码哪里有毛病
工欲善其事必先利其器
addr2line
addr2line translates addresses into file names and line numbers.
Given an address in an executable or an offset in a section of a relocatable object,
it uses the debugging information to figure out which file name and line number are associated with it.
addr2line
工具是一个可以将指令的地址和可执行映像转换成文件名、函数名和源代码行数的工具。
一般适用于 debug
版本或带有 symbol
信息的库。
addr2line工具位置
addr2line工具在NDK 里的路径如下(注意:每个版本都不一样)
Windows:
32位:D:\AndroidSDK\ndk\21.4.7075529\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin\
arm-linux-androideabi-addr2line.exe
64位:D:\AndroidSDK\ndk\21.4.7075529\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\bin\
aarch64-linux-android-addr2line.exe
addr2line命令如下:
The options are:@<file> Read options from <file>-a --addresses Show addresses//显示地址-b --target=<bfdname> Set the binary file format-e --exe=<executable> Set the input file name (default is a.out)//设置so库的路径-i --inlines Unwind inlined functions-j --section=<name> Read section-relative offsets instead of addresses-p --pretty-print Make the output easier to read for humans//设置输出信息可读性更强-s --basenames Strip directory names-f --functions Show function names//显示函数名称-C --demangle[=style] Demangle function names-h --help Display this information-v --version Display the program's version
分析crash log
com.cy.ndkcrashdemo A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 22618 (cy.ndkcrashdemo), pid 22618 (cy.ndkcrashdemo)
DEBUG: Softversion: PD2073B_A_1.8.15
DEBUG: Time: 2022-04-20 15:34:49
DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
DEBUG: Build fingerprint: 'vivo/PD2073/PD2073:11/RP1A.200720.012/compiler1228233519:user/release-keys'
DEBUG: Revision: '0'
DEBUG: ABI: 'arm64'
DEBUG: Timestamp: 2022-04-20 15:34:49+0800
DEBUG: pid: 22618, tid: 22618, name: cy.ndkcrashdemo >>> com.cy.ndkcrashdemo <<<
DEBUG: uid: 10252
DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
DEBUG: Cause: null pointer dereference
DEBUG: x0 0000000000000000 x1 0000000000000000 x2 0000000000000018 x3 00000076eecbf000
DEBUG: x4 0000000000000000 x5 b4000076ee95ac00 x6 00000076497d53af x7 000000000000001b
DEBUG: x8 0**************1 x9 ad1a1eb4209bd757 x10 0000000000430000 x11 00000000069d2cd0
DEBUG: x12 0000000000371314 x13 00000000006476c0 x14 000000000051d6c0 x15 ffffffffffffffff
DEBUG: x16 000000765387ce98 x17 00000076ec1cf4b0 x18 00000076eeec6000 x19 b4000076ee95ac00
DEBUG: x20 0000000000000000 x21 b4000076ee95ac00 x22 00000076eecbf000 x23 b4000076ee95acb8
DEBUG: x24 0000007667d48478 x25 00000076eecbf000 x26 000000000000000b x27 0000000000000002
DEBUG: x28 0000007fdeb3db00 x29 0000007fdeb3da10
DEBUG: lr 000000765385757c sp 0000007fdeb3da00 pc 00000076ec1cf4c0 pst 0000000080001000
DEBUG: backtrace:
DEBUG: #00 pc 00000000000894c0 /apex/com.android.runtime/lib64/bionic/libc.so (strlen_default+16) (BuildId: d010ec9d0da07ff241689a4e9691c733)
DEBUG: #01 pc 000000000000f578 /data/app/~~ipBdrIwT8qi72hDEkPx-ZQ==/com.cy.ndkcrashdemo-bwJhACJJBkJfPLjIt-tS0Q==/lib/arm64/libndkcrashdemo.so (std::__ndk1::char_traits<char>::length(char const*)+20) (BuildId: 34e2ac7e22782a65c51f760e5d9b4376d0cbea1d)
DEBUG: #02 pc 000000000000f064 /data/app/~~ipBdrIwT8qi72hDEkPx-ZQ==/com.cy.ndkcrashdemo-bwJhACJJBkJfPLjIt-tS0Q==/lib/arm64/libndkcrashdemo.so (std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >::basic_string<std::nullptr_t>(char const*)+48) (BuildId: 34e2ac7e22782a65c51f760e5d9b4376d0cbea1d)
DEBUG: #03 pc 000000000000efa4 /data/app/~~ipBdrIwT8qi72hDEkPx-ZQ==/com.cy.ndkcrashdemo-bwJhACJJBkJfPLjIt-tS0Q==/lib/arm64/libndkcrashdemo.so (Java_com_cy_ndkcrashdemo_MainActivity_stringFromJNI+56) (BuildId: 34e2ac7e22782a65c51f760e5d9b4376d0cbea1d)
DEBUG: #04 pc 000000000013ced4 /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+148) (BuildId: 5aeb6fe6030b3ee85ca5c14f3f2f06e9)
DEBUG: #05 pc 0000000000133564 /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: 5aeb6fe6030b3ee85ca5c14f3f2f06e9)
DEBUG: #06 pc 0000000000197e94 /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+204) (BuildId: 5aeb6fe6030b3ee85ca5c14f3f2f06e9)
DEBUG: #07 pc 000000000030347c /apex/com.android.art/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+376) (BuildId: 5aeb6fe6030b3ee85ca5c14f3f2f06e9)
DEBUG: #84 pc 0000000000529d10 /apex/com.android.art/lib64/libart.so (art::JValue art::InvokeWithVarArgs<_jmethodID*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+92) (BuildId: 5aeb6fe6030b3ee85ca5c14f3f2f06e9)
DEBUG: #85 pc 000000000041bd84 /apex/com.android.art/lib64/libart.so (art::JNI<true>::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+656) (BuildId: 5aeb6fe6030b3ee85ca5c14f3f2f06e9)
DEBUG: #86 pc 0000000000099434 /system/lib64/libandroid_runtime.so (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+124) (BuildId: c8f8eb3a06894fb8e5258f8c2f08e801)
DEBUG: #87 pc 00000000000a0ca0 /system/lib64/libandroid_runtime.so (android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool)+836) (BuildId: c8f8eb3a06894fb8e5258f8c2f08e801)
DEBUG: #88 pc 0000000000003564 /system/bin/app_process64 (main+1308) (BuildId: a4535eefb34c582385a2cf7c5548aea0)
DEBUG: #89 pc 0000000000088188 /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108) (BuildId: d010ec9d0da07ff241689a4e9691c733)
Cause: null pointer dereference
告诉我们出现了空指针
backtrace
以下,显示了程序调用过程
可以看到自己写的JNI
方法Java_com_cy_ndkcrashdemo_MainActivity_stringFromJNI
+56,这个函数对应的pc
值(函数编译地址)是000000000000efa4
根据 .so 是 32 位还是 64 位选择对应的 addr2line 工具
使用方式如下:
addr2line -f -p -e so文件路径 报错函数对应的pc值
打开命令行窗口,进入aarch64-linux-android-addr2line
(这里举例用的64位)所在目录,输入如下命令:
D:\AndroidSDK\ndk\21.4.7075529\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\bin>
aarch64-linux-android-addr2line -f -p -e
E:\AndroidStudioWorkspace\NDKCrashDemo\app\build\intermediates\merged_native_libs\
debug\out\lib\arm64-v8a\libndkcrashdemo.so 000000000000efa4
输出如下:
Java_com_cy_ndkcrashdemo_MainActivity_stringFromJNI at
E:/AndroidStudioWorkspace/NDKCrashDemo/app/src/main/cpp/native-lib.cpp:8
指出了crash
发生在哪个文件的哪个函数,以及行号
你也可以将addr2line
工具所在目录添加到系统环境变量path
中,在命令行窗口中不用再进入addr2line
所在目录,也可执行
so strip
一个完整的 so 由C/C++代码编译后的输出和
debug
信息组成,这些debug信息会记录 so
中所有方法的对照表,就是方法名和其编译地址的对应表,也叫做符号表,这种so
也叫做未strip
的,通常体积会比较大。通常
release
的 so 都是需要经过一个strip
操作的,这样strip之后的 so 中的debug
信息会被剥离,整个 so
的体积也会缩小。
如下可以看到strip之前和之后的大小对比
未strip
的so
已strip
的so
如果debug信息丢了,无法再定位代码。
所以,这些debug信息尤为重要,是我们分析native crash问题的关键信息,那么我们在编译 so
时候务必保留一份未被strip的so 或者剥离后的符号表信息,以供后面问题分析,并且每次编译的so
都需要保存,一旦产生代码修改重新编译,那么修改前后的符号表信息会无法对应,也无法进行分析。
如下图所示,merged_native_libs下是含有debug信息的so,striped_native_libs下是去除了debug信息的so。
注意:不同版本死丢丢目录不一致。
所以开发so
库的时候,每次编译
之后,如果需要提供给别人使用,我们需要保留一份未strip
的so库和JNI代码
,strip
的so库提供给别人使用,当出现native crash
的时候,我们可以通过未strip
的so库定位strip
的so库发生crash的代码位置,因为未strip
和已strip
的so库的函数的编译地址是一致的,strip去除的只是debug
信息。
欢迎联系、指正、批评
Github:https://github.com/AnJiaoDe
CSDN:https://blog.csdn.net/confusing_awakening
OpenCV入门教程:https://blog.csdn.net/confusing_awakening/article/details/113372425
ffmpeg入门教程:https://blog.csdn.net/confusing_awakening/article/details/102007792
微信公众号
QQ群
Android NDK入门教程之快速定位Crash问题相关推荐
- 《Delphi XE6 android 编程入门教程》推荐
近5.6年已经没有看见关于delphi的新技术的书出来了(看来在国内delphi的使用量确实很低了), 高勇同学最近出了一本<Delphi XE6 android 编程入门教程>,上周刚拿 ...
- Android基础入门教程——4.2.3 Service精通
Android基础入门教程--4.2.3 Service精通 标签(空格分隔): Android基础入门教程 本节引言: 本节,我们继续来研究Service(服务)组件,本节将会学习下Android中 ...
- el-date-picker设置默认日期_ERP入门教程:快速掌握金蝶ERP的基础-物料批次管理的应用及设置...
ERP入门教程:快速掌握金蝶ERP的基础-物料的批次管理的应用及设置 关注我,我将定期分享更多的ERP解决方案 转发关注并私信我,了解更多的解决方案及操作方法哦 一.应用软件版本:金蝶KIS旗舰版6. ...
- android 编辑9图片,Android基础入门教程——1.6 .9(九妹)图片怎么玩
Android基础入门教程--1.6 .9(九妹)图片怎么玩 Android基础入门教程 1.本节引言: 可能有的一些疑问: 1.什么是.9图片? 答:图片后缀名前有.9的图片,如pic1.9.png ...
- android设置webview缓存目录,Android基础入门教程——7.5.5 WebView缓存问题
Android基础入门教程--7.5.5 WebView缓存问题 Android基础入门教程 本节引言:现在很多门户类信息网站,比如虎嗅,ifanr,钛媒体等等的APP,简单点说是信息阅读类的APP, ...
- Android WebRTC 入门教程(一) -- 使用相机
前言,最近在搞网页投屏,发现 WebRTC 的Android 版本较少,这里的话,参考了一些优秀的博客,主要是这个大佬的 https://www.jianshu.com/p/eb5fd116e6c8 ...
- Android基础入门教程——4.3.1 BroadcastReceiver牛刀小试
Android基础入门教程--4.3.1 BroadcastReceiver牛刀小试 标签(空格分隔): Android基础入门教程 本节引言 本节我们将来学习Android四大组件中的第三个:Bro ...
- Android基础入门教程——10.1 TelephonyManager(电话管理器)
Android基础入门教程--10.1 TelephonyManager(电话管理器) 标签(空格分隔): Android基础入门教程 本节引言: 本章节是Android基础入门教程的最后一章,主要讲 ...
- 最新Android基础入门教程目录(完结版)
第一章:环境搭建与开发相关(已完结 10/10) https://blog.csdn.net/coder_pig/article/details/50000773 Android基础入门教程--1.1 ...
最新文章
- Linux C编程--进程间通信(IPC)3--信号集和发送信号介绍
- java 广义表_java 输入广义表 生成二叉树 | 学步园
- C#和NewSQL更配 —— TiDB入门
- linux系统刷分辨率,Linux下设置其分辨率及刷新率
- python内置函数返回序列中最大元素_Python之路(第八篇)Python内置函数、zip()、max()、min()...
- 如何在Ubuntu 14.04上安装MySQL
- 如何利用MySQL Workbench创建Model EER 图
- 通才还是专才——由摩托裁员引发的讨论
- Hadoop完全分布式集群安装Hbase
- PyTorch1.2安装(Anaconda3 + Python3.6 + cpu版本)
- 《计算机组成原理》第二版第一章课后习题答案
- VirtualBox安装教程(Win10)含软件安装包
- flash 围棋_中国卫视执白0.5目胜flash77
- Mac Dotnet 坑 - Donet EF
- Windows取证分析基础知识大全
- python实现ddos防护_python实现的防DDoS脚本
- CentOS 7.6使用Percona XtraBackup 2.4备份恢复MySQL 5.7
- Tivoli Storage Manager安装配置
- 漫谈大数据 - 实时数据仓库以及大厂实际应用
- 中国工程师如何获 Google 的工作机会?
热门文章
- Segmentation Fault 错误原因总结及解决方法
- ORACLE ORA错误码大全 (备忘)
- 此beta版已额满_日志MIUI 11 第439周开发版内测日志补充
- python实例练习(12)身体质量指数BMI计算
- 文档级关系抽取:A Densely Connected Criss-Cross Attention Network for Document-level Relation Extraction
- 文读懂安防视频监控系统中H.265、SVAC、GB/T28181、ONVIF、PSIA的区别。
- matlab 可见度和衬噪比
- 微软雅黑字体包替换XP的宋体(附下载)
- 洛谷 - P3374 树状数组1
- 三方协议服务器不填,毕业生三方协议可以不填么