Android Jni 用动态库的加载与卸载函数说明

转至:http://blog.sina.com.cn/s/blog_4c451e0e0101339i.html

Android Jni 用动态库的加载与卸载函数说明

一、当 Android 的 Virtual Machine 执行到 System.loadLibrary( "动态库名" ) 函数时,
首先会去执行 C 语言动态库里的 JNI_OnLoad 函数。
它的用途有两个:
1)告诉 Virtual Machine 当前动态库使用了哪个版本的 Jni。
  如果当前动态库中没有提供 JNI_OnLoad 函数,
  Virtual Machine 会默认为动态库使用的是最老的 Jni 1.1 版本。
  由于新版 Jni 做了许多扩充,例如 Jni 1.4 的 java.nio.ByteBuffer。
2)动态库的开发者可以在 JNI_OnLoad 函数中进行动态库内的初始化设置(Initialization), 将此动态库中提供的各个本地函数(Native Function)登记到 Virtual Machine 里, 以便能加快以后调用动态库中的本地函数的效率,就是初始化设置的重要一项。 应用层级的 Java 类通过 Virtual Machine 才能调用到动态库中的本地函数。 如果没有注册登记过的话,Virtual Machine 就在 动态库名.so 里寻找要调用的本地函数。 如果需要连续调用很多次且每次都需要寻找一遍的话,会多花许多时间。 因此 C 语言动态库开发者可以自已将动态库中的本地函数向 Virtual Machine 进行注册登记。
代码示例:(注:由于新浪博客不支持 C 注释,所以请将 /^ ^/ 想像替换为 /星 星/) jint JNI_OnLoad( JavaVM* vm, void* reserved ) { jint jintResult = -1; JNIEnv* env = NULL;
/^Reference types, in C. typedef void* jobject; typedef jobject jclass; ^/ jclass cls = NULL; /^ typedef struct { const char* name; /^ Java 代码中调用的函数名字 ^/ const char* signature; /^ 描述了函数的 参数 和 返回值 ^/ void* fnPtr; /^ 函数指针转成无符号指针 ^/ } JNINativeMethod; 其中比较复杂的是第二个参数, 例如 "()V" 或 "(II)V" 或 "(Ljava/lang/String;)V" 实际上这些字符是与函数的 参数 及 返回值 类型是一一对应的, 括号()中的字符表示参数,括号后面的则代表返回值, 例如 "()V" 就表示 void 函数名();    "(II)V" 就表示 void 函数名( int, int );    "(Ljava/lang/String;)V" 就表示 void 函数名( jstring ); 具体的每一个字符所表示的意义下面部分有所详见 ^/ /^ 动态库中的本地函数信息数组 ^/ JNINativeMethod aJNINativeMethod[] = { { "MeasureDistance", "(Ljava/lang/String;)V", (void*)Java_MyJni_MyNDK_MyDemo_MyJniNDKDemo_MeasureDistance } };
/^ #if defined(__cplusplus) typedef _JNIEnv JNIEnv; typedef _JavaVM JavaVM; #else typedef const struct JNINativeInterface* JNIEnv; typedef const struct JNIInvokeInterface* JavaVM; #endif ^/ /^ JavaVM::GetEnv 原型为 jint (*GetEnv)(JavaVM*, void**, jint); ^/ /^ GetEnv()函数返回的 Jni 环境对每个线程来说是不同的,^/ /^ 因此我们必须在每次进入函数时都要重新获取 ^/ if ( JNI_OK != (*vm)->GetEnv( vm, (void**)env, JNI_VERSION_1_6 ) ) { /^ 输出的 log 一般是到 /dev/log/ 下的三个设备中,可以用 logcat 工具查看 ^/ __android_log_write( ANDROID_LOG_INFO, /^ 日志信息 ^/ "MyJniDemo", /^ 日志标签 ^/ "Call JavaVM::GetEnv failed" ); /^ 日志内容 ^/ return jintResult; /^ 此时返回的是负壹(-1) ^/ }
/^ 如果 将动态库中的本地函数向 Virtual Machine 进行注册登记失败 的话,则 ^/ /^ 由于 aJNINativeMethod 是一组 函数名称 与 函数指针 的对照表, 在程序执行期间可以多次调用registerNativeMethods函数来更换注册登记本地函数 ^/ /^ #if defined(__cplusplus) typedef _JNIEnv JNIEnv; typedef _JavaVM JavaVM; #else typedef const struct JNINativeInterface* JNIEnv; typedef const struct JNIInvokeInterface* JavaVM; #endif ^/ /^ Reference types, in C. typedef void* jobject; typedef jobject jclass; ^/ /^ struct JNINativeInterface 里的函数指针 jint (*RegisterNatives)( JNIEnv*, jclass, const JNINativeMethod*, jint ); ^/ cls = (*env)->FindClass( env, /^ 下面的字符串就是描述 Java 代码中的主类 ^/ "MyJni/MyNDK/MyDemo/MyJniNDKDemo" ); if ( 0 > (*env)->RegisterNatives( env, cls, aJNINativeMethod, sizeof( aJNINativeMethod ) / sizeof( aJNINativeMethod[0] ) ) ) { /^ 输出的 log 一般是到 /dev/log/ 下的三个设备中,可以用 logcat 工具查看 ^/ __android_log_write( ANDROID_LOG_INFO, /^日志信息^/ "MyJniDemo", /^日志标签^/ "Register native methods failed" ); /^日志内容^/ return jintResult; /^ 此时返回的是负壹(-1) ^/ } jintResult = JNI_VERSION_1_6;
/^ 此函数回传 JNI_VERSION_1_6 宏值给 Virtual Machine, 于是 Virtual Machine 就知道当前动态库所使用的 Jni 版本了 ^/ return jintResult; /^ JNI_VERSION_1_6(0x00010006) ^/ }

二、JNI_OnUnload 函数与 JNI_OnLoad 函数相对应。 在 JNI_OnLoad 函数中进行的动态库内的初期化设置, 要在 Virtual Machine 释放该动态库时调用 JNI_OnUnload 函数来进行善后清除。 同 Virtual Machine 调用 JNI_OnLoad 一样, 调用 JNI_Unload 函数时,也会将 JavaVM 的指针做为第一个参数传递,原型如下: jint JNI_OnUnload( JavaVM* vm, void* reserved );
三、JNINativeMethod::signature 描述字符串字符意义说明: 1)基本类型对应关系: 标识符 Jni 类型 C 类型 V void void Z jboolean boolean I jint int J jlong long D jdouble double F jfloat float B jbyte byte C jchar char S jshort short
2)基本类型数组:(则以 [ 开始,用两个字符表示) 标识串 Jni 类型 C 类型 [Z jbooleanArray boolean[] [I jintArray int[] [J jlongArray long[] [D jdoubleArray double[] [F jfloatArray float[] [B jbyteArray byte[] [C jcharArray char[] [S jshortArray short[]
3)类(class):(则以 L 开头,以 ; 结尾,中间是用 / 隔开的 包 及 类名) 标识串        Java 类型  Jni 类型 L包1/包n/类名; 类名     jobject 例子: Ljava/net/Socket; Socket jobject
4)例外(String 类): 标识串 Java 类型 Jni 类型 Ljava/lang/String; String jstring
5)嵌套类(类位于另一个类之中,则用$作为类名间的分隔符) 标识串         Java 类型  Jni 类型 L包1/包n/类名$嵌套类名;     类名     jobject 例子: Landroid/os/FileUtils$FileStatus; FileStatus jobject
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值