BraveVPNService.onRevoke: treat as user-initiated stop#2697
Open
dsremo wants to merge 1 commit into
Open
Conversation
`onRevoke()` is the Android system's signal that the user has explicitly disabled this VPN — via Settings → Network & internet → VPN → toggle off, or by selecting a different VPN app, or by switching Always-On VPN to a different app. In every one of those cases the user IS deliberately stopping us — it is not a crash, not a transient error. The current code passes `userInitiated = false` to signalStopService. That matters because of how signalStopService manages persistent state (whatever specific implementation a maintainer chooses): a non-user-initiated stop is treated as a transient interruption, leaving "VPN should be running" state intact for autostart to recover from. But onRevoke is the opposite — the user has made an explicit choice via a system UI surface that this VPN should stop. Persistent state should reflect that intent. The user-facing symptom: user disables RethinkDNS in Android system VPN settings, then on the next boot / screen unlock / app update, the BraveAutoStartReceiver sees `activationRequested == true` and relaunches us. From the user's perspective, "I disabled it but it keeps coming back." Fix: pass `userInitiated = true`. This is the canonical interpretation in other VPN apps (StrongSwan, WireGuard for Android, OpenVPN for Android all treat onRevoke as the terminal user-stop signal).
Contributor
Author
|
Hi, and thanks a lot for maintaining RethinkDNS — happy to help however I can. 🙏 I noticed the CodeQL check seems to be failing on PRs in general (not specific to this one), at the results-upload step: From what I can tell, this happens when both CodeQL configurations are active at the same time:
GitHub blocks the SARIF upload while both are enabled, so the Whenever you get a chance, either of these should resolve it repo-wide (no action needed on contributor PRs):
No urgency at all — just flagging in case it's useful. Thanks again! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
BraveVPNService.onRevoke()currently calls:```kotlin
signalStopService("revoked", false)
```
onRevokeis the Android system's signal that the user has explicitly disabled this VPN — via one of:In every one of those cases the user IS deliberately stopping RethinkDNS. It is not a crash, not a transient network error, not a system memory-kill.
But passing
userInitiated = falsetells signalStopService to treat this as a transient interruption — i.e., the kind of stop where autostart should recover from on next boot/unlock. The visible consequence: user disables RethinkDNS in Android system VPN settings, then on the next boot / screen unlock / app update,BraveAutoStartReceiverseesactivationRequested == trueand relaunches the service. From the user's perspective, "I disabled it but it keeps coming back."(Reported informally; couples with #2694 — even with that PR honoring the auto-start pref on all triggers,
activationRequestedbeing stuck true from a missing user-intent clear here would still allow the relaunch path.)Fix
Pass
userInitiated = true:```kotlin
signalStopService("revoked", userInitiated = true)
```
Why this is correct
onRevokeas the terminal user-stop signal:disconnect()signalStopService("revoked", …)— the"revoked"reason string explicitly distinguishes this fromoutOfSync,noTunnel,nwRegFail,restartVpnErrorand other internal failure reasons that are non-user-initiated.Edge cases checked
activationRequestedis briefly cleared, the user's next explicit start tap re-sets it. No worse than current behavior.signalStopServicealready handles userInitiated=true gracefully (it's the default value and the in-app stop path uses it).Tested
BraveAutoStartReceiverlog line showsactivationRequested=falseafter the revoke (wastruebefore).