Permissão fantasma no Android (Implied permission)

Fala galera, hoje vou contar sobre um episódio que ocorreu comigo recentemente desenvolvendo para Android.

Minha tarefa a primeira vista era muito simples, remover uma feature que eliminaria a permissão para ler status do telefone do usuário (READ_PHONE_STATE).

Imagino que como eu, você também deve ter pensado, essa é mamata. Só ir no AndroidManifest e excluir a permissão, correto?

Pois é foi o que eu pensei também. Exclui a linha, comitei a alteração, gerei o apk e instalei no device para última checagem. Ao instalar o apk para minha surpresa a primeira permissão era a READ_PHONE_STATE.

Mas como é possível uma coisa dessa Cucharro? Graças a uma dica do Anderson Silva (@ladoleste) que ouvi num meetup do GDG-SP eu tinha uma pista.

Na sua apresentação sobre maps, o Anderson comentou que o play-services já adicionava algumas permissões automaticamente e por isso não era necessário adiciona-las ao seu AndroidManifest.

Na hora pensei comigo, é isso. Mas como eu vejo quais permissões cada lib do play-services pede?

Graças a essa resposta marota no stackoverflow e uma ajudinha do meu amigo @cleberdantas vou mostrar aqui pra vocês.

No mac/linux as libraries do play-services são baixadas no diretório $ANDROID_SDK/extras/google/m2repository/com/google/gms e dentro dele você pode ver cada uma delas como na imagem abaixo:

Você pode então descompactar o arquivo .aar usando por exemplo o comando tar -xzf play-services-8.1.0.aar e voilá tá lá o /res e o AndroidManifest pra você inspecionar e descobrir quais permissões eles adicionam ao seu app.

Problema resolvido então? Infelizmente não, no meu caso o app usava quatro libraries do play-services e nenhuma delas adicionavam a permissão. A titulo de curiosidade descobri o seguinte:

play-services-ads e play-services-analytics 8.1 adicionam:

<uses-permission android:name=”android.permission.INTERNET”/>

<uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE”/>

play-service-gcm 8.1 adiciona:

<uses-permission android:name=”com.google.android.c2dm.permission.RECEIVE” />

<uses-permission android:name=”android.permission.INTERNET” />

play-services-maps 8.1 adiciona:

<uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE”/>
<uses-permission android:name=”android.permission.INTERNET”/>
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/>

Maaaaaas… não era o play-services. Bom fiquei meio sem alternativa e me lembrei do processo de build do app e de que o processo de criaçao do apk é feito em partes acessíveis, como conseguimos ver na imagem abaixo:

No /intermediates notei por exemplo o exploded-aar que como dá pra inferir pelo nome possui todos os arquivos .aar descompactados facilmente acessíveis. Tchaaaaaaaaan! :)

Mesmo com isso e olhando as outras dependências, nada ainda. Por último dentro de outputs onde fica o apk gerado, há também o diretório logs e dentro dele, enfim o salvador manifest-merger-report.txt

Nele é possível entender o processo realizado pelo ManifestMerger uma ferramenta parte do build process que mescla então todos os manifests que fazem parte da aplicação gerando o resultado final.

No meu caso era a lib appirater que definia como minSDK versão 3, e por conta disso a permissão READ_PHONE_STATE é implícita (IMPLIED PERMISSION) e adicionada ao AndroidManifest final.

Como nesse caso eu tinha acesso ao fonte do appirater o trabalho foi aumentar o minSDK dele para o mesmo do app e ai sim, problema resolvido.

Isso tudo me tomou boas horas e espero que graças a esse post quando chegar a sua vez você leve 5 minutos. :)

Abraço e até a próxima!