Skip to content

Commit

Permalink
fix: tile control and kernel sync (#320)
Browse files Browse the repository at this point in the history
increase auto tunnel delay to 3 seconds

optimize stats job by killing it when app is backgrounded

fix tunnel launch from background

add restart of services and tunnels after update
  • Loading branch information
zaneschepke authored Aug 18, 2024
1 parent 3f4673b commit 30851a7
Show file tree
Hide file tree
Showing 22 changed files with 235 additions and 109 deletions.
17 changes: 17 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,16 @@
android:stopWithTask="false"
tools:node="merge" />

<service
android:name=".service.foreground.TunnelBackgroundService"
android:exported="false"
android:foregroundServiceType="systemExempted"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
</service>

<receiver
android:name=".receiver.BootReceiver"
android:enabled="true"
Expand All @@ -184,6 +194,13 @@
android:name=".receiver.BackgroundActionReceiver"
android:enabled="true"
android:exported="false"/>
<receiver
android:name=".receiver.AppUpdateReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
<receiver
android:name=".receiver.KernelReceiver"
android:exported="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ package com.zaneschepke.wireguardautotunnel
import android.app.Application
import android.os.StrictMode
import android.os.StrictMode.ThreadPolicy
import com.zaneschepke.logcatter.LocalLogCollector
import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.module.IoDispatcher
import com.zaneschepke.wireguardautotunnel.util.ReleaseTree
import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject

Expand All @@ -17,6 +22,13 @@ class WireGuardAutoTunnel : Application() {
@ApplicationScope
lateinit var applicationScope: CoroutineScope

@Inject
lateinit var localLogCollector: LocalLogCollector

@Inject
@IoDispatcher
lateinit var ioDispatcher: CoroutineDispatcher

override fun onCreate() {
super.onCreate()
instance = this
Expand All @@ -33,6 +45,11 @@ class WireGuardAutoTunnel : Application() {
} else {
Timber.plant(ReleaseTree())
}
if (!isRunningOnTv()) {
applicationScope.launch(ioDispatcher) {
localLogCollector.start()
}
}
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.zaneschepke.wireguardautotunnel.receiver

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.util.extensions.startTunnelBackground
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject

@AndroidEntryPoint
class AppUpdateReceiver : BroadcastReceiver() {

@Inject
@ApplicationScope
lateinit var applicationScope: CoroutineScope

@Inject
lateinit var appDataRepository: AppDataRepository

@Inject
lateinit var serviceManager: ServiceManager

@Inject
lateinit var tunnelService: TunnelService

override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_MY_PACKAGE_REPLACED) return
applicationScope.launch {
val settings = appDataRepository.settings.getSettings()
if (settings.isAutoTunnelEnabled) {
Timber.i("Restarting services after upgrade")
serviceManager.startWatcherServiceForeground(context)
}
if (!settings.isAutoTunnelEnabled || settings.isAutoTunnelPaused) {
val tunnels = appDataRepository.tunnels.getAll().filter { it.isActive }
if (tunnels.isNotEmpty()) context.startTunnelBackground(tunnels.first().id)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import android.content.Context
import android.content.Intent
import com.zaneschepke.wireguardautotunnel.data.repository.TunnelConfigRepository
import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Provider

Expand All @@ -25,14 +27,19 @@ class BackgroundActionReceiver : BroadcastReceiver() {
@Inject
lateinit var tunnelConfigRepository: TunnelConfigRepository

@Inject
lateinit var serviceManager: ServiceManager

override fun onReceive(context: Context, intent: Intent) {
val id = intent.getIntExtra(TUNNEL_ID_EXTRA_KEY, 0)
if (id == 0) return
when (intent.action) {
ACTION_CONNECT -> {
Timber.d("Connect actions")
applicationScope.launch {
val tunnel = tunnelConfigRepository.getById(id)
tunnel?.let {
serviceManager.startTunnelBackgroundService(context)
tunnelService.get().startTunnel(it)
}
}
Expand All @@ -41,6 +48,7 @@ class BackgroundActionReceiver : BroadcastReceiver() {
applicationScope.launch {
val tunnel = tunnelConfigRepository.getById(id)
tunnel?.let {
serviceManager.stopTunnelBackgroundService(context)
tunnelService.get().stopTunnel(it)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.util.extensions.startTunnelBackground
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -35,7 +36,7 @@ class BootReceiver : BroadcastReceiver() {
val settings = appDataRepository.settings.getSettings()
if (settings.isRestoreOnBootEnabled) {
appDataRepository.getStartTunnelConfig()?.let {
tunnelService.get().startTunnel(it)
context.startTunnelBackground(it.id)
}
}
if (settings.isAutoTunnelEnabled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,20 @@ class ServiceManager {
AutoTunnelService::class.java,
)
}

fun startTunnelBackgroundService(context: Context) {
actionOnService(
Action.START_FOREGROUND,
context,
TunnelBackgroundService::class.java,
)
}

fun stopTunnelBackgroundService(context: Context) {
actionOnService(
Action.STOP,
context,
TunnelBackgroundService::class.java,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.zaneschepke.wireguardautotunnel.service.foreground

import android.app.Notification
import android.os.Bundle
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class TunnelBackgroundService : ForegroundService() {

@Inject
lateinit var notificationService: NotificationService

private val foregroundId = 123

override fun onCreate() {
super.onCreate()
startForeground(foregroundId, createNotification())
}

override fun startService(extras: Bundle?) {
super.startService(extras)
startForeground(foregroundId, createNotification())
}

override fun stopService() {
super.stopService()
stopForeground(STOP_FOREGROUND_REMOVE)
}

private fun createNotification(): Notification {
return notificationService.createNotification(
getString(R.string.vpn_channel_id),
getString(R.string.vpn_channel_name),
getString(R.string.tunnel_start_text),
description = "",
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.service.foreground.Action
import com.zaneschepke.wireguardautotunnel.service.foreground.AutoTunnelService
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.util.extensions.startTunnelBackground
import com.zaneschepke.wireguardautotunnel.util.extensions.stopTunnelBackground
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -42,8 +44,8 @@ class ShortcutsActivity : ComponentActivity() {
Timber.d("Shortcut action on name: ${tunnelConfig?.name}")
tunnelConfig?.let {
when (intent.action) {
Action.START.name -> tunnelService.get().startTunnel(it)
Action.STOP.name -> tunnelService.get().stopTunnel(it)
Action.START.name -> this@ShortcutsActivity.startTunnelBackground(it.id)
Action.STOP.name -> this@ShortcutsActivity.stopTunnelBackground(it.id)
else -> Unit
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class TunnelControlTile : TileService(), LifecycleOwner {
override fun onClick() {
super.onClick()
unlockAndRun {
Timber.d("Click")
lifecycleScope.launch {
val context = this@TunnelControlTile
val lastActive = appDataRepository.getStartTunnelConfig()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ interface TunnelService : Tunnel, org.amnezia.awg.backend.Tunnel {
suspend fun runningTunnelNames(): Set<String>

suspend fun getState(): TunnelState

fun cancelStatsJob()
fun startStatsJob()
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import com.zaneschepke.wireguardautotunnel.service.tunnel.statistics.TunnelStati
import com.zaneschepke.wireguardautotunnel.service.tunnel.statistics.WireGuardStatistics
import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.extensions.requestTunnelTileServiceStateUpdate
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
Expand Down Expand Up @@ -153,6 +152,14 @@ constructor(
}
}

override fun cancelStatsJob() {
statsJob?.cancel()
}

override fun startStatsJob() {
statsJob = startTunnelStatisticsJob()
}

override fun getName(): String {
return _vpnState.value.tunnelConfig?.name ?: ""
}
Expand All @@ -164,15 +171,9 @@ constructor(
private fun handleStateChange(state: TunnelState) {
emitTunnelState(state)
WireGuardAutoTunnel.instance.requestTunnelTileServiceStateUpdate()
if (state == TunnelState.UP) {
statsJob = startTunnelStatisticsJob()
}
if (state == TunnelState.DOWN) {
try {
statsJob?.cancel()
} catch (e: CancellationException) {
Timber.i("Stats job cancelled")
}
when (state) {
TunnelState.UP -> startStatsJob()
else -> cancelStatsJob()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository
import com.zaneschepke.wireguardautotunnel.data.repository.SettingsRepository
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavBar
import com.zaneschepke.wireguardautotunnel.ui.common.prompt.CustomSnackBar
import com.zaneschepke.wireguardautotunnel.ui.screens.config.ConfigScreen
Expand All @@ -65,10 +64,7 @@ class MainActivity : AppCompatActivity() {
lateinit var appStateRepository: AppStateRepository

@Inject
lateinit var settingsRepository: SettingsRepository

@Inject
lateinit var serviceManager: ServiceManager
lateinit var tunnelService: TunnelService

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -77,13 +73,6 @@ class MainActivity : AppCompatActivity() {

enableEdgeToEdge(navigationBarStyle = SystemBarStyle.dark(Color.Transparent.toArgb()))

lifecycleScope.launch {
val settings = settingsRepository.getSettings()
if (settings.isAutoTunnelEnabled) {
serviceManager.startWatcherService(application.applicationContext)
}
}

setContent {
val appViewModel = hiltViewModel<AppViewModel>()
val appUiState by appViewModel.appUiState.collectAsStateWithLifecycle()
Expand Down Expand Up @@ -241,4 +230,9 @@ class MainActivity : AppCompatActivity() {
}
}
}

override fun onDestroy() {
super.onDestroy()
tunnelService.cancelStatsJob()
}
}
Loading

0 comments on commit 30851a7

Please sign in to comment.