mirror of
https://github.com/rust-mobile/android-activity.git
synced 2026-07-09 08:17:28 +00:00
Only init ndk-context once with an Application ref
Instead of initializing `ndk-context` with an `Activity` reference (for the `android.context.Context` subclass) we now initialize with an `android.app.Application` reference (also an `android.context.Context` subclass). The benefit of this is that we can strictly initialize `ndk-context` once (via a `OnceLock`) so there's no risk of a panic in case an application starts more than one Activity within the same process. Fixes: #58 Fixes: #228
This commit is contained in:
@@ -970,7 +970,6 @@ pub unsafe extern "C" fn _rust_glue_entry(native_app: *mut ffi::android_app) {
|
||||
let (jvm, jni_activity) = unsafe {
|
||||
let jvm = (*(*native_app).activity).vm;
|
||||
let activity: jobject = (*(*native_app).activity).javaGameActivity;
|
||||
ndk_context::initialize_android_context(jvm.cast(), activity.cast());
|
||||
(jni::JavaVM::from_raw(jvm), activity)
|
||||
};
|
||||
// Note: At this point we can assume jni::JavaVM::singleton is initialized
|
||||
@@ -1011,8 +1010,6 @@ pub unsafe extern "C" fn _rust_glue_entry(native_app: *mut ffi::android_app) {
|
||||
// "Note that this method can be called from any thread; it will send a message
|
||||
// to the main thread of the process where the Java finish call will take place"
|
||||
ffi::GameActivity_finish((*native_app).activity);
|
||||
|
||||
ndk_context::release_android_context();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -875,7 +875,6 @@ fn rust_glue_entry(rust_glue: NativeActivityGlue, activity: *mut ndk_sys::ANativ
|
||||
let (jvm, jni_activity) = unsafe {
|
||||
let jvm: *mut jni::sys::JavaVM = (*activity).vm.cast();
|
||||
let jni_activity: jni::sys::jobject = (*activity).clazz as _; // Completely bogus name; this is the _instance_ not class pointer
|
||||
ndk_context::initialize_android_context(jvm.cast(), jni_activity.cast());
|
||||
(jni::JavaVM::from_raw(jvm), jni_activity)
|
||||
};
|
||||
// Note: At this point we can assume jni::JavaVM::singleton is initialized
|
||||
@@ -923,8 +922,6 @@ fn rust_glue_entry(rust_glue: NativeActivityGlue, activity: *mut ndk_sys::ANativ
|
||||
// "Note that this method can be called from any thread; it will send a message
|
||||
// to the main thread of the process where the Java finish call will take place"
|
||||
ndk_sys::ANativeActivity_finish(activity);
|
||||
|
||||
ndk_context::release_android_context();
|
||||
}
|
||||
|
||||
rust_glue.notify_main_thread_stopped_running();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use jni::{
|
||||
jni_str,
|
||||
jni_sig, jni_str,
|
||||
objects::{JObject, JString, JThread},
|
||||
vm::JavaVM,
|
||||
};
|
||||
@@ -12,6 +12,7 @@ use std::{
|
||||
fd::{FromRawFd as _, RawFd},
|
||||
raw::c_char,
|
||||
},
|
||||
sync::OnceLock,
|
||||
};
|
||||
|
||||
pub fn try_get_path_from_ptr(path: *const c_char) -> Option<std::path::PathBuf> {
|
||||
@@ -117,6 +118,24 @@ pub(crate) fn abort_on_panic<R>(f: impl FnOnce() -> R) -> R {
|
||||
})
|
||||
}
|
||||
|
||||
static NDK_CONTEXT_ONCE: OnceLock<()> = OnceLock::new();
|
||||
|
||||
// Get the Application instance from the Activity
|
||||
fn get_application<'local, 'any>(
|
||||
env: &mut jni::Env<'local>,
|
||||
activity: &JObject<'any>,
|
||||
) -> jni::errors::Result<JObject<'local>> {
|
||||
let app = env
|
||||
.call_method(
|
||||
activity,
|
||||
jni_str!("getApplication"),
|
||||
jni_sig!(() -> android.app.Application),
|
||||
&[],
|
||||
)?
|
||||
.l()?;
|
||||
Ok(app)
|
||||
}
|
||||
|
||||
/// Name the Java Thread + native thread "android_main" and set the Java Thread context class loader
|
||||
/// so that jni code can more-easily find non-system Java classes.
|
||||
pub(crate) fn init_android_main_thread(
|
||||
@@ -125,6 +144,18 @@ pub(crate) fn init_android_main_thread(
|
||||
) -> jni::errors::Result<()> {
|
||||
vm.with_local_frame(10, |env| -> jni::errors::Result<()> {
|
||||
let activity_class = env.get_object_class(jni_activity)?;
|
||||
|
||||
if let Ok(application) = get_application(env, jni_activity) {
|
||||
NDK_CONTEXT_ONCE.get_or_init(|| unsafe {
|
||||
let app_global = env
|
||||
.new_global_ref(application)
|
||||
.expect("Failed to create global ref for Application");
|
||||
// Make sure we don't delete the global reference via Drop
|
||||
let app_global = app_global.into_raw();
|
||||
ndk_context::initialize_android_context(vm.get_raw().cast(), app_global.cast());
|
||||
});
|
||||
}
|
||||
|
||||
let class_loader = activity_class.get_class_loader(env)?;
|
||||
|
||||
let thread = JThread::current_thread(env)?;
|
||||
|
||||
Reference in New Issue
Block a user