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 (em inglês).

Diferenciar interfaces SDK e não SDK

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 APIs não SDK

A cada versão do Android, mais interfaces não SDK sã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
Lista de bloqueio (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 delas, o sistema emitirá um erro.
Bloqueio condicional (greylist-max-x)

A partir do Android 9 (nível 28 da API), cada nível da API tem interfaces não SDK restritas caso sejam a API de destino do app.

Essas listas são rotuladas pelo nível máximo da API (max-target-x) que pode ser o destino do app antes de ele não conseguir mais acessar as interfaces não SDK incluídas nelas. Por exemplo, uma interface não SDK que não foi bloqueada no Android Pie, mas foi no Android 10, faz parte da lista max-target-p (greylist-max-p), em que "p" significa Pie ou Android 9 (nível 28 da API).

Caso o app tente acessar uma interface restrita no nível da API de destino, o sistema se comportará como se ela estivesse na lista de bloqueio.

Incompatível (greylist) São interfaces não SDK que ainda não são restritas e podem ser usadas pelo app. No entanto, elas não são compatíveis e estão sujeitas a mudanças sem aviso prévio. Pressuponha que essas interfaces serão bloqueadas condicionalmente em versões futuras do Android por uma lista max-target-x.
SDK (whitelist) São interfaces que podem ser usadas livremente e no momento são aceitas como parte do Índice de pacote do framework do Android oficialmente documentado.

Embora dependendo do nível da API de destino do app ainda seja possível usar algumas interfaces não SDK, o uso de qualquer método ou campo delas sempre implica um alto risco de corromper o app. 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 a interface não 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 11

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

Para saber mais sobre as mudanças na lista de APIs não SDK no Android 11, incluindo sugestões de alternativas públicas para APIs que são bloqueadas condicionalmente nele, consulte as alterações na lista do Android 11.

Android 10

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

Para saber mais sobre as mudanças na lista de APIs não SDK no Android 10, incluindo sugestões de alternativas públicas para APIs que são bloqueadas condicionalmente nele, consulte as alterações na lista do Android 10.

Android 9

O seguinte arquivo de texto contém a lista de APIs não SDK que não são restritas no Android 9 (nível 28 da API): hiddenapi-light-greylist.txt.

A lista de bloqueio (blacklist) e a lista de APIs bloqueadas condicionalmente (lista cinza-escuro) são derivadas no momento da compilaçã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 não SDK restritas são acessadas

A tabela a seguir descreve o comportamento esperado caso o app tente acessar uma interface não SDK incluída na lista de bloqueio.

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 não SDK, você verá erros ou avisos do build, dependendo da lista a que essas interfaces pertencem.

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 não SDK, um erro ou aviso será exibido no relatório de pré-lançamento, dependendo da lista a que elas pertencem.

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 não SDK incluídas na lista de bloqueio ou bloqueadas condicionalmente para o nível da API de destino.

Perguntas sobre listas de interface não SDK

Onde encontro as listas de APIs não SDK 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.

As APIs não SDK são as mesmas em dispositivos de OEM diferentes que tenham a mesma versão do Android?

Os OEMs podem adicionar suas próprias interfaces à lista de bloqueio, mas não podem removê-las das listas de APIs não SDK do AOSP. O CDD impede essas mudanças, e os 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 alguns apps de imagem do sistema. Essas exceções se aplicam somente a apps que fazem parte da imagem do sistema ou a apps de imagem do sistema atualizados. A lista é destinada somente a apps criados com base nas APIs da plataforma privada, não nas APIs do SDK (em que LOCAL_PRIVATE_PLATFORM_APIS := true).