Skip to content

Commit 58cc082

Browse files
authored
fix(android): drop MainPipe on activity destroy (#1415)
fixes a memory leak when the activity is destroyed but the app is opened in the foreground ref tauri-apps/tauri#11609
1 parent 0c192f4 commit 58cc082

File tree

5 files changed

+34
-8
lines changed

5 files changed

+34
-8
lines changed

src/android/binding.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ macro_rules! android_binding {
3232
($domain:ident, $package:ident, $wry:path) => {{
3333
use $wry::{android_setup as _, prelude::*};
3434

35+
android_fn!($domain, $package, WryActivity, onActivityDestroy, [JObject]);
36+
3537
android_fn!(
3638
$domain,
3739
$package,
@@ -258,6 +260,11 @@ fn handle_request(
258260
Ok(*JObject::null())
259261
}
260262

263+
#[allow(non_snake_case)]
264+
pub unsafe fn onActivityDestroy(_: JNIEnv, _: JClass, _: JObject) {
265+
super::MainPipe::send(super::WebViewMessage::OnDestroy);
266+
}
267+
261268
#[allow(non_snake_case)]
262269
pub unsafe fn handleRequest(
263270
mut env: JNIEnv,

src/android/kotlin/WryActivity.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ abstract class WryActivity : AppCompatActivity() {
9393
override fun onDestroy() {
9494
super.onDestroy()
9595
destroy()
96+
onActivityDestroy()
9697
}
9798

9899
override fun onLowMemory() {
@@ -125,6 +126,7 @@ abstract class WryActivity : AppCompatActivity() {
125126
private external fun stop()
126127
private external fun save()
127128
private external fun destroy()
129+
private external fun onActivityDestroy()
128130
private external fun memory()
129131
private external fun focus(focus: Boolean)
130132

src/android/main_pipe.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ pub static MAIN_PIPE: Lazy<[OwnedFd; 2]> = Lazy::new(|| {
2121
unsafe { pipe.map(|fd| OwnedFd::from_raw_fd(fd)) }
2222
});
2323

24+
pub enum MainPipeState {
25+
Alive,
26+
Destroyed,
27+
}
28+
2429
pub struct MainPipe<'a> {
2530
pub env: JNIEnv<'a>,
2631
pub activity: GlobalRef,
@@ -42,7 +47,7 @@ impl<'a> MainPipe<'a> {
4247
}
4348
}
4449

45-
pub fn recv(&mut self) -> JniResult<()> {
50+
pub fn recv(&mut self) -> JniResult<MainPipeState> {
4651
let activity = self.activity.as_obj();
4752
if let Ok(message) = CHANNEL.1.recv() {
4853
match message {
@@ -341,9 +346,12 @@ impl<'a> MainPipe<'a> {
341346
.unwrap();
342347
}
343348
}
349+
WebViewMessage::OnDestroy => {
350+
return Ok(MainPipeState::Destroyed);
351+
}
344352
}
345353
}
346-
Ok(())
354+
Ok(MainPipeState::Alive)
347355
}
348356
}
349357

@@ -413,6 +421,7 @@ pub(crate) enum WebViewMessage {
413421
LoadUrl(String, Option<http::HeaderMap>),
414422
LoadHtml(String),
415423
ClearAllBrowsingData,
424+
OnDestroy,
416425
}
417426

418427
pub(crate) struct CreateWebViewAttributes {

src/android/mod.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,17 @@ use std::{
2727
collections::HashMap,
2828
os::fd::{AsFd as _, AsRawFd as _},
2929
sync::{mpsc::channel, Mutex},
30+
time::Duration,
3031
};
3132

3233
pub(crate) mod binding;
3334
mod main_pipe;
34-
use main_pipe::{CreateWebViewAttributes, MainPipe, WebViewMessage, MAIN_PIPE};
35+
use main_pipe::{CreateWebViewAttributes, MainPipe, MainPipeState, WebViewMessage, MAIN_PIPE};
3536

3637
use crate::util::Counter;
3738

3839
static COUNTER: Counter = Counter::new();
40+
const MAIN_PIPE_TIMEOUT: Duration = Duration::from_secs(10);
3941

4042
pub struct Context<'a, 'b> {
4143
pub env: &'a mut JNIEnv<'b>,
@@ -133,8 +135,11 @@ pub unsafe fn android_setup(
133135
let size = std::mem::size_of::<bool>();
134136
let mut wake = false;
135137
if libc::read(fd.as_raw_fd(), &mut wake as *mut _ as *mut _, size) == size as libc::ssize_t {
136-
main_pipe.recv().is_ok()
138+
let res = main_pipe.recv();
139+
// unregister itself on errors or destroy event
140+
matches!(res, Ok(MainPipeState::Alive))
137141
} else {
142+
// unregister itself
138143
false
139144
}
140145
})
@@ -300,7 +305,7 @@ impl InnerWebView {
300305
});
301306

302307
(custom_protocol.1)(webview_id, request, RequestAsyncResponder { responder });
303-
return Some(rx.recv().unwrap());
308+
return Some(rx.recv_timeout(MAIN_PIPE_TIMEOUT).unwrap());
304309
}
305310
None
306311
},
@@ -337,7 +342,7 @@ impl InnerWebView {
337342
pub fn url(&self) -> crate::Result<String> {
338343
let (tx, rx) = bounded(1);
339344
MainPipe::send(WebViewMessage::GetUrl(tx));
340-
rx.recv().map_err(Into::into)
345+
rx.recv_timeout(MAIN_PIPE_TIMEOUT).map_err(Into::into)
341346
}
342347

343348
pub fn eval(&self, js: &str, callback: Option<impl Fn(String) + Send + 'static>) -> Result<()> {
@@ -391,7 +396,7 @@ impl InnerWebView {
391396
pub fn cookies_for_url(&self, url: &str) -> Result<Vec<cookie::Cookie<'static>>> {
392397
let (tx, rx) = bounded(1);
393398
MainPipe::send(WebViewMessage::GetCookies(tx, url.to_string()));
394-
rx.recv().map_err(Into::into)
399+
rx.recv_timeout(MAIN_PIPE_TIMEOUT).map_err(Into::into)
395400
}
396401

397402
pub fn cookies(&self) -> Result<Vec<cookie::Cookie<'static>>> {
@@ -440,7 +445,7 @@ impl JniHandle {
440445
pub fn platform_webview_version() -> Result<String> {
441446
let (tx, rx) = bounded(1);
442447
MainPipe::send(WebViewMessage::GetWebViewVersion(tx));
443-
rx.recv().unwrap()
448+
rx.recv_timeout(MAIN_PIPE_TIMEOUT).unwrap()
444449
}
445450

446451
fn with_html_head<F: FnOnce(&NodeRef)>(document: &mut NodeRef, f: F) {

src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ pub enum Error {
2828
NulError(#[from] std::ffi::NulError),
2929
#[error(transparent)]
3030
ReceiverError(#[from] std::sync::mpsc::RecvError),
31+
#[cfg(target_os = "android")]
32+
#[error(transparent)]
33+
ReceiverTimeoutError(#[from] crossbeam_channel::RecvTimeoutError),
3134
#[error(transparent)]
3235
SenderError(#[from] std::sync::mpsc::SendError<String>),
3336
#[error("Failed to send the message")]

0 commit comments

Comments
 (0)