做者:仰简
, 连接:https://www.jianshu.com/p/9a5ba53b1e55java
1、前言
这篇文章我们来看看 Android Native Error / Crash
的问题在开发时如何调试分析。固然,只要能分析出缘由,天然就知道如何去解决啦。android
2、问题分析过程
下面的代码,在运行时必然发生空指针 NULL 异常,从而 引起 App Native Crash
。git
char *p = NULL;
char c = *p;
本地 / 开发时调试,很明显就是咱们在开发时遇到程序发生的崩溃,或者这是一个能够复现的问题。固然,也假设这个 so 是咱们本身的。那么,这个时候咱们的 so 是 unstripped (未剥离版共享库),简单来讲就是带有 debug 时的符号表。github
下面,咱们先来看一下,上面的代码在发生异常时,其报错的大体异常 log 会是怎么样的。web
--------- beginning of crash
02-17 23:05:30.893 2610 2610 F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 2610 (ly.com.crash)
02-17 23:05:30.998 1297 1297 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
02-17 23:05:30.999 1297 1297 F DEBUG : Build fingerprint: 'Android/sdk_phone_x86_64/generic_x86_64:6.0/MASTER/4174734:userdebug/test-keys'
02-17 23:05:30.999 1297 1297 F DEBUG : Revision: '0'
02-17 23:05:30.999 1297 1297 F DEBUG : ABI: 'x86_64'
02-17 23:05:30.999 1297 1297 F DEBUG : pid: 2610, tid: 2610, name: ly.com.crash >>> ly.com.crash <<<
02-17 23:05:30.999 1297 1297 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
02-17 23:05:31.003 1297 1297 F DEBUG : rax 0000000000000000 rbx 0000000012c53500 rcx 0000000000000000 rdx 000000000000000e
02-17 23:05:31.003 1297 1297 F DEBUG : rsi 00007fffbd76dee7 rdi 00007fffbd76df8f
02-17 23:05:31.003 1297 1297 F DEBUG : r8 0000000070799dd8 r9 0000000071d8c3b0 r10 00007fffbd76db80 r11 00007f722f0b21a0
02-17 23:05:31.003 1297 1297 F DEBUG : r12 0000000000000000 r13 0000000012cba100 r14 0000000012c53500 r15 0000000012c82100
02-17 23:05:31.003 1297 1297 F DEBUG : cs 0000000000000033 ss 000000000000002b
02-17 23:05:31.003 1297 1297 F DEBUG : rip 00007f722f0b21e0 rbp 00007fffbd76dfa0 rsp 00007fffbd76df30 eflags 0000000000010202
02-17 23:05:31.004 1297 1297 F DEBUG :
02-17 23:05:31.004 1297 1297 F DEBUG : backtrace:
02-17 23:05:31.004 1297 1297 F DEBUG : #00 pc 000000000000f1e0 /data/app/ly.com.crash-1/lib/x86_64/libnative-lib.so (Java_ly_com_crash_MainActivity_stringFromJNI+64)
02-17 23:05:31.004 1297 1297 F DEBUG : #01 pc 000000000070ba69 /data/app/ly.com.crash-1/oat/x86_64/base.odex (offset 0x2e2000) (java.lang.String ly.com.crash.MainActivity.stringFromJNI()+157)
02-17 23:05:31.004 1297 1297 F DEBUG : #02 pc 000000000070b950 /data/app/ly.com.crash-1/oat/x86_64/base.odex (offset 0x2e2000) (void ly.com.crash.MainActivity.onCreate(android.os.Bundle)+228)
02-17 23:05:31.004 1297 1297 F DEBUG : #03 pc 00000000734ab4bc /data/dalvik-cache/x86_64/system@framework@boot.oat (offset 0x1ed6000)
02-17 23:05:31.040 1297 1297 F DEBUG :
02-17 23:05:31.040 1297 1297 F DEBUG : Tombstone written to: /data/tombstones/tombstone_00
02-17 23:05:31.040 1297 1297 E DEBUG : AM write failed: Broken pipe
这个错误堆栈是从 logcat 里面获取的,其崩溃信息已经相对完善了。并且其中还有一句告知了更详细的崩溃日志被写入到了 /data/tombstones/tombstone_00
。咱们能够借助这个 /data/tombstones/tombstone_00
做更详尽的分析。编程
而后,针对这个错误。从它的 backtrace 中咱们能够看到其异常发生在咱们本身的 native-lib.so
中了,发生异常的错误栈为:微信
#00 pc 000000000000f1e0 /data/app/ly.com.crash-2/lib/x86_64/libnative-lib.so (Java_ly_com_crash_MainActivity_stringFromJNI+64)
在 Android NDK 中给咱们提供了一个工具 ndk-stack ,利用 ndk-stack 就能够轻松的将上面的异常栈转换成可定位到源码具体位置的可读性更强的异常栈。app
使用 ndk-stack 时,咱们除了须要包含出问题时的异常栈的 log 以外,咱们还须要经过参数 -sym 来指定一个 unstripped 的 .so
。通常在开发时,这个 so 的位置可能以下:编程语言
-
若是你使用的是 ndk-build 来编译的话,它可能位于 $PROJECT_PATH/app/build/intermediates/ndk-build/debug/obj/x86_64/***.so
若是使用的是 cmake 来编译的话,它可能位于$PROJECT_PATH/app/build/intermediates/cmake/debug/obj/x86_64/***.so
而对于指定异常 log 的方式,ndk-stack 也提供了两种方式:编辑器
-
将 logcat 直接做为输入:
adb logcat | ndk-stack -sym $PROJECT_PATH/app/build/intermediates/cmake/debug/obj/x86_64
-
经过 -dump 指定一个包含异常日志的文件
ndk-stack -sym $PROJECT_PATH/app/build/intermediates/cmake/debug/obj/x86_64 -dump foo.txt
上面的 $PROJECT_PATH
你须要替换成你本身的工程绝对路径。
就这样,经过上面一顿猛如虎的操做以后,咱们能够获得异常栈转换后的可读性更强的栈:
#00 0x000000000000f1e0 /data/app/ly.com.crash-2/lib/x86_64/libnative-lib.so (Java_ly_com_crash_MainActivity_stringFromJNI+64)
Java_ly_com_crash_MainActivity_stringFromJNI
/Users/ly/github/HelloCrash/app/src/main/cpp/native-lib.cpp:10:14
能够看到,发生异常的地方在 native-lib.cpp
的 第 10 行第 14
列。
三思考 针对开发时,所发生的 native crash 来分析仍是很简单的。那么,当咱们的应用打成 release 包以后,发布线上以后又该如何分析呢?
---END---


本文分享自微信公众号 - 技术最TOP(Tech-Android)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。