JNI 接口指针(JNIEnv)仅在当前线程中有效。 如果另一个线程需要访问 Java VM,它必须首先调用 AttachCurrentThread() 将自己附加到 VM 并获取 JNI 接口指针(JNIEnv)。 一旦连接到 VM, native线程就像在native方法中运行的普通 Java 线程一样工作。 native线程一直连接到 VM,直到它调用 DetachCurrentThread() 来分离自己。
https://github.com/sfackler/rust-jni-sys/blob/master/src/lib.rs
这里定义了
pub type JavaVM = *const JNIInvokeInterface_;
#[repr(C)]
#[derive(Copy)]
pub struct JNIInvokeInterface_ {
pub reserved0: *mut c_void,
pub reserved1: *mut c_void,
pub reserved2: *mut c_void,
pub DestroyJavaVM: Option<unsafe extern "system" fn(vm: *mut JavaVM) -> jint>,
pub AttachCurrentThread: Option<
unsafe extern "system" fn(vm: *mut JavaVM,
penv: *mut *mut c_void,
args: *mut c_void)
-> jint,
>,
pub DetachCurrentThread: Option<unsafe extern "system" fn(vm: *mut JavaVM) -> jint>,
pub GetEnv: Option<
unsafe extern "system" fn(vm: *mut JavaVM,
penv: *mut *mut c_void,
version: jint)
-> jint,
>,
pub AttachCurrentThreadAsDaemon: Option<
unsafe extern "system" fn(vm: *mut JavaVM,
penv: *mut *mut c_void,
args: *mut c_void)
-> jint,
>,
}
impl Clone for JNIInvokeInterface_ {
fn clone(&self) -> Self {
*self
}
}
这就是一个JNI C接口在rust中的表示。
可以Copy, 可以Clone
在 https://github.com/jni-rs/jni-rs/blob/master/src/wrapper/java_vm/vm.rs 中
#[repr(transparent)]
pub struct JavaVM(*mut sys::JavaVM);
...
impl JavaVM {
...
pub unsafe fn from_raw(ptr: *mut sys::JavaVM) -> Result<self> {
non_null!(ptr, "from_raw ptr argument");
Ok(JavaVM(ptr))
}
pub fn get_java_vm_pointer(&self) -> *mut sys::JavaVM {
self.0
}
可以看到,直接从sys::JavaVM生成的
而JNI_OnLoad在rust中的签名是
pub unsafe extern "system" fn JNI_OnLoad(vm: *const JavaVM, _reserved: *const c_void) -> jint pub unsafe extern fn JNI_OnLoad(vm: *mut JavaVM, reserved: *mut c_void) -> jint
或者
#[allow(non_snake_case)]
#[no_mangle]
pub extern "system" fn JNI_OnLoad(vm: JavaVM, _: *mut c_void) -> jint {
let env = vm.get_env().expect("Cannot get reference to the JNIEnv");
JNI_VERSION_1_8
}
JNIEnv是一个用来在Java和Native代码之间通信的结构体的指针。
这个通信的ABI几乎由每个JVM(和Android)实现。
这个结构体有多个版本,所以为什么要在JNIEnv里有GetVersion这个玩意。