NDK调试心得

来源:互联网 发布:mac系统内存清理 编辑:程序博客网 时间:2024/05/02 23:37

最近为了性能需求,开始搞JNI,白手起搞真心不容易。中间差点崩溃了好几次,最终总算得到一点心得。

 

JNI对性能的提升没有我预想中的大,对于for循环的速度提升大概在1倍左右,所以如果数量级不大的话,性能提升不会很明显

JNI编完之后,不能调试,是不是很蛋疼,不像android Java可以看出错信息。JNI crash之后,界面上表示为没有任何反应,过段时间直接退出应用,没有提示、也没有XXX已停止运行。第一次遇到真是无从下手,有没有!!!,经过对Java层的log研究发现,原来JNI crash后,cpu就直接死在那里(相当于assert,程序停止运行)。果断时间后JAVA层发现程序已挂之后(进程僵死),就强制杀死该进程。于是程序直接退出而无提示。(以上分析纯属个人分析,如有不对,敬请指正)

 

jni crash之后在logcat中会打出一段dump,这段dump没有tag,没有所属进程,所以如果ddms有filter会忽略这段dump而只看到

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000

signal后面一般是11,目测应该是crash信号,code表示不同错误码,有linux基础应该能看懂

JNI crash dump 一般以***********************************开头

11-25 15:13:20.788: I/DEBUG(1825): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
11-25 15:13:20.788: I/DEBUG(1825): Build fingerprint: 'samsung/GT-I9100/GT-I9100:4.0.3/IML74K/ZSLPG:user/release-keys'
11-25 15:13:20.788: I/DEBUG(1825): pid: 6454, tid: 6454  >>> com.ty.jnidebug <<<
11-25 15:13:20.788: I/DEBUG(1825): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000
11-25 15:13:20.788: I/DEBUG(1825):  r0 0000f448  r1 95e00019  r2 00000001  r3 00000000
11-25 15:13:20.788: I/DEBUG(1825):  r4 4c1c9a88  r5 000129d0  r6 00000000  r7 4be45da0
11-25 15:13:20.788: I/DEBUG(1825):  r8 beafe668  r9 4be45d98  10 00000000  fp beafe67c
11-25 15:13:20.788: I/DEBUG(1825):  ip 4c773bb9  sp beafe650  lr 40917cf4  pc 4c773bc6  cpsr 20000030
11-25 15:13:20.788: I/DEBUG(1825):  d0  0000000080000000  d1  0000000080000000
11-25 15:13:20.788: I/DEBUG(1825):  d2  0000000000000000  d3  0000000000000000
11-25 15:13:20.798: I/DEBUG(1825):  d4  8000000000000000  d5  42dc00003f800000
11-25 15:13:20.798: I/DEBUG(1825):  d6  00000000c2dc0000  d7  0000000000000000
11-25 15:13:20.798: I/DEBUG(1825):  d8  0000000000000000  d9  0000000000000000
11-25 15:13:20.798: I/DEBUG(1825):  d10 0000000000000000  d11 0000000000000000
11-25 15:13:20.798: I/DEBUG(1825):  d12 0000000000000000  d13 0000000000000000
11-25 15:13:20.803: I/DEBUG(1825):  d14 0000000000000000  d15 0000000000000000
11-25 15:13:20.803: I/DEBUG(1825):  d16 000000000000000c  d17 c05b800000000000
11-25 15:13:20.803: I/DEBUG(1825):  d18 0000000000000000  d19 0000000000000000
11-25 15:13:20.803: I/DEBUG(1825):  d20 3ff0000000000000  d21 8000000000000000
11-25 15:13:20.803: I/DEBUG(1825):  d22 0000000000000000  d23 ff00ff00ff00ff00
11-25 15:13:20.803: I/DEBUG(1825):  d24 ed12c639a9569e61  d25 ff00ff00ff00ff00
11-25 15:13:20.803: I/DEBUG(1825):  d26 f5f5f5f5f5f5f5f5  d27 ffffffffffffffff
11-25 15:13:20.803: I/DEBUG(1825):  d28 00f7003e00f1003d  d29 3ff0000000000000
11-25 15:13:20.803: I/DEBUG(1825):  d30 0000000000000000  d31 3ff0000000000000
11-25 15:13:20.803: I/DEBUG(1825):  scr 20000012
11-25 15:13:21.003: I/DEBUG(1825):          #00  pc 00000bc6  /data/data/com.ty.jnidebug/lib/libJNIDebug.so (Java_com_ty_jnidebug_MainActivity_test)
11-25 15:13:21.003: I/DEBUG(1825):          #01  pc 0001ecf0  /system/lib/libdvm.so (dvmPlatformInvoke)
11-25 15:13:21.003: I/DEBUG(1825):          #02  pc 00058fac  /system/lib/libdvm.so (_Z16dvmCallJNIMethodPKjP6JValuePK6MethodP6Thread)
11-25 15:13:21.008: I/DEBUG(1825): code around pc:
11-25 15:13:21.008: I/DEBUG(1825): 4c773ba4 0000345c e59f0004 e08f0000 eaffffe5  \4..............
11-25 15:13:21.008: I/DEBUG(1825): 4c773bb4 0000344c 9001b086 23009100 9b049304  L4.........#....
11-25 15:13:21.008: I/DEBUG(1825): 4c773bc4 601a2201 93032300 9b03e004 9b039305  .".`.#..........
11-25 15:13:21.008: I/DEBUG(1825): 4c773bd4 93033301 4b029a03 ddf6429a 4770b006  .3.....K.B....pG
11-25 15:13:21.008: I/DEBUG(1825): 4c773be4 000003e7 e5903000 e3130101 13833102  .....0.......1..
11-25 15:13:21.008: I/DEBUG(1825): code around lr:
11-25 15:13:21.008: I/DEBUG(1825): 40917cd4 3497c004 3488c004 3afffff9 e2888004  ...4...4...:....
11-25 15:13:21.008: I/DEBUG(1825): 40917ce4 eafffff9 e899000c e59bc00c e12fff3c  ............<./.
11-25 15:13:21.008: I/DEBUG(1825): 40917cf4 e3560000 159bc010 e24bd014 188c0003  ..V.......K.....
11-25 15:13:21.008: I/DEBUG(1825): 40917d04 e8bd8bc0 e1a0ce22 e59b6008 e2866001  ...."....`...`..
11-25 15:13:21.008: I/DEBUG(1825): 40917d14 e3a02000 e4d6c001 e35c0000 0a000007  . ........\.....
11-25 15:13:21.008: I/DEBUG(1825): stack:
11-25 15:13:21.008: I/DEBUG(1825):     beafe610  beafe644  [stack]
11-25 15:13:21.008: I/DEBUG(1825):     beafe614  40111091  /system/lib/libutils.so
11-25 15:13:21.008: I/DEBUG(1825):     beafe618  001d2690  [heap]
11-25 15:13:21.008: I/DEBUG(1825):     beafe61c  40094540 
11-25 15:13:21.008: I/DEBUG(1825):     beafe620  00000068 
11-25 15:13:21.008: I/DEBUG(1825):     beafe624  400944b4 
11-25 15:13:21.008: I/DEBUG(1825):     beafe628  001d2698  [heap]
11-25 15:13:21.008: I/DEBUG(1825):     beafe62c  4be45cf4 
11-25 15:13:21.008: I/DEBUG(1825):     beafe630  00000000 
11-25 15:13:21.008: I/DEBUG(1825):     beafe634  40061ab9  /system/lib/libc.so
11-25 15:13:21.008: I/DEBUG(1825):     beafe638  00000000 
11-25 15:13:21.008: I/DEBUG(1825):     beafe63c  00186258  [heap]
11-25 15:13:21.013: I/DEBUG(1825):     beafe640  00000000 
11-25 15:13:21.013: I/DEBUG(1825):     beafe644  4be45cfc 
11-25 15:13:21.013: I/DEBUG(1825):     beafe648  df0027ad 
11-25 15:13:21.013: I/DEBUG(1825):     beafe64c  00000000 
11-25 15:13:21.013: I/DEBUG(1825): #00 beafe650  95e00019 
11-25 15:13:21.013: I/DEBUG(1825):     beafe654  0000f448  [heap]
11-25 15:13:21.013: I/DEBUG(1825):     beafe658  000129d0  [heap]
11-25 15:13:21.013: I/DEBUG(1825):     beafe65c  00012a78  [heap]
11-25 15:13:21.013: I/DEBUG(1825):     beafe660  00000000 
11-25 15:13:21.013: I/DEBUG(1825):     beafe664  4094d4d7  /system/lib/libdvm.so
11-25 15:13:21.013: I/DEBUG(1825): #01 beafe668  4be45d94 
11-25 15:13:21.013: I/DEBUG(1825):     beafe66c  00000001 
11-25 15:13:21.013: I/DEBUG(1825):     beafe670  414fc1a8  /dev/ashmem/dalvik-heap (deleted)
11-25 15:13:21.013: I/DEBUG(1825):     beafe674  000129e0  [heap]
11-25 15:13:21.013: I/DEBUG(1825):     beafe678  beafe8f8  [stack]
11-25 15:13:21.013: I/DEBUG(1825):     beafe67c  40951faf  /system/lib/libdvm.so

 

这段dump里面,包含了crash时cpu当时寄存器的信息,数据总线,callstack等信息,一般主要看lr pc寄存器来程序死在哪个代码上,看这么一堆地址自然看不出到底是哪个位置,这时我们需要一个symbol文件,sym文件包含了地址和函数入口的映射信息。为此google release了ndk-stack这个工具来查看死机时的callstack(其余的一些寄存器信息被过滤掉了,因为对于上层开发大部分没什么大用)

ndk-stack 使用方法

ndk-stack -sym <sym-file path> [-dump <dump-file-path>]

sym-file 一般用ndk-build编译出来生成在$project\obj\local\armeabi

dump-file就是logcat抓出来的log,注意里面需要有以***********************开头的信息,这个dump-file是可选的,如果没有指定则默认为默认输入流,那么可以这样用

adb logcat | $NDK/ndk-stack -sym $PROJECT_PATH/obj/local/armeabi

注意 “|”前后没有空格,否则会报错

 

更多信息可以查看ndk文档 your ndk-path/docs/NDK-STACK.html



JNI  logging方法

在android.mk 里LOCAL_LDLIBS:= -llog

在C/C++源文件里面包含头文件#include <android/log.h>

为了使用方便,最好使用如下宏定义

#define  LOG_TAG    "libripplejni"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)


这样,在logcat中的打印出来的JNI log 和 Java的就一样了


注意,如果实在framework下编JNI和使用NDK编译的方法有点不一样

注意实在android.mk中的定义和在include的头文件不一样。。。在framework中编写jni最好参考其他的JNI源码,并且注意要在AndroidRuntime.cpp中注册该函数