Skip to content

Commit 0f49d96

Browse files
committed
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
1 parent 2b20da7 commit 0f49d96

File tree

3 files changed

+32
-7
lines changed

3 files changed

+32
-7
lines changed

android-activity/src/game_activity/mod.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,6 @@ pub unsafe extern "C" fn _rust_glue_entry(native_app: *mut ffi::android_app) {
970970
let (jvm, jni_activity) = unsafe {
971971
let jvm = (*(*native_app).activity).vm;
972972
let activity: jobject = (*(*native_app).activity).javaGameActivity;
973-
ndk_context::initialize_android_context(jvm.cast(), activity.cast());
974973
(jni::JavaVM::from_raw(jvm), activity)
975974
};
976975
// 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) {
10111010
// "Note that this method can be called from any thread; it will send a message
10121011
// to the main thread of the process where the Java finish call will take place"
10131012
ffi::GameActivity_finish((*native_app).activity);
1014-
1015-
ndk_context::release_android_context();
10161013
}
10171014

10181015
Ok(())

android-activity/src/native_activity/glue.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,6 @@ fn rust_glue_entry(rust_glue: NativeActivityGlue, activity: *mut ndk_sys::ANativ
875875
let (jvm, jni_activity) = unsafe {
876876
let jvm: *mut jni::sys::JavaVM = (*activity).vm.cast();
877877
let jni_activity: jni::sys::jobject = (*activity).clazz as _; // Completely bogus name; this is the _instance_ not class pointer
878-
ndk_context::initialize_android_context(jvm.cast(), jni_activity.cast());
879878
(jni::JavaVM::from_raw(jvm), jni_activity)
880879
};
881880
// 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
923922
// "Note that this method can be called from any thread; it will send a message
924923
// to the main thread of the process where the Java finish call will take place"
925924
ndk_sys::ANativeActivity_finish(activity);
926-
927-
ndk_context::release_android_context();
928925
}
929926

930927
rust_glue.notify_main_thread_stopped_running();

android-activity/src/util.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use jni::{
2-
jni_str,
2+
jni_sig, jni_str,
33
objects::{JObject, JString, JThread},
44
vm::JavaVM,
55
};
@@ -12,6 +12,7 @@ use std::{
1212
fd::{FromRawFd as _, RawFd},
1313
raw::c_char,
1414
},
15+
sync::OnceLock,
1516
};
1617

1718
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 {
117118
})
118119
}
119120

121+
static NDK_CONTEXT_ONCE: OnceLock<()> = OnceLock::new();
122+
123+
// Get the Application instance from the Activity
124+
fn get_application<'local, 'any>(
125+
env: &mut jni::Env<'local>,
126+
activity: &JObject<'any>,
127+
) -> jni::errors::Result<JObject<'local>> {
128+
let app = env
129+
.call_method(
130+
activity,
131+
jni_str!("getApplication"),
132+
jni_sig!(() -> android.app.Application),
133+
&[],
134+
)?
135+
.l()?;
136+
Ok(app)
137+
}
138+
120139
/// Name the Java Thread + native thread "android_main" and set the Java Thread context class loader
121140
/// so that jni code can more-easily find non-system Java classes.
122141
pub(crate) fn init_android_main_thread(
@@ -125,6 +144,18 @@ pub(crate) fn init_android_main_thread(
125144
) -> jni::errors::Result<()> {
126145
vm.with_local_frame(10, |env| -> jni::errors::Result<()> {
127146
let activity_class = env.get_object_class(jni_activity)?;
147+
148+
if let Ok(application) = get_application(env, jni_activity) {
149+
NDK_CONTEXT_ONCE.get_or_init(|| unsafe {
150+
let app_global = env
151+
.new_global_ref(application)
152+
.expect("Failed to create global ref for Application");
153+
// Make sure we don't delete the global reference via Drop
154+
let app_global = app_global.into_raw();
155+
ndk_context::initialize_android_context(vm.get_raw().cast(), app_global.cast());
156+
});
157+
}
158+
128159
let class_loader = activity_class.get_class_loader(env)?;
129160

130161
let thread = JThread::current_thread(env)?;

0 commit comments

Comments
 (0)