Skip to content

Commit

Permalink
fix(android): memory leak on WindowManager global ref
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog committed Nov 8, 2024
1 parent 1f72c24 commit 1bb92d0
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changes/fix-android-leak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

Fix memory leak on Android.
4 changes: 2 additions & 2 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ impl Window {
#[cfg(feature = "rwh_06")]
pub fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
// 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
Expand Down Expand Up @@ -780,7 +780,7 @@ impl MonitorHandle {

pub fn size(&self) -> PhysicalSize<u32> {
// 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();
Expand Down
23 changes: 19 additions & 4 deletions src/platform_impl/android/ndk_glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use ndk::{
};
use once_cell::sync::{Lazy, OnceCell};
use std::{
cell::RefCell,
ffi::{CStr, CString},
fs::File,
io::{BufRead, BufReader},
Expand Down Expand Up @@ -104,13 +105,26 @@ pub fn android_log(level: Level, tag: &CStr, msg: &CStr) {
}
}

static WINDOW_MANGER: OnceCell<GlobalRef> = OnceCell::new();
pub(crate) struct StaticCell<T>(RefCell<T>);

unsafe impl<T> Send for StaticCell<T> {}
unsafe impl<T> Sync for StaticCell<T> {}

impl<T> std::ops::Deref for StaticCell<T> {
type Target = RefCell<T>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

static WINDOW_MANAGER: StaticCell<Option<GlobalRef>> = StaticCell(RefCell::new(None));
static INPUT_QUEUE: Lazy<RwLock<Option<InputQueue>>> = Lazy::new(|| Default::default());
static CONTENT_RECT: Lazy<RwLock<Rect>> = Lazy::new(|| Default::default());
static LOOPER: Lazy<Mutex<Option<ForeignLooper>>> = Lazy::new(|| Default::default());

pub fn window_manager() -> Option<&'static GlobalRef> {
WINDOW_MANGER.get()
pub fn window_manager() -> std::cell::Ref<'static, Option<GlobalRef>> {
WINDOW_MANAGER.0.borrow()
}

pub fn input_queue() -> RwLockReadGuard<'static, Option<InputQueue>> {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 1bb92d0

Please sign in to comment.