summaryrefslogtreecommitdiffhomepage
path: root/android/app/src
diff options
context:
space:
mode:
authorAlbin <albin@mullvad.net>2023-01-10 15:58:10 +0100
committerAlbin <albin@mullvad.net>2023-01-10 15:58:10 +0100
commit7ea38a3881b92b17658a5be4f0e627601212db6c (patch)
tree96c12212b3f95c7ea588099aec7cb5fdb22942ed /android/app/src
parentfee3b5804555b3287c9c59aecd3682f118735ba8 (diff)
parent57008a509342f547f5e56ef781a7f2e8a18298c0 (diff)
downloadmullvadvpn-7ea38a3881b92b17658a5be4f0e627601212db6c.tar.xz
mullvadvpn-7ea38a3881b92b17658a5be4f0e627601212db6c.zip
Merge branch 'add-instrumented-tests-using-mocked-api'
Diffstat (limited to 'android/app/src')
-rw-r--r--android/app/src/debug/AndroidManifest.xml4
-rw-r--r--android/app/src/debug/kotlin/net/mullvad/mullvadvpn/TestActivity.kt (renamed from android/app/src/debug/kotlin/net.mullvad.mullvadvpn/TestActivity.kt)0
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/ApiEndpoint.kt13
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonInstance.kt56
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt14
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt33
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt8
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionManager.kt13
8 files changed, 86 insertions, 55 deletions
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
index 2a866ff601..e1a8f8be40 100644
--- a/android/app/src/debug/AndroidManifest.xml
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -1,5 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
<application android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
diff --git a/android/app/src/debug/kotlin/net.mullvad.mullvadvpn/TestActivity.kt b/android/app/src/debug/kotlin/net/mullvad/mullvadvpn/TestActivity.kt
index df36947eab..df36947eab 100644
--- a/android/app/src/debug/kotlin/net.mullvad.mullvadvpn/TestActivity.kt
+++ b/android/app/src/debug/kotlin/net/mullvad/mullvadvpn/TestActivity.kt
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/ApiEndpoint.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/ApiEndpoint.kt
deleted file mode 100644
index df40bfac4d..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/ApiEndpoint.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.mullvad.mullvadvpn.model
-
-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,
- val forceDirectConnection: Boolean
-) : Parcelable
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonInstance.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonInstance.kt
index 0d1750f625..67ec721a52 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonInstance.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonInstance.kt
@@ -2,6 +2,8 @@ package net.mullvad.mullvadvpn.service
import java.io.File
import kotlin.properties.Delegates.observable
+import kotlin.reflect.KClass
+import kotlin.reflect.safeCast
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.Channel
@@ -9,14 +11,17 @@ import kotlinx.coroutines.channels.ClosedReceiveChannelException
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.actor
import kotlinx.coroutines.channels.trySendBlocking
+import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointConfiguration
import net.mullvad.mullvadvpn.util.Intermittent
private const val RELAYS_FILE = "relays.json"
-class DaemonInstance(val vpnService: MullvadVpnService) {
- private enum class Command {
- START,
- STOP,
+class DaemonInstance(
+ val vpnService: MullvadVpnService
+) {
+ sealed class Command {
+ data class Start(val apiEndpointConfiguration: ApiEndpointConfiguration) : Command()
+ object Stop : Command()
}
private val commandChannel = spawnActor()
@@ -27,12 +32,12 @@ class DaemonInstance(val vpnService: MullvadVpnService) {
val intermittentDaemon = Intermittent<MullvadDaemon>()
- fun start() {
- commandChannel.trySendBlocking(Command.START)
+ fun start(apiEndpointConfiguration: ApiEndpointConfiguration) {
+ commandChannel.trySendBlocking(Command.Start(apiEndpointConfiguration))
}
fun stop() {
- commandChannel.trySendBlocking(Command.STOP)
+ commandChannel.trySendBlocking(Command.Stop)
}
fun onDestroy() {
@@ -46,30 +51,25 @@ class DaemonInstance(val vpnService: MullvadVpnService) {
prepareFiles()
while (isRunning) {
- if (!waitForCommand(channel, Command.START)) {
- break
- }
-
- startDaemon()
-
- isRunning = waitForCommand(channel, Command.STOP)
-
+ val startCommand = waitForCommand(channel, Command.Start::class) ?: break
+ startDaemon(startCommand.apiEndpointConfiguration)
+ isRunning = waitForCommand(channel, Command.Stop::class) is Command.Stop
stopDaemon()
}
}
- private suspend fun waitForCommand(
+ private suspend fun <T : Command> waitForCommand(
channel: ReceiveChannel<Command>,
- command: Command
- ): Boolean {
- try {
- while (channel.receive() != command) {
- // Wait for command
- }
-
- return true
+ command: KClass<T>
+ ): T? {
+ return try {
+ var receivedCommand: T?
+ do {
+ receivedCommand = command.safeCast(channel.receive())
+ } while (receivedCommand == null)
+ receivedCommand
} catch (exception: ClosedReceiveChannelException) {
- return false
+ null
}
}
@@ -91,8 +91,10 @@ class DaemonInstance(val vpnService: MullvadVpnService) {
}
}
- private suspend fun startDaemon() {
- val newDaemon = MullvadDaemon(vpnService).apply {
+ private suspend fun startDaemon(
+ apiEndpointConfiguration: ApiEndpointConfiguration
+ ) {
+ val newDaemon = MullvadDaemon(vpnService, apiEndpointConfiguration).apply {
onDaemonStopped = {
intermittentDaemon.spawnUpdate(null)
daemon = null
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt
index aac23cee25..6d82ee617c 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt
@@ -2,7 +2,8 @@ package net.mullvad.mullvadvpn.service
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
-import net.mullvad.mullvadvpn.model.ApiEndpoint
+import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpoint
+import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointConfiguration
import net.mullvad.mullvadvpn.model.AppVersionInfo
import net.mullvad.mullvadvpn.model.Device
import net.mullvad.mullvadvpn.model.DeviceEvent
@@ -21,7 +22,10 @@ import net.mullvad.mullvadvpn.model.TunnelState
import net.mullvad.mullvadvpn.model.VoucherSubmissionResult
import net.mullvad.talpid.util.EventNotifier
-class MullvadDaemon(vpnService: MullvadVpnService) {
+class MullvadDaemon(
+ vpnService: MullvadVpnService,
+ apiEndpointConfiguration: ApiEndpointConfiguration
+) {
protected var daemonInterfaceAddress = 0L
val onSettingsChange = EventNotifier<Settings?>(null)
@@ -39,8 +43,12 @@ class MullvadDaemon(vpnService: MullvadVpnService) {
init {
System.loadLibrary("mullvad_jni")
+
initialize(
- vpnService, vpnService.cacheDir.absolutePath, vpnService.filesDir.absolutePath, null
+ vpnService = vpnService,
+ cacheDirectory = vpnService.cacheDir.absolutePath,
+ resourceDirectory = vpnService.filesDir.absolutePath,
+ apiEndpoint = apiEndpointConfiguration.apiEndpoint()
)
onSettingsChange.notify(getSettings())
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
index 4753294376..c35125c326 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
@@ -12,7 +12,11 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
+import net.mullvad.mullvadvpn.BuildConfig
import net.mullvad.mullvadvpn.di.vpnServiceModule
+import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointConfiguration
+import net.mullvad.mullvadvpn.lib.endpoint.DefaultApiEndpointConfiguration
+import net.mullvad.mullvadvpn.lib.endpoint.getApiEndpointConfigurationExtras
import net.mullvad.mullvadvpn.model.Settings
import net.mullvad.mullvadvpn.model.TunnelState
import net.mullvad.mullvadvpn.service.endpoint.ServiceEndpoint
@@ -64,11 +68,15 @@ class MullvadVpnService : TalpidVpnService() {
}
}
+ private var apiEndpointConfiguration: ApiEndpointConfiguration =
+ DefaultApiEndpointConfiguration()
+
override fun onCreate() {
super.onCreate()
Log.d(TAG, "Initializing service")
loadKoinModules(vpnServiceModule)
+
daemonInstance = DaemonInstance(this)
keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
@@ -97,14 +105,6 @@ class MullvadVpnService : TalpidVpnService() {
endpoint.accountCache
)
- daemonInstance.apply {
- intermittentDaemon.registerListener(this@MullvadVpnService) { daemon ->
- handleDaemonInstance(daemon)
- }
-
- start()
- }
-
// Remove any leftover tunnel state persistence data
getSharedPreferences("tunnel_state", MODE_PRIVATE)
.edit()
@@ -114,6 +114,21 @@ class MullvadVpnService : TalpidVpnService() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "Starting service")
+
+ if (BuildConfig.DEBUG) {
+ intent?.getApiEndpointConfigurationExtras()?.let {
+ apiEndpointConfiguration = it
+ }
+ }
+
+ daemonInstance.apply {
+ intermittentDaemon.registerListener(this@MullvadVpnService) { daemon ->
+ handleDaemonInstance(daemon)
+ }
+
+ start(apiEndpointConfiguration)
+ }
+
val startResult = super.onStartCommand(intent, flags, startId)
var quitCommand = false
@@ -231,7 +246,7 @@ class MullvadVpnService : TalpidVpnService() {
daemonInstance.apply {
stop()
- start()
+ start(apiEndpointConfiguration)
}
} else {
Log.d(TAG, "Ignoring restart because onDestroy has executed")
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
index becf82a69e..fc53d94aaf 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
@@ -22,7 +22,6 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
@@ -34,6 +33,7 @@ import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.component.ChangelogDialog
import net.mullvad.mullvadvpn.dataproxy.MullvadProblemReport
import net.mullvad.mullvadvpn.di.uiModule
+import net.mullvad.mullvadvpn.lib.endpoint.getApiEndpointConfigurationExtras
import net.mullvad.mullvadvpn.model.AccountExpiry
import net.mullvad.mullvadvpn.model.DeviceState
import net.mullvad.mullvadvpn.ui.fragments.DeviceRevokedFragment
@@ -103,7 +103,11 @@ open class MainActivity : FragmentActivity() {
override fun onStart() {
Log.d("mullvad", "Starting main activity")
super.onStart()
- serviceConnectionManager.bind(vpnPermissionRequestHandler = ::requestVpnPermission)
+
+ serviceConnectionManager.bind(
+ vpnPermissionRequestHandler = ::requestVpnPermission,
+ apiEndpointConfiguration = intent?.getApiEndpointConfigurationExtras()
+ )
}
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionManager.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionManager.kt
index e1654476b8..f912f765a8 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionManager.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionManager.kt
@@ -8,6 +8,9 @@ import android.os.Messenger
import android.util.Log
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
+import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointConfiguration
+import net.mullvad.mullvadvpn.lib.endpoint.BuildConfig
+import net.mullvad.mullvadvpn.lib.endpoint.putApiEndpointConfigurationExtra
import net.mullvad.mullvadvpn.service.MullvadVpnService
import net.mullvad.talpid.util.EventNotifier
@@ -47,9 +50,17 @@ class ServiceConnectionManager(
}
}
- fun bind(vpnPermissionRequestHandler: () -> Unit) {
+ fun bind(
+ vpnPermissionRequestHandler: () -> Unit,
+ apiEndpointConfiguration: ApiEndpointConfiguration?
+ ) {
this.vpnPermissionRequestHandler = vpnPermissionRequestHandler
val intent = Intent(context, MullvadVpnService::class.java)
+
+ if (BuildConfig.DEBUG && apiEndpointConfiguration != null) {
+ intent.putApiEndpointConfigurationExtra(apiEndpointConfiguration)
+ }
+
context.startService(intent)
context.bindService(intent, serviceConnection, 0)
}