注册的本质是建立(Java层)native方法和(Native/C++层)JNI函数之间的一对一关系。静态注册指的是映射规则预先设定,一个native方法名可以转换成一个唯一的JNI函数名。动态注册的映射规则由程序员自己设定,通过结构体将native方法和JNI函数指针绑定起来。
库加载
如果需要在Java中使用so库中的代码,那么首先要做的就是库加载。库加载一般放在static代码块中,保证类加载后第一时间执行。
package com.hangl.jni;
public class TestJNI {
static {
System.loadLibrary(“native”);
}
…
}
众所周知,库加载时会去调用库中的JNI_Onload
函数。在ART源码中,System.loadLibrary
最终会调用JavaVMExt::LoadNativeLibrary
。首先去库中寻找JNI_Onload
符号,将其转成函数指针进行调用。接着,JNI_Onload
函数返回该库所必需的JNI版本号,由虚拟机判断是否支持。
void* sym = library->FindSymbol(“JNI_OnLoad”, nullptr);
using JNI_OnLoadFn = int()(JavaVM, void*);
JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
int version = (*jni_on_load)(this, nullptr);
…
if (version == JNI_ERR) {
StringAppendF(error_msg, “JNI_ERR returned from JNI_OnLoad in “%s””, path.c_str());
} else if (JavaVMExt::IsBadJniVersion(version)) {
StringAppendF(error_msg, “Bad JNI version returned from JNI_OnLoad in “%s”: %d”,
path.c_str(), version);
…
} else {
was_successful = true;
}
当前虚拟机只支持三个JNI版本,如下所示。一般库返回较多的是JNI_VERSION_1_4。与1_4相比,1_6版本的JNI只多了一个GetObjectRefType
函数[链接],如果我们的库用不到这个函数,只需要1_4即可。
bool JavaVMExt::IsBadJniVersion(int version) {
// We don’t support JNI_VERSION_1_1. These are the only other valid versions.
return version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 && ver