summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2020-01-13 12:00:24 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2020-01-13 12:00:24 -0300
commit8dabfcfc8950e9b249a10cf4ebd964f8685dc5dc (patch)
treed5ec667e71457bd2934584db5bbe26b0074d4877
parentb73ab60bb5bf94409a0b49f91b355de43c62c06c (diff)
parent4ba5fcde44e30f2c59edb9457fdd4aa571a1feb0 (diff)
downloadmullvadvpn-8dabfcfc8950e9b249a10cf4ebd964f8685dc5dc.tar.xz
mullvadvpn-8dabfcfc8950e9b249a10cf4ebd964f8685dc5dc.zip
Merge branch 'restart-service-on-daemon-crash'
-rw-r--r--CHANGELOG.md1
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt5
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt26
-rw-r--r--mullvad-jni/src/lib.rs52
4 files changed, 71 insertions, 13 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2067af6894..82e677657a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -49,6 +49,7 @@ Line wrap the file at 100 chars. Th
#### Android
- Fix crash when starting the app right after quitting it.
+- Restart background service if it stops responding.
### Security
#### Windows
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt
index c3b1661907..a175efc5ca 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt
@@ -20,6 +20,7 @@ class MullvadDaemon(val vpnService: MullvadVpnService) {
var onKeygenEvent: ((KeygenEvent) -> Unit)? = null
var onRelayListChange: ((RelayList) -> Unit)? = null
var onTunnelStateChange: ((TunnelState) -> Unit)? = null
+ var onDaemonStopped: (() -> Unit)? = null
init {
System.loadLibrary("mullvad_jni")
@@ -138,6 +139,10 @@ class MullvadDaemon(val vpnService: MullvadVpnService) {
onTunnelStateChange?.invoke(event)
}
+ private fun notifyDaemonStopped() {
+ onDaemonStopped?.invoke()
+ }
+
private fun finalize() {
deinitialize()
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
index f22094dfe9..6d8747f915 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
@@ -34,8 +34,7 @@ class MullvadVpnService : TalpidVpnService() {
override fun onRebind(intent: Intent) {
if (isStopping) {
- tearDown()
- setUp()
+ restart()
isStopping = false
}
}
@@ -46,7 +45,6 @@ class MullvadVpnService : TalpidVpnService() {
override fun onDestroy() {
tearDown()
- daemon.cancel()
super.onDestroy()
}
@@ -72,6 +70,12 @@ class MullvadVpnService : TalpidVpnService() {
onSettingsChange.subscribe { settings ->
notificationManager.loggedIn = settings?.accountToken != null
}
+
+ onDaemonStopped = {
+ if (!isStopping) {
+ restart()
+ }
+ }
}
serviceNotifier.notify(ServiceInstance(daemon, connectionProxy, connectivityListener))
@@ -88,20 +92,28 @@ class MullvadVpnService : TalpidVpnService() {
private fun stop() {
isStopping = true
+ stopDaemon()
+ stopSelf()
+ }
- serviceNotifier.notify(null)
-
+ private fun stopDaemon() {
if (daemon.isCompleted) {
runBlocking { daemon.await().shutdown() }
} else {
daemon.cancel()
}
-
- stopSelf()
}
private fun tearDown() {
+ serviceNotifier.notify(null)
+ stopDaemon()
+
connectionProxy.onDestroy()
notificationManager.onDestroy()
}
+
+ private fun restart() {
+ tearDown()
+ setUp()
+ }
}
diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs
index 1a4a3e0da3..e8d8c92321 100644
--- a/mullvad-jni/src/lib.rs
+++ b/mullvad-jni/src/lib.rs
@@ -12,10 +12,10 @@ use crate::{
};
use jnix::{
jni::{
- objects::{JObject, JString, JValue},
+ objects::{GlobalRef, JObject, JString, JValue},
signature::{JavaType, Primitive},
sys::{jboolean, jlong, JNI_FALSE, JNI_TRUE},
- JNIEnv,
+ JNIEnv, JavaVM,
},
IntoJava, JnixEnv,
};
@@ -161,10 +161,15 @@ fn spawn_daemon(
android_context: AndroidContext,
) -> Result<DaemonCommandSender, Error> {
let listener = JniEventListener::spawn(env, this).map_err(Error::SpawnJniEventListener)?;
+ let daemon_object = env
+ .new_global_ref(*this)
+ .map_err(Error::CreateGlobalReference)?;
let (tx, rx) = mpsc::channel();
- thread::spawn(
- move || match create_daemon(listener, log_dir, android_context) {
+ thread::spawn(move || {
+ let jvm = android_context.jvm.clone();
+
+ match create_daemon(listener, log_dir, android_context) {
Ok(daemon) => {
let _ = tx.send(Ok(daemon.command_sender()));
match daemon.run() {
@@ -175,8 +180,10 @@ fn spawn_daemon(
Err(error) => {
let _ = tx.send(Err(error));
}
- },
- );
+ }
+
+ notify_daemon_stopped(jvm, daemon_object);
+ });
rx.recv().unwrap()
}
@@ -201,6 +208,39 @@ fn create_daemon(
Ok(daemon)
}
+fn notify_daemon_stopped(jvm: Arc<JavaVM>, daemon_object: GlobalRef) {
+ match jvm.attach_current_thread_as_daemon() {
+ Ok(env) => {
+ let env = JnixEnv::from(env);
+ let class = env.get_class("net/mullvad/mullvadvpn/service/MullvadDaemon");
+ let object = daemon_object.as_obj();
+ let method_id = env
+ .get_method_id(&class, "notifyDaemonStopped", "()V")
+ .expect("Failed to get method ID for MullvadDaemon.notifyDaemonStopped");
+ let return_type = JavaType::Primitive(Primitive::Void);
+
+ let result = env.call_method_unchecked(object, method_id, return_type, &[]);
+
+ match result {
+ Ok(JValue::Void) => {}
+ Ok(value) => panic!(
+ "Unexpected return value from MullvadDaemon.notifyDaemonStopped: {:?}",
+ value
+ ),
+ Err(error) => panic!(
+ "{}",
+ error
+ .display_chain_with_msg("Failed to call MullvadDaemon.notifyDaemonStopped")
+ ),
+ }
+ }
+ Err(error) => log::error!(
+ "{}",
+ error.display_chain_with_msg("Failed to notify that the daemon stopped")
+ ),
+ }
+}
+
fn set_daemon_interface_address(env: &JnixEnv<'_>, this: &JObject<'_>, address: jlong) {
let class = env.get_class("net/mullvad/mullvadvpn/service/MullvadDaemon");
let method_id = env