介绍几个分析Android native问题的方法:
一,使用addr2line
addr2line是一个可以将指令的地址和可执行映像转换成文件名、函数名和源代码行数的工具.
用linux自带addr2line工具(/usr/bin/目录)查看调用栈:
1.编译生成带符号的so库文件,将相应的bin文件烧入手机,重现问题;
2.根据dump文件恢复调用栈:
(1)进入xxx\symbols\system\lib 目录,找到相应库文件,命令行进入该目录;
(2)输入命令addr2line [-option1] [-option2] 偏移量,可得到文件位置;
例:
05-14 03:38:52.169 101 101 I DEBUG : #00 pc 00043ae4 /system/lib/libdvm.so (dvmAbort)
05-14 03:38:52.169 101 101 I DEBUG : #01 pc 000375cc /system/lib/libdvm.so
addr2line [...][...] 43ae4
addr2line -f -e libdvm.so 43ae4
-f: 显示函数名
-e: 指定映像文件
二,使用ndk stack工具
该方法可以包含更多内容,是前一种方法的补充。
ndk-stack是一个简单工具,允许你过滤在adb logcat输出中显示的堆栈跟踪,并且把共享库内的任意地址替换成相应的冒号值,得到对应函数名及文件所在的行。
下面介绍使用方法:
1.下载NDK工具包
地址:http://developer.android.com/tools/sdk/ndk/index.html
解压后可以看到有个ndk-stack.exe
2.问题binary对应的带symbol的so文件目录
注意目录格式是linux格式,即使用 "/"
3.发生问题的log
ndk-stack通过"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***"来查找初始行,所以log中要包含这些内容,类似这样:
01-03 20:00:22.120 245 245 I DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-03 20:00:22.120 245 245 I DEBUG : Build fingerprint: 'samsung/xxx/:4.4.2/KOT49H/T330ZCE1ANC2:eng/test-keys'
01-03 20:00:22.120 245 245 I DEBUG : Revision: '8'
01-03 20:00:22.120 245 245 I DEBUG : pid: 18531, tid: 18546, name: thumbs thread >>> android.process.media
4.运行ndk-stack
命令格式:ndk-stack -sym <so文件所在目录> -dump <log文件>
例子:
我的ndk工具包解压在F盘,test.txt为带有native错误的log文件
F:\android-ndk-r9d-windows-x86\android-ndk-r9d>ndk-stack -sym ./out/target/product/milletwifi/symbols/system/lib/ -dump ./test.txt
运行后在命令行会显示出结果。
对比:
原来log中的内容为
01-03 20:00:22.480 245 245 I DEBUG : backtrace:
01-03 20:00:22.480 245 245 I DEBUG : #00 pc 00022274 /system/lib/libc.so (__memcpy_base+219)
01-03 20:00:22.480 245 245 I DEBUG : #01 pc 0004e6d9 /system/lib/libdvm.so
01-03 20:00:22.480 245 245 I DEBUG : #02 pc 0003e31d /system/lib/libdvm.so
01-03 20:00:22.480 245 245 I DEBUG : #03 pc 00000d9f /system/lib/libexif_jni.so
01-03 20:00:22.480 245 245 I DEBUG : #04 pc 00020d8c /system/lib/libdvm.so (dvmPlatformInvoke+112)
01-03 20:00:22.480 245 245 I DEBUG : #05 pc 00051b87 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*,
Thread*)+398)
01-03 20:00:22.480 245 245 I DEBUG : #06 pc 0003c0dd /system/lib/libdvm.so (dvmCheckCallJNIMethod(unsigned int const*, JValue*, Method const*,
Thread*)+8)
......
运行后结果:
********** Crash dump: **********
Build fingerprint: 'samsung/milletwifizc/milletwifi:4.4.2/KOT49H/T330ZCE1ANC2:eng/test-keys'
pid: 18531, tid: 18546, name: thumbs thread >>> android.process.media <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 78fef000
Stack frame #00 pc 00022274 /system/lib/libc.so (__memcpy_base+219): Routine __memcpy_base at
/home/dpi/qb5_8814/workspace/MILLETWIFI_CHN_OPEN/android/bionic/libc/arch-arm/krait/bionic/memcpy_base.S:157
Stack frame #01 pc 0004e6d9 /system/lib/libdvm.so: Routine memcpy at
/home/dpi/qb5_8814/workspace/MILLETWIFI_CHN_OPEN/android/bionic/libc/include/../include/string.h:108 (discriminator 4)
Stack frame #02 pc 0003e31d /system/lib/libdvm.so: Routine Check_SetByteArrayRegion at
/home/dpi/qb5_8814/workspace/MILLETWIFI_CHN_OPEN/android/dalvik/vm/CheckJni.cpp:1880
Stack frame #03 pc 00000d9f /system/lib/libexif_jni.so: Routine getThumbnail at
/home/dpi/qb5_8814/workspace/MILLETWIFI_CHN_OPEN/android/external/jhead/main.c:462
Stack frame #04 pc 00020d8c /system/lib/libdvm.so (dvmPlatformInvoke+112): Routine dvmPlatformInvoke at
/home/dpi/qb5_8814/workspace/MILLETWIFI_CHN_OPEN/android/dalvik/vm/arch/arm/CallEABI.S:258
Stack frame #05 pc 00051b87 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+398): Routine dvmCallJNIMethod
(unsigned int const*, JValue*, Method const*, Thread*) at /home/dpi/qb5_8814/workspace/MILLETWIFI_CHN_OPEN/android/dalvik/vm/Jni.cpp:1185
Stack frame #06 pc 0003c0dd /system/lib/libdvm.so (dvmCheckCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+8): Routine
dvmCheckCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*) at
/home/dpi/qb5_8814/workspace/MILLETWIFI_CHN_OPEN/android/dalvik/vm/CheckJni.cpp:
145
......
可以看到每个so后面都带有对应的冒号值,即调用栈的函数名。