android JNI 系列 一

    技术2022-05-20  45

    本文介绍一下用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项目,例子如下:

    package org.eshock.jnitest; import android.app.Activity; import android.os.Bundle; public class JNITest extends Activity { public native int plus(int x, int y); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); int x = plus(1,2); android.util.Log.d("jni", String.valueOf(x)); } static { System.loadLibrary("jnitest"); } }

     

    5. 编译该android工程,目的是为了在bin下面生成class文件

    6. 在项目根目录输入: javah -classpath <bin下面类包的根目录> -d jni org.eshock.jnitest.JNITest, 此时会在项目根目的jni文件夹下生成一个org_eshock_jnitest_JNITest.h 文件,

    内容如下:

    /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class org_eshock_jnitest_JNITest */ #ifndef _Included_org_eshock_jnitest_JNITest #define _Included_org_eshock_jnitest_JNITest #ifdef __cplusplus extern "C" { #endif /* * Class: org_eshock_jnitest_JNITest * Method: plus * Signature: (II)I */ JNIEXPORT jint JNICALL Java_org_eshock_jnitest_JNITest_plus (JNIEnv *, jobject, jint, jint); #ifdef __cplusplus } #endif #endif

    7.在jni目录手机创建相应的cpp文件,代码如下:

    #include "org_eshock_jnitest_JNITest.h" JNIEXPORT jint JNICALL Java_org_eshock_jnitest_JNITest_plus (JNIEnv *env, jobject c, jint a, jint b) { return (a + b); }

     

    8. 在jni文件夹下编写Android.mk文件,内容如下:

    LOCAL_PATH :=$(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := jnitest LOCAL_SRC_FILES :=org_eshock_jnitest_JNITest.c include $(BUILD_SHARED_LIBRARY)

    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


    最新回复(0)