fix(android-vpn): Blocklist-Self-Heal — kein Neustart nach erster Aktivierung
Der VpnService lädt die Blockliste bei onStartCommand(START). Ist blocklist.bin beim ersten Aktivieren noch nicht gesynct → 0 Hashes. syncBlocklist schickt zwar ACTION_RELOAD, aber via ctx.startService(), das Android 8+ als Background-Start still verwerfen kann → Filter bleibt auf 0 Hashes bis Geräte-Neustart: VPN aktiv, aber nichts geblockt. scheduleBlocklistSelfHeal: lädt hashList nach 2/5/15/30/60s erneut bis Hashes da sind (max 30 Versuche). Greift unabhängig vom ACTION_RELOAD- Intent. Analog zum iOS-PacketTunnel-Self-Heal. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
435aaeefb1
commit
9a22bcd114
@ -38,6 +38,7 @@ class RebreakVpnService : VpnService() {
|
||||
private var tun: ParcelFileDescriptor? = null
|
||||
private var workerThread: Thread? = null
|
||||
@Volatile private var running = false
|
||||
@Volatile private var selfHealActive = false
|
||||
private lateinit var hashList: HashList
|
||||
|
||||
override fun onCreate() {
|
||||
@ -61,6 +62,13 @@ class RebreakVpnService : VpnService() {
|
||||
startForeground(NOTIF_ID, buildNotification())
|
||||
hashList.load()
|
||||
Log.i(TAG, "blocklist loaded — ${hashList.count()} hashes")
|
||||
// Self-Heal: war die Blockliste beim Start leer (blocklist.bin
|
||||
// noch nicht gesynct, oder ACTION_RELOAD verschluckt), per
|
||||
// Backoff erneut laden bis Hashes da sind.
|
||||
if (hashList.count() == 0) {
|
||||
Log.i(TAG, "blocklist beim Start leer — Self-Heal-Retry gestartet")
|
||||
scheduleBlocklistSelfHeal()
|
||||
}
|
||||
startVpn()
|
||||
return START_STICKY
|
||||
}
|
||||
@ -145,6 +153,43 @@ class RebreakVpnService : VpnService() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Self-Heal: hat der Service die Blockliste leer geladen — `blocklist.bin`
|
||||
* war beim Start noch nicht gesynct, ODER das `ACTION_RELOAD` nach
|
||||
* `syncBlocklist` wurde von Androids Background-Start-Restriction
|
||||
* verschluckt — wird `hashList.load()` mit Backoff erneut versucht, bis
|
||||
* Hashes da sind. Ohne das bliebe der Filter auf 0 Hashes bis zum nächsten
|
||||
* Service-(=Geräte-)Neustart — VPN aktiv, aber nichts wird geblockt.
|
||||
*/
|
||||
private fun scheduleBlocklistSelfHeal() {
|
||||
if (selfHealActive) return
|
||||
selfHealActive = true
|
||||
Thread {
|
||||
// Backoff in ms; ab Index 5 konstant 60 s. Max 30 Versuche (~25 min).
|
||||
val backoff = longArrayOf(2_000, 5_000, 15_000, 30_000, 60_000)
|
||||
var attempt = 0
|
||||
try {
|
||||
while (running && !Thread.currentThread().isInterrupted && attempt < 30) {
|
||||
val delay = if (attempt < backoff.size) backoff[attempt] else 60_000L
|
||||
Thread.sleep(delay)
|
||||
if (!running) return@Thread
|
||||
hashList.load()
|
||||
val n = hashList.count()
|
||||
if (n > 0) {
|
||||
Log.i(TAG, "blocklist self-heal ok — $n hashes (Versuch ${attempt + 1})")
|
||||
return@Thread
|
||||
}
|
||||
attempt++
|
||||
}
|
||||
Log.w(TAG, "blocklist self-heal: nach $attempt Versuchen weiter leer")
|
||||
} catch (_: InterruptedException) {
|
||||
// Service gestoppt — ok.
|
||||
} finally {
|
||||
selfHealActive = false
|
||||
}
|
||||
}.also { it.isDaemon = true; it.start() }
|
||||
}
|
||||
|
||||
override fun onRevoke() {
|
||||
Log.i(TAG, "onRevoke: User hat VPN in System-Settings deaktiviert")
|
||||
clearEnabledFlag()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user