No, una aplicació VpnService no pot activar la VPN del telèfon
L’aplicació posseeix un túnel i el seu cicle de vida, no l’interruptor de VPN del telèfon. El consentiment es pot revocar, només s’executa una VPN alhora, i els paquets són cosa vostra d’analitzar.
La suposició equivocada és que una aplicació VpnService acciona un interruptor del sistema i que, a partir d’aleshores, el telèfon queda protegit. El que passa de debò és més estret: l’aplicació demana consentiment, construeix una interfície, llegeix i escriu paquets a través d’un descriptor de fitxer, i torna la interfície quan s’atura. Només pot haver-hi viu un túnel així alhora, i el sistema pot prendre’l sense preguntar. La major part del comportament confús que la gent atribueix al protocol prové d’aquest model de propietat.
Tracteu cada transició del cicle de vida com a part del disseny i no com un cas límit.
Mite: l’aplicació activa la VPN del telèfon
El flux comença amb VpnService.prepare(), que retorna un Intent que l’usuari ha d’acceptar, i continua amb establish(), que després encara pot fallar per motius que l’aplicació no controla. Establir un segon túnel desactiva la primera interfície i substitueix la notificació del sistema. En cap punt d’aquesta seqüència l’aplicació posseeix un interruptor de tot el dispositiu; posseeix el descriptor que se li ha concedit i els paquets que hi arriben. Fins i tot la notificació persistent pertany al sistema i no al disseny de l’aplicació.
Com que la interfície es concedeix en lloc de conquerir-se, un altre client pot ocupar la plaça en qualsevol moment. L’aplicació ho sap per una crida de retorn, no per un valor de retorn.
L’aturada forçada de l’aplicació es veu al tauler de notificacions pel mateix motiu: el sistema informa del que ha concedit, no del que l’aplicació ha triat mostrar.
Mite: el consentiment es dóna una sola vegada
Quan el sistema lliura el túnel a un altre client, envia una transacció de revocació pel binder que la classe base retorna des de onBind(). Una aplicació que substitueixi aquest binder pel seu ha de reenviar ella mateixa la transacció de revocació, o VpnService.onRevoke() no s’activarà mai i el servei continuarà escrivint en un descriptor que ja no existeix. L’aprovació també la pot retirar l’usuari, i el sistema pot aturar el servei durant un reinici o una reconnexió sempre actiu.
Gestionar-ho és feina concreta i no una línia de registre: deixeu de llegir el descriptor, tanqueu-lo, netegeu la marca de connectat i digueu a l’usuari en quin estat es troba. Després decidiu si l’aplicació ha de tornar a establir, tornar a preguntar o esperar, perquè en una configuració sempre actiu el sistema pot recuperar el servei per si sol.
Una aplicació que tracti la revocació com una excepció i no com un estat informarà d’estat connectat mentre cada paquet que escriu es descarta, que és el pitjor mode de fallada possible per a una eina de privadesa.
Mite: la interfície filtra el trànsit per vosaltres
El que arriba és IP cru. Capturar o filtrar vol dir analitzar capçaleres IP, TCP, UDP i IPv6, seguir fluxos i escriure les respostes de tornada al descriptor, cosa que converteix una aplicació de captura en una petita pila de xarxa i no en una instal·lació del sistema. protect() existeix perquè el socket de transport propi de l’aplicació eviti el seu túnel en lloc de capturar-se a si mateixa, i retorna un booleà que mereix una comprovació a cada socket creat després que el túnel estigui en marxa.
Les llistes d’aplicacions permeses i prohibides del constructor decideixen de qui entra el trànsit a la interfície. No donen accés a càrrega útil més enllà dels paquets IP que la interfície transporta, i cap API no exposa el túnel d’un altre client ni llista els perfils de VPN del sistema. Les capacitats de xarxa poden dir que una xarxa és transport de VPN, però no de qui és el túnel.
Per això les preguntes sobre l’estat d’altres aplicacions reben respostes contradictòries: la informació simplement no s’exposa al vostre procés.
Què exigeix realment el cicle de vida
Seguiu els estats que controleu: preparat, establert, revocat, aturat. La reconnexió hauria de ser desmuntar i després establir, amb un sol propietari del descriptor i del socket de transport, perquè dos components que competeixin per establir es barallaran per l’única plaça disponible. Els inicis en segon pla estan restringits a l’Android modern, així que un broadcast d’arrencada no és cap garantia; feu servir un servei en primer pla amb la seva notificació on el nivell d’API ho permeti.
Registreu la transició i no només l’estat final, i manteniu la màquina d’estats prou petita per provar tots els camins. Un estat al qual no podeu arribar en una prova és un estat que trobareu al camp sense registre.
Proveu el cicle de vida en un dispositiu
Els emuladors poden falsejar la connectivitat però no el camí de consentiment i revocació de manera convincent, així que executeu-ho en un dispositiu real amb un segon client VPN instal·lat que robi la plaça.
adb shell dumpsys connectivity | grep -i -A3 vpn
adb shell dumpsys activity services | grep -i -A2 vpnservice
adb logcat -s VpnService:V AndroidRuntime:E
adb shell am force-stop com.example.vpnapp
Inicieu el túnel, confirmeu la notificació i la interfície, després connecteu l’altre client i observeu si s’executa la crida de retorn de revocació i si l’estat es neteja. Atureu l’aplicació forçadament i comproveu si alguna cosa encara informa d’un descriptor viu.
Repetiu la seqüència després d’un reinici sempre actiu, perquè aquest camí difereix d’una connexió iniciada per l’usuari. El que busqueu no és una icona verda sinó la prova que l’aplicació ha deixat d’usar un descriptor que ja no posseïa.