jni_glue/vm.rs
1use super::*;
2
3/// FFI: Use **&VM** instead of *const JavaVM. This represents a global, process-wide Java exection environment.
4///
5/// On Android, there is only one VM per-process, although on desktop it's possible (if rare) to have multiple VMs
6/// within the same process. While this library does not yet support having multiple VMs active simultaniously, please
7/// don't hesitate to [file an issue](https://github.com/MaulingMonkey/jni-bindgen/issues/new) if this is an important
8/// use case for you.
9///
10/// This is a "safe" alternative to jni_sys::JavaVM raw pointers, with the following caveats:
11///
12/// 1) A null vm will result in **undefined behavior**. Java should not be invoking your native functions with a null
13/// *mut JavaVM, however, so I don't believe this is a problem in practice unless you've bindgened the C header
14/// definitions elsewhere, calling them (requiring `unsafe`), and passing null pointers (generally UB for JNI
15/// functions anyways, so can be seen as a caller soundness issue.)
16///
17/// 2) Allowing the underlying JavaVM to be modified is **undefined behavior**. I don't believe the JNI libraries
18/// modify the JavaVM, so as long as you're not accepting a *mut JavaVM elsewhere, using unsafe to dereference it,
19/// and mucking with the methods on it yourself, I believe this "should" be fine.
20#[repr(transparent)]
21pub struct VM(JavaVM);
22impl VM {
23 pub fn as_java_vm(&self) -> *const JavaVM { &self.0 }
24 pub unsafe fn from_jni_local(vm: &JavaVM) -> &VM { &*(vm as *const JavaVM as *const VM) }
25
26 pub fn with_env<F, R>(&self, callback: F) -> R
27 where
28 F: FnOnce(&Env) -> R,
29 {
30 let java_vm = self.as_java_vm() as *mut JavaVM;
31 let mut env = null_mut();
32 match unsafe { (**java_vm).GetEnv.unwrap()(java_vm, &mut env, JNI_VERSION_1_2) } {
33 JNI_OK => callback(unsafe { Env::from_jni_void_ref(&env) }),
34 JNI_EDETACHED => match unsafe { (**java_vm).AttachCurrentThread.unwrap()(java_vm, &mut env, null_mut()) } {
35 JNI_OK => callback(unsafe { Env::from_jni_void_ref(&env) }),
36 unexpected => panic!("AttachCurrentThread returned unknown error: {}", unexpected),
37 },
38 JNI_EVERSION => panic!("GetEnv returned JNI_EVERSION"),
39 unexpected => panic!("GetEnv returned unknown error: {}", unexpected),
40 }
41 }
42}
43
44unsafe impl Send for VM {}
45unsafe impl Sync for VM {}