Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(android): memory leak on WindowManager global ref #1005

Merged
merged 1 commit into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading