Android JNI(实现自己的JNI_OnLoad函数)
发布日期:2021-07-01 05:54:21 浏览次数:2 分类:技术文章

本文共 3214 字,大约阅读时间需要 10 分钟。

简单的Jni 例子都是映射模式,及对应的Jni 的c/c++ 实现需要,被java的函数命名规则限制死,为了解决这类毛病,引入的JNI_OnLoad这类方法。

jint JNI_OnLoad(JavaVM* vm, void* reserved)
该方法在Jni so 被加载时调用。该方法告诉VM此C组件使用高级的JNI版本。如果你的*.so文件没有使用JNI_OnLoad()函数,VM会默认该*.so是使用最老的JNI1.1版本。新版的JNI做了许多的扩充,如果需要使用新版的功能,如JNI 1.4 java.nio.ByteBuffer,就必须藉由JNI_OnLoad()函数来告知VM.

转载自:http://blog.csdn.net/zhenyongyuan123/archive/2010/09/03/5862054.aspx

实现JNI中本地函数注册可以两种方式: 

(1)采用默认的本地函数注册流程。 
(2)自己重写JNI_OnLoad()函数。(本文介绍)(Android中采用这种)

Java端代码:

package com.jni;public class JavaHello {public static native String hello();static {// load library: libtest.sotry {System.loadLibrary("test");} catch (UnsatisfiedLinkError ule) {System.err.println("WARNING: Could not load library!");}}public staticvoid main(String[] args) {String s = new JavaHello().hello();System.out.println(s);}}
本地C语言代码:
#include 
#include
#include
#include
#include
JNIEXPORT jstring JNICALL native_hello(JNIEnv *env, jclass clazz){printf("hello in c native code.\n");return (*env)->NewStringUTF(env, "hello world returned.");}#define JNIREG_CLASS "com/jni/JavaHello"//指定要注册的类/*** Table of methods associated with a single class.*/static JNINativeMethod gMethods[] = {{ "hello", "()Ljava/lang/String;", (void*)native_hello },//绑定};/** Register several native methods for one class.*/static int registerNativeMethods(JNIEnv* env, constchar* className,JNINativeMethod* gMethods, int numMethods){jclass clazz;clazz = (*env)->FindClass(env, className);if (clazz == NULL) {return JNI_FALSE;}if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {return JNI_FALSE;}return JNI_TRUE;}/** Register native methods for all classes we know about.*/static int registerNatives(JNIEnv* env){if (!registerNativeMethods(env, JNIREG_CLASS, gMethods, sizeof(gMethods) / sizeof(gMethods[0])))return JNI_FALSE;return JNI_TRUE;}/** Set some test stuff up.** Returns the JNI version on success, -1 on failure.*/JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){JNIEnv* env = NULL;jint result = -1;if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {return -1;}assert(env != NULL);if (!registerNatives(env)) {//注册return -1;}/* success -- return valid version number */result = JNI_VERSION_1_4;return result;}

编译及运行流程:


Linux环境下:


1 设置三个环境变量: 

export JAVA_HOME:=/usr/lib/jvm/java-6-sun-1.6.0.15 
export JAVA_SRC_PATH:=/home/kortide/Jackey/jni/jni_onload/com/jfo 
export NATIVE_SRC_PATH:=/home/kortide/Jackey/jni/jni_onload/jni


2 编译JavaHello.java: 

javac $JAVA_SRC_PATH/JavaHello.java


3. 编译NativeHello.c,生成共享库 

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -c -o $NATIVE_SRC_PATH/NativeHello.o  $NATIVE_SRC_PATH/NativeHello.c


gcc -fPIC -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -shared -o $NATIVE_SRC_PATH/libtest.so $NATIVE_SRC_PATH/NativeHello.o


4. 运行 

java com/jni/JavaHello


 Windows环境下:


HelloJNI_Load工程



补充:


JNI_OnUnload()函数与JNI_OnLoad()相对应的。在加载C组件时会立即呼叫JNI_OnLoad()来进行组件内的初期动作;而当VM释放该C组件时,则会呼叫JNI_OnUnload()函数来进行善后清除动作。


由于VM通常是多线程(Multi-threading)的执行环境。每一个线程在呼叫JNI_OnLoad()时,所传递进来的JNIEnv指标值都是不同的。为了配合这种多线程的环境,C组件开发者在撰写本地函数时,可藉由JNIEnv指标值之不同而避免线程的数据冲突问题,才能确保所写的本地函数能安全地在Android的多线程VM 里安全地执行。基于这个理由,当在呼叫C组件的函数时,都会将JNIEnv指标值传递给它


 


 

转载地址:https://panda1234lee.blog.csdn.net/article/details/8261806 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:基于 Android NDK 的学习之旅-----目录
下一篇:javah 使用(Javah生成JNI头文件)

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年04月09日 21时08分32秒