Como contornar a lista negra de APIs ocultas no Android 9+

O Google introduziu restrições no Android 9 sobre as APIs que podem ser acessadas pelos desenvolvedores. Veja como contornar essas restrições ocultas da API.

Em 2018, o Google lançou o Android Pie. Entre as mudanças na interface do usuário e novos recursos, também houve algumas mudanças do lado do desenvolvedor. Essas mudanças incluíram novas APIs, correções de bugs para APIs existentes e também restrições de acesso a APIs ocultas.

Felizmente, porém, existem maneiras de contornar essas restrições. Antes de entrar em como contornar as restrições, devo explicar um pouco sobre o que são APIs ocultas, por que elas foram restritas em primeiro lugar e por que você pode querer acessá-las.

APIs ocultas são APIs no Android que os desenvolvedores de aplicativos normalmente não conseguem ver. Se você der uma olhada no código do AOSP, verá um monte de classes, variáveis ​​e métodos que possuem um @hide anotação dentro de um bloco de comentários acima deles.

Esta anotação instrui qualquer ferramenta que o Google usa ao compilar o SDK para excluir o item contido nele. Esse SDK é então distribuído aos desenvolvedores dentro dos SDKs baixados por meio do Android Studio. A menos que você use um SDK modificado, o Android Studio pensará que qualquer um desses itens ocultos simplesmente não existe. Se você tentar usar um diretamente, ele será exibido em vermelho e se recusará a compilar.

Existem vários motivos pelos quais uma API pode estar oculta. Algumas coisas devem ser usadas apenas por aplicativos internos ou do sistema e não funcionarão se usadas por aplicativos de terceiros. Outros são experimentais ou instáveis ​​e podem ser removidos ou alterados no futuro. Alguns são apenas APIs que o Google simplesmente não deseja seguir o ciclo normal de descontinuação caso sejam removidos.

Embora o Android SDK padrão tenha um muito nele, às vezes não é suficiente. Às vezes, há algo que você deseja fazer e que já existe no Android, mas não está exposto publicamente.

Por exemplo, muitos dos aplicativos que faço, incluindo Sintonizador SystemUI e Widgets de tela de bloqueio, faça uso de várias APIs ocultas diferentes. O SystemUI Tuner precisa acessar alguns para rastrear, alterar e redefinir opções adequadamente. Lockscreen Widgets usa alguns para mostrar o papel de parede abaixo dele, entre outras coisas.

A maioria dos desenvolvedores não precisa acessar APIs ocultas, mas às vezes elas podem ser bastante úteis.

Com o lançamento do Android 9 (Pie), o Google introduziu a lista negra de APIs ocultas. Nem todas as APIs ocultas foram incluídas e havia diferentes níveis de listas. APIs ocultas na lista de permissões podem ser acessadas por qualquer pessoa. APIs ocultas na lista cinza clara podem ser acessadas por qualquer aplicativo, mas podem ficar inacessíveis em versões futuras do Android. Qualquer coisa na lista cinza escura só poderia ser acessada por aplicativos direcionados a níveis de API anteriores ao Pie (ou seja, antes do nível 28 da API). Aplicativos direcionados ao Pie e posteriores teriam acesso negado. Por fim, as APIs ocultas na lista negra não podiam ser acessadas por nenhum aplicativo que não fosse do sistema (ou que não estivesse na lista de permissões), independentemente da API de destino.

O Android 10 mudou a forma como as listas eram organizadas e simplificou-as um pouco, mas a ideia permaneceu a mesma. Certas APIs ocultas podem ser acessadas por aplicativos enquanto outras são bloqueadas. Android 11 reforçou a detecção de acesso para bloquear um desvio usado para Torta e 10.

Em todas as versões do Android, sempre que um aplicativo de terceiros tentar acessar uma API oculta na lista negra, o Android gerará o erro "não encontrado" apropriado.

Na verdade, existem algumas maneiras de superar a lista negra de APIs ocultas. Dependendo de suas necessidades, você pode escolher aqueles que funcionam para todas as versões do Android, aqueles que funcionam apenas para Android 9 e 10, aqueles que usam código C++ nativo e aqueles que são totalmente baseados em Java. Existe até uma solução alternativa apenas para desenvolvimento usando ADB.

Solução alternativa do ADB

Se o seu dispositivo estiver executando o Android Pie, execute os dois comandos ADB a seguir para ativar o acesso oculto à API.

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

Se o seu dispositivo estiver executando o Android 10 ou posterior, execute o seguinte comando ADB para habilitar o acesso oculto à API.

adb shell settings put global hidden_api_policy 1

Para reverter ao comportamento padrão, basta substituir put com delete e remova o 1.

Obviamente, esses comandos não são exatamente úteis para um aplicativo de produção. Posso dizer em primeira mão que instruir adequadamente os usuários sobre como usar o ADB é incrivelmente difícil. Mas eles podem ser úteis se você precisar atualizar um aplicativo antigo para cumprir as novas restrições.

Solução alternativa nativa/JNI

Existem duas maneiras de contornar a lista negra de APIs ocultas usando JNI em seu aplicativo Android. Um funciona para Android 9 e 10 e o outro funciona para Android 9 e posterior.

Android 9 e 10

Se você já possui uma parte nativa do seu aplicativo, isso será fácil de implementar. Basta usar o JNI_OnLoad() função.

arte estática:: Tempo de execução* tempo de execução = nullptr;

extern "C"jint JNI_OnLoad(JavaVM *vm, void *reserved){
...
runtime = reinterpret_cast<: javavmext>(vm)->GetRuntime();
runtime->SetHiddenApiEnforcementPolicy(art:: hiddenapi:: EnforcementPolicy:: kNoChecks);
...
}

Esteja ciente de que este método só funciona no Android 9 e 10.

Android 9 e posterior

Para qualquer versão do Android, você pode escolher entre duas bibliotecas para contornar a restrição oculta da API: FreeReflection e RestrictionBypass.

Ambos são fáceis de implementar e usar.

Para implementar o FreeReflection, adicione a dependência ao build.gradle no nível do módulo.

implementation 'me.weishu: free_reflection: 3.0.1'

Então substitua attachBaseContext() na sua classe Application.

@Override
protectedvoidattachBaseContext(Context base){
super.attachBaseContext(base);
Reflection.unseal(base);
}

Se você não tiver uma classe Application, poderá adicioná-la facilmente. Crie uma nova classe que estenda Application e aponte para ele em seu AndroidManifest.xml.

Exemplo:

publicclassAppextendsApplication{
...
@Override
protectedvoidattachBaseContext(Context base){
super.attachBaseContext(base);

Reflection.unseal(base);
}
}

<manifest>
...
...
name=".App">
...
application>
manifest>

Para implementar RestrictionBypass, adicione o repositório JitPack ao build.gradle no nível do projeto.

allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}

Em seguida, adicione a dependência ao build.gradle em nível de módulo.

implementation 'com.github.ChickenHook: RestrictionBypass: 2.2'

E é isso. Esta biblioteca remove automaticamente as restrições da lista negra.

Solução alternativa Java

Embora as soluções JNI sejam eficazes, há momentos em que você pode não querer usar código nativo. Se você ainda não estiver fazendo coisas em C++, isso poderá adicionar tamanho desnecessário, juntamente com restrições de plataforma, ao seu aplicativo. Felizmente, existem maneiras de contornar a lista negra de APIs ocultas usando apenas Java.

Android 9 e 10

No Android 9 e 10, você pode usar o que pode ser chamado de reflexão dupla ou meta-reflexão para ignorar a lista negra de APIs ocultas. Como o sistema verifica apenas o que os aplicativos de terceiros estão chamando, a dupla reflexão o leva a pensar que o sistema está fazendo as chamadas de API ocultas.

Esse truque pode ser usado para chamar um método para fornecer isenções de API ocultas ao seu aplicativo, apropriadamente chamado setHiddenApiExemptions(). Basta adicionar o seguinte código em algum lugar no início do ciclo de vida do seu aplicativo (como o código do aplicativo onCreate() método) e ele irá contornar a lista negra.

Method forName = Class.class.getDeclaredMethod("forName", String.class);
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);

Class vmRuntimeClass = (Class) forName.invoke(null, "dalvik.system.VMRuntime");
Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
Method setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", newClass[] { String[].class} );

Object vmRuntime = getRuntime.invoke(null);
setHiddenApiExemptions.invoke(vmRuntime, newString[][] { newString[] { "L" } });

Se o seu aplicativo for compatível com versões do Android anteriores à 9, lembre-se de incluir isso em uma verificação de versão.

Android 9 e posterior

Para ignorar a lista negra de APIs ocultas no Android 9 e qualquer versão posterior, você pode usar a biblioteca do LSPosed. Esta biblioteca usa a API Unsafe do Java, portanto é improvável que alguma vez quebre.

Para implementá-lo, basta adicionar a dependência ao build.gradle de nível de módulo.

implementation 'org.lsposed.hiddenapibypass: hiddenapibypass: 2.0'

Em seguida, use-o para ignorar a lista negra.

HiddenApiBypass.addHiddenApiExemptions("L");

Se o seu aplicativo for compatível com versões do Android anteriores à 9, lembre-se de incluir isso em uma verificação de versão.

Conclusão e mais informações

Existem muitas opções para contornar a lista negra de APIs ocultas no Android, independentemente da versão da plataforma que você segmenta ou usa. Se você estiver curioso para saber mais sobre como esses métodos e bibliotecas funcionam, verifique os links a seguir.

  • Minhas perguntas e respostas sobre Stack Overflow.
  • Biblioteca Hidden API Bypass do LSposed no GitHub.
  • Biblioteca RestrictionBypass do ChickenHook no GitHub.
  • biblioteca FreeReflection de tiann no GitHub.
  • Documentação do Google sobre a lista negra de APIs ocultas.