Skip to content

Commit c10bffe

Browse files
MarkusPettersson98Rawa
authored andcommitted
Request (poll) initial NetworkState at startup
1 parent 341c10b commit c10bffe

File tree

4 files changed

+83
-4
lines changed

4 files changed

+83
-4
lines changed

mullvad-daemon/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,8 @@ impl Daemon {
790790
mullvad_types::TUNNEL_FWMARK,
791791
#[cfg(target_os = "linux")]
792792
mullvad_types::TUNNEL_TABLE_ID,
793+
#[cfg(target_os = "android")]
794+
config.android_context.clone(),
793795
)
794796
.await
795797
.map_err(Error::RouteManager)?;

talpid-core/src/connectivity_listener.rs

-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ pub struct ConnectivityListener {
4747
android_listener: GlobalRef,
4848
}
4949

50-
// Clean this up
5150
static CONNECTIVITY_TX: Mutex<Option<UnboundedSender<Connectivity>>> = Mutex::new(None);
5251

5352
impl ConnectivityListener {

talpid-routing/src/unix/android.rs

+76-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ use futures::channel::oneshot;
77
use futures::future::FutureExt;
88
use futures::select_biased;
99
use futures::stream::StreamExt;
10+
use jnix::jni::objects::JValue;
1011
use jnix::jni::{objects::JObject, JNIEnv};
1112
use jnix::{FromJava, JnixEnv};
1213

13-
use talpid_types::android::NetworkState;
14+
use talpid_types::android::{AndroidContext, NetworkState};
1415

1516
use crate::{imp::RouteManagerCommand, Route};
1617

@@ -23,6 +24,19 @@ pub enum Error {
2324
RoutesTimedOut,
2425
}
2526

27+
/// Internal errors that may only happen during the initial poll for [NetworkState].
28+
#[derive(Debug, thiserror::Error)]
29+
enum JvmError {
30+
#[error("Failed to attach Java VM to tunnel thread")]
31+
AttachJvmToThread(#[source] jnix::jni::errors::Error),
32+
#[error("Failed to call Java method {0}")]
33+
CallMethod(&'static str, #[source] jnix::jni::errors::Error),
34+
#[error("Failed to create global reference to Java object")]
35+
CreateGlobalRef(#[source] jnix::jni::errors::Error),
36+
#[error("Received an invalid result from {0}.{1}: {2}")]
37+
InvalidMethodResult(&'static str, &'static str, String),
38+
}
39+
2640
/// The sender used by [Java_net_mullvad_talpid_ConnectivityListener_notifyDefaultNetworkChange]
2741
/// to notify the route manager of changes to the network.
2842
static ROUTE_UPDATES_TX: Mutex<Option<UnboundedSender<Option<NetworkState>>>> = Mutex::new(None);
@@ -42,15 +56,28 @@ pub struct RouteManagerImpl {
4256

4357
impl RouteManagerImpl {
4458
#[allow(clippy::unused_async)]
45-
pub async fn new() -> Result<Self, Error> {
59+
pub async fn new(android_context: AndroidContext) -> Result<Self, Error> {
4660
// Create a channel between the kotlin client and route manager
4761
let (tx, rx) = futures::channel::mpsc::unbounded();
4862

4963
*ROUTE_UPDATES_TX.lock().unwrap() = Some(tx);
5064

65+
// Try to poll for the current network state at startup.
66+
// This will most likely be null, but it covers the edge case where a NetworkState
67+
// update has been emitted before we anyone starts to listen for route updates some
68+
// time in the future (when connecting).
69+
let last_state = match current_network_state(android_context) {
70+
Ok(initial_state) => initial_state,
71+
Err(err) => {
72+
log::error!("Failed while polling for initial NetworkState");
73+
log::error!("{err}");
74+
None
75+
}
76+
};
77+
5178
let route_manager = RouteManagerImpl {
5279
network_state_updates: rx,
53-
last_state: Default::default(),
80+
last_state,
5481
waiting_for_routes: Default::default(),
5582
};
5683

@@ -157,3 +184,49 @@ pub extern "system" fn Java_net_mullvad_talpid_ConnectivityListener_notifyDefaul
157184
log::warn!("Failed to send offline change event");
158185
}
159186
}
187+
188+
/// Return the current NetworkState according to Android
189+
fn current_network_state(
190+
android_context: AndroidContext,
191+
) -> Result<Option<NetworkState>, JvmError> {
192+
let env = JnixEnv::from(
193+
android_context
194+
.jvm
195+
.attach_current_thread_as_daemon()
196+
.map_err(JvmError::AttachJvmToThread)?,
197+
);
198+
199+
let result = env
200+
.call_method(
201+
android_context.vpn_service.as_obj(),
202+
"getConnectivityListener",
203+
"()Lnet/mullvad/talpid/ConnectivityListener;",
204+
&[],
205+
)
206+
.map_err(|cause| JvmError::CallMethod("getConnectivityListener", cause))?;
207+
208+
let connectivity_listener = match result {
209+
JValue::Object(object) => env
210+
.new_global_ref(object)
211+
.map_err(JvmError::CreateGlobalRef)?,
212+
value => {
213+
return Err(JvmError::InvalidMethodResult(
214+
"MullvadVpnService",
215+
"getConnectivityListener",
216+
format!("{:?}", value),
217+
))
218+
}
219+
};
220+
221+
let network_state = env
222+
.call_method(
223+
connectivity_listener.as_obj(),
224+
"getCurrentDefaultNetworkState",
225+
"()Lnet/mullvad/talpid/model/NetworkState;",
226+
&[],
227+
)
228+
.map_err(|cause| JvmError::CallMethod("getCurrentDefaultNetworkState", cause))?;
229+
230+
let network_state: Option<NetworkState> = FromJava::from_java(&env, network_state);
231+
Ok(network_state)
232+
}

talpid-routing/src/unix/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use futures::channel::{
1111
oneshot,
1212
};
1313
use std::sync::Arc;
14+
#[cfg(target_os = "android")]
15+
use talpid_types::android::AndroidContext;
1416

1517
#[cfg(any(target_os = "linux", target_os = "macos"))]
1618
use futures::stream::Stream;
@@ -165,6 +167,7 @@ impl RouteManagerHandle {
165167
pub async fn spawn(
166168
#[cfg(target_os = "linux")] fwmark: u32,
167169
#[cfg(target_os = "linux")] table_id: u32,
170+
#[cfg(target_os = "android")] android_context: AndroidContext,
168171
) -> Result<Self, Error> {
169172
let (manage_tx, manage_rx) = mpsc::unbounded();
170173
let manage_tx = Arc::new(manage_tx);
@@ -175,6 +178,8 @@ impl RouteManagerHandle {
175178
table_id,
176179
#[cfg(target_os = "macos")]
177180
Arc::downgrade(&manage_tx),
181+
#[cfg(target_os = "android")]
182+
android_context,
178183
)
179184
.await?;
180185
tokio::spawn(manager.run(manage_rx));

0 commit comments

Comments
 (0)