En Android 10 e posteriores, unha aplicación que abre /proc/net/tcp recibe unha denegación de acceso en lugar dunha táboa de sockets. Á interface VPN non lle importa: os paquetes seguen chegando, porque o túnel é unha decisión de encamiñamento, non un permiso de ficheiro. O que cambiou é a resposta a unha pregunta máis estreita: «que aplicación posúe esta conexión?» O substituto é ConnectivityManager.getConnectionOwnerUid, a consulta por conexión admitida, e escoller entre o vello costume e a nova API depende de cal das tres tarefas ten realmente: recibir paquetes, atribuír un fluxo ou sumar consumo.

Dúas formas de responder á pregunta do propietario

Antes da API 29, un proceso privilexiado ou root podía ler as táboas de sockets do kernel, emparellar a cuádrupla e coñecer o UID propietario. Iso daba un inventario de todo o dispositivo nun só ficheiro. Desde a API 29 a vista do sistema de ficheiros está restrinxida, e a ruta admitida é unha consulta por conexión co protocolo, o enderezo local e o enderezo remoto.

QuestionLegacy socket tablesgetConnectionOwnerUid
Who owns this flow?Scan and match the tupleAsk once per tuple
Device-wide inventory?Yes, when readableNo, one flow at a time
Historical usage?NoNo; that is NetworkStatsManager
Works without root?No on modern releasesYes, for authorized callers

A comparación non é «vello contra novo». Son tres tarefas distintas que antes satisfacía un único ficheiro lexible e agora satisfán tres interfaces distintas con tres contratos distintos.

O enderezo local é o extremo da aplicación

A sinatura do método toma un protocolo, un enderezo de socket local e un enderezo de socket remoto. «Local» significa o lado da aplicación na conexión, non o extremo que no momento da inspección resulta ser a orixe do paquete. Un paquete que viaxa do servidor remoto de volta á aplicación ten a orixe e o destino invertidos respecto desa definición.

ConnectivityManager cm = getSystemService(ConnectivityManager.class);
int uid = cm.getConnectionOwnerUid(
    OsConstants.IPPROTO_TCP, appLocalAddress, appRemoteAddress);

Este erro de dirección é a razón máis común de que unha consulta correcta devolva unha resposta equivocada ou ningunha. Rexistre ambos os extremos antes da chamada e confirme o par contra a conexión que a aplicación abriu realmente. A familia de enderezos tamén importa: un enderezo mapeado por IPv4 e un enderezo IPv6 nativo son tuplas distintas, e tamén o son os fluxos TCP e UDP nos mesmos portos.

A autorización e os resultados descoñecidos forman parte do contrato

A consulta está restrinxida a chamadores autorizados, incluída a aplicación VPN activa para o usuario correspondente. Unha aplicación de monitorización allea non pode supor que pode enumerar as conexións doutro perfil, e unha chamada non autorizada pode lanzar unha excepción de seguridade en lugar de devolver un erro amable. Xestione ambos os resultados de forma explícita.

Un propietario ausente non é un nome de paquete. O fluxo puido pecharse entre o paquete e a consulta, a tupla pode estar incompleta, ou pode que simplemente non se lle permita sabelo ao chamador. Almacenar a primeira resposta correcta e reutilizala despois atribúe unha conexión nova a unha aplicación vella, o que é peor que informar descoñecido.

Cando a atribución falla, o tráfico segue necesitando unha decisión: bloquealo onde a política o esixa, permitir só un ámbito que entenda, ou amosar o oco. Ese respaldo pertence ao deseño, non a un comentario.

A contabilidade é outra pregunta

NetworkStatsManager informa do consumo segundo as súas propias regras de acceso. Pode dicirlle canto transferiu un UID durante un período; non pode dicirlle o propietario dun paquete vivo arbitrario. As capacidades de rede describen propiedades dunha rede, non un directorio de sockets. Mesturar as tres produce paneis que parecen coherentes e non o son.

Para o caso simple de decidir que aplicacións usan o túnel, as listas admitidas de aplicacións permitidas e denegadas de Android xa expresan a política sen extraer nada. Reserve a atribución por fluxo para os casos que realmente a necesitan, e orzamente unha implementación mantida que trate dirección, permisos e estados descoñecidos en conxunto.

Escolla a ferramenta segundo a tarefa e logo probe os bordos

Se o requisito é a selección de túnel, use a lista da plataforma. Se é atribución en vivo, use a consulta de propietario e trate cada tupla sen resposta como descoñecida. Se son totais históricos, use a API de estatísticas. Logo probe os tres bordos que rompen as implementacións inxenuas: un paquete en sentido inverso, un fluxo que se pecha antes de consultalo e un chamador que non é a VPN activa.

Nada disto require desactivar SELinux, facer root no teléfono nin facer as táboas do kernel lexibles globalmente. A restrición é o punto: a plataforma moveu a atribución detrás dun contrato para que a resposta estea dispoñible para o compoñente que lexitimamente a necesita, e para ninguén máis.

Artigos relacionados