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

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

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 manuseio de interfaces não 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ó devem usar as partes oficialmente documentadas das classes no SDK. Isso também significa que você não deve 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 lançamento do Android, mais interfaces não SDK serão restritas. Sabemos que essas restriçõ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 não SDK, uma oportunidade de nos fornecer feedback e tempo para planejar e se ajustar às novas políticas.

Para minimizar o impacto das restrições de interfaces não SDK no seu fluxo de trabalho de desenvolvimento, as interfaces não SDK 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 proibições São interfaces não 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 não SDK que você pode usar, desde que 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 não 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 não 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 não SDK que fazem parte da lista cinza (dependendo do nível de API de destino do app), o uso de qualquer método ou campo não SDK sempre apresenta um alto risco de corromper o app. Se ele depende de interfaces não SDK, você deve começar a planejar uma migração para interfaces SDK ou outras alternativas. Caso você não encontre uma alternativa para deixar de usar uma interface não SDK para um recurso no seu app, solicite uma nova API pública.

Determinar a que lista uma interface pertence

As listas de interfaces não SDK são construídas como parte da plataforma.

Para o Android 9 (nível 28 da API), este arquivo de texto contém a lista de APIs na lista cinza que não são restritas. A lista de proibições e a lista cinza restrita são derivadas no momento da criação. Existe uma regra de compilação que gera as listas no AOSP. Embora as listas do AOSP não sejam iguais às listas do Android 9, há muitos itens em comum nelas. Você também pode gerar a lista de proibições fazendo o download do AOSP e executando o seguinte comando:

make hiddenapi-aosp-blacklist
    

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

out/target/common/obj/PACKAGING/hiddenapi-aosp-blacklist.txt
    

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 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 Class.getDeclaredField() ou Class.getField() NoSuchFieldException exibido
Reflexão por Class.getDeclaredMethod(), Class.getMethod() NoSuchMethodException exibido
Reflexão por Class.getDeclaredFields(), Class.getFields() Membros não SDK não estão nos resultados
Reflexão por Class.getDeclaredMethods(), Class.getMethods() Membros não SDK não estão nos resultados
JNI pelo env->GetFieldID() NULL retornado, NoSuchFieldError exibido
JNI pelo env->GetMethodID() NULL retornado, NoSuchMethodError exibido

Testar seu app para interfaces não SDK

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

Teste usando um app de depuração

Você pode testar interfaces não SDK criando e executando 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 28 da API do seu app.

Ao fazer testes no app, o sistema imprime uma mensagem de registro caso seu app acesse determinadas interfaces não 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 tempo de execução do Android).
  • Os meios de acesso: veiculação, reflexão ou JNI.
  • A que lista a interface não SDK 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, uma entrada no registro pode ser a seguinte:

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

Teste usando a API StrictMode

Você também pode testar interfaces não SDK usando a API StrictMode. Use o método detectNonSdkApiUsage para ativar isso. Depois de ativar a API StrictMode, você pode receber um retorno de chamada para cada uso de uma interface não SDK usando um penaltyListener, onde você pode 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.

Teste usando a ferramenta veridex

Também é possível executar 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 não 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.

Solicitar uma nova API pública

Caso você não encontre uma alternativa para deixar de usar uma interface não SDK para um recurso no seu app, é possível criar uma solicitação de recurso para que uma nova API pública seja adicionada ao SDK.

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, levamos em conta o uso da API e o feedback dos desenvolvedores por meio do rastreador de problemas.

Como posso ativar o acesso a interfaces não SDK?

Você pode ativar o acesso a interfaces não SDK em dispositivos de desenvolvimento alterando a política de aplicação da API com 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
    

Esses comandos não exigem um dispositivo com acesso root.

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 não SDK. O uso dessa configuração desativa todas as mensagens de registro para uso de uma interface não 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 não 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 pertencentes à lista de proibições ou a uma lista cinza e que estão restritas ao nível da sua API de destino.
  • 3: não permite o uso de interfaces não SDK pertencentes à lista de proibições, mas permite o uso de interfaces pertences à lista cinza e que estão restritas ao nível da sua API de destino.

Perguntas sobre listas de interface não 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 de CTS garantem que o tempo 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 não SDK, mas se comprometer a manter a compatibilidade com futuras versões do Android? O Android poderá renunciar os requisitos de compatibilidade nesse caso?

Não temos planos de dispensar os requisitos de compatibilidade para SDKs específicos. Se um desenvolvedor de SDK puder manter compatibilidade apenas dependendo das interfaces nas listas cinza, ele deverá começar a planejar uma 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 não SDK.

 

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

Sim, no entanto, 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 apenas a apps que fazem parte da imagem do sistema (ou apps de imagem do sistema atualizados). A lista se destina apenas a apps criados com base nas APIs da plataforma privada, em vez das APIs do SDK (em que LOCAL_PRIVATE_PLATFORM_APIS := true).