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这个玩意。