VpnBackend class that each protocol implementation extends. A provider selects and prepares the right backend based on the user’s protocol preference.
The VpnBackend abstract class
VpnBackend (vpn/VpnBackend.kt) is the common contract for all protocol implementations. It:
- Manages a local agent connection (certificate-based mTLS channel to the VPN server)
- Tracks the tunnel’s
VpnStatevia aMutableStateFlow - Handles certificate refresh and key rotation
- Surfaces NetShield statistics and exit IP information
Local agent
Every connected backend opens a local agent channel — a TLS connection to the VPN server’s local agent endpoint. The agent:- Authenticates the session with the client certificate
- Sends feature flags (NetShield level, randomised NAT, VPN Accelerator)
- Delivers NetShield statistics and
connectionDetails(exit IP) - Reports certificate errors and policy violations
VpnAgentClient class implements the NativeClient interface from the gopenpgp/localAgent Go library and translates callbacks into VpnState updates on the main coroutine scope.
VPN state
Protocol state is tracked in two places:VpnConnectionManager observes selfStateFlow and forwards it to VpnStateMonitor.
Protocol implementations
- WireGuard
- ProTun
WireguardBackend (vpn/wireguard/WireguardBackend.kt) wraps the WireGuard Android library (com.wireguard.android.backend.GoBackend).Supported transmission protocols: UDP (default), TCP, TLSprepareForConnectionscans available ports on the server.connectbuilds a WireGuard tunnel config fromConnectionParamsWireguard(including the X25519 key fromCertificateRepository) and callsbackend.setState(Tunnel.State.UP, config, transmissionStr, serverNameStrategy).- A monitoring coroutine (
startMonitoringJob) pollsbackend.statein a loop and maps the raw integer state toVpnState:
WireguardWrapperService is the VpnService subclass for WireGuard. References to the service are held weakly by the backend via serviceCreated / serviceDestroyed callbacks.On Android 10+, the backend waits for the tunnel’s
NET_CAPABILITY_VALIDATED network capability before opening the local agent connection. This prevents TLS failures on newer OS versions.ProtonVpnBackendProvider
ProtonVpnBackendProvider (vpn/ProtonVpnBackendProvider.kt) implements VpnBackendProvider and decides which backend to use for a given connection request.
AppModule.kt:
Protocol selection logic
prepareConnection maps a ProtocolSelection to the right backend:
Smart protocol tries backends in order of preference and returns the first one that responds:
getSmartEnabledBackends checks AppConfig.getSmartProtocolConfig() to determine which protocols are enabled (WireGuard UDP/TCP/TLS, ProTun). Feature flag wireguardTlsEnabled gates TCP and TLS transmission modes.
Fallback pinging (pingAll)
When VpnConnectionErrorHandler needs to find an alternative server after a failure, it calls pingAll. This method concurrently probes a list of candidate servers across all smart-enabled backends and returns the first server that responds:
PING_ALL_MAX_PORTS = 3 ports unless it is designated as the fullScanServer, in which case all ports are scanned.
Certificate management
CertificateRepository (vpn/CertificateRepository.kt) manages the Ed25519 keypair and the short-lived VPN certificate issued by the Proton API.
Key lifecycle
- Generate —
CertificateKeyProvider.generateCertInfo()creates a new Ed25519 keypair using thegopenpgpGo library. The result is stored inCertificateStorage(encrypted with Android Keystore viaCertStorageCrypto). - Fetch —
updateCertificateFromBackendcallsapi.getCertificate(sessionId, publicKeyPem)and stores the returned PEM certificate alongside the keys. - Refresh — Certificates are refreshed proactively via
PeriodicUpdateManager. The next refresh time is derived from the API response (refreshAt) or set to halfway between now and expiry on error. - Revoke — If the local agent reports
errorCodeBadCertSignatureorerrorCodeCertificateRevoked, the backend callsrevokeCertificateAndReconnect, which generates a new keypair and forces an immediate certificate fetch before reconnecting.
currentCertUpdateFlow shared flow notifies active backends when a new certificate is available, triggering an agent reconnection without tearing down the VPN tunnel.
Error types
ErrorType (defined in VpnState.kt) enumerates all terminal and recoverable errors that backends can emit:
Recoverable errors trigger
VpnConnectionErrorHandler, which attempts to find an alternative server via pingAll before surfacing a failure to the user.