@@ -12,7 +12,7 @@ import arrow.atomic.AtomicInt
12
12
import co.touchlab.kermit.Logger
13
13
import java.io.File
14
14
import kotlinx.coroutines.flow.filter
15
- import kotlinx.coroutines.flow.first
15
+ import kotlinx.coroutines.flow.filterIsInstance
16
16
import kotlinx.coroutines.launch
17
17
import kotlinx.coroutines.runBlocking
18
18
import net.mullvad.mullvadvpn.lib.common.constant.KEY_CONNECT_ACTION
@@ -90,6 +90,15 @@ class MullvadVpnService : TalpidVpnService() {
90
90
91
91
Logger .i(" Start management service" )
92
92
managementService.start()
93
+
94
+ lifecycleScope.launch {
95
+ // If the service is started with a connect command and a non-blocking error occur (e.g.
96
+ // unable to start the tunnel) then the service is demoted from foreground.
97
+ managementService.tunnelState
98
+ .filterIsInstance<TunnelState .Error >()
99
+ .filter { ! it.errorState.isBlocking }
100
+ .collect { foregroundNotificationHandler.stopForeground() }
101
+ }
93
102
}
94
103
95
104
override fun onStartCommand (intent : Intent ? , flags : Int , startId : Int ): Int {
@@ -105,15 +114,24 @@ class MullvadVpnService : TalpidVpnService() {
105
114
keyguardManager.isKeyguardLocked -> {
106
115
Logger .i(" Keyguard is locked, ignoring command" )
107
116
}
117
+
108
118
intent.isFromSystem() || intent?.action == KEY_CONNECT_ACTION -> {
109
- // Only show on foreground if we have permission
110
- if (prepare(this ) == null ) {
111
- foregroundNotificationHandler.startForeground()
112
- }
119
+ foregroundNotificationHandler.startForeground()
113
120
lifecycleScope.launch { connectionProxy.connectWithoutPermissionCheck() }
114
121
}
122
+
115
123
intent?.action == KEY_DISCONNECT_ACTION -> {
124
+ // MullvadTileService might have launched this service with the expectancy of it
125
+ // being foreground, thus it must go into foreground to please the android system
126
+ // requirements.
127
+ foregroundNotificationHandler.startForeground()
116
128
lifecycleScope.launch { connectionProxy.disconnect() }
129
+
130
+ // If disconnect intent is received and no one is using this service, simply stop
131
+ // foreground and let system stop service when it deems it not to be necessary.
132
+ if (bindCount.get() == 0 ) {
133
+ foregroundNotificationHandler.stopForeground()
134
+ }
117
135
}
118
136
}
119
137
@@ -180,25 +198,6 @@ class MullvadVpnService : TalpidVpnService() {
180
198
foregroundNotificationHandler.stopForeground()
181
199
}
182
200
183
- if (count == 0 ) {
184
- Logger .i(" No one bound to the service, stopSelf()" )
185
- lifecycleScope.launch {
186
- Logger .i(" Waiting for disconnected state" )
187
- // TODO This needs reworking, we should not wait for the disconnected state, what we
188
- // want is the notification of disconnected to go out before we start shutting down
189
- connectionProxy.tunnelState
190
- .filter {
191
- it is TunnelState .Disconnected ||
192
- (it is TunnelState .Error && ! it.errorState.isBlocking)
193
- }
194
- .first()
195
-
196
- if (bindCount.get() == 0 ) {
197
- Logger .i(" Stopping service" )
198
- stopSelf()
199
- }
200
- }
201
- }
202
201
return true
203
202
}
204
203
@@ -209,8 +208,10 @@ class MullvadVpnService : TalpidVpnService() {
209
208
210
209
Logger .i(" Shutdown MullvadDaemon" )
211
210
MullvadDaemon .shutdown()
211
+
212
212
Logger .i(" Enter Idle" )
213
213
managementService.enterIdle()
214
+
214
215
Logger .i(" Shutdown complete" )
215
216
super .onDestroy()
216
217
}
0 commit comments