1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > Android NDK入门教程之快速定位Crash问题

Android NDK入门教程之快速定位Crash问题

时间:2023-06-09 12:00:18

相关推荐

Android NDK入门教程之快速定位Crash问题

文章目录

首先制造一个 so crash问题addr2lineaddr2line工具位置addr2line命令如下:分析crash logso 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 JNICALLJava_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-printMake 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.15DEBUG: Time: -04-20 15:34:49DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***DEBUG: Build fingerprint: 'vivo/PD2073/PD2073:11/RP1A.20.012/compiler1228233519:user/release-keys'DEBUG: Revision: '0'DEBUG: ABI: 'arm64'DEBUG: Timestamp: -04-20 15:34:49+0800DEBUG: pid: 22618, tid: 22618, name: cy.ndkcrashdemo >>> com.cy.ndkcrashdemo <<<DEBUG: uid: 10252DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0DEBUG: Cause: null pointer dereferenceDEBUG:x0 0000000000000000 x1 0000000000000000 x2 0000000000000018 x3 00000076eecbf000DEBUG:x4 0000000000000000 x5 b4000076ee95ac00 x6 00000076497d53af x7 000000000000001bDEBUG:x8 0**************1 x9 ad1a1eb4209bd757 x10 0000000000430000 x11 00000000069d2cd0DEBUG:x12 0000000000371314 x13 00000000006476c0 x14 000000000051d6c0 x15 ffffffffffffffffDEBUG:x16 000000765387ce98 x17 00000076ec1cf4b0 x18 00000076eeec6000 x19 b4000076ee95ac00DEBUG:x20 0000000000000000 x21 b4000076ee95ac00 x22 00000076eecbf000 x23 b4000076ee95acb8DEBUG:x24 0000007667d48478 x25 00000076eecbf000 x26 000000000000000b x27 0000000000000002DEBUG:x28 0000007fdeb3db00 x29 0000007fdeb3da10DEBUG:lr 000000765385757c sp 0000007fdeb3da00 pc 00000076ec1cf4c0 pst 0000000080001000DEBUG: 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 atE:/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:/AnJiaoDe

CSDN:/confusing_awakening

OpenCV入门教程:/confusing_awakening/article/details/113372425

ffmpeg入门教程:/confusing_awakening/article/details/10792

微信公众号

QQ群

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。