Skip to content

Commit

Permalink
fix: service status out of sync
Browse files Browse the repository at this point in the history
This fixes the status of service becoming out of sync with the user settings by getting service status from ActivityManager.
  • Loading branch information
zaneschepke committed Jul 1, 2023
1 parent f894a3e commit 98da234
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 22 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ android {

val versionMajor = 1
val versionMinor = 1
val versionPatch = 3
val versionPatch = 4
val versionBuild = 0

defaultConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ open class ForegroundService : Service() {
if (isServiceStarted) return
Timber.d("Starting ${this.javaClass.simpleName}")
isServiceStarted = true
ServiceTracker.setServiceState(this, ServiceState.STARTED, this.javaClass)
}

protected open fun stopService(extras : Bundle?) {
Expand All @@ -57,6 +56,5 @@ open class ForegroundService : Service() {
Timber.d("Service stopped without being started: ${e.message}")
}
isServiceStarted = false
ServiceTracker.setServiceState(this, ServiceState.STOPPED, this.javaClass)
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
package com.zaneschepke.wireguardautotunnel.service.foreground

import android.app.ActivityManager
import android.app.Application
import android.app.Service
import android.content.Context
import android.content.Context.ACTIVITY_SERVICE
import android.content.Intent
import android.content.SharedPreferences
import com.zaneschepke.wireguardautotunnel.R

object ServiceTracker {
fun <T : Service> setServiceState(context: Context, state: ServiceState, cls : Class<T>) {
val sharedPrefs = getPreferences(context)
sharedPrefs.edit().let {
it.putString(cls.simpleName, state.name)
it.apply()
}
}

private fun <T : Service> getServiceState(context: Context, cls : Class<T>): ServiceState {
val sharedPrefs = getPreferences(context)
val value = sharedPrefs.getString(cls.simpleName, ServiceState.STOPPED.name)
return ServiceState.valueOf(value!!)
}
@Suppress("DEPRECATION")
private // Deprecated for third party Services.
fun <T> Context.isServiceRunning(service: Class<T>) =
(getSystemService(ACTIVITY_SERVICE) as ActivityManager)
.getRunningServices(Integer.MAX_VALUE)
.any { it.service.className == service.name }

private fun getPreferences(context: Context): SharedPreferences {
return context.getSharedPreferences(context.resources.getString(R.string.foreground_file), 0)
fun <T : Service> getServiceState(context: Context, cls : Class<T>): ServiceState {
val isServiceRunning = context.isServiceRunning(cls)
return if(isServiceRunning) ServiceState.STARTED else ServiceState.STOPPED
}

fun <T : Service> actionOnService(action: Action, application: Application, cls : Class<T>, extras : Map<String,String>? = null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,12 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
if(!settings.isNullOrEmpty()) {
setting = settings[0]
}
watchForWifiConnectivityChanges()
if(setting.isTunnelOnMobileDataEnabled) {
GlobalScope.launch {
watchForMobileDataConnectivityChanges()
}
}
watchForWifiConnectivityChanges()
}
}

Expand Down Expand Up @@ -171,16 +171,18 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
isWifiConnected = true
}
is NetworkStatus.CapabilitiesChanged -> {
Timber.d("Wifi capabilities changed")
isWifiConnected = true
if (!connecting && !disconnecting) {
Timber.d("Not connect and not disconnecting")
val ssid = wifiService.getNetworkName(it.networkCapabilities);
Timber.d("SSID: $ssid")
if ((setting.trustedNetworkSSIDs?.contains(ssid) == false) && vpnService.getState() == Tunnel.State.DOWN) {
Timber.d("Starting VPN Tunnel for untrusted network: $ssid")
startVPN()
} else if (!disconnecting && vpnService.getState() == Tunnel.State.UP && (setting.trustedNetworkSSIDs?.contains(
} else if (!disconnecting && vpnService.getState() == Tunnel.State.UP && setting.trustedNetworkSSIDs.contains(
ssid
) == true)
)
) {
Timber.d("Stopping VPN Tunnel for trusted network with ssid: $ssid")
stopVPN()
Expand All @@ -191,7 +193,10 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
isWifiConnected = false
Timber.d("Lost Wi-Fi connection")
if(setting.isTunnelOnMobileDataEnabled && vpnService.getState() == Tunnel.State.DOWN
&& isMobileDataConnected) startVPN()
&& isMobileDataConnected){
Timber.d("Wifi not available so starting vpn for mobile data")
startVPN()
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.wireguard.config.Config
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.repository.Repository
import com.zaneschepke.wireguardautotunnel.service.foreground.Action
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceState
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceTracker
import com.zaneschepke.wireguardautotunnel.service.foreground.WireGuardConnectivityWatcherService
import com.zaneschepke.wireguardautotunnel.service.foreground.WireGuardTunnelService
Expand All @@ -23,6 +24,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject


Expand All @@ -48,11 +50,26 @@ class MainViewModel @Inject constructor(private val application : Application,
viewModelScope.launch {
settingsRepo.itemFlow.collect {
val settings = it.first()
validateWatcherServiceState(settings)
_settings.emit(settings)
}
}
}

private fun validateWatcherServiceState(settings: Settings) {
val watcherState = ServiceTracker.getServiceState(application, WireGuardConnectivityWatcherService::class.java)
if(settings.isAutoTunnelEnabled && watcherState == ServiceState.STOPPED && settings.defaultTunnel != null) {
startWatcherService(settings.defaultTunnel!!)
}
}

private fun startWatcherService(tunnel : String) {
ServiceTracker.actionOnService(
Action.START, application,
WireGuardConnectivityWatcherService::class.java,
mapOf(application.resources.getString(R.string.tunnel_extras_key) to tunnel))
}

fun onDelete(tunnel : TunnelConfig) {
viewModelScope.launch {
if(tunnelRepo.count() == 1L) {
Expand Down

0 comments on commit 98da234

Please sign in to comment.