Restrições para interfaces que não são do SDK

A partir do Android 9 (nível 28 da API), a plataforma restringe quais interfaces de fora do SDK seu app pode usar. Essas restrições são aplicadas sempre que um app se refere a uma interface externa ao SDK ou tenta buscar o identificador dela usando reflexão ou JNI. As limitações foram implementadas para ajudar a melhorar a experiência do usuário e do desenvolvedor e reduzir os riscos de falhas para os usuários e lançamentos de emergência para os desenvolvedores. Para saber mais sobre essa decisão, consulte como reduzir o uso de interfaces externas ao SDK para melhorar a estabilidade.

Diferenciar interfaces do SDK e externas

De um modo geral, as interfaces públicas do SDK são aquelas encontradas documentadas no índice de pacotes do framework Android. O processamento de interfaces externas ao SDK é um detalhe de implementação que a API abstrai. Portanto, essas interfaces estão sujeitas a alterações sem aviso prévio.

Para evitar falhas e comportamentos inesperados, os apps só podem usar as partes oficialmente documentadas das classes no SDK. Isso também significa que não é permitido acessar métodos ou campos que não estejam listados no SDK ao interagir com uma classe por meio de mecanismos como reflexão.

Listas de proibições, listas cinza e listas de permissões

A cada versão do Android, mais interfaces que não forem do SDK serão restritas. Sabemos que essas limitações podem afetar o fluxo de trabalho da sua versão e queremos garantir que você tenha as ferramentas para detectar o uso de interfaces de fora do SDK, uma oportunidade de dar feedback e tempo para planejar e se ajustar às novas políticas.

Para minimizar o impacto das restrições de interfaces externas ao SDK no seu fluxo de trabalho de desenvolvimento, essas interfaces são divididas em listas que definem até que ponto o uso é restrito, dependendo de qual nível da API está sendo segmentado. A tabela a seguir descreve cada uma dessas listas:

Lista Descrição
Blacklist São interfaces externas ao SDK que não podem ser usadas, independentemente do nível da API de destino do app. Caso seu app tente acessar uma dessas interfaces, o sistema emitirá um erro.
Lista cinza São interfaces externas ao SDK que você pode usar, desde que elas não sejam restritas no nível da API de destino do seu app.

A partir do Android 9 (nível 28 da API), cada nível da API tem interfaces externas ao SDK restritas nesse nível de API. Embora uma API de lista cinza restrita possa ser acessada desde que o app segmente um nível de API mais baixo, se o app tentar acessar uma interface externa ao SDK restrita no nível da API de destino, o sistema se comportará como se a API estivesse na lista de proibições.

Observação: no Android 9 (nível 28 da API), as interfaces não SDK da lista cinza não restrita eram chamadas de lista cinza-claro, e as interfaces não SDK da lista cinza restrita eram chamadas de lista cinza-escuro.

Lista de permissões São interfaces que podem ser usadas livremente e são aceitas como parte do Índice de pacote do framework do Android oficialmente documentado.

Embora atualmente seja possível usar as interfaces externas ao SDK que fazem parte da lista cinza (dependendo do nível da API de destino do app), o uso de qualquer método ou campo que não esteja no SDK sempre implica um alto risco de que o app seja corrompido. Se ele depender de interfaces externas, comece a planejar uma migração para opções do SDK ou outras alternativas. Caso você não encontre uma alternativa para deixar de usar uma interface externa ao SDK em um recurso no seu app, solicite uma nova API pública.

Determinar a que lista uma interface pertence

As listas de interfaces externas ao SDK são criadas como parte da plataforma. Consulte as seções abaixo para saber mais sobre cada versão do Android.

Android 10

Para o Android 10 (API nível 29), o seguinte arquivo descreve todas as interfaces externas ao SDK e as listas correspondentes: hiddenapi-flags.csv.

Android 9

Para o Android 9 (API de nível 28), o seguinte arquivo de texto contém a lista de APIs na lista cinza que não são restritas: hiddenapi-light-greylist.txt.

A lista de proibições e a lista cinza restrita são derivadas no momento da criação.

Gerar listas do AOSP

Ao trabalhar com o AOSP, você pode gerar um arquivo hiddenapi-flags.csv que contenha todas as interfaces externas ao SDK e as listas correspondentes. Para fazer isso, faça o download da origem do AOSP e execute o seguinte comando:

m out/soong/hiddenapi/hiddenapi-flags.csv

Depois disso, será possível encontrar o arquivo no seguinte local:

out/soong/hiddenapi/hiddenapi-flags.csv

Comportamento esperado quando as interfaces restritas e externas ao SDK são acessadas

A tabela a seguir descreve o comportamento esperado caso o app tente acessar uma interface externa ao SDK que faça parte da lista de proibições.

Meios de acesso Resultado
Instrução Dalvik referenciando um campo NoSuchFieldError exibido
Instrução Dalvik referenciando um método NoSuchMethodError exibido
Reflexão por meio de Class.getDeclaredField() ou Class.getField() NoSuchFieldException exibido
Reflexão por meio de Class.getDeclaredMethod(), Class.getMethod() NoSuchMethodException exibido
Reflexão por meio de Class.getDeclaredFields(), Class.getFields() Membros externos ao SDK excluídos dos resultados
Reflexão por meio de Class.getDeclaredMethods(), Class.getMethods() Membros externos ao SDK excluídos dos resultados
JNI por meio de env->GetFieldID() NULL retornado, NoSuchFieldError exibido
JNI por meio de env->GetMethodID() NULL retornado, NoSuchMethodError exibido

Testar se há interfaces que não são do SDK no seu app

Existem vários métodos que você pode usar para testar interfaces externas ao SDK no seu app.

Testar usando um app de depuração

Para testar se há interfaces externas ao SDK, crie e execute um app de depuração em um dispositivo ou emulador com Android 9 (nível 28 da API) ou superior. Certifique-se de que o dispositivo ou emulador que você está usando corresponda ao nível da API de destino do seu app.

Ao fazer testes no app, o sistema imprime uma mensagem de registro caso seu app acesse determinadas interfaces externas ao SDK. É possível inspecionar as mensagens de registro do app para encontrar os seguintes detalhes:

  • A classe, o nome e o tipo declarantes (no formato usado pelo ambiente de execução do Android).
  • Os meios de acesso: veiculação, reflexão ou JNI.
  • A que lista a interface externa pertence.

É possível usar o adb logcat para acessar essas mensagens de registro, que aparecem sob o PID do app em execução. Por exemplo, pode haver uma entrada assim no registro:

Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)

Testar usando a API StrictMode

Também é possível testar se há interfaces externas ao SDK usando a API StrictMode. Use o método detectNonSdkApiUsage para ativar. Depois de ativar a API StrictMode, você pode receber um retorno de chamada para cada uso de uma interface externa usando um penaltyListener, em que é possível implementar o tratamento personalizado. O objeto Violation fornecido no retorno de chamada deriva de Throwable, e o stack trace incluído fornece o contexto do uso.

Testar usando a ferramenta veridex

Também é possível ativar a ferramenta de análise estática veridex no seu APK. A ferramenta veridex examina toda a base de código do APK, incluindo quaisquer bibliotecas de terceiros, e relata qualquer uso de interfaces externas ao SDK que encontrar.

Limitações da ferramenta veridex incluem o seguinte:

  • Não é possível detectar invocações por meio do JNI.
  • É possível detectar apenas um subconjunto de invocações por meio da reflexão.
  • A análise para caminhos de código inativos é limitada a verificações no nível da API.
  • Ele só pode ser executado em máquinas compatíveis com as instruções SSE4.2 e POPCNT.

Windows

Os binários nativos do Windows não são fornecidos, mas você pode ativar a ferramenta veridex no Windows executando os binários do Linux com o Windows Subsystem for Linux (WSL). Antes de seguir as etapas nesta seção, instale o WSL e escolha o Ubuntu como a distribuição Linux.

Após a instalação do Ubuntu, inicie um terminal Ubuntu e siga estas etapas:

  1. Faça o download da ferramenta veridex no repositório de pré-versões do ambiente de execução do Android.
  2. Extraia o conteúdo do arquivo appcompat.tar.gz.
  3. Na pasta extraída, localize o arquivo veridex-linux.zip e descompacte-o.
  4. Navegue até a pasta descompactada e execute o seguinte comando, em que your-app.apk é o APK que você quer testar:

    ./appcompat.sh --dex-file=your-app.apk
    

macOS

Para ativar a ferramenta veridex no macOS, siga estas etapas:

  1. Faça o download da ferramenta veridex no repositório de pré-versões do ambiente de execução do Android.
  2. Extraia o conteúdo do arquivo appcompat.tar.gz.
  3. Na pasta extraída, localize o arquivo veridex-mac.zip e descompacte-o.
  4. Navegue até a pasta descompactada e execute o seguinte comando, em que /path-from-root/your-app.apk é o caminho para o APK que você quer testar, começando do diretório raiz do sistema:

    ./appcompat.sh --dex-file=/path-from-root/your-app.apk
    

Linux

Para ativar a ferramenta veridex no Linux, siga estas etapas:

  1. Faça o download da ferramenta veridex no repositório de pré-versões do ambiente de execução do Android.
  2. Extraia o conteúdo do arquivo appcompat.tar.gz.
  3. Na pasta extraída, localize o arquivo veridex-linux.zip e descompacte-o.
  4. Navegue até a pasta descompactada e execute o seguinte comando, em que your-app.apk é o APK que você quer testar:

    ./appcompat.sh --dex-file=your-app.apk
    

Testar usando a ferramenta lint do Android Studio

Sempre que você cria um app no Android Studio, a ferramenta lint inspeciona o código em busca de possíveis problemas. Se o app usar interfaces externas ao SDK, você poderá ver erros ou avisos de versão caso elas façam parte da lista de proibições ou das listas cinza.

Também é possível executar a ferramenta lint na linha de comando ou executar inspeções manualmente em um projeto, uma pasta ou um arquivo específico.

Testar usando o Play Console

Ao fazer upload do app para uma faixa de teste no Play Console, o app é automaticamente testado para possíveis problemas, e um relatório de pré-lançamento é gerado. Se o app usar interfaces externas ao SDK, um erro ou aviso será exibido no relatório de pré-lançamento caso elas façam parte da lista de proibições ou das listas cinza.

Para saber mais, consulte a seção Compatibilidade do Android em Usar relatórios de pré-lançamento para identificar problemas.

Solicitar uma nova API pública

Caso você não encontre uma alternativa para deixar de usar uma interface externa ao SDK para um recurso no seu app, é possível solicitar uma nova API pública criando uma solicitação de recurso no Issue Tracker.

Ao criar uma solicitação de recurso, forneça as seguintes informações:

  • Quais APIs na lista cinza você está usando atualmente, incluindo o descritor completo visto na mensagem logcat Accessing hidden ....
  • Por que você precisa usar essas APIs, incluindo detalhes sobre o recurso de alto nível para que a API é necessária, e não apenas detalhes de baixo nível.
  • Por que as APIs públicas do SDK relacionadas são insuficientes para seus objetivos.
  • Quaisquer outras alternativas que você tenha tentado e por que elas não funcionaram.

Ao fornecer esses detalhes na sua solicitação de recurso, você aumenta a probabilidade de uma nova API pública ser concedida.

Mais perguntas

Esta seção inclui algumas respostas para outras perguntas que os desenvolvedores realizam com frequência:

Perguntas gerais

Como o Google pode ter certeza de que capturará as necessidades de todos os apps por meio do issuetracker?

Criamos as listas iniciais do Android 9 (nível 28 da API) por meio da análise estática de apps, que foi complementada usando os seguintes métodos:

  • Teste manual dos principais apps do Google Play e de outras fontes
  • Relatórios internos
  • Coleta automática de dados de usuários internos
  • Relatórios de visualização do desenvolvedor
  • Análise estática adicional que foi projetada para incluir, de modo conservador, mais falsos positivos.

À medida que avaliamos as listas para cada nova versão, consideramos o uso da API e o feedback dos desenvolvedores por meio do rastreador de problemas.

Como posso ativar o acesso a interfaces que não são do SDK?

É possível ativar o acesso a interfaces externas em dispositivos de desenvolvimento usando comandos adb para alterar a política de aplicação da API. Os comandos que você usa variam, dependendo do nível da API. Esses comandos não exigem um dispositivo com acesso root.

Android 10 (nível 29 da API)

Para ativar o acesso, use o seguinte comando adb:

adb shell settings put global hidden_api_policy  1

Para redefinir a política de aplicação da API para as configurações padrão, use o seguinte comando:

adb shell settings delete global hidden_api_policy
Android 9 (API de nível 28)

Para ativar o acesso, use os seguintes comandos adb:

adb shell settings put global hidden_api_policy_pre_p_apps  1
adb shell settings put global hidden_api_policy_p_apps 1

Para redefinir a política de aplicação da API para as configurações padrão, use os seguintes comandos:

adb shell settings delete global hidden_api_policy_pre_p_apps
adb shell settings delete global hidden_api_policy_p_apps

Você pode definir o número inteiro na política de aplicação da API como um dos seguintes valores:

  • 0: desativa todas as detecções de interfaces que não são do SDK. O uso dessa configuração desativa todas as mensagens de registro para uso de interface externa ao SDK e impede que você teste seu app usando a API StrictMode. Essa configuração não é recomendada.
  • 1: ativa o acesso a todas as interfaces externas ao SDK, mas imprime mensagens de registro com avisos para qualquer uso desse tipo de interface. O uso dessa configuração também permite testar seu app usando a API StrictMode.
  • 2: não permite o uso de interfaces externas ao SDK pertencentes à lista de proibições ou a uma lista cinza e que estão restritas ao nível da sua API de destino.

Perguntas sobre listas de interfaces externas ao SDK

Onde posso encontrar a lista de proibições e as listas cinza na imagem do sistema?

Elas são codificadas nos bits de sinalização de acesso a campo e método nos arquivos dex da plataforma. Não há arquivo separado na imagem do sistema que contenha essas listas.

A lista de proibições e as listas cinza são iguais em diferentes dispositivos OEM com as mesmas versões do Android?

Os OEMs podem adicionar as próprias interfaces à lista de proibições, mas não podem remover interfaces das listas de proibições ou listas cinza do AOSP. O CDD impede essas alterações, e esses testes do CTS garantem que o ambiente de execução do Android aplique a lista.

Existe alguma restrição em interfaces não NDK no código nativo?

O SDK do Android inclui interfaces Java. A plataforma começou a restringir o acesso a interfaces não NDK para códigos C/C++ nativos no Android 7 (nível 26 da API). Para mais informações, consulte como melhorar a estabilidade com restrições de símbolo C/C++ privado no Android N.

Existe algum plano para restringir a manipulação de arquivos dex2oat ou DEX?

Não temos planos ativos para restringir o acesso ao binário dex2oat, mas não pretendemos que o formato de arquivo DEX seja estável ou uma interface pública além das partes que são publicamente especificadas no formato executável Dalvik. Reservamo-nos o direito de modificar ou eliminar o dex2oat e as partes não especificadas do formato DEX a qualquer momento. Os arquivos derivados produzidos pelo dex2oat, como ODEX (também conhecido como OAT), VDEX e CDEX, são formatos não especificados.

E se um SDK de terceiros crucial (por exemplo, um ofuscador) não puder evitar o uso de interfaces que não são do SDK, mas se comprometer a manter a compatibilidade com futuras versões do Android? O Android poderá renunciar aos requisitos de compatibilidade nesse caso?

Não temos planos de renunciar aos requisitos de compatibilidade para SDKs específicos. Se um desenvolvedor de SDK puder manter compatibilidade somente dependendo das interfaces nas listas cinza, ele precisará começar a planejar a migração para interfaces SDK ou outras alternativas e solicitar uma nova API pública sempre que não puder encontrar uma alternativa ao uso de uma interface externa ao SDK.

As restrições de interface externa ao SDK se aplicam a todos os apps, incluindo apps do sistema e de terceiros, e não somente apps de terceiros?

Sim, mas isentamos apps assinados com a chave da plataforma e também temos uma lista de permissões de pacotes para alguns apps de imagem do sistema. Essas exceções se aplicam somente a apps que fazem parte da imagem do sistema (ou apps de imagem do sistema atualizados). A lista é destinada somente a apps criados com base nas APIs da plataforma privada, e não nas APIs do SDK (em que LOCAL_PRIVATE_PLATFORM_APIS := true).