use crate::sys::jni;
use std::ffi::{CStr, CString};
use std::marker::PhantomData;
use std::ptr;
use std::rc::Rc;
pub struct JniEnv {
env: *mut jni::JNIEnv,
_not_send_sync: PhantomData<Rc<()>>,
}
impl JniEnv {
pub unsafe fn from_raw(env: *mut jni::JNIEnv) -> Self {
JniEnv { env, _not_send_sync: PhantomData }
}
pub fn raw(&self) -> *mut jni::JNIEnv {
self.env
}
pub fn get_java_vm(&self) -> Result<*mut jni::JavaVM, jni::jint> {
let mut vm: *mut jni::JavaVM = ptr::null_mut();
unsafe {
let vtable = *self.env;
let result = ((*vtable).GetJavaVM)(self.env, &mut vm);
if result == 0 { Ok(vm) } else { Err(result) }
}
}
pub fn get_version(&self) -> jni::jint {
unsafe {
let vtable = *self.env;
((*vtable).GetVersion)(self.env)
}
}
pub fn find_class(&self, name: &str) -> Option<jni::jclass> {
let c_name = CString::new(name).ok()?;
unsafe {
let vtable = *self.env;
let cls = ((*vtable).FindClass)(self.env, c_name.as_ptr());
if cls.is_null() { None } else { Some(cls) }
}
}
pub fn define_class(&self, name: &str, loader: jni::jobject, bytes: &[u8]) -> Option<jni::jclass> {
if bytes.len() > jni::jsize::MAX as usize {
return None;
}
let c_name = CString::new(name).ok()?;
unsafe {
let vtable = *self.env;
let cls = ((*vtable).DefineClass)(
self.env,
c_name.as_ptr(),
loader,
bytes.as_ptr() as *const jni::jbyte,
bytes.len() as jni::jsize,
);
if cls.is_null() { None } else { Some(cls) }
}
}
pub fn get_superclass(&self, cls: jni::jclass) -> Option<jni::jclass> {
unsafe {
let vtable = *self.env;
let super_cls = ((*vtable).GetSuperclass)(self.env, cls);
if super_cls.is_null() { None } else { Some(super_cls) }
}
}
pub fn is_assignable_from(&self, cls1: jni::jclass, cls2: jni::jclass) -> bool {
unsafe {
let vtable = *self.env;
((*vtable).IsAssignableFrom)(self.env, cls1, cls2) != 0
}
}
pub fn get_object_class(&self, obj: jni::jobject) -> jni::jclass {
unsafe {
let vtable = *self.env;
((*vtable).GetObjectClass)(self.env, obj)
}
}
pub fn is_instance_of(&self, obj: jni::jobject, cls: jni::jclass) -> bool {
unsafe {
let vtable = *self.env;
((*vtable).IsInstanceOf)(self.env, obj, cls) != 0
}
}
pub fn class_loader_parent(&self, loader: jni::jobject) -> Option<jni::jobject> {
if loader.is_null() {
return None;
}
let class_loader_class = self.find_class("java/lang/ClassLoader")?;
let Some(method) = self.get_method_id(class_loader_class, "getParent", "()Ljava/lang/ClassLoader;") else {
self.delete_local_ref(class_loader_class);
return None;
};
let parent = self.call_object_method(loader, method, &[]);
self.delete_local_ref(class_loader_class);
if parent.is_null() { None } else { Some(parent) }
}
pub fn system_class_loader(&self) -> Option<jni::jobject> {
let class_loader_class = self.find_class("java/lang/ClassLoader")?;
let Some(method) = self.get_static_method_id(class_loader_class, "getSystemClassLoader", "()Ljava/lang/ClassLoader;") else {
self.delete_local_ref(class_loader_class);
return None;
};
let loader = self.call_static_object_method(class_loader_class, method, &[]);
self.delete_local_ref(class_loader_class);
if loader.is_null() { None } else { Some(loader) }
}
pub fn module_name(&self, module: jni::jobject) -> Option<String> {
if module.is_null() {
return None;
}
let module_class = self.get_object_class(module);
let Some(method) = self.get_method_id(module_class, "getName", "()Ljava/lang/String;") else {
self.delete_local_ref(module_class);
return None;
};
let name_obj = self.call_object_method(module, method, &[]);
self.delete_local_ref(module_class);
if name_obj.is_null() {
return None;
}
let name = self.get_string_utf(name_obj as jni::jstring);
self.delete_local_ref(name_obj);
name
}
pub fn module_packages(&self, module: jni::jobject) -> Option<Vec<String>> {
if module.is_null() {
return None;
}
let module_class = self.get_object_class(module);
let Some(method) = self.get_method_id(module_class, "getPackages", "()Ljava/util/Set;") else {
self.delete_local_ref(module_class);
return None;
};
let package_set = self.call_object_method(module, method, &[]);
self.delete_local_ref(module_class);
if package_set.is_null() {
return Some(Vec::new());
}
let set_class = self.get_object_class(package_set);
let Some(to_array) = self.get_method_id(set_class, "toArray", "()[Ljava/lang/Object;") else {
self.delete_local_ref(set_class);
self.delete_local_ref(package_set);
return None;
};
let array = self.call_object_method(package_set, to_array, &[]) as jni::jobjectArray;
self.delete_local_ref(set_class);
self.delete_local_ref(package_set);
if array.is_null() {
return Some(Vec::new());
}
let len = self.get_array_length(array);
let mut packages = Vec::new();
for index in 0..len {
let element = self.get_object_array_element(array, index);
if !element.is_null() {
if let Some(package_name) = self.get_string_utf(element as jni::jstring) {
packages.push(package_name);
}
self.delete_local_ref(element);
}
}
self.delete_local_ref(array);
Some(packages)
}
pub fn module_class_loader(&self, module: jni::jobject) -> Option<jni::jobject> {
if module.is_null() {
return None;
}
let module_class = self.get_object_class(module);
let Some(method) = self.get_method_id(module_class, "getClassLoader", "()Ljava/lang/ClassLoader;") else {
self.delete_local_ref(module_class);
return None;
};
let loader = self.call_object_method(module, method, &[]);
self.delete_local_ref(module_class);
if loader.is_null() { None } else { Some(loader) }
}
pub fn module_can_read(&self, module: jni::jobject, other: jni::jobject) -> bool {
if module.is_null() || other.is_null() {
return false;
}
let module_class = self.get_object_class(module);
let Some(method) = self.get_method_id(module_class, "canRead", "(Ljava/lang/Module;)Z") else {
self.delete_local_ref(module_class);
return false;
};
let args = [jni::jvalue { l: other }];
let can_read = self.call_boolean_method(module, method, &args);
self.delete_local_ref(module_class);
can_read
}
pub fn module_is_exported_to(&self, module: jni::jobject, package_name: &str, other: jni::jobject) -> bool {
self.module_package_access(module, package_name, other, "isExported")
}
pub fn module_is_open_to(&self, module: jni::jobject, package_name: &str, other: jni::jobject) -> bool {
self.module_package_access(module, package_name, other, "isOpen")
}
fn module_package_access(&self, module: jni::jobject, package_name: &str, other: jni::jobject, method_name: &str) -> bool {
if module.is_null() || other.is_null() {
return false;
}
let module_class = self.get_object_class(module);
let Some(method) = self.get_method_id(module_class, method_name, "(Ljava/lang/String;Ljava/lang/Module;)Z") else {
self.delete_local_ref(module_class);
return false;
};
let Some(package) = self.new_string_utf(package_name) else {
self.delete_local_ref(module_class);
return false;
};
let args = [jni::jvalue { l: package }, jni::jvalue { l: other }];
let result = self.call_boolean_method(module, method, &args);
self.delete_local_ref(package);
self.delete_local_ref(module_class);
result
}
pub fn exception_check(&self) -> bool {
unsafe {
let vtable = *self.env;
((*vtable).ExceptionCheck)(self.env) != 0
}
}
pub fn exception_clear(&self) {
unsafe {
let vtable = *self.env;
((*vtable).ExceptionClear)(self.env);
}
}
pub fn exception_describe(&self) {
unsafe {
let vtable = *self.env;
((*vtable).ExceptionDescribe)(self.env);
}
}
pub fn exception_occurred(&self) -> Option<jni::jthrowable> {
unsafe {
let vtable = *self.env;
let exc = ((*vtable).ExceptionOccurred)(self.env);
if exc.is_null() { None } else { Some(exc) }
}
}
pub fn throw(&self, obj: jni::jthrowable) -> Result<(), jni::jint> {
unsafe {
let vtable = *self.env;
let result = ((*vtable).Throw)(self.env, obj);
if result == 0 { Ok(()) } else { Err(result) }
}
}
pub fn throw_new(&self, cls: jni::jclass, msg: &str) -> Result<(), jni::jint> {
let c_msg = CString::new(msg).map_err(|_| -1)?;
unsafe {
let vtable = *self.env;
let result = ((*vtable).ThrowNew)(self.env, cls, c_msg.as_ptr());
if result == 0 { Ok(()) } else { Err(result) }
}
}
pub fn new_string_utf(&self, s: &str) -> Option<jni::jstring> {
let c_str = CString::new(s).ok()?;
unsafe {
let vtable = *self.env;
let jstr = ((*vtable).NewStringUTF)(self.env, c_str.as_ptr());
if jstr.is_null() { None } else { Some(jstr) }
}
}
pub fn new_string(&self, s: &str) -> Option<jni::jstring> {
let utf16: Vec<jni::jchar> = s.encode_utf16().collect();
unsafe {
let vtable = *self.env;
let jstr = ((*vtable).NewString)(self.env, utf16.as_ptr(), utf16.len() as jni::jsize);
if jstr.is_null() { None } else { Some(jstr) }
}
}
pub fn get_string_utf(&self, s: jni::jstring) -> Option<String> {
if s.is_null() {
return None;
}
unsafe {
let vtable = *self.env;
let chars = ((*vtable).GetStringUTFChars)(self.env, s, ptr::null_mut());
if chars.is_null() {
return None;
}
let result = CStr::from_ptr(chars).to_str().ok().map(|s| s.to_string());
((*vtable).ReleaseStringUTFChars)(self.env, s, chars);
result
}
}
pub fn get_string(&self, s: jni::jstring) -> Option<String> {
if s.is_null() {
return None;
}
unsafe {
let vtable = *self.env;
let chars = ((*vtable).GetStringChars)(self.env, s, ptr::null_mut());
if chars.is_null() {
return None;
}
let len = ((*vtable).GetStringLength)(self.env, s) as usize;
let slice = std::slice::from_raw_parts(chars, len);
let result = String::from_utf16_lossy(slice);
((*vtable).ReleaseStringChars)(self.env, s, chars);
Some(result)
}
}
pub fn get_string_utf_length(&self, s: jni::jstring) -> jni::jsize {
unsafe {
let vtable = *self.env;
((*vtable).GetStringUTFLength)(self.env, s)
}
}
pub fn get_string_length(&self, s: jni::jstring) -> jni::jsize {
unsafe {
let vtable = *self.env;
((*vtable).GetStringLength)(self.env, s)
}
}
pub fn get_method_id(&self, cls: jni::jclass, name: &str, sig: &str) -> Option<jni::jmethodID> {
let c_name = CString::new(name).ok()?;
let c_sig = CString::new(sig).ok()?;
unsafe {
let vtable = *self.env;
let mid = ((*vtable).GetMethodID)(self.env, cls, c_name.as_ptr(), c_sig.as_ptr());
if mid.is_null() { None } else { Some(mid) }
}
}
pub fn get_static_method_id(&self, cls: jni::jclass, name: &str, sig: &str) -> Option<jni::jmethodID> {
let c_name = CString::new(name).ok()?;
let c_sig = CString::new(sig).ok()?;
unsafe {
let vtable = *self.env;
let mid = ((*vtable).GetStaticMethodID)(self.env, cls, c_name.as_ptr(), c_sig.as_ptr());
if mid.is_null() { None } else { Some(mid) }
}
}
pub fn get_field_id(&self, cls: jni::jclass, name: &str, sig: &str) -> Option<jni::jfieldID> {
let c_name = CString::new(name).ok()?;
let c_sig = CString::new(sig).ok()?;
unsafe {
let vtable = *self.env;
let fid = ((*vtable).GetFieldID)(self.env, cls, c_name.as_ptr(), c_sig.as_ptr());
if fid.is_null() { None } else { Some(fid) }
}
}
pub fn get_static_field_id(&self, cls: jni::jclass, name: &str, sig: &str) -> Option<jni::jfieldID> {
let c_name = CString::new(name).ok()?;
let c_sig = CString::new(sig).ok()?;
unsafe {
let vtable = *self.env;
let fid = ((*vtable).GetStaticFieldID)(self.env, cls, c_name.as_ptr(), c_sig.as_ptr());
if fid.is_null() { None } else { Some(fid) }
}
}
pub fn alloc_object(&self, cls: jni::jclass) -> Option<jni::jobject> {
unsafe {
let vtable = *self.env;
let obj = ((*vtable).AllocObject)(self.env, cls);
if obj.is_null() { None } else { Some(obj) }
}
}
pub fn new_object(&self, cls: jni::jclass, method_id: jni::jmethodID, args: &[jni::jvalue]) -> Option<jni::jobject> {
unsafe {
let vtable = *self.env;
let obj = ((*vtable).NewObjectA)(self.env, cls, method_id, args.as_ptr());
if obj.is_null() { None } else { Some(obj) }
}
}
pub fn is_same_object(&self, ref1: jni::jobject, ref2: jni::jobject) -> bool {
unsafe {
let vtable = *self.env;
((*vtable).IsSameObject)(self.env, ref1, ref2) != 0
}
}
pub fn new_global_ref(&self, obj: jni::jobject) -> jni::jobject {
unsafe {
let vtable = *self.env;
((*vtable).NewGlobalRef)(self.env, obj)
}
}
pub fn delete_global_ref(&self, obj: jni::jobject) {
unsafe {
let vtable = *self.env;
((*vtable).DeleteGlobalRef)(self.env, obj);
}
}
pub fn new_local_ref(&self, obj: jni::jobject) -> jni::jobject {
unsafe {
let vtable = *self.env;
((*vtable).NewLocalRef)(self.env, obj)
}
}
pub fn delete_local_ref(&self, obj: jni::jobject) {
unsafe {
let vtable = *self.env;
((*vtable).DeleteLocalRef)(self.env, obj);
}
}
pub fn new_weak_global_ref(&self, obj: jni::jobject) -> jni::jweak {
unsafe {
let vtable = *self.env;
((*vtable).NewWeakGlobalRef)(self.env, obj)
}
}
pub fn delete_weak_global_ref(&self, obj: jni::jweak) {
unsafe {
let vtable = *self.env;
((*vtable).DeleteWeakGlobalRef)(self.env, obj);
}
}
pub fn ensure_local_capacity(&self, capacity: jni::jint) -> Result<(), jni::jint> {
unsafe {
let vtable = *self.env;
let result = ((*vtable).EnsureLocalCapacity)(self.env, capacity);
if result == 0 { Ok(()) } else { Err(result) }
}
}
pub fn push_local_frame(&self, capacity: jni::jint) -> Result<(), jni::jint> {
unsafe {
let vtable = *self.env;
let result = ((*vtable).PushLocalFrame)(self.env, capacity);
if result == 0 { Ok(()) } else { Err(result) }
}
}
pub fn pop_local_frame(&self, result: jni::jobject) -> jni::jobject {
unsafe {
let vtable = *self.env;
((*vtable).PopLocalFrame)(self.env, result)
}
}
pub fn get_array_length(&self, array: jni::jarray) -> jni::jsize {
unsafe {
let vtable = *self.env;
((*vtable).GetArrayLength)(self.env, array)
}
}
pub fn new_object_array(&self, length: jni::jsize, cls: jni::jclass, init: jni::jobject) -> Option<jni::jobjectArray> {
unsafe {
let vtable = *self.env;
let arr = ((*vtable).NewObjectArray)(self.env, length, cls, init);
if arr.is_null() { None } else { Some(arr) }
}
}
pub fn get_object_array_element(&self, array: jni::jobjectArray, index: jni::jsize) -> jni::jobject {
unsafe {
let vtable = *self.env;
((*vtable).GetObjectArrayElement)(self.env, array, index)
}
}
pub fn set_object_array_element(&self, array: jni::jobjectArray, index: jni::jsize, value: jni::jobject) {
unsafe {
let vtable = *self.env;
((*vtable).SetObjectArrayElement)(self.env, array, index, value);
}
}
pub fn new_byte_array(&self, length: jni::jsize) -> Option<jni::jbyteArray> {
unsafe {
let vtable = *self.env;
let arr = ((*vtable).NewByteArray)(self.env, length);
if arr.is_null() { None } else { Some(arr) }
}
}
pub fn get_byte_array_region(&self, array: jni::jbyteArray, start: jni::jsize, len: jni::jsize, buf: &mut [jni::jbyte]) {
unsafe {
let vtable = *self.env;
((*vtable).GetByteArrayRegion)(self.env, array, start, len, buf.as_mut_ptr());
}
}
pub fn set_byte_array_region(&self, array: jni::jbyteArray, start: jni::jsize, len: jni::jsize, buf: &[jni::jbyte]) {
unsafe {
let vtable = *self.env;
((*vtable).SetByteArrayRegion)(self.env, array, start, len, buf.as_ptr());
}
}
pub fn new_int_array(&self, length: jni::jsize) -> Option<jni::jintArray> {
unsafe {
let vtable = *self.env;
let arr = ((*vtable).NewIntArray)(self.env, length);
if arr.is_null() { None } else { Some(arr) }
}
}
pub fn get_int_array_region(&self, array: jni::jintArray, start: jni::jsize, len: jni::jsize, buf: &mut [jni::jint]) {
unsafe {
let vtable = *self.env;
((*vtable).GetIntArrayRegion)(self.env, array, start, len, buf.as_mut_ptr());
}
}
pub fn set_int_array_region(&self, array: jni::jintArray, start: jni::jsize, len: jni::jsize, buf: &[jni::jint]) {
unsafe {
let vtable = *self.env;
((*vtable).SetIntArrayRegion)(self.env, array, start, len, buf.as_ptr());
}
}
pub fn new_long_array(&self, length: jni::jsize) -> Option<jni::jlongArray> {
unsafe {
let vtable = *self.env;
let arr = ((*vtable).NewLongArray)(self.env, length);
if arr.is_null() { None } else { Some(arr) }
}
}
pub fn get_long_array_region(&self, array: jni::jlongArray, start: jni::jsize, len: jni::jsize, buf: &mut [jni::jlong]) {
unsafe {
let vtable = *self.env;
((*vtable).GetLongArrayRegion)(self.env, array, start, len, buf.as_mut_ptr());
}
}
pub fn set_long_array_region(&self, array: jni::jlongArray, start: jni::jsize, len: jni::jsize, buf: &[jni::jlong]) {
unsafe {
let vtable = *self.env;
((*vtable).SetLongArrayRegion)(self.env, array, start, len, buf.as_ptr());
}
}
pub fn call_void_method(&self, obj: jni::jobject, method_id: jni::jmethodID, args: &[jni::jvalue]) {
unsafe {
let vtable = *self.env;
((*vtable).CallVoidMethodA)(self.env, obj, method_id, args.as_ptr());
}
}
pub fn call_int_method(&self, obj: jni::jobject, method_id: jni::jmethodID, args: &[jni::jvalue]) -> jni::jint {
unsafe {
let vtable = *self.env;
((*vtable).CallIntMethodA)(self.env, obj, method_id, args.as_ptr())
}
}
pub fn call_long_method(&self, obj: jni::jobject, method_id: jni::jmethodID, args: &[jni::jvalue]) -> jni::jlong {
unsafe {
let vtable = *self.env;
((*vtable).CallLongMethodA)(self.env, obj, method_id, args.as_ptr())
}
}
pub fn call_boolean_method(&self, obj: jni::jobject, method_id: jni::jmethodID, args: &[jni::jvalue]) -> bool {
unsafe {
let vtable = *self.env;
((*vtable).CallBooleanMethodA)(self.env, obj, method_id, args.as_ptr()) != 0
}
}
pub fn call_object_method(&self, obj: jni::jobject, method_id: jni::jmethodID, args: &[jni::jvalue]) -> jni::jobject {
unsafe {
let vtable = *self.env;
((*vtable).CallObjectMethodA)(self.env, obj, method_id, args.as_ptr())
}
}
pub fn call_static_void_method(&self, cls: jni::jclass, method_id: jni::jmethodID, args: &[jni::jvalue]) {
unsafe {
let vtable = *self.env;
((*vtable).CallStaticVoidMethodA)(self.env, cls, method_id, args.as_ptr());
}
}
pub fn call_static_int_method(&self, cls: jni::jclass, method_id: jni::jmethodID, args: &[jni::jvalue]) -> jni::jint {
unsafe {
let vtable = *self.env;
((*vtable).CallStaticIntMethodA)(self.env, cls, method_id, args.as_ptr())
}
}
pub fn call_static_object_method(&self, cls: jni::jclass, method_id: jni::jmethodID, args: &[jni::jvalue]) -> jni::jobject {
unsafe {
let vtable = *self.env;
((*vtable).CallStaticObjectMethodA)(self.env, cls, method_id, args.as_ptr())
}
}
pub fn get_object_field(&self, obj: jni::jobject, field_id: jni::jfieldID) -> jni::jobject {
unsafe {
let vtable = *self.env;
((*vtable).GetObjectField)(self.env, obj, field_id)
}
}
pub fn get_int_field(&self, obj: jni::jobject, field_id: jni::jfieldID) -> jni::jint {
unsafe {
let vtable = *self.env;
((*vtable).GetIntField)(self.env, obj, field_id)
}
}
pub fn get_long_field(&self, obj: jni::jobject, field_id: jni::jfieldID) -> jni::jlong {
unsafe {
let vtable = *self.env;
((*vtable).GetLongField)(self.env, obj, field_id)
}
}
pub fn set_object_field(&self, obj: jni::jobject, field_id: jni::jfieldID, value: jni::jobject) {
unsafe {
let vtable = *self.env;
((*vtable).SetObjectField)(self.env, obj, field_id, value);
}
}
pub fn set_int_field(&self, obj: jni::jobject, field_id: jni::jfieldID, value: jni::jint) {
unsafe {
let vtable = *self.env;
((*vtable).SetIntField)(self.env, obj, field_id, value);
}
}
pub fn set_long_field(&self, obj: jni::jobject, field_id: jni::jfieldID, value: jni::jlong) {
unsafe {
let vtable = *self.env;
((*vtable).SetLongField)(self.env, obj, field_id, value);
}
}
pub fn get_static_object_field(&self, cls: jni::jclass, field_id: jni::jfieldID) -> jni::jobject {
unsafe {
let vtable = *self.env;
((*vtable).GetStaticObjectField)(self.env, cls, field_id)
}
}
pub fn get_static_int_field(&self, cls: jni::jclass, field_id: jni::jfieldID) -> jni::jint {
unsafe {
let vtable = *self.env;
((*vtable).GetStaticIntField)(self.env, cls, field_id)
}
}
pub fn set_static_object_field(&self, cls: jni::jclass, field_id: jni::jfieldID, value: jni::jobject) {
unsafe {
let vtable = *self.env;
((*vtable).SetStaticObjectField)(self.env, cls, field_id, value);
}
}
pub fn monitor_enter(&self, obj: jni::jobject) -> Result<(), jni::jint> {
unsafe {
let vtable = *self.env;
let result = ((*vtable).MonitorEnter)(self.env, obj);
if result == 0 { Ok(()) } else { Err(result) }
}
}
pub fn monitor_exit(&self, obj: jni::jobject) -> Result<(), jni::jint> {
unsafe {
let vtable = *self.env;
let result = ((*vtable).MonitorExit)(self.env, obj);
if result == 0 { Ok(()) } else { Err(result) }
}
}
pub fn register_natives(&self, cls: jni::jclass, methods: &[jni::JNINativeMethod]) -> Result<(), jni::jint> {
unsafe {
let vtable = *self.env;
let result = ((*vtable).RegisterNatives)(self.env, cls, methods.as_ptr(), methods.len() as jni::jint);
if result == 0 { Ok(()) } else { Err(result) }
}
}
pub fn unregister_natives(&self, cls: jni::jclass) -> Result<(), jni::jint> {
unsafe {
let vtable = *self.env;
let result = ((*vtable).UnregisterNatives)(self.env, cls);
if result == 0 { Ok(()) } else { Err(result) }
}
}
}
pub struct LocalRef<'a> {
env: &'a JniEnv,
obj: jni::jobject,
}
impl<'a> LocalRef<'a> {
pub fn new(env: &'a JniEnv, obj: jni::jobject) -> Self {
LocalRef { env, obj }
}
pub fn get(&self) -> jni::jobject {
self.obj
}
pub fn into_inner(self) -> jni::jobject {
let obj = self.obj;
std::mem::forget(self);
obj
}
}
impl<'a> Drop for LocalRef<'a> {
fn drop(&mut self) {
if !self.obj.is_null() {
self.env.delete_local_ref(self.obj);
}
}
}
pub struct GlobalRef {
vm: *mut jni::JavaVM,
obj: jni::jobject,
_not_send_sync: PhantomData<Rc<()>>,
}
impl GlobalRef {
pub unsafe fn new(env: &JniEnv, local_obj: jni::jobject) -> Self {
let global = env.new_global_ref(local_obj);
let vm = env.get_java_vm().unwrap_or(ptr::null_mut());
GlobalRef {
vm,
obj: global,
_not_send_sync: PhantomData,
}
}
pub fn get(&self) -> jni::jobject {
self.obj
}
}
impl Drop for GlobalRef {
fn drop(&mut self) {
if self.obj.is_null() || self.vm.is_null() {
return;
}
unsafe {
let get_env_fn = (**self.vm).GetEnv;
let attach_fn = (**self.vm).AttachCurrentThread;
let detach_fn = (**self.vm).DetachCurrentThread;
let mut env_ptr: *mut std::ffi::c_void = ptr::null_mut();
let res = get_env_fn(self.vm, &mut env_ptr, jni::JNI_VERSION_1_6);
if res == jni::JNI_OK && !env_ptr.is_null() {
let env = JniEnv::from_raw(env_ptr as *mut jni::JNIEnv);
env.delete_global_ref(self.obj);
return;
}
if res == jni::JNI_EDETACHED {
let mut attach_env: *mut std::ffi::c_void = ptr::null_mut();
let ares = attach_fn(self.vm, &mut attach_env, ptr::null_mut());
if ares == jni::JNI_OK && !attach_env.is_null() {
let env = JniEnv::from_raw(attach_env as *mut jni::JNIEnv);
env.delete_global_ref(self.obj);
let _ = detach_fn(self.vm);
}
}
}
}
}