fix: foreground service start crashes
Attempt to fix startForegrounService causing crashes on some devices by not meeting the 5 second notification rule. Add notification to onCreate of services. Limit startForeground to only be called where it is truly necessary in the TileService to allow starting the VPN while app is not running. Attempt to manually initialize mlkit for QR code scanning to remediate some crashes caused by config scanning.
This commit is contained in:
parent
c1b560e822
commit
64bb9f3b82
|
@ -17,7 +17,7 @@ android {
|
||||||
|
|
||||||
val versionMajor = 2
|
val versionMajor = 2
|
||||||
val versionMinor = 4
|
val versionMinor = 4
|
||||||
val versionPatch = 2
|
val versionPatch = 3
|
||||||
val versionBuild = 0
|
val versionBuild = 0
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
|
import com.google.mlkit.common.MlKit
|
||||||
import com.zaneschepke.wireguardautotunnel.repository.Repository
|
import com.zaneschepke.wireguardautotunnel.repository.Repository
|
||||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings
|
import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings
|
||||||
import dagger.hilt.android.HiltAndroidApp
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
|
@ -22,6 +23,11 @@ class WireGuardAutoTunnel : Application() {
|
||||||
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false);
|
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false);
|
||||||
Timber.plant(Timber.DebugTree())
|
Timber.plant(Timber.DebugTree())
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
MlKit.initialize(this)
|
||||||
|
} catch (e : Exception) {
|
||||||
|
Timber.e(e.message)
|
||||||
|
}
|
||||||
settingsRepo.init()
|
settingsRepo.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,5 +2,6 @@ package com.zaneschepke.wireguardautotunnel.service.foreground
|
||||||
|
|
||||||
enum class Action {
|
enum class Action {
|
||||||
START,
|
START,
|
||||||
|
START_FOREGROUND,
|
||||||
STOP
|
STOP
|
||||||
}
|
}
|
|
@ -22,7 +22,7 @@ open class ForegroundService : Service() {
|
||||||
val action = intent.action
|
val action = intent.action
|
||||||
Timber.d("using an intent with action $action")
|
Timber.d("using an intent with action $action")
|
||||||
when (action) {
|
when (action) {
|
||||||
Action.START.name -> startService(intent.extras)
|
Action.START.name, Action.START_FOREGROUND.name -> startService(intent.extras)
|
||||||
Action.STOP.name -> stopService(intent.extras)
|
Action.STOP.name -> stopService(intent.extras)
|
||||||
"android.net.VpnService" -> {
|
"android.net.VpnService" -> {
|
||||||
Timber.d("Always-on VPN starting service")
|
Timber.d("Always-on VPN starting service")
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package com.zaneschepke.wireguardautotunnel.service.foreground
|
package com.zaneschepke.wireguardautotunnel.service.foreground
|
||||||
|
|
||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
import android.app.Application
|
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Context.ACTIVITY_SERVICE
|
import android.content.Context.ACTIVITY_SERVICE
|
||||||
|
@ -9,7 +8,6 @@ import android.content.Intent
|
||||||
import com.google.firebase.crashlytics.ktx.crashlytics
|
import com.google.firebase.crashlytics.ktx.crashlytics
|
||||||
import com.google.firebase.ktx.Firebase
|
import com.google.firebase.ktx.Firebase
|
||||||
import com.zaneschepke.wireguardautotunnel.R
|
import com.zaneschepke.wireguardautotunnel.R
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
object ServiceManager {
|
object ServiceManager {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
|
@ -36,13 +34,11 @@ object ServiceManager {
|
||||||
intent.component?.javaClass
|
intent.component?.javaClass
|
||||||
try {
|
try {
|
||||||
when(action) {
|
when(action) {
|
||||||
|
Action.START_FOREGROUND -> {
|
||||||
|
context.startForegroundService(intent)
|
||||||
|
}
|
||||||
Action.START -> {
|
Action.START -> {
|
||||||
try {
|
context.startService(intent)
|
||||||
context.startForegroundService(intent)
|
|
||||||
} catch (e : Exception) {
|
|
||||||
Timber.e("Unable to start service foreground ${e.message}")
|
|
||||||
context.startService(intent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Action.STOP -> context.startService(intent)
|
Action.STOP -> context.startService(intent)
|
||||||
}
|
}
|
||||||
|
@ -66,6 +62,22 @@ object ServiceManager {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startVpnServiceForeground(context : Context, tunnelConfig : String) {
|
||||||
|
actionOnService(
|
||||||
|
Action.START_FOREGROUND,
|
||||||
|
context,
|
||||||
|
WireGuardTunnelService::class.java,
|
||||||
|
mapOf(context.getString(R.string.tunnel_extras_key) to tunnelConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startWatcherServiceForeground(context : Context, tunnelConfig : String) {
|
||||||
|
actionOnService(
|
||||||
|
Action.START, context,
|
||||||
|
WireGuardConnectivityWatcherService::class.java, mapOf(context.
|
||||||
|
getString(R.string.tunnel_extras_key) to
|
||||||
|
tunnelConfig))
|
||||||
|
}
|
||||||
|
|
||||||
fun startWatcherService(context : Context, tunnelConfig : String) {
|
fun startWatcherService(context : Context, tunnelConfig : String) {
|
||||||
actionOnService(
|
actionOnService(
|
||||||
Action.START, context,
|
Action.START, context,
|
||||||
|
@ -87,4 +99,12 @@ object ServiceManager {
|
||||||
ServiceState.STOPPED -> startWatcherService(context, tunnelConfig)
|
ServiceState.STOPPED -> startWatcherService(context, tunnelConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun toggleWatcherServiceForeground(context: Context, tunnelConfig : String) {
|
||||||
|
when(getServiceState( context,
|
||||||
|
WireGuardConnectivityWatcherService::class.java,)) {
|
||||||
|
ServiceState.STARTED -> stopWatcherService(context)
|
||||||
|
ServiceState.STOPPED -> startWatcherServiceForeground(context, tunnelConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -59,8 +59,16 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
||||||
private val tag = this.javaClass.name;
|
private val tag = this.javaClass.name;
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
launchWatcherNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun startService(extras: Bundle?) {
|
override fun startService(extras: Bundle?) {
|
||||||
super.startService(extras)
|
super.startService(extras)
|
||||||
|
launchWatcherNotification()
|
||||||
val tunnelId = extras?.getString(getString(R.string.tunnel_extras_key))
|
val tunnelId = extras?.getString(getString(R.string.tunnel_extras_key))
|
||||||
if (tunnelId != null) {
|
if (tunnelId != null) {
|
||||||
this.tunnelConfig = tunnelId
|
this.tunnelConfig = tunnelId
|
||||||
|
@ -68,7 +76,6 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
||||||
// we need this lock so our service gets not affected by Doze Mode
|
// we need this lock so our service gets not affected by Doze Mode
|
||||||
initWakeLock()
|
initWakeLock()
|
||||||
cancelWatcherJob()
|
cancelWatcherJob()
|
||||||
launchWatcherNotification()
|
|
||||||
if(this::tunnelConfig.isInitialized) {
|
if(this::tunnelConfig.isInitialized) {
|
||||||
startWatcherJob()
|
startWatcherJob()
|
||||||
} else {
|
} else {
|
||||||
|
@ -181,7 +188,7 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun manageVpn() {
|
private suspend fun manageVpn() {
|
||||||
while(watcherJob.isActive) {
|
while(true) {
|
||||||
if(setting.isTunnelOnMobileDataEnabled &&
|
if(setting.isTunnelOnMobileDataEnabled &&
|
||||||
!isWifiConnected &&
|
!isWifiConnected &&
|
||||||
isMobileDataConnected
|
isMobileDataConnected
|
||||||
|
|
|
@ -37,8 +37,16 @@ class WireGuardTunnelService : ForegroundService() {
|
||||||
|
|
||||||
private var tunnelName : String = ""
|
private var tunnelName : String = ""
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
launchVpnStartingNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun startService(extras : Bundle?) {
|
override fun startService(extras : Bundle?) {
|
||||||
super.startService(extras)
|
super.startService(extras)
|
||||||
|
launchVpnStartingNotification()
|
||||||
val tunnelConfigString = extras?.getString(getString(R.string.tunnel_extras_key))
|
val tunnelConfigString = extras?.getString(getString(R.string.tunnel_extras_key))
|
||||||
cancelJob()
|
cancelJob()
|
||||||
job = CoroutineScope(Dispatchers.IO).launch {
|
job = CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
@ -47,7 +55,6 @@ class WireGuardTunnelService : ForegroundService() {
|
||||||
val tunnelConfig = TunnelConfig.from(tunnelConfigString)
|
val tunnelConfig = TunnelConfig.from(tunnelConfigString)
|
||||||
tunnelName = tunnelConfig.name
|
tunnelName = tunnelConfig.name
|
||||||
vpnService.startTunnel(tunnelConfig)
|
vpnService.startTunnel(tunnelConfig)
|
||||||
launchVpnStartingNotification()
|
|
||||||
} catch (e : Exception) {
|
} catch (e : Exception) {
|
||||||
Timber.e("Problem starting tunnel: ${e.message}")
|
Timber.e("Problem starting tunnel: ${e.message}")
|
||||||
stopService(extras)
|
stopService(extras)
|
||||||
|
@ -61,7 +68,6 @@ class WireGuardTunnelService : ForegroundService() {
|
||||||
val tunnelConfig = TunnelConfig.from(setting.defaultTunnel!!)
|
val tunnelConfig = TunnelConfig.from(setting.defaultTunnel!!)
|
||||||
tunnelName = tunnelConfig.name
|
tunnelName = tunnelConfig.name
|
||||||
vpnService.startTunnel(tunnelConfig)
|
vpnService.startTunnel(tunnelConfig)
|
||||||
launchVpnStartingNotification()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +106,7 @@ class WireGuardTunnelService : ForegroundService() {
|
||||||
|
|
||||||
override fun stopService(extras : Bundle?) {
|
override fun stopService(extras : Bundle?) {
|
||||||
super.stopService(extras)
|
super.stopService(extras)
|
||||||
CoroutineScope(Dispatchers.IO).launch() {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
vpnService.stopTunnel()
|
vpnService.stopTunnel()
|
||||||
}
|
}
|
||||||
cancelJob()
|
cancelJob()
|
||||||
|
|
|
@ -66,7 +66,7 @@ class TunnelControlTile : TileService() {
|
||||||
if(vpnService.getState() == Tunnel.State.UP) {
|
if(vpnService.getState() == Tunnel.State.UP) {
|
||||||
ServiceManager.stopVpnService(this@TunnelControlTile)
|
ServiceManager.stopVpnService(this@TunnelControlTile)
|
||||||
} else {
|
} else {
|
||||||
ServiceManager.startVpnService(this@TunnelControlTile, tunnel.toString())
|
ServiceManager.startVpnServiceForeground(this@TunnelControlTile, tunnel.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e : Exception) {
|
} catch (e : Exception) {
|
||||||
|
@ -100,7 +100,7 @@ class TunnelControlTile : TileService() {
|
||||||
if (!settings.isNullOrEmpty()) {
|
if (!settings.isNullOrEmpty()) {
|
||||||
val setting = settings.first()
|
val setting = settings.first()
|
||||||
if(setting.isAutoTunnelEnabled) {
|
if(setting.isAutoTunnelEnabled) {
|
||||||
ServiceManager.toggleWatcherService(this@TunnelControlTile, tunnelConfig)
|
ServiceManager.toggleWatcherServiceForeground(this@TunnelControlTile, tunnelConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
@ -103,6 +102,7 @@ fun MainScreen(
|
||||||
val state by viewModel.state.collectAsStateWithLifecycle(Tunnel.State.DOWN)
|
val state by viewModel.state.collectAsStateWithLifecycle(Tunnel.State.DOWN)
|
||||||
val tunnelName by viewModel.tunnelName.collectAsStateWithLifecycle("")
|
val tunnelName by viewModel.tunnelName.collectAsStateWithLifecycle("")
|
||||||
|
|
||||||
|
|
||||||
// Nested scroll for control FAB
|
// Nested scroll for control FAB
|
||||||
val nestedScrollConnection = remember {
|
val nestedScrollConnection = remember {
|
||||||
object : NestedScrollConnection {
|
object : NestedScrollConnection {
|
||||||
|
@ -242,7 +242,8 @@ fun MainScreen(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
.nestedScroll(nestedScrollConnection),
|
.nestedScroll(nestedScrollConnection),
|
||||||
) {
|
) {
|
||||||
itemsIndexed(tunnels.toList()) { index, tunnel ->
|
itemsIndexed(tunnels.toList()) { index, tunnel ->
|
||||||
|
|
|
@ -13,7 +13,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application") version "8.2.0-beta01" apply false
|
id("com.android.application") version "8.2.0-beta03" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
|
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
|
||||||
id("com.google.dagger.hilt.android") version "2.44" apply false
|
id("com.google.dagger.hilt.android") version "2.44" apply false
|
||||||
kotlin("plugin.serialization") version "1.8.22" apply false
|
kotlin("plugin.serialization") version "1.8.22" apply false
|
||||||
|
|
Loading…
Reference in New Issue