1use crate::{JNI_OK, JNIEnv, JNIInvPtr, JavaVM, JavaVMInitArgs, JavaVMOption, jint};
2
3use alloc::ffi::CString;
4use alloc::vec::Vec;
5use core::ffi::{c_char, c_void};
6use core::ptr::null_mut;
7use sync_ptr::SyncMutPtr;
8
9#[cfg(feature = "loadjvm")]
10use alloc::boxed::Box;
11#[cfg(feature = "loadjvm")]
12use alloc::string::String;
13#[cfg(all(feature = "loadjvm", not(feature = "dynlink")))]
14use alloc::string::ToString;
15#[cfg(feature = "loadjvm")]
16use core::error::Error;
17#[cfg(feature = "loadjvm")]
18use core::fmt::{Display, Formatter};
19
20#[cfg(not(feature = "dynlink"))]
21use crate::jsize;
22
23#[cfg(not(feature = "dynlink"))]
24use sync_ptr::{SyncFnPtr, sync_fn_ptr_from_addr};
25
26#[cfg(feature = "dynlink")]
30mod dynlink {
31 use crate::{JNIEnv, JNIInvPtr, JavaVMInitArgs, jint, jsize};
32
33 unsafe extern "system" {
34 pub fn JNI_CreateJavaVM(invoker: *mut JNIInvPtr, env: *mut JNIEnv, initargs: *mut JavaVMInitArgs) -> jint;
35 pub fn JNI_GetCreatedJavaVMs(array: *mut JNIInvPtr, len: jsize, out: *mut jsize) -> jint;
36 }
37}
38
39#[cfg(not(feature = "dynlink"))]
41type JNI_CreateJavaVM = unsafe extern "C" fn(*mut JNIInvPtr, *mut JNIEnv, *mut JavaVMInitArgs) -> jint;
42
43#[cfg(not(feature = "dynlink"))]
45type JNI_GetCreatedJavaVMs = unsafe extern "C" fn(*mut JNIInvPtr, jsize, *mut jsize) -> jint;
46
47#[cfg(not(feature = "dynlink"))]
49#[derive(Debug, Copy, Clone)]
50pub struct JNIDynamicLink {
51 JNI_CreateJavaVM: SyncFnPtr<JNI_CreateJavaVM>,
53 JNI_GetCreatedJavaVMs: SyncFnPtr<JNI_GetCreatedJavaVMs>,
55}
56
57#[cfg(not(feature = "dynlink"))]
58impl JNIDynamicLink {
59 #[must_use]
63 pub fn new(JNI_CreateJavaVM: *const c_void, JNI_GetCreatedJavaVMs: *const c_void) -> Self {
64 assert!(!JNI_GetCreatedJavaVMs.is_null(), "JNI_GetCreatedJavaVMs is null");
65 assert!(!JNI_CreateJavaVM.is_null(), "JNI_CreateJavaVM is null");
66
67 unsafe {
68 Self {
69 JNI_CreateJavaVM: sync_fn_ptr_from_addr!(JNI_CreateJavaVM, JNI_CreateJavaVM),
70 JNI_GetCreatedJavaVMs: sync_fn_ptr_from_addr!(JNI_GetCreatedJavaVMs, JNI_GetCreatedJavaVMs),
71 }
72 }
73 }
74
75 #[must_use]
77 pub fn JNI_CreateJavaVM(&self) -> JNI_CreateJavaVM {
78 self.JNI_CreateJavaVM.unwrap()
79 }
80
81 #[must_use]
83 pub fn JNI_GetCreatedJavaVMs(&self) -> JNI_GetCreatedJavaVMs {
84 self.JNI_GetCreatedJavaVMs.unwrap()
85 }
86}
87
88#[cfg(feature = "std")]
89#[cfg(not(feature = "dynlink"))]
90mod std_link {
92 use crate::linking::JNIDynamicLink;
93
94 static LINK: std::sync::RwLock<Option<JNIDynamicLink>> = std::sync::RwLock::new(None);
96
97 pub fn link_write() -> std::sync::RwLockWriteGuard<'static, Option<JNIDynamicLink>> {
99 LINK.write().unwrap_or_else(|e| {
100 LINK.clear_poison();
101 e.into_inner()
102 })
103 }
104
105 pub fn link_read() -> std::sync::RwLockReadGuard<'static, Option<JNIDynamicLink>> {
107 LINK.read().unwrap_or_else(|e| {
108 LINK.clear_poison();
109 e.into_inner()
110 })
111 }
112}
113
114#[cfg(feature = "std")]
115#[cfg(not(feature = "dynlink"))]
116pub use std_link::{link_read, link_write};
117
118#[cfg(not(feature = "std"))]
119#[cfg(not(feature = "dynlink"))]
120mod spin_link {
122 use crate::linking::JNIDynamicLink;
128 use core::cell::UnsafeCell;
129 use core::ops::{Deref, DerefMut};
130 use core::sync::atomic::AtomicUsize;
131 use core::sync::atomic::Ordering::SeqCst;
132
133 struct UCellWrapper(UnsafeCell<Option<JNIDynamicLink>>);
135 unsafe impl Send for UCellWrapper {}
136 unsafe impl Sync for UCellWrapper {}
137
138 static LOCK: AtomicUsize = AtomicUsize::new(0);
142
143 static LINK: UCellWrapper = UCellWrapper(UnsafeCell::new(None));
145
146 const USIZE_HALF: usize = usize::MAX / 2;
148
149 pub struct SpinLockGuard;
151 impl Deref for SpinLockGuard {
152 type Target = Option<JNIDynamicLink>;
153
154 fn deref(&self) -> &Self::Target {
155 unsafe { &*LINK.0.get() }
156 }
157 }
158
159 impl Drop for SpinLockGuard {
160 fn drop(&mut self) {
161 let r = LOCK.fetch_sub(1, SeqCst);
162 debug_assert!(r != 0);
163 }
164 }
165
166 pub struct SpinLockGuardMut;
168
169 impl Deref for SpinLockGuardMut {
170 type Target = Option<JNIDynamicLink>;
171
172 fn deref(&self) -> &Self::Target {
173 unsafe { &*LINK.0.get() }
174 }
175 }
176
177 impl DerefMut for SpinLockGuardMut {
178 fn deref_mut(&mut self) -> &mut Self::Target {
179 unsafe { &mut *LINK.0.get() }
180 }
181 }
182
183 impl Drop for SpinLockGuardMut {
184 fn drop(&mut self) {
185 let r = LOCK.fetch_sub(USIZE_HALF, SeqCst);
186 debug_assert!(r >= USIZE_HALF);
187 }
188 }
189
190 pub fn link_write() -> SpinLockGuardMut {
192 loop {
193 if LOCK.compare_exchange(0, USIZE_HALF, SeqCst, SeqCst).is_ok() {
194 return SpinLockGuardMut;
195 }
196
197 core::hint::spin_loop();
198 }
199 }
200
201 pub fn link_read() -> SpinLockGuard {
203 loop {
204 if LOCK.fetch_add(1, SeqCst) < USIZE_HALF - 1 {
208 return SpinLockGuard;
209 }
210 LOCK.fetch_sub(1, SeqCst);
211
212 core::hint::spin_loop();
213 }
214 }
215}
216
217#[cfg(not(feature = "std"))]
218#[cfg(not(feature = "dynlink"))]
219pub use spin_link::{link_read, link_write};
220
221#[cfg(not(feature = "dynlink"))]
235#[must_use]
236pub fn init_dynamic_link(JNI_CreateJavaVM: *const c_void, JNI_GetCreatedJavaVMs: *const c_void) -> bool {
237 let mut guard = link_write();
238 if guard.is_some() {
239 return false;
240 }
241
242 *guard = Some(JNIDynamicLink::new(JNI_CreateJavaVM, JNI_GetCreatedJavaVMs));
243 true
244}
245
246#[cfg(feature = "dynlink")]
257#[allow(clippy::missing_const_for_fn)]
258#[must_use]
259pub fn init_dynamic_link(_: *const c_void, _: *const c_void) -> bool {
260 false
262}
263
264#[cfg(not(feature = "dynlink"))]
268#[must_use]
269pub fn is_jvm_loaded() -> bool {
270 link_read().is_some()
271}
272
273#[cfg(not(feature = "dynlink"))]
277fn get_link() -> JNIDynamicLink {
278 link_read().expect("jni_simple::init_dynamic_link not called")
279}
280
281#[cfg(feature = "dynlink")]
285#[must_use]
286#[allow(clippy::missing_const_for_fn)]
287pub fn is_jvm_loaded() -> bool {
288 true
289}
290
291#[cfg(feature = "loadjvm")]
292#[non_exhaustive]
293#[derive(Debug)]
294pub enum LoadFromLibraryError {
295 AlreadyLoaded,
297 LoadingSharedObjectFailed {
299 path: String,
301 error: Box<dyn Error>,
303 },
304 JNICreateJavaVmNotFound {
306 path: String,
308 error: Box<dyn Error>,
310 },
311 JNIGetCreatedJavaVMsNotFound {
313 path: String,
315 error: Box<dyn Error>,
317 },
318}
319
320#[cfg(feature = "loadjvm")]
321impl Display for LoadFromLibraryError {
322 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
323 match self {
324 Self::AlreadyLoaded => f.write_str("The dynamic linker has already loaded the jvm."),
325 Self::LoadingSharedObjectFailed { .. } => f.write_str("The dynamic linker failed to load the jvm shared object."),
326 Self::JNICreateJavaVmNotFound { .. } => f.write_str("The dynamic linker could not find the JNI_CreateJavaVM symbol in the shared object."),
327 Self::JNIGetCreatedJavaVMsNotFound { .. } => f.write_str("The dynamic linker could not find the JNI_GetCreatedJavaVMs symbol in the shared object."),
328 }
329 }
330}
331
332#[cfg(feature = "loadjvm")]
333impl Error for LoadFromLibraryError {
334 fn source(&self) -> Option<&(dyn Error + 'static)> {
335 match self {
336 Self::AlreadyLoaded => None,
337 Self::LoadingSharedObjectFailed { error, .. } | Self::JNICreateJavaVmNotFound { error, .. } | Self::JNIGetCreatedJavaVMsNotFound { error, .. } => Some(&**error),
338 }
339 }
340}
341
342#[cfg(feature = "loadjvm")]
346impl From<LoadFromLibraryError> for String {
347 fn from(value: LoadFromLibraryError) -> Self {
348 alloc::format!("{value}")
349 }
350}
351
352#[cfg(feature = "loadjvm")]
366#[cfg(not(feature = "dynlink"))]
367pub unsafe fn load_jvm_from_library(path: &str) -> Result<(), LoadFromLibraryError> {
368 let mut guard = link_write();
369 if guard.is_some() {
370 drop(guard);
371 return Err(LoadFromLibraryError::AlreadyLoaded);
372 }
373
374 unsafe {
375 let lib = libloading::Library::new(path).map_err(|e| LoadFromLibraryError::LoadingSharedObjectFailed {
376 path: path.to_string(),
377 error: Box::new(e),
378 })?;
379
380 #[cfg(any(target_os = "netbsd", target_vendor = "apple"))]
386 let lib = core::mem::ManuallyDrop::new(lib);
387
388 let JNI_CreateJavaVM_ptr = lib
389 .get::<JNI_CreateJavaVM>(b"JNI_CreateJavaVM\0")
390 .map_err(|e| LoadFromLibraryError::JNICreateJavaVmNotFound {
391 path: path.to_string(),
392 error: Box::new(e),
393 })?
394 .try_as_raw_ptr()
395 .ok_or_else(|| LoadFromLibraryError::JNICreateJavaVmNotFound {
396 path: path.to_string(),
397 error: Box::new(libloading::Error::DlSymUnknown),
398 })?;
399
400 if JNI_CreateJavaVM_ptr.is_null() {
401 return Err(LoadFromLibraryError::JNICreateJavaVmNotFound {
402 path: path.to_string(),
403 error: Box::new(libloading::Error::DlSymUnknown),
404 });
405 }
406
407 let JNI_GetCreatedJavaVMs_ptr = lib
408 .get::<JNI_GetCreatedJavaVMs>(b"JNI_GetCreatedJavaVMs\0")
409 .map_err(|e| LoadFromLibraryError::JNIGetCreatedJavaVMsNotFound {
410 path: path.to_string(),
411 error: Box::new(e),
412 })?
413 .try_as_raw_ptr()
414 .ok_or_else(|| LoadFromLibraryError::JNIGetCreatedJavaVMsNotFound {
415 path: path.to_string(),
416 error: Box::new(libloading::Error::DlSymUnknown),
417 })?;
418
419 if JNI_GetCreatedJavaVMs_ptr.is_null() {
420 return Err(LoadFromLibraryError::JNIGetCreatedJavaVMsNotFound {
421 path: path.to_string(),
422 error: Box::new(libloading::Error::DlSymUnknown),
423 });
424 }
425
426 #[cfg(not(any(target_os = "netbsd", target_vendor = "apple")))] core::mem::forget(lib);
429 *guard = Some(JNIDynamicLink::new(JNI_CreateJavaVM_ptr, JNI_GetCreatedJavaVMs_ptr));
430 drop(guard);
431 }
432
433 Ok(())
434}
435
436#[cfg(feature = "loadjvm")]
450#[cfg(feature = "dynlink")]
451pub unsafe fn load_jvm_from_library(_: &str) -> Result<(), LoadFromLibraryError> {
452 Err(LoadFromLibraryError::AlreadyLoaded)
453}
454
455#[cfg(feature = "loadjvm")]
456#[cfg(feature = "std")]
457#[non_exhaustive]
458#[derive(Debug)]
459pub enum LoadFromJavaHomeError {
460 AlreadyLoaded,
462 LoadingSharedObjectFailed {
464 path: String,
466 error: Box<dyn Error>,
468 },
469 JNICreateJavaVmNotFound {
471 path: String,
473 error: Box<dyn Error>,
475 },
476 JNIGetCreatedJavaVMsNotFound {
478 path: String,
480 error: Box<dyn Error>,
482 },
483 UnknownJavaHomeLayout,
485 IOError(std::io::Error),
487 EnvironmentVariableError(std::env::VarError),
489}
490
491#[cfg(feature = "loadjvm")]
492#[cfg(feature = "std")]
493impl From<LoadFromJavaHomeFolderError> for LoadFromJavaHomeError {
494 fn from(value: LoadFromJavaHomeFolderError) -> Self {
495 match value {
496 LoadFromJavaHomeFolderError::AlreadyLoaded => Self::AlreadyLoaded,
497 LoadFromJavaHomeFolderError::LoadingSharedObjectFailed { path, error } => Self::LoadingSharedObjectFailed { path, error },
498 LoadFromJavaHomeFolderError::JNICreateJavaVmNotFound { path, error } => Self::JNICreateJavaVmNotFound { path, error },
499 LoadFromJavaHomeFolderError::JNIGetCreatedJavaVMsNotFound { path, error } => Self::JNIGetCreatedJavaVMsNotFound { path, error },
500 LoadFromJavaHomeFolderError::UnknownJavaHomeLayout => Self::UnknownJavaHomeLayout,
501 LoadFromJavaHomeFolderError::IOError(e) => Self::IOError(e),
502 }
503 }
504}
505
506#[cfg(feature = "loadjvm")]
507#[cfg(feature = "std")]
508impl From<LoadFromLibraryError> for LoadFromJavaHomeError {
509 fn from(value: LoadFromLibraryError) -> Self {
510 match value {
511 LoadFromLibraryError::AlreadyLoaded => Self::AlreadyLoaded,
512 LoadFromLibraryError::LoadingSharedObjectFailed { path, error } => Self::LoadingSharedObjectFailed { path, error },
513 LoadFromLibraryError::JNICreateJavaVmNotFound { path, error } => Self::JNICreateJavaVmNotFound { path, error },
514 LoadFromLibraryError::JNIGetCreatedJavaVMsNotFound { path, error } => Self::JNIGetCreatedJavaVMsNotFound { path, error },
515 }
516 }
517}
518
519#[cfg(feature = "loadjvm")]
520#[cfg(feature = "std")]
521impl Display for LoadFromJavaHomeError {
522 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
523 match self {
524 Self::AlreadyLoaded => f.write_str("The dynamic linker has already loaded the jvm."),
525 Self::LoadingSharedObjectFailed { .. } => f.write_str("The dynamic linker failed to load the jvm shared object."),
526 Self::JNICreateJavaVmNotFound { .. } => f.write_str("The dynamic linker could not find the JNI_CreateJavaVM symbol in the shared object."),
527 Self::JNIGetCreatedJavaVMsNotFound { .. } => f.write_str("The dynamic linker could not find the JNI_GetCreatedJavaVMs symbol in the shared object."),
528 Self::UnknownJavaHomeLayout => f.write_str("The layout of the java installation was not recognized."),
529 Self::IOError(_) => f.write_str("I/O Error while determining the layout of the java installation."),
530 Self::EnvironmentVariableError(_) => f.write_str("The environment variable JAVA_HOME is invalid"),
531 }
532 }
533}
534
535#[cfg(feature = "loadjvm")]
536#[cfg(feature = "std")]
537impl Error for LoadFromJavaHomeError {
538 fn source(&self) -> Option<&(dyn Error + 'static)> {
539 match self {
540 Self::AlreadyLoaded | Self::UnknownJavaHomeLayout => None,
541 Self::LoadingSharedObjectFailed { error, .. } | Self::JNICreateJavaVmNotFound { error, .. } | Self::JNIGetCreatedJavaVMsNotFound { error, .. } => Some(&**error),
542 Self::IOError(e) => Some(e),
543 Self::EnvironmentVariableError(e) => Some(e),
544 }
545 }
546}
547
548#[cfg(feature = "loadjvm")]
552#[cfg(feature = "std")]
553impl From<LoadFromJavaHomeError> for String {
554 fn from(value: LoadFromJavaHomeError) -> Self {
555 alloc::format!("{value}")
556 }
557}
558
559#[cfg(feature = "loadjvm")]
571#[cfg(feature = "std")]
572pub unsafe fn load_jvm_from_java_home() -> Result<(), LoadFromJavaHomeError> {
573 let java_home = std::env::var("JAVA_HOME").map_err(LoadFromJavaHomeError::EnvironmentVariableError)?;
574
575 unsafe {
576 load_jvm_from_java_home_folder(&java_home)?;
577 }
578 Ok(())
579}
580
581#[cfg(feature = "loadjvm")]
583#[cfg(feature = "std")]
584#[non_exhaustive]
585#[derive(Debug)]
586pub enum LoadFromJavaHomeFolderError {
587 AlreadyLoaded,
589 LoadingSharedObjectFailed {
591 path: String,
593 error: Box<dyn Error>,
595 },
596 JNICreateJavaVmNotFound {
598 path: String,
600 error: Box<dyn Error>,
602 },
603 JNIGetCreatedJavaVMsNotFound {
605 path: String,
607 error: Box<dyn Error>,
609 },
610 UnknownJavaHomeLayout,
612 IOError(std::io::Error),
614}
615
616#[cfg(feature = "loadjvm")]
617#[cfg(feature = "std")]
618impl Display for LoadFromJavaHomeFolderError {
619 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
620 match self {
621 Self::AlreadyLoaded => f.write_str("The dynamic linker has already loaded the jvm."),
622 Self::LoadingSharedObjectFailed { .. } => f.write_str("The dynamic linker failed to load the jvm shared object."),
623 Self::JNICreateJavaVmNotFound { .. } => f.write_str("The dynamic linker could not find the JNI_CreateJavaVM symbol in the shared object."),
624 Self::JNIGetCreatedJavaVMsNotFound { .. } => f.write_str("The dynamic linker could not find the JNI_GetCreatedJavaVMs symbol in the shared object."),
625 Self::UnknownJavaHomeLayout => f.write_str("The layout of the java installation was not recognized."),
626 Self::IOError(_) => f.write_str("I/O Error while determining the layout of the java installation."),
627 }
628 }
629}
630
631#[cfg(feature = "loadjvm")]
632#[cfg(feature = "std")]
633impl From<LoadFromLibraryError> for LoadFromJavaHomeFolderError {
634 fn from(value: LoadFromLibraryError) -> Self {
635 match value {
636 LoadFromLibraryError::AlreadyLoaded => Self::AlreadyLoaded,
637 LoadFromLibraryError::LoadingSharedObjectFailed { path, error } => Self::LoadingSharedObjectFailed { path, error },
638 LoadFromLibraryError::JNICreateJavaVmNotFound { path, error } => Self::JNICreateJavaVmNotFound { path, error },
639 LoadFromLibraryError::JNIGetCreatedJavaVMsNotFound { path, error } => Self::JNIGetCreatedJavaVMsNotFound { path, error },
640 }
641 }
642}
643
644#[cfg(feature = "loadjvm")]
648#[cfg(feature = "std")]
649impl From<LoadFromJavaHomeFolderError> for String {
650 fn from(value: LoadFromJavaHomeFolderError) -> Self {
651 alloc::format!("{value}")
652 }
653}
654
655#[cfg(feature = "loadjvm")]
665#[cfg(feature = "std")]
666pub unsafe fn load_jvm_from_java_home_folder(java_home: &str) -> Result<(), LoadFromJavaHomeFolderError> {
667 static COMMON_LIBJVM_PATHS: &[&[&str]] = &[
669 #[cfg(all(unix, not(target_vendor = "apple")))]
670 &["lib", "server", "libjvm.so"], #[cfg(all(unix, not(target_vendor = "apple")))]
672 &["jre", "lib", "amd64", "server", "libjvm.so"], #[cfg(all(unix, not(target_vendor = "apple")))]
674 &["lib", "amd64", "server", "libjvm.so"], #[cfg(all(unix, not(target_vendor = "apple")))]
676 &["jre", "lib", "aarch32", "server", "libjvm.so"], #[cfg(all(unix, not(target_vendor = "apple")))]
678 &["lib", "aarch32", "server", "libjvm.so"], #[cfg(all(unix, not(target_vendor = "apple")))]
680 &["jre", "lib", "aarch64", "server", "libjvm.so"], #[cfg(all(unix, not(target_vendor = "apple")))]
682 &["lib", "aarch64", "server", "libjvm.so"], #[cfg(windows)]
685 &["jre", "bin", "server", "jvm.dll"], #[cfg(windows)]
687 &["bin", "server", "jvm.dll"], #[cfg(target_vendor = "apple")]
690 &["jre", "lib", "server", "libjvm.dylib"], #[cfg(target_vendor = "apple")]
692 &["Contents", "Home", "jre", "lib", "server", "libjvm.dylib"], #[cfg(target_vendor = "apple")]
694 &["lib", "server", "libjvm.dylib"], #[cfg(target_vendor = "apple")]
696 &["Contents", "Home", "lib", "server", "libjvm.dylib"], ];
698
699 for parts in COMMON_LIBJVM_PATHS {
700 let mut buf = std::path::PathBuf::from(java_home);
701 for part in *parts {
702 buf.push(part);
703 }
704
705 if buf.try_exists().map_err(LoadFromJavaHomeFolderError::IOError)? {
706 let full_path = buf
707 .to_str()
708 .ok_or_else(|| LoadFromJavaHomeFolderError::IOError(std::io::Error::other("Failed to concatenate JAVA_HOME library path")))?;
709
710 unsafe {
711 load_jvm_from_library(full_path)?;
712 }
713
714 return Ok(());
715 }
716 }
717
718 Err(LoadFromJavaHomeFolderError::UnknownJavaHomeLayout)
719}
720
721pub unsafe fn JNI_GetCreatedJavaVMs(vms: &mut [Option<JavaVM>]) -> Result<usize, jint> {
747 #[cfg(not(feature = "dynlink"))]
748 let link = get_link().JNI_GetCreatedJavaVMs();
749 #[cfg(feature = "dynlink")]
750 let link = dynlink::JNI_GetCreatedJavaVMs;
751
752 let mut buf: [JNIInvPtr; 64] = [SyncMutPtr::null(); 64];
755 let mut count: jint = 0;
756 let res = unsafe { link(buf.as_mut_ptr(), 64, &raw mut count) };
757 if res != JNI_OK {
758 return Err(res);
759 }
760
761 let count = usize::try_from(count).expect("JNI_GetCreatedJavaVMs did set count to < 0");
762
763 for (i, env) in buf.into_iter().enumerate().take(count) {
764 assert!(!env.is_null(), "JNI_GetCreatedJavaVMs VM #{i} is null! count is {count}");
765 }
766
767 for (i, target) in vms.iter_mut().enumerate() {
768 if i >= count {
769 *target = None;
770 continue;
771 }
772
773 *target = Some(JavaVM { vtable: buf[i] });
774 }
775
776 Ok(count)
777}
778pub unsafe fn JNI_GetCreatedJavaVMs_first() -> Result<Option<JavaVM>, jint> {
795 unsafe {
796 let mut vm = [None];
797 _ = JNI_GetCreatedJavaVMs(vm.as_mut())?;
798 Ok(vm[0])
799 }
800}
801
802pub unsafe fn JNI_CreateJavaVM(arguments: *mut JavaVMInitArgs) -> Result<(JavaVM, JNIEnv), jint> {
818 #[cfg(feature = "asserts")]
819 {
820 assert!(!arguments.is_null(), "JNI_CreateJavaVM arguments must not be null");
821 }
822
823 #[cfg(not(feature = "dynlink"))]
824 let link = get_link().JNI_CreateJavaVM();
825 #[cfg(feature = "dynlink")]
826 let link = dynlink::JNI_CreateJavaVM;
827
828 let mut jvm: JNIInvPtr = SyncMutPtr::null();
829 let mut env: JNIEnv = JNIEnv { vtable: null_mut() };
830
831 let res = unsafe { link(&raw mut jvm, &raw mut env, arguments) };
832 if res != JNI_OK {
833 return Err(res);
834 }
835
836 assert!(!jvm.is_null(), "JNI_CreateJavaVM returned JNI_OK but the JavaVM pointer is null");
837
838 assert!(!env.vtable.is_null(), "JNI_CreateJavaVM returned JNI_OK but the JNIEnv pointer is null");
839
840 Ok((JavaVM { vtable: jvm }, env))
841}
842
843pub unsafe fn JNI_CreateJavaVM_with_string_args<T: AsRef<str>>(version: jint, arguments: &[T], ignore_unrecognized_options: bool) -> Result<(JavaVM, JNIEnv), jint> {
923 unsafe {
924 struct DropGuard(*mut c_char);
926 impl Drop for DropGuard {
927 fn drop(&mut self) {
928 unsafe {
929 _ = CString::from_raw(self.0);
930 }
931 }
932 }
933
934 let mut vm_args: Vec<JavaVMOption> = Vec::with_capacity(arguments.len());
935 let mut dealloc_list = Vec::with_capacity(arguments.len());
936 for arg in arguments {
937 let jvm_arg = CString::new(arg.as_ref()).expect("Argument contains 0 byte").into_raw();
938 dealloc_list.push(DropGuard(jvm_arg));
939
940 vm_args.push(JavaVMOption {
941 optionString: jvm_arg,
942 extraInfo: null_mut(),
943 });
944 }
945
946 let mut args = JavaVMInitArgs {
947 version,
948 nOptions: i32::try_from(vm_args.len()).expect("Too many arguments"),
949 options: vm_args.as_mut_ptr(),
950 ignoreUnrecognized: u8::from(ignore_unrecognized_options),
951 };
952
953 let result = JNI_CreateJavaVM(&raw mut args);
954 drop(dealloc_list);
955 result
956 }
957}