@@ -34,6 +34,7 @@ import androidx.annotation.StringRes
34
34
import androidx.core.app.NotificationCompat
35
35
import androidx.core.content.ContextCompat
36
36
import dev.clombardo.dnsnet.DnsNetApplication.Companion.applicationContext
37
+ import dev.clombardo.dnsnet.FileHelper
37
38
import dev.clombardo.dnsnet.Intents
38
39
import dev.clombardo.dnsnet.MainActivity
39
40
import dev.clombardo.dnsnet.NotificationChannels
@@ -44,10 +45,15 @@ import dev.clombardo.dnsnet.logd
44
45
import dev.clombardo.dnsnet.logi
45
46
import dev.clombardo.dnsnet.logw
46
47
import dev.clombardo.dnsnet.vpn.VpnStatus.Companion.toVpnStatus
48
+ import kotlinx.atomicfu.atomic
49
+ import kotlinx.coroutines.CoroutineScope
50
+ import kotlinx.coroutines.Dispatchers
47
51
import kotlinx.coroutines.flow.MutableStateFlow
48
52
import kotlinx.coroutines.flow.asStateFlow
53
+ import kotlinx.coroutines.launch
49
54
import uniffi.net.AdVpnCallback
50
55
import uniffi.net.RuleDatabase
56
+ import uniffi.net.RuleDatabaseController
51
57
52
58
enum class VpnStatus {
53
59
STARTING ,
@@ -81,6 +87,7 @@ enum class Command {
81
87
PAUSE ,
82
88
RESUME ,
83
89
RESTART ,
90
+ RELOAD_DATABASE ,
84
91
}
85
92
86
93
class AdVpnService : VpnService (), Handler.Callback, AdVpnCallback {
@@ -147,6 +154,15 @@ class AdVpnService : VpnService(), Handler.Callback, AdVpnCallback {
147
154
ContextCompat .startForegroundService(context, Intents .getRestartVpnIntent())
148
155
}
149
156
157
+ fun reloadDatabase (context : Context ) {
158
+ if (! isRunning()) {
159
+ logw(" VPN is stopped, cannot reload database" )
160
+ return
161
+ }
162
+
163
+ context.startService(Intents .getReloadDatabaseIntent())
164
+ }
165
+
150
166
private fun getOpenMainActivityPendingIntent () = PendingIntent .getActivity(
151
167
applicationContext,
152
168
0 ,
@@ -176,7 +192,28 @@ class AdVpnService : VpnService(), Handler.Callback, AdVpnCallback {
176
192
177
193
private val handler = Handler (Looper .myLooper()!! , this )
178
194
179
- private val ruleDatabase = RuleDatabase ()
195
+ // Guard against multiple coroutines waiting to reload the database
196
+ private val reloadPending = atomic(false )
197
+ private val ruleDatabaseController = RuleDatabaseController ()
198
+ private val ruleDatabase = RuleDatabase (controller = ruleDatabaseController).also {
199
+ it.reload()
200
+ }
201
+
202
+ fun RuleDatabase.reload () {
203
+ if (reloadPending.getAndSet(true )) {
204
+ return
205
+ }
206
+
207
+ CoroutineScope (Dispatchers .IO ).launch {
208
+ waitOnInit()
209
+ reloadPending.getAndSet(false )
210
+ initialize(
211
+ androidFileHelper = FileHelper ,
212
+ hostItems = config.hosts.items.map { it.toNative() },
213
+ hostExceptions = config.hosts.exceptions.map { it.toNative() },
214
+ )
215
+ }
216
+ }
180
217
181
218
private val vpnThread = AdVpnThread (
182
219
adVpnService = this ,
@@ -457,6 +494,10 @@ class AdVpnService : VpnService(), Handler.Callback, AdVpnCallback {
457
494
Command .PAUSE -> pauseVpn()
458
495
459
496
Command .RESTART -> restartVpnThread()
497
+
498
+ Command .RELOAD_DATABASE -> {
499
+ ruleDatabase.reload()
500
+ }
460
501
}
461
502
462
503
return START_STICKY
@@ -618,6 +659,7 @@ class AdVpnService : VpnService(), Handler.Callback, AdVpnCallback {
618
659
619
660
override fun onDestroy () {
620
661
logi(" Destroyed, shutting down" )
662
+ ruleDatabaseController.setShouldStop(true )
621
663
stopVpn()
622
664
}
623
665
0 commit comments