From 1bb92d01e05cea3a7af2629965bbb2978d7cc022 Mon Sep 17 00:00:00 2001 From: Lucas Nogueira Date: Fri, 8 Nov 2024 11:11:31 -0300 Subject: [PATCH] fix(android): memory leak on WindowManager global ref ref https://github.com/tauri-apps/tauri/issues/11609 --- .changes/fix-android-leak.md | 5 +++++ src/platform_impl/android/mod.rs | 4 ++-- src/platform_impl/android/ndk_glue.rs | 23 +++++++++++++++++++---- 3 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 .changes/fix-android-leak.md diff --git a/.changes/fix-android-leak.md b/.changes/fix-android-leak.md new file mode 100644 index 000000000..c320a21fc --- /dev/null +++ b/.changes/fix-android-leak.md @@ -0,0 +1,5 @@ +--- +"tao": patch +--- + +Fix memory leak on Android. \ No newline at end of file diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index a24155a0f..19d8e1b04 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -728,7 +728,7 @@ impl Window { #[cfg(feature = "rwh_06")] pub fn raw_window_handle_rwh_06(&self) -> Result { // TODO: Use main activity instead? - if let Some(w) = ndk_glue::window_manager() { + if let Some(w) = ndk_glue::window_manager().as_ref() { let native_window = unsafe { std::ptr::NonNull::new_unchecked(w.as_obj().as_raw() as *mut _) }; // native_window shuldn't be null @@ -780,7 +780,7 @@ impl MonitorHandle { pub fn size(&self) -> PhysicalSize { // TODO decide how to get JNIENV - if let Some(w) = ndk_glue::window_manager() { + if let Some(w) = ndk_glue::window_manager().as_ref() { let ctx = ndk_context::android_context(); let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }.unwrap(); let mut env = vm.attach_current_thread().unwrap(); diff --git a/src/platform_impl/android/ndk_glue.rs b/src/platform_impl/android/ndk_glue.rs index bcdff6e2f..5b1f3c7b8 100644 --- a/src/platform_impl/android/ndk_glue.rs +++ b/src/platform_impl/android/ndk_glue.rs @@ -16,6 +16,7 @@ use ndk::{ }; use once_cell::sync::{Lazy, OnceCell}; use std::{ + cell::RefCell, ffi::{CStr, CString}, fs::File, io::{BufRead, BufReader}, @@ -104,13 +105,26 @@ pub fn android_log(level: Level, tag: &CStr, msg: &CStr) { } } -static WINDOW_MANGER: OnceCell = OnceCell::new(); +pub(crate) struct StaticCell(RefCell); + +unsafe impl Send for StaticCell {} +unsafe impl Sync for StaticCell {} + +impl std::ops::Deref for StaticCell { + type Target = RefCell; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +static WINDOW_MANAGER: StaticCell> = StaticCell(RefCell::new(None)); static INPUT_QUEUE: Lazy>> = Lazy::new(|| Default::default()); static CONTENT_RECT: Lazy> = Lazy::new(|| Default::default()); static LOOPER: Lazy>> = Lazy::new(|| Default::default()); -pub fn window_manager() -> Option<&'static GlobalRef> { - WINDOW_MANGER.get() +pub fn window_manager() -> std::cell::Ref<'static, Option> { + WINDOW_MANAGER.0.borrow() } pub fn input_queue() -> RwLockReadGuard<'static, Option> { @@ -198,7 +212,7 @@ pub unsafe fn create( .l() .unwrap(); let window_manager = env.new_global_ref(window_manager).unwrap(); - WINDOW_MANGER.get_or_init(move || window_manager); + WINDOW_MANAGER.replace(Some(window_manager)); let activity = env.new_global_ref(jobject).unwrap(); let vm = env.get_java_vm().unwrap(); let env = vm.attach_current_thread_as_daemon().unwrap(); @@ -305,6 +319,7 @@ pub unsafe fn save(_: JNIEnv, _: JClass, _: JObject) { pub unsafe fn destroy(_: JNIEnv, _: JClass, _: JObject) { wake(Event::Destroy); ndk_context::release_android_context(); + WINDOW_MANAGER.take(); } pub unsafe fn memory(_: JNIEnv, _: JClass, _: JObject) {