rust global jvm

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

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注