JNI實(shí)現(xiàn)原理
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
插件機(jī)制:
https://github.com/tiann/epic/tree/master/library/src/main/cpp
https://blog.csdn.net/omnispace/article/details/73320940
JNI的實(shí)現(xiàn)可涉及兩個關(guān)鍵類:JNIEnv和JavaVM闰蚕。
JavaVM:這個代表java的虛擬機(jī)霹崎。所有的工作都是從獲取虛擬機(jī)的接口開始的雷酪。
第一種方式阿宅,在加載動態(tài)鏈接庫的時候嚼酝,JVM會調(diào)用JNI_OnLoad(JavaVM* jvm, void* reserved)(如果定義了該函數(shù))。第一個參數(shù)會傳入JavaVM指針扰魂。
第二種方式蝶桶,在native code中調(diào)用JNI_CreateJavaVM(&jvm, (void*)&env, &vm_args)可以得到JavaVM指針。
兩種情況下爱榔,都可以用全局變量被环,比如JavaVM g_jvm來保存獲得的指針以便在任意上下文中使用。
Android系統(tǒng)是利用第二種方式Invocation interface來創(chuàng)建JVM的详幽。
JNIEnv:JNI Interface Pointer, 是提供JNI Native函數(shù)的基礎(chǔ)環(huán)境筛欢,線程相關(guān),不同線程的JNIEnv相互獨(dú)立唇聘。
?JNIEnv只在當(dāng)前線程中有效版姑。本地方法不 能將JNIEnv從一個線程傳遞到另一個線程中。相同的 Java 線程中對本地方法多次調(diào)用時迟郎,傳遞給該本地方法的JNIEnv是相同的剥险。但是,一個本地方法可被不同的 Java 線程所調(diào)用宪肖,因此可以接受不同的 JNIEnv表制。
JavaVM則可以在進(jìn)程中的各線程間共享。理論上一個進(jìn)程可以有多個JavaVM,但Android只允許一個(JavaVm and JIEnv)控乾。需要強(qiáng)調(diào)的是JNIEnv是跟線程相關(guān)的么介。sdk文檔中強(qiáng)調(diào)了do not cache JNIEnv*,要用的時候在不同線程中再通過JavaVM *jvm的方法來獲取與當(dāng)前線程相關(guān)的JNIEnv*蜕衡。兩者都可以理解為函數(shù)表(Function Pointer Table), 前者是使用Java程序創(chuàng)建的運(yùn)行環(huán)境(從屬于一個JVM)提供JNI Native函數(shù)壤短。
注意點(diǎn):
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
## 調(diào)用Java層的方法
1. 通過 `jclass clazz = env->FindClass("含有路徑的類名");` 找到類
2. 通過 `jmethodID mid = env->GetMethodID(clazz,"方法名","方法簽名信息");`找到Java層方法的ID
* 注意 jmethodID 是一個專門記錄 Java 層方法的類型
* 類似的還有一個 jfieldID
3. 通過 `env->CallxxxMethod(jobj,mid,param1,param2...);` 調(diào)用 Java 層的方法
* CallxxxMethod 中的 xxx 是 Java 方法的返回值類型,比如 CallVoidMethod慨仿,CallIntMethod
* 第一個參數(shù)是指調(diào)用哪個對象的方法久脯,就是 Java 中`.`前面的那個對象
* 第二個參數(shù) Java 中的 MethodID
* 后面的參數(shù)就是 Java 方法的參數(shù)了,其類型都要是 java 中能處理的類型镰吆,比如 jstring帘撰,jint,jobject
## get和set Java層的field
1. 通過 `jclass clazz = env->FindClass("含有路徑的類名");` 找到類
2. 通過 `jfieldID fid = env->GetFieldID(clazz,"成員名","成員類型標(biāo)示");`找到Java層成員變量的ID
3. 通過 `GetxxxField(env,obj,fid);` / `SetxxxField(env,obj,fid,value);` 來get/set相應(yīng)的成員變量