Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

gobley/jvm-getter

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jvm-getter

License Crates.io GitHub Actions Workflow Status

⚠️ This library depends on implementation details of Android, not its public APIs. Use at your own risk.

A tiny no_std library for finding JNI_GetCreatedJavaVMs() on Android 24 to 30.

JNI_GetCreatedJavaVMs() is a JNI function that returns the list of Java VM instances that have been created during runtime. Unfortunately, on Android API level 30 or lower, JNI_GetCreatedJavaVMs() is not one of the public APIs. Therefore, the recommended way by the official Android documentation is to use JNI_OnLoad(), which has a JavaVM parameter.

This is painful for cross-platform library developers, especially when the OS feature they want to use is coupled with Java on Android, as they have to provide a way to pass JNIEnv to the library. By using JNI_GetCreatedJavaVMs(), you can retrieve the JavaVM instance, and you can even create JNIEnv instances for threads created on the Rust side.

With jvm-getter, libraries can provide cross-platform interfaces without demaning the consumers to manually handle Java-specific logic for Android. To learn about the strategy to find JNI_GetCreatedJavaVMs() used by jvm-getter, please refer to the documentation of find_jni_get_created_java_vms(). For compatibility, find_jni_get_created_java_vms() is also available on Desktop platforms, including Windows, macOS, and Linux.

How to use

jvm-getter is designed to have only one public function, find_jni_get_created_java_vms. This function directly retrieves the pointer to JNI_GetCreatedJavaVMs without implementing any internal caching. For efficient and safe access to the JavaVM pointer, it is recommended to implement your own caching mechanism. A common approach is to use std::sync::OnceLock or once_cell::sync::OnceCell to store and initialize the JavaVM instance exactly once. The following example demonstrates how to retrieve and cache the JavaVM pointer using jvm-getter and std::sync::OnceLock:

use std::mem::MaybeUninit;
use std::sync::OnceLock;

use jni::sys::{JavaVM as RawJavaVM, JNI_OK};
use jni::JavaVM;

pub fn vm() -> &'static JavaVM {
    static VM: OnceLock<JavaVM> = OnceLock::new();
    VM.get_or_init(|| {
        #[allow(non_snake_case)]
        let JNI_GetCreatedJavaVMs = unsafe {
            jvm_getter::find_jni_get_created_java_vms()
                .expect("could not find JNI_GetCreatedJavaVMs")
        };

        let mut vm: MaybeUninit<*mut RawJavaVM> = MaybeUninit::uninit();
        let status = unsafe { JNI_GetCreatedJavaVMs(vm.as_mut_ptr(), 1, &mut 0) };
        if status != JNI_OK {
            panic!("no JavaVM was found by JNI_GetCreatedJavaVMs");
        }

        let vm = unsafe { JavaVM::from_raw(vm.assume_init()) };
        vm.expect("JNI_GetCreatedJavaVMs returned nullptr")
    })
}

jvm-getter provides several Cargo features to control the behavior of find_jni_get_created_java_vms. Here's the list of the Cargo features:

  • alloc: Enables the use of alloc::vec::Vec (std::vec::Vec) for allocating a memory buffer for libart.so.
  • sym-search: Enables finding JNI_GetCreatedJavaVMs using platform-specific symbol-searching APIs.
    • sym-search-unix: Enables finding using dlsym on Unix systems.
    • sym-search-windows: Enables finding using GetProcAddress on Windows.
  • art-parsing: Enables finding JNI_GetCreatedJavaVMs by directly parsing libart.so.

All features are enabled by default. If you want to completely remove the dependency on the standard library, set default-features to false and enable sym-search and art-parsing only.

If your app targets API level 31 (Android 12) or a higher version, you can also disable art-parsing as JNI_GetCreatedJavaVMs is a public API.

jvm-getter = { version = "0.1", default-features = false, features = [
    "sym-search",
    "art-parsing",
] }

Contribution

If you find a device on which jvm-getter doesn’t run correctly, please report it. If you also succeed in getting jvm-getter to work on that device without breaking compatibility on other supported devices, you’re welcome to open a pull request.

About

JNI_GetCreatedJavaVMs for Android API 24 to 30

Topics

Resources

Stars

Watchers

Forks

Releases

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.