Não, uma aplicação VpnService não pode ligar a VPN do telemóvel
A aplicação possui um túnel e o seu ciclo de vida, não o interruptor de VPN do telemóvel. O consentimento pode ser revogado, só corre uma VPN de cada vez, e os pacotes são para você analisar.
A suposição errada é que uma aplicação VpnService aciona um interruptor do sistema e que, a partir daí, o telemóvel fica protegido. O que realmente acontece é mais estreito: a aplicação pede consentimento, constrói uma interface, lê e escreve pacotes através de um descritor de ficheiro, e devolve a interface quando para. Só pode estar vivo um túnel desses de cada vez, e o sistema pode retirá-lo sem perguntar. A maior parte do comportamento confuso que as pessoas atribuem ao protocolo vem desse modelo de propriedade.
Trate cada transição do ciclo de vida como parte do projeto e não como um caso limite.
Mito: a aplicação liga a VPN do telemóvel
O fluxo começa com VpnService.prepare(), que devolve um Intent que o utilizador tem de aceitar, e continua com establish(), que ainda pode falhar depois por motivos que a aplicação não controla. Estabelecer um segundo túnel desativa a primeira interface e substitui a notificação do sistema. Em nenhum ponto dessa sequência a aplicação possui um interruptor para todo o dispositivo; possui o descritor que lhe foi concedido e os pacotes que nele aterram. Até a notificação persistente pertence ao sistema e não ao projeto da aplicação.
Como a interface é concedida e não tomada, outro cliente pode ocupar o lugar a qualquer momento. A aplicação sabe disso através de uma chamada de retorno, não através de um valor de retorno.
A paragem forçada da aplicação vê-se no painel de notificações pelo mesmo motivo: o sistema reporta o que concedeu, não o que a aplicação escolheu mostrar.
Mito: o consentimento é dado uma vez
Quando o sistema entrega o túnel a outro cliente, envia uma transação de revogação no binder que a classe base devolve de onBind(). Uma aplicação que substitua esse binder pelo seu tem de reencaminhar ela própria a transação de revogação, caso contrário VpnService.onRevoke() nunca é acionado e o serviço continua a escrever num descritor que já não existe. A aprovação também pode ser retirada pelo utilizador, e o sistema pode parar o serviço durante um reinício ou uma reconexão sempre ativa.
Lidar com isso é trabalho concreto e não uma linha de registo: pare de ler o descritor, feche-o, limpe o indicador de ligado e diga ao utilizador em que estado está. Depois decida se a aplicação deve restabelecer, voltar a perguntar ou esperar, porque numa configuração sempre ativa o sistema pode trazer o serviço de volta sozinho.
Uma aplicação que trate a revogação como exceção e não como estado vai reportar ligada enquanto cada pacote que escreve é descartado, e esse é o pior modo de falha possível para uma ferramenta de privacidade.
Mito: a interface filtra o tráfego por si
O que chega é IP em bruto. Capturar ou filtrar significa analisar cabeçalhos IP, TCP, UDP e IPv6, seguir fluxos e escrever as respostas de volta ao descritor, o que torna uma aplicação de captura numa pequena pilha de rede e não numa instalação do sistema. protect() existe para que o socket de transporte da própria aplicação contorne o seu túnel em vez de se capturar a si mesma, e devolve um booleano que merece verificação em cada socket criado depois de o túnel estar de pé.
As listas de aplicações permitidas e proibidas do construtor decidem de quem entra o tráfego na interface. Não dão acesso à carga útil para além dos pacotes IP que a interface transporta, e nenhuma API expõe o túnel de outro cliente nem enumera os perfis de VPN do sistema. As capacidades de rede podem dizer que uma rede é transporte de VPN, mas não de quem é o túnel.
É por isso que as perguntas sobre o estado de outras aplicações recebem respostas contraditórias: a informação simplesmente não é exposta ao seu processo.
O que o ciclo de vida exige realmente
Siga os estados que controla: preparado, estabelecido, revogado, parado. A reconexão deve ser desmontar e depois estabelecer, com um único proprietário do descritor e do socket de transporte, porque dois componentes que competem para estabelecer vão lutar pelo único lugar disponível. Os arranques em segundo plano estão restringidos no Android moderno, por isso uma difusão de arranque não é garantia; use um serviço em primeiro plano com a sua notificação onde o nível de API o permitir.
Registe a transição e não apenas o estado final, e mantenha a máquina de estados pequena o suficiente para testar todos os caminhos. Um estado a que não consegue chegar num teste é um estado que vai encontrar no terreno sem registo.
Teste o ciclo de vida num dispositivo
Os emuladores conseguem falsificar a conectividade mas não o caminho de consentimento e revogação de forma convincente, por isso execute estes testes num dispositivo real com um segundo cliente VPN instalado para roubar o lugar.
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
Inicie o túnel, confirme a notificação e a interface, depois ligue o outro cliente e observe se a chamada de retorno de revogação corre e se o estado é limpo. Pare a aplicação à força e verifique se algo ainda reporta um descritor vivo.
Repita a sequência após um reinício sempre ativo, porque esse caminho é diferente de uma ligação iniciada pelo utilizador. O que procura não é um ícone verde mas a prova de que a aplicação deixou de usar um descritor que já não possuía.