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!