本文介绍一下用ndk实现jni的方式。
静态注册函数
1. 下载linux版的ndk,windows配环境好像有点麻烦,所以就不说了
2. 配置NDK环境变量:
a.sudo gedit ~/.bashrc
b.在文件中输入如下的内容:
NDKROOT=/home/username/android/ndk/android-ndk-r8
export NDKROOT;
c.更新一下环境配置:source ~/.bashrc
4.创建一个android项目,例子如下:
5. 编译该android工程,目的是为了在bin下面生成class文件
6. 在项目根目录输入: javah -classpath <bin下面类包的根目录> -d jni org.eshock.jnitest.JNITest, 此时会在项目根目的jni文件夹下生成一个org_eshock_jnitest_JNITest.h 文件,
内容如下:
7.在jni目录手机创建相应的cpp文件,代码如下:
8. 在jni文件夹下编写Android.mk文件,内容如下:
9. 把整个项目文件夹拷到ndk/samples/下面。
10. 进入到ndk/samples/<projectname>/ 下,然后输入 $NDKROOT/ndk-build <module name>
11. 它会在ndk/samples/<projectname>/下生成obj/local/armeabi/lib***.so
动态注册函数
加Java定义如下:
class Test{
private native int add(int a, int b);
}
1. JNI在加载时,会调用JNI_OnLoad,而卸载时会调用JNI_UnLoad,所以我们可以在JNI_OnLoad里面注册我们的native函数
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK){
LOGE("ERROR:GetEnv failed\n");
goto bail;
}
assert(env != NULL);
if (register_native_function(env) < 0) {
LOGE("ERROR: Boa Server native registration failed");
goto bail;
}
result = JNI_VERSION_1_4;
bail:
return result;
}
2. 自已定义register_native_function函数
int register_ckt_BehaviorManager(JNIEnv *env){
return jniRegisterNativeMethods(env, "com/lht/Test",
gMethods, NELEM(gMethods));
}
jniRegisterNativeMethods是JNI注册函数,"com/lht/Test"是对应的Java类,gMethods是一个Java和Native方法对应的数据结构。
typedef struct {
const char* name; //Java中申明的Native函数名称
const char* signature; //函数描述,这个具体的写法在以后的篇章里会定义
void* fnPtr; //Natvie函数指针
} JNINativeMethod;
3. 定义JNINativeMethod
static JNINativeMethod gMethods[] = {
{"add", "(II)I", (void*)com_lht_Test_add},
};
4. 实现add函数:
jint com_lht_Test_add(JNIEnv *env, jobject clazz, jint a, jint b){ return (a + b); }
5.Makefile定义
以下方式是用NDK编译的方式
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 添加代码文件
LOCAL_SRC_FILES:= \
com_lht_Test.cpp
# 添加头文件
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
# 添加相关库文件
LOCAL_SHARED_LIBRARIES := \
libur \
libcutils \
# 生成的目标so名称
LOCAL_MODULE := libTest_jni
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
NDK_stack
追踪出问题代码的行数
源码:
#include "com_example_testjni_MainActivity.h"
JNIEXPORT jint JNICALL Java_com_example_testjni_MainActivity_add
(JNIEnv *env, jobject c, jint a, jint b)
{
char *str = "abc\n";
str[4] = 8;
return (a + b);
}
F/libc (14337): Fatal signal 11 (SIGSEGV) at 0x752cb0fc (code=2), thread 14337 (example.testjni)
I/DEBUG ( 263): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( 263): Build fingerprint: 'eng/debug,test-keys'
I/DEBUG ( 263): Revision: '115'
I/DEBUG ( 263): pid: 14337, tid: 14337, name: example.testjni >>> com.example.testjni <<<
I/DEBUG ( 263): signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 752cb0fc
I/DEBUG ( 263): r0 00000008 r1 752cb0f8 r2 00000003 r3 00000005
I/DEBUG ( 263): r4 6d8b9438 r5 415e68f8 r6 00000004 r7 41535ca0
I/DEBUG ( 263): r8 be9b42b8 r9 41535c98 sl 415e6908 fp be9b42cc
I/DEBUG ( 263): ip 752c9bb9 sp be9b42b8 lr 41607450 pc 752c9bbe cpsr 000b0030
I/DEBUG ( 263): d0 6d6178652f6d6f63 d1 747365742f656c70
I/DEBUG ( 263): d2 6e69614d2f696e6a d3 7974697669746341
I/DEBUG ( 263): d4 0000000000000000 d5 0000000000000000
I/DEBUG ( 263): d6 0000000000000000 d7 4140000000000000
I/DEBUG ( 263): d8 0000000000000000 d9 0000000000000000
I/DEBUG ( 263): d10 0000000000000000 d11 0000000000000000
I/DEBUG ( 263): d12 0000000000000000 d13 0000000000000000
I/DEBUG ( 263): d14 0000000000000000 d15 0000000000000000
I/DEBUG ( 263): d16 41ad6c7041abbf68 d17 41ac50d041ad1770
I/DEBUG ( 263): d18 000000010000012e d19 000000010000016d
I/DEBUG ( 263): d20 00000001000012dc d21 00000001000014eb
I/DEBUG ( 263): d22 00000001000014fa d23 00000001000014fc
I/DEBUG ( 263): d24 0000000000000000 d25 0000000000000000
I/DEBUG ( 263): d26 0000000000000000 d27 8080808080808080
I/DEBUG ( 263): d28 0100010001000100 d29 0100010001000100
I/DEBUG ( 263): d30 8080808080808080 d31 8080808080808080
I/DEBUG ( 263): scr 60000010
I/DEBUG ( 263):
I/DEBUG ( 263): backtrace:
I/DEBUG ( 263): #00 pc 00000bbe /data/app-lib/com.example.testjni-1/libjnitest.so (Java_com_example_testjni_MainActivity_add+5)
I/DEBUG ( 263): #01 pc 0002044c /system/lib/libdvm.so (dvmPlatformInvoke+112)
I/DEBUG ( 263): #02 pc 000512b3 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+398)
I/DEBUG ( 263): #03 pc 0003b83d /system/lib/libdvm.so (dvmCheckCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+8)
I/DEBUG ( 263): #04 pc 00052cb5 /system/lib/libdvm.so (dvmResolveNativeMethod(unsigned int const*, JValue*, Method const*, Thread*)+184)
I/DEBUG ( 263): #05 pc 000298e0 /system/lib/libdvm.so
I/DEBUG ( 263): #06 pc 00030e30 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
I/DEBUG ( 263): #07 pc 0002e4c8 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
I/DEBUG ( 263): #08 pc 00063a11 /system/lib/libdvm.so (dvmInvokeMethod(Object*, Method const*, ArrayObject*, ArrayObject*, ClassObject*, bool)+392)
I/DEBUG ( 263): #09 pc 0006b873 /system/lib/libdvm.so
I/DEBUG ( 263): #10 pc 000298e0 /system/lib/libdvm.so
I/DEBUG ( 263): #11 pc 00030e30 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
I/DEBUG ( 263): #12 pc 0002e4c8 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
I/DEBUG ( 263): #13 pc 0006372d /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+336)
I/DEBUG ( 263): #14 pc 0004ce9b /system/lib/libdvm.so
I/DEBUG ( 263): #15 pc 0003fe05 /system/lib/libdvm.so
I/DEBUG ( 263): #16 pc 0004fb7f /system/lib/libandroid_runtime.so
I/DEBUG ( 263): #17 pc 000508c5 /system/lib/libandroid_runtime.so (android::AndroidRuntime::start(char const*, char const*)+388)
I/DEBUG ( 263): #18 pc 0000105b /system/bin/app_process
I/DEBUG ( 263): #19 pc 0000e593 /system/lib/libc.so (__libc_init+50)
I/DEBUG ( 263): #20 pc 00000d7c /system/bin/app_process
I/DEBUG ( 263):
I/DEBUG ( 263): stack:
I/DEBUG ( 263): be9b4278 be9b42e0 [stack]
I/DEBUG ( 263): be9b427c 4009d49f /system/lib/libc.so (dlfree+50)
I/DEBUG ( 263): be9b4280 400d6000 /system/lib/libc.so
I/DEBUG ( 263): be9b4284 c31b3810
I/DEBUG ( 263): be9b4288 752e4840
I/DEBUG ( 263): be9b428c 00000000
I/DEBUG ( 263): be9b4290 00000000
I/DEBUG ( 263): be9b4294 00000000
I/DEBUG ( 263): be9b4298 00000000
I/DEBUG ( 263): be9b429c c31b3810
I/DEBUG ( 263): be9b42a0 41aab530 /dev/ashmem/dalvik-heap (deleted)
I/DEBUG ( 263): be9b42a4 415e68f8 [heap]
I/DEBUG ( 263): be9b42a8 415e69a0 [heap]
I/DEBUG ( 263): be9b42ac 416a4c38 /system/lib/libdvm.so
I/DEBUG ( 263): be9b42b0 df0027ad
I/DEBUG ( 263): be9b42b4 00000000
I/DEBUG ( 263): #00 be9b42b8 41535c94
I/DEBUG ( 263): ........ ........
I/DEBUG ( 263): #01 be9b42b8 41535c94
I/DEBUG ( 263): be9b42bc 00000001
I/DEBUG ( 263): be9b42c0 00000000
I/DEBUG ( 263): be9b42c4 41aab530 /dev/ashmem/dalvik-heap (deleted)
I/DEBUG ( 263): be9b42c8 41aa3fa4 /dev/ashmem/dalvik-heap (deleted)
I/DEBUG ( 263): be9b42cc 416382b7 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+402)
I/DEBUG ( 263): #02 be9b42d0 41535c94
I/DEBUG ( 263): be9b42d4 7528331e /data/dalvik-cache/data@app@com.example.testjni-1.apk@classes.dex
I/DEBUG ( 263): be9b42d8 752c9bb9 /data/app-lib/com.example.testjni-1/libjnitest.so (Java_com_example_testjni_MainActivity_add)
I/DEBUG ( 263): be9b42dc 415e6908 [heap]
I/DEBUG ( 263): be9b42e0 752e5b68
I/DEBUG ( 263): be9b42e4 752e5b70
I/DEBUG ( 263): be9b42e8 00000000
I/DEBUG ( 263): be9b42ec 00000000
I/DEBUG ( 263): be9b42f0 7179824c
I/DEBUG ( 263): be9b42f4 400da394
I/DEBUG ( 263): be9b42f8 400d6000 /system/lib/libc.so
I/DEBUG ( 263): be9b42fc 752e5bf1
I/DEBUG ( 263): be9b4300 752e5bf1
I/DEBUG ( 263): be9b4304 752e5b70
I/DEBUG ( 263): be9b4308 752e5bc0
I/DEBUG ( 263): be9b430c 00000000
I/DEBUG ( 263): ........ ........
adb logcat | $NDKROOT/ndk-stack -sym $PROJECT_PATH/obj/local/armeabi
$NDKROOT/ndk-stack -sym obj/local/armeabi/ -dump exception.log
********** Crash dump: **********
Build fingerprint: ‘test-keys'
pid: 14337, tid: 14337, name: example.testjni >>> com.example.testjni <<<
signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 752cb0fc
Stack frame #00 pc 00000bbe /data/app-lib/com.example.testjni-1/libjnitest.so (Java_com_example_testjni_MainActivity_add+5): Routine Java_com_example_testjni_MainActivity_add at /home/luohaitao/work/android/ndk/android-ndk-r9d/samples/testJNI/jni/com_example_testjni_MainActivity.cpp:6
Stack frame #01 pc 0002044c /system/lib/libdvm.so (dvmPlatformInvoke+112)
Stack frame #02 pc 000512b3 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+398)
Stack frame #03 pc 0003b83d /system/lib/libdvm.so (dvmCheckCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+8)
Stack frame #04 pc 00052cb5 /system/lib/libdvm.so (dvmResolveNativeMethod(unsigned int const*, JValue*, Method const*, Thread*)+184)
Stack frame #05 pc 000298e0 /system/lib/libdvm.so
Stack frame #06 pc 00030e30 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
Stack frame #07 pc 0002e4c8 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
Stack frame #08 pc 00063a11 /system/lib/libdvm.so (dvmInvokeMethod(Object*, Method const*, ArrayObject*, ArrayObject*, ClassObject*, bool)+392)
Stack frame #09 pc 0006b873 /system/lib/libdvm.so
Stack frame #10 pc 000298e0 /system/lib/libdvm.so
Stack frame #11 pc 00030e30 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
Stack frame #12 pc 0002e4c8 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
Stack frame #13 pc 0006372d /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+336)
Stack frame #14 pc 0004ce9b /system/lib/libdvm.so
Stack frame #15 pc 0003fe05 /system/lib/libdvm.so
Stack frame #16 pc 0004fb7f /system/lib/libandroid_runtime.so
Stack frame #17 pc 000508c5 /system/lib/libandroid_runtime.so (android::AndroidRuntime::start(char const*, char const*)+388)
Stack frame #18 pc 0000105b /system/bin/app_process
Stack frame #19 pc 0000e593 /system/lib/libc.so (__libc_init+50)
Stack frame #20 pc 00000d7c /system/bin/app_process