summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson@mullvad.net>2024-08-30 13:54:11 +0200
committerDavid Göransson <david.goransson@mullvad.net>2024-08-30 13:54:11 +0200
commitb0c1bcc5b49aa83c80dc125980f8ab745008397e (patch)
treeb324a4dfcb01d4206f773390809ec4fc8b3a5b2c
parent2c8d4f1be088c7d55526c5d2dea6e65bc6f94193 (diff)
parent7f1fcf7503b5f0a8556d067dcf6e1bab443c849f (diff)
downloadmullvadvpn-b0c1bcc5b49aa83c80dc125980f8ab745008397e.tar.xz
mullvadvpn-b0c1bcc5b49aa83c80dc125980f8ab745008397e.zip
Merge branch 'managementservicestop-sometimes-crashes-droid-1284'
-rw-r--r--android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/constant/DiConstant.kt2
-rw-r--r--android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpoint.kt12
-rw-r--r--android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointConfiguration.kt7
-rw-r--r--android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointIntentExtensions.kt8
-rw-r--r--android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointOverride.kt17
-rw-r--r--android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt21
-rw-r--r--android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/DefaultApiEndpointConfiguration.kt8
-rw-r--r--android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonConfig.kt11
-rw-r--r--android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt4
-rw-r--r--android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt68
-rw-r--r--android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/di/ApiEndpointModule.kt19
-rw-r--r--android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/di/VpnServiceModule.kt23
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt4
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt8
-rw-r--r--mullvad-jni/src/api.rs150
-rw-r--r--mullvad-jni/src/classes.rs1
16 files changed, 167 insertions, 196 deletions
diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/constant/DiConstant.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/constant/DiConstant.kt
index 0acd41c7ec..9fac18a479 100644
--- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/constant/DiConstant.kt
+++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/constant/DiConstant.kt
@@ -1,3 +1,5 @@
package net.mullvad.mullvadvpn.lib.common.constant
const val GRPC_SOCKET_FILE_NAMED_ARGUMENT = "RPC_SOCKET"
+const val FILES_DIR_NAMED_ARGUMENT = "FILES_DIR"
+const val CACHE_DIR_NAMED_ARGUMENT = "CACHE_DIR"
diff --git a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpoint.kt b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpoint.kt
deleted file mode 100644
index 1fd26bddae..0000000000
--- a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpoint.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.mullvad.mullvadvpn.lib.endpoint
-
-import android.os.Parcelable
-import java.net.InetSocketAddress
-import kotlinx.parcelize.Parcelize
-
-@Parcelize
-data class ApiEndpoint(
- val address: InetSocketAddress,
- val disableAddressCache: Boolean,
- val disableTls: Boolean,
-) : Parcelable
diff --git a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointConfiguration.kt b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointConfiguration.kt
deleted file mode 100644
index 164a9fffa7..0000000000
--- a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointConfiguration.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package net.mullvad.mullvadvpn.lib.endpoint
-
-import android.os.Parcelable
-
-interface ApiEndpointConfiguration : Parcelable {
- fun apiEndpoint(): ApiEndpoint?
-}
diff --git a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointIntentExtensions.kt b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointIntentExtensions.kt
index cf2f2fb0dd..9e46c5dda8 100644
--- a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointIntentExtensions.kt
+++ b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointIntentExtensions.kt
@@ -5,13 +5,13 @@ import android.os.Build
private const val OVERRIDE_API_EXTRA_NAME = "override_api"
-fun Intent.putApiEndpointConfigurationExtra(apiEndpointConfiguration: ApiEndpointConfiguration) {
- putExtra(OVERRIDE_API_EXTRA_NAME, apiEndpointConfiguration)
+fun Intent.putApiEndpointConfigurationExtra(apiEndpointOverrideConfiguration: ApiEndpointOverride) {
+ putExtra(OVERRIDE_API_EXTRA_NAME, apiEndpointOverrideConfiguration)
}
-fun Intent.getApiEndpointConfigurationExtras(): ApiEndpointConfiguration? {
+fun Intent.getApiEndpointConfigurationExtras(): ApiEndpointOverride? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- getParcelableExtra(OVERRIDE_API_EXTRA_NAME, ApiEndpointConfiguration::class.java)
+ getParcelableExtra(OVERRIDE_API_EXTRA_NAME, ApiEndpointOverride::class.java)
} else {
getParcelableExtra(OVERRIDE_API_EXTRA_NAME)
}
diff --git a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointOverride.kt b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointOverride.kt
new file mode 100644
index 0000000000..5201e86386
--- /dev/null
+++ b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointOverride.kt
@@ -0,0 +1,17 @@
+package net.mullvad.mullvadvpn.lib.endpoint
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class ApiEndpointOverride(
+ val hostname: String,
+ val port: Int = CUSTOM_ENDPOINT_HTTPS_PORT,
+ val disableAddressCache: Boolean = true,
+ val disableTls: Boolean = false,
+ val forceDirectConnection: Boolean = true,
+) : Parcelable {
+ companion object {
+ const val CUSTOM_ENDPOINT_HTTPS_PORT = 443
+ }
+}
diff --git a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt
deleted file mode 100644
index 92dffed35f..0000000000
--- a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package net.mullvad.mullvadvpn.lib.endpoint
-
-import java.net.InetSocketAddress
-import kotlinx.parcelize.Parcelize
-
-const val CUSTOM_ENDPOINT_HTTPS_PORT = 443
-
-@Parcelize
-data class CustomApiEndpointConfiguration(
- val hostname: String,
- val port: Int,
- val disableAddressCache: Boolean = true,
- val disableTls: Boolean = false,
-) : ApiEndpointConfiguration {
- override fun apiEndpoint() =
- ApiEndpoint(
- address = InetSocketAddress(hostname, port),
- disableAddressCache = disableAddressCache,
- disableTls = disableTls,
- )
-}
diff --git a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/DefaultApiEndpointConfiguration.kt b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/DefaultApiEndpointConfiguration.kt
deleted file mode 100644
index 90b9bc7896..0000000000
--- a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/DefaultApiEndpointConfiguration.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package net.mullvad.mullvadvpn.lib.endpoint
-
-import kotlinx.parcelize.Parcelize
-
-@Parcelize
-class DefaultApiEndpointConfiguration : ApiEndpointConfiguration {
- override fun apiEndpoint(): ApiEndpoint? = null
-}
diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonConfig.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonConfig.kt
new file mode 100644
index 0000000000..06450a1583
--- /dev/null
+++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonConfig.kt
@@ -0,0 +1,11 @@
+package net.mullvad.mullvadvpn.service
+
+import java.io.File
+import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointOverride
+
+data class DaemonConfig(
+ val rpcSocket: File,
+ val filesDir: File,
+ val cacheDir: File,
+ val apiEndpointOverride: ApiEndpointOverride?,
+)
diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt
index 5bfae14383..d95892305b 100644
--- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt
+++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt
@@ -1,6 +1,6 @@
package net.mullvad.mullvadvpn.service
-import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpoint
+import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointOverride
object MullvadDaemon {
init {
@@ -12,7 +12,7 @@ object MullvadDaemon {
rpcSocketPath: String,
filesDirectory: String,
cacheDirectory: String,
- apiEndpoint: ApiEndpoint?,
+ apiEndpointOverride: ApiEndpointOverride?,
)
external fun shutdown()
diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
index 5603392376..2b7833fb8d 100644
--- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
+++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
@@ -11,21 +11,17 @@ import androidx.lifecycle.lifecycleScope
import arrow.atomic.AtomicInt
import co.touchlab.kermit.Logger
import java.io.File
-import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
-import net.mullvad.mullvadvpn.lib.common.constant.GRPC_SOCKET_FILE_NAMED_ARGUMENT
import net.mullvad.mullvadvpn.lib.common.constant.KEY_CONNECT_ACTION
import net.mullvad.mullvadvpn.lib.common.constant.KEY_DISCONNECT_ACTION
import net.mullvad.mullvadvpn.lib.daemon.grpc.ManagementService
-import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointConfiguration
import net.mullvad.mullvadvpn.lib.endpoint.getApiEndpointConfigurationExtras
import net.mullvad.mullvadvpn.lib.intent.IntentProvider
import net.mullvad.mullvadvpn.lib.model.TunnelState
import net.mullvad.mullvadvpn.lib.shared.ConnectionProxy
-import net.mullvad.mullvadvpn.service.di.apiEndpointModule
import net.mullvad.mullvadvpn.service.di.vpnServiceModule
import net.mullvad.mullvadvpn.service.migration.MigrateSplitTunneling
import net.mullvad.mullvadvpn.service.notifications.ForegroundNotificationManager
@@ -34,7 +30,6 @@ import net.mullvad.mullvadvpn.service.notifications.NotificationManager
import net.mullvad.talpid.TalpidVpnService
import org.koin.android.ext.android.getKoin
import org.koin.core.context.loadKoinModules
-import org.koin.core.qualifier.named
private const val RELAYS_FILE = "relays.json"
@@ -42,12 +37,11 @@ class MullvadVpnService : TalpidVpnService() {
private lateinit var keyguardManager: KeyguardManager
- private lateinit var apiEndpointConfiguration: ApiEndpointConfiguration
private lateinit var managementService: ManagementService
private lateinit var migrateSplitTunneling: MigrateSplitTunneling
private lateinit var intentProvider: IntentProvider
private lateinit var connectionProxy: ConnectionProxy
- private lateinit var rpcSocketFile: File
+ private lateinit var daemonConfig: DaemonConfig
private lateinit var foregroundNotificationHandler: ForegroundNotificationManager
@@ -59,7 +53,7 @@ class MullvadVpnService : TalpidVpnService() {
super.onCreate()
Logger.i("MullvadVpnService: onCreate")
- loadKoinModules(listOf(vpnServiceModule, apiEndpointModule))
+ loadKoinModules(listOf(vpnServiceModule))
with(getKoin()) {
// Needed to create all the notification channels
get<NotificationChannelFactory>()
@@ -70,27 +64,32 @@ class MullvadVpnService : TalpidVpnService() {
ForegroundNotificationManager(this@MullvadVpnService, get())
get<NotificationManager>()
- apiEndpointConfiguration = get()
+ daemonConfig = get()
migrateSplitTunneling = get()
intentProvider = get()
connectionProxy = get()
- rpcSocketFile = get(named(GRPC_SOCKET_FILE_NAMED_ARGUMENT))
}
keyguardManager = getSystemService<KeyguardManager>()!!
- // TODO We should avoid lifecycleScope.launch (current needed due to InetSocketAddress
- // with intent from API)
- lifecycleScope.launch(context = Dispatchers.IO) {
- prepareFiles(this@MullvadVpnService)
- migrateSplitTunneling.migrate()
+ prepareFiles(this@MullvadVpnService)
+ migrateSplitTunneling.migrate()
- Logger.i("Start daemon")
- startDaemon()
+ // If it is a debug build and we have an api override in the intent, use it
+ // This is for injecting hostname and port for our mock api tests
+ val intentApiOverride =
+ intentProvider.getLatestIntent()?.getApiEndpointConfigurationExtras()
+ val updatedConfig =
+ if (BuildConfig.DEBUG && intentApiOverride != null) {
+ daemonConfig.copy(apiEndpointOverride = intentApiOverride)
+ } else {
+ daemonConfig
+ }
+ Logger.i("Start daemon")
+ startDaemon(updatedConfig)
- Logger.i("Start management service")
- managementService.start()
- }
+ Logger.i("Start management service")
+ managementService.start()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@@ -147,24 +146,17 @@ class MullvadVpnService : TalpidVpnService() {
}
}
- private fun startDaemon() {
- val apiEndpointConfiguration =
- if (BuildConfig.DEBUG) {
- intentProvider.getLatestIntent()?.getApiEndpointConfigurationExtras()
- ?: apiEndpointConfiguration
- } else {
- apiEndpointConfiguration
- }
-
- MullvadDaemon.initialize(
- vpnService = this@MullvadVpnService,
- rpcSocketPath = rpcSocketFile.absolutePath,
- filesDirectory = filesDir.absolutePath,
- cacheDirectory = cacheDir.absolutePath,
- apiEndpoint = apiEndpointConfiguration.apiEndpoint(),
- )
- Logger.i("MullvadVpnService: Daemon initialized")
- }
+ private fun startDaemon(daemonConfig: DaemonConfig) =
+ with(daemonConfig) {
+ MullvadDaemon.initialize(
+ vpnService = this@MullvadVpnService,
+ rpcSocketPath = rpcSocket.absolutePath,
+ filesDirectory = filesDir.absolutePath,
+ cacheDirectory = cacheDir.absolutePath,
+ apiEndpointOverride = apiEndpointOverride,
+ )
+ Logger.i("MullvadVpnService: Daemon initialized")
+ }
private fun emptyBinder() =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/di/ApiEndpointModule.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/di/ApiEndpointModule.kt
deleted file mode 100644
index 4d86559bc6..0000000000
--- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/di/ApiEndpointModule.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.mullvad.mullvadvpn.service.di
-
-import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointConfiguration
-import net.mullvad.mullvadvpn.lib.endpoint.CUSTOM_ENDPOINT_HTTPS_PORT
-import net.mullvad.mullvadvpn.lib.endpoint.CustomApiEndpointConfiguration
-import net.mullvad.mullvadvpn.lib.endpoint.DefaultApiEndpointConfiguration
-import net.mullvad.mullvadvpn.service.BuildConfig
-import org.koin.dsl.bind
-import org.koin.dsl.module
-
-val apiEndpointModule = module {
- single {
- if (BuildConfig.FLAVOR_infrastructure != "prod") {
- CustomApiEndpointConfiguration(BuildConfig.API_ENDPOINT, CUSTOM_ENDPOINT_HTTPS_PORT)
- } else {
- DefaultApiEndpointConfiguration()
- }
- } bind ApiEndpointConfiguration::class
-}
diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/di/VpnServiceModule.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/di/VpnServiceModule.kt
index e229e0ed24..9d4636cf07 100644
--- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/di/VpnServiceModule.kt
+++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/di/VpnServiceModule.kt
@@ -2,7 +2,13 @@ package net.mullvad.mullvadvpn.service.di
import androidx.core.app.NotificationManagerCompat
import kotlinx.coroutines.MainScope
+import net.mullvad.mullvadvpn.lib.common.constant.CACHE_DIR_NAMED_ARGUMENT
+import net.mullvad.mullvadvpn.lib.common.constant.FILES_DIR_NAMED_ARGUMENT
+import net.mullvad.mullvadvpn.lib.common.constant.GRPC_SOCKET_FILE_NAMED_ARGUMENT
+import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointOverride
import net.mullvad.mullvadvpn.lib.model.NotificationChannel
+import net.mullvad.mullvadvpn.service.BuildConfig
+import net.mullvad.mullvadvpn.service.DaemonConfig
import net.mullvad.mullvadvpn.service.migration.MigrateSplitTunneling
import net.mullvad.mullvadvpn.service.notifications.NotificationChannelFactory
import net.mullvad.mullvadvpn.service.notifications.NotificationManager
@@ -12,12 +18,15 @@ import net.mullvad.mullvadvpn.service.notifications.tunnelstate.TunnelStateNotif
import org.koin.android.ext.koin.androidContext
import org.koin.core.module.dsl.createdAtStart
import org.koin.core.module.dsl.withOptions
+import org.koin.core.qualifier.named
import org.koin.dsl.bind
import org.koin.dsl.module
val vpnServiceModule = module {
single { NotificationManagerCompat.from(androidContext()) }
single { androidContext().resources }
+ single(named(FILES_DIR_NAMED_ARGUMENT)) { androidContext().filesDir }
+ single(named(CACHE_DIR_NAMED_ARGUMENT)) { androidContext().cacheDir }
single { NotificationChannel.TunnelUpdates } bind NotificationChannel::class
single { NotificationChannel.AccountUpdates } bind NotificationChannel::class
@@ -46,4 +55,18 @@ val vpnServiceModule = module {
}
single { MigrateSplitTunneling(androidContext()) }
+
+ single {
+ DaemonConfig(
+ rpcSocket = get(named(GRPC_SOCKET_FILE_NAMED_ARGUMENT)),
+ filesDir = get(named(FILES_DIR_NAMED_ARGUMENT)),
+ cacheDir = get(named(CACHE_DIR_NAMED_ARGUMENT)),
+ apiEndpointOverride =
+ if (BuildConfig.FLAVOR_infrastructure != "prod") {
+ ApiEndpointOverride(BuildConfig.API_ENDPOINT)
+ } else {
+ null
+ },
+ )
+ }
}
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt
index 9abd2aa7e2..5684b58e17 100644
--- a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt
@@ -6,7 +6,7 @@ import android.widget.Button
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
-import net.mullvad.mullvadvpn.lib.endpoint.CustomApiEndpointConfiguration
+import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointOverride
import net.mullvad.mullvadvpn.lib.endpoint.putApiEndpointConfigurationExtra
import net.mullvad.mullvadvpn.test.common.constant.APP_LAUNCH_TIMEOUT
import net.mullvad.mullvadvpn.test.common.constant.CONNECTION_TIMEOUT
@@ -23,7 +23,7 @@ class AppInteractor(
private val targetContext: Context,
private val targetPackageName: String,
) {
- fun launch(customApiEndpointConfiguration: CustomApiEndpointConfiguration? = null) {
+ fun launch(customApiEndpointConfiguration: ApiEndpointOverride? = null) {
device.pressHome()
// Wait for launcher
device.wait(
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt
index bd236bb978..d3590fc056 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt
@@ -8,7 +8,7 @@ import androidx.test.uiautomator.UiDevice
import co.touchlab.kermit.Logger
import de.mannodermaus.junit5.extensions.GrantPermissionExtension
import java.net.InetAddress
-import net.mullvad.mullvadvpn.lib.endpoint.CustomApiEndpointConfiguration
+import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointOverride
import net.mullvad.mullvadvpn.test.common.interactor.AppInteractor
import net.mullvad.mullvadvpn.test.common.rule.CaptureScreenshotOnFailedTestRule
import net.mullvad.mullvadvpn.test.mockapi.constant.LOG_TAG
@@ -33,7 +33,7 @@ abstract class MockApiTest {
lateinit var device: UiDevice
lateinit var targetContext: Context
lateinit var app: AppInteractor
- lateinit var endpoint: CustomApiEndpointConfiguration
+ lateinit var endpoint: ApiEndpointOverride
@BeforeEach
open fun setup() {
@@ -54,8 +54,8 @@ abstract class MockApiTest {
mockWebServer.shutdown()
}
- private fun createEndpoint(port: Int): CustomApiEndpointConfiguration {
- return CustomApiEndpointConfiguration(
+ private fun createEndpoint(port: Int): ApiEndpointOverride {
+ return ApiEndpointOverride(
InetAddress.getLocalHost().hostName,
port,
disableAddressCache = true,
diff --git a/mullvad-jni/src/api.rs b/mullvad-jni/src/api.rs
index 3f76e74839..b7dd5d6747 100644
--- a/mullvad-jni/src/api.rs
+++ b/mullvad-jni/src/api.rs
@@ -1,103 +1,95 @@
-use jnix::{
- jni::{
- objects::JObject,
- signature::{JavaType, Primitive},
- },
- FromJava, JnixEnv,
-};
-use std::net::{IpAddr, SocketAddr};
+#[cfg(feature = "api-override")]
+use jnix::FromJava;
+use jnix::{jni::objects::JObject, JnixEnv};
+#[cfg(feature = "api-override")]
+use std::net::{SocketAddr, ToSocketAddrs};
+#[cfg(feature = "api-override")]
pub fn api_endpoint_from_java(
env: &JnixEnv<'_>,
- object: JObject<'_>,
+ endpoint_override: JObject<'_>,
) -> Option<mullvad_api::ApiEndpoint> {
- if object.is_null() {
+ if endpoint_override.is_null() {
return None;
}
- let mut endpoint = mullvad_api::ApiEndpoint::from_env_vars();
+ let hostname = hostname_from_java(env, endpoint_override);
+ let port = port_from_java(env, endpoint_override);
+ let address = Some(create_socket_addr(hostname.clone(), port));
- let address = env
- .call_method(object, "component1", "()Ljava/net/InetSocketAddress;", &[])
- .expect("missing ApiEndpoint.address")
- .l()
- .expect("ApiEndpoint.address is not an InetSocketAddress");
+ Some(mullvad_api::ApiEndpoint {
+ host: Some(hostname),
+ address,
+ disable_address_cache: disable_address_cache_from_java(env, endpoint_override),
+ disable_tls: disable_tls_from_java(env, endpoint_override),
+ force_direct: force_direct_from_java(env, endpoint_override),
+ })
+}
- endpoint.address = Some(
- try_socketaddr_from_java(env, address).expect("received unresolved InetSocketAddress"),
- );
- endpoint.host = try_hostname_from_java(env, address);
- #[cfg(feature = "api-override")]
- {
- endpoint.disable_address_cache = env
- .call_method(object, "component2", "()Z", &[])
- .expect("missing ApiEndpoint.disableAddressCache")
- .z()
- .expect("ApiEndpoint.disableAddressCache is not a bool");
- endpoint.disable_tls = env
- .call_method(object, "component3", "()Z", &[])
- .expect("missing ApiEndpoint.disableTls")
- .z()
- .expect("ApiEndpoint.disableTls is not a bool");
+#[cfg(not(feature = "api-override"))]
+pub fn api_endpoint_from_java(
+ _env: &JnixEnv<'_>,
+ endpoint_override: JObject<'_>,
+) -> Option<mullvad_api::ApiEndpoint> {
+ if endpoint_override.is_null() {
+ return None;
}
-
- Some(endpoint)
+ panic!("Trying to set api override when feature is disabled")
}
-/// Converts InetSocketAddress to a SocketAddr. Return `None` if the hostname is unresolved.
-fn try_socketaddr_from_java(env: &JnixEnv<'_>, address: JObject<'_>) -> Option<SocketAddr> {
- let class = env.get_class("java/net/InetSocketAddress");
-
- let method_id = env
- .get_method_id(&class, "getAddress", "()Ljava/net/InetAddress;")
- .expect("Failed to get method ID for InetSocketAddress.getAddress()");
- let return_type = JavaType::Object("java/net/InetAddress".to_owned());
+/// Resolves the hostname and port to SocketAddr
+#[cfg(feature = "api-override")]
+fn create_socket_addr(hostname: String, port: u16) -> SocketAddr {
+ //Resolve ip address from hostname
+ (hostname, port)
+ .to_socket_addrs()
+ .expect("could not resolve address")
+ .next()
+ .expect("no ip address received")
+}
- let ip_addr = env
- .call_method_unchecked(address, method_id, return_type, &[])
- .expect("Failed to call InetSocketAddress.getAddress()")
+#[cfg(feature = "api-override")]
+fn hostname_from_java(env: &JnixEnv<'_>, endpoint_override: JObject<'_>) -> String {
+ let hostname = env
+ .call_method(endpoint_override, "component1", "()Ljava/lang/String;", &[])
+ .expect("missing ApiEndpointOverride.hostname")
.l()
- .expect("Call to InetSocketAddress.getAddress() did not return an object");
+ .expect("ApiEndpointOverride.hostname is not a string");
- if ip_addr.is_null() {
- return None;
- }
-
- let method_id = env
- .get_method_id(&class, "getPort", "()I")
- .expect("Failed to get method ID for InetSocketAddress.getPort()");
- let return_type = JavaType::Primitive(Primitive::Int);
+ String::from_java(env, hostname)
+}
+#[cfg(feature = "api-override")]
+fn port_from_java(env: &JnixEnv<'_>, endpoint_override: JObject<'_>) -> u16 {
let port = env
- .call_method_unchecked(address, method_id, return_type, &[])
- .expect("Failed to call InetSocketAddress.getPort()")
+ .call_method(endpoint_override, "component2", "()I", &[])
+ .expect("missing ApiEndpointOverride.port")
.i()
- .expect("Call to InetSocketAddress.getPort() did not return an int");
+ .expect("ApiEndpointOverride.port is not a int");
- Some(SocketAddr::new(
- IpAddr::from_java(env, ip_addr),
- u16::try_from(port).expect("invalid port"),
- ))
+ u16::try_from(port).expect("invalid port")
}
-/// Returns the hostname for an InetSocketAddress. This may be an IP address converted to a string.
-fn try_hostname_from_java(env: &JnixEnv<'_>, address: JObject<'_>) -> Option<String> {
- let class = env.get_class("java/net/InetSocketAddress");
-
- let method_id = env
- .get_method_id(&class, "getHostString", "()Ljava/lang/String;")
- .expect("Failed to get method ID for InetSocketAddress.getHostString()");
- let return_type = JavaType::Object("java/lang/String".to_owned());
-
- let hostname = env
- .call_method_unchecked(address, method_id, return_type, &[])
- .expect("Failed to call InetSocketAddress.getHostString()")
- .l()
- .expect("Call to InetSocketAddress.getHostString() did not return an object");
+#[cfg(feature = "api-override")]
+fn disable_address_cache_from_java(env: &JnixEnv<'_>, endpoint_override: JObject<'_>) -> bool {
+ env.call_method(endpoint_override, "component3", "()Z", &[])
+ .expect("missing ApiEndpointOverride.disableAddressCache")
+ .z()
+ .expect("ApiEndpointOverride.disableAddressCache is not a bool")
+}
- if hostname.is_null() {
- return None;
- }
+#[cfg(feature = "api-override")]
+fn disable_tls_from_java(env: &JnixEnv<'_>, endpoint_override: JObject<'_>) -> bool {
+ env.call_method(endpoint_override, "component4", "()Z", &[])
+ .expect("missing ApiEndpointOverride.disableTls")
+ .z()
+ .expect("ApiEndpointOverride.disableTls is not a bool")
+}
- Some(String::from_java(env, hostname))
+#[cfg(feature = "api-override")]
+fn force_direct_from_java(env: &JnixEnv<'_>, endpoint_override: JObject<'_>) -> bool {
+ env.call_method(endpoint_override, "component5", "()Z", &[])
+ .expect("missing ApiEndpointOverride.forceDirectConnection")
+ .z()
+ .expect("ApiEndpointOverride.forceDirectConnection is not a bool")
}
diff --git a/mullvad-jni/src/classes.rs b/mullvad-jni/src/classes.rs
index 7d8b64cf37..2dcb44156f 100644
--- a/mullvad-jni/src/classes.rs
+++ b/mullvad-jni/src/classes.rs
@@ -13,4 +13,5 @@ pub const CLASSES: &[&str] = &[
"net/mullvad/talpid/model/CreateTunResult$TunnelDeviceError",
"net/mullvad/talpid/ConnectivityListener",
"net/mullvad/talpid/TalpidVpnService",
+ "net/mullvad/mullvadvpn/lib/endpoint/ApiEndpointOverride",
];