JNI原理

JNI实现原理

JNI系列:JavaVM和JNIEnv等原理
http://blog4jimmy.com/2017/11/242.html
http://blog4jimmy.com/category/the_java_native_interface_programmer_guide_and_specificationjni
http://blog.guorongfei.com/2017/01/24/android-jni-tips-md/
https://www.cnblogs.com/fnlingnzb-learner/p/7366025.html
https://www.zybuluo.com/cxm-2016/note/566619
https://blog.csdn.net/omnispace/article/details/73320940
反射:
http://blog4jimmy.com/2017/11/224.html

http://androidxref.com/8.0.0_r4/xref/libnativehelper/include/nativehelper/jni.h

插件机制:
https://github.com/tiann/epic/tree/master/library/src/main/cpp
https://blog.csdn.net/omnispace/article/details/73320940

JNI的实现可涉及两个关键类:JNIEnv和JavaVM。
JavaVM:这个代表java的虚拟机。所有的工作都是从获取虚拟机的接口开始的。
第一种方式,在加载动态链接库的时候,JVM会调用JNI_OnLoad(JavaVM* jvm, void* reserved)(如果定义了该函数)。第一个参数会传入JavaVM指针。
第二种方式,在native code中调用JNI_CreateJavaVM(&jvm, (void*)&env, &vm_args)可以得到JavaVM指针。
两种情况下,都可以用全局变量,比如JavaVM
g_jvm来保存获得的指针以便在任意上下文中使用。
Android系统是利用第二种方式Invocation interface来创建JVM的。

JNIEnv:JNI Interface Pointer, 是提供JNI Native函数的基础环境,线程相关,不同线程的JNIEnv相互独立。
�JNIEnv只在当前线程中有效。本地方法不 能将JNIEnv从一个线程传递到另一个线程中。相同的 Java 线程中对本地方法多次调用时,传递给该本地方法的JNIEnv是相同的。但是,一个本地方法可被不同的 Java 线程所调用,因此可以接受不同的 JNIEnv。

     JavaVM则可以在进程中的各线程间共享。理论上一个进程可以有多个JavaVM,但Android只允许一个(JavaVm and JIEnv)。需要强调的是JNIEnv是跟线程相关的。sdk文档中强调了do not cache JNIEnv*,要用的时候在不同线程中再通过JavaVM *jvm的方法来获取与当前线程相关的JNIEnv*。两者都可以理解为函数表(Function Pointer Table), 前者是使用Java程序创建的运行环境(从属于一个JVM)提供JNI Native函数。

注意点:
http://www.10tiao.com/html/330/201711/2653579453/1.html

pthread_key:
https://zhuanlan.zhihu.com/p/33411235

http://blog.csdn.net/zsl_oo7/article/details/71081291
http://wiki.jikexueyuan.com/project/jni-ndk-developer-guide/function.html

## 调用Java层的方法

1.  通过 `jclass clazz = env->FindClass("含有路径的类名");` 找到类
2.  通过 `jmethodID mid = env->GetMethodID(clazz,"方法名","方法签名信息");`找到Java层方法的ID 

    *   注意 jmethodID 是一个专门记录 Java 层方法的类型
    *   类似的还有一个 jfieldID
3.  通过 `env->CallxxxMethod(jobj,mid,param1,param2...);` 调用 Java 层的方法 

    *   CallxxxMethod 中的 xxx 是 Java 方法的返回值类型,比如 CallVoidMethod,CallIntMethod
    *   第一个参数是指调用哪个对象的方法,就是 Java 中`.`前面的那个对象
    *   第二个参数 Java 中的 MethodID
    *   后面的参数就是 Java 方法的参数了,其类型都要是 java 中能处理的类型,比如 jstring,jint,jobject

## get和set Java层的field

1.  通过 `jclass clazz = env->FindClass("含有路径的类名");` 找到类
2.  通过 `jfieldID fid = env->GetFieldID(clazz,"成员名","成员类型标示");`找到Java层成员变量的ID
3.  通过 `GetxxxField(env,obj,fid);` / `SetxxxField(env,obj,fid,value);` 来get/set相应的成员变量

你可能感兴趣的:(JNI原理)