How Libraries can silently add permissions to your Android App

The other day, I was checking support requestes for Glucosio, a Diabetes app I’m building, when I found a mail from an user complaining about some “invasive permissions” we were asking.

My first reaction was: What? We were just asking for storage writing permissions (to export data and statistics), NFC sensor access to receive data from sensors (like FreeStyle Libre) and network access, for our research API and user feedback. They were not invasive at all, considering that today lots of apps on the store need internet access.

Then I decided to visit our Google Play Developer Console, to double check the permissions with the production apk. That’s what I’ve found:

Again, my reaction was: What?? Record Audio? Microphone access? Really?

I opened my editor and checked Glucosio’s Manifest again.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.glucosio.android">

<uses-permission android:name="android.permission.NFC" android:required="false"/>
<uses-feature android:name="android.hardware.nfc" android:required="false" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<!-- Required for Instabug -->
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE"/>
<permission
android:name="${applicationId}.permission.C2D_MESSAGE"
android:protectionLevel="signature"/>

No traces of that record audio permission. So where did it come from?

The answer is pretty simple: external libraries that you’re using in your app can silently set additional permissions in your final apk, even if you don’t declare them in your Android Manifest.

To identify these permissions you have 2 important resources on your side: the Manifest Merger Log and the final Manifest of your app. Each time you build an Android app, a new build/ folder is generated in your project directory. The real final Manifest is somewhere in there. In fact, if we look at

app/build/intermediates/manifests/full/debug/AndroidManifest.xml

you’ll see the final Manifest file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.glucosio.android.daily"
android:versionCode="12"
android:versionName="0.10.0-DEVEL" >

<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="23" />

<uses-permission
android:name="android.permission.NFC"
android:required="false" />

<uses-feature
android:name="android.hardware.nfc"
android:required="false" />

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Required for Instabug -->
<uses-permission android:name="org.glucosio.android.daily.permission.C2D_MESSAGE" />

<permission android:name="org.glucosio.android.daily.permission.C2D_MESSAGE"
android:protectionLevel="signature" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

<permission
android:name="com.instabug.library.permission.C2D_MESSAGE"
android:protectionLevel="signature" />

<uses-permission android:name="com.instabug.library.permission.C2D_MESSAGE" />

As you can see, we’ve finally found our record audio permission. This manifest is the result of a merge of your main Manifest with the ones of all the libraries you’re including in the app. So where did it exactly this record audio permission came from? Have a look at

app/build/outputs/logs/manifest-merger-debug-report.txt

This is a very big file, so I’ll just paste here the interesting parts:

-- Merging decision tree log ---
manifest
ADDED from [com.google.android.gms:play-services-analytics:8.4.0] /home/paolo/dev/glucosio/glucosio-android/app/build/intermediates/exploded-aar/com.google.android.gms/play-services-analytics/8.4.0/AndroidManifest.xml:22:22–76
uses-permission#android.permission.VIBRATE
ADDED from [com.instabug.library:instabug:2.1.1] /home/paolo/dev/glucosio/glucosio-android/app/build/intermediates/exploded-aar/com.instabug.library/instabug/2.1.1/AndroidManifest.xml:12:22–73
uses-permission#android.permission.RECORD_AUDIO
ADDED from [com.instabug.library:instabug:2.1.1] /home/paolo/dev/glucosio/glucosio-android/app/build/intermediates/exploded-aar/com.instabug.library/instabug/2.1.1/AndroidManifest.xml:13:22–68
uses-permission#android.permission.WAKE_LOCK

and so on… So each third party library is adding some new permission to your final Manifest file. For example, Google Play Services added the Vibrate Permission, and Instabug (the tool we use for user feedback) is in fact requesting the Record Audio permission.

I’ve checked Instabug functionalities and there’s actually no need to ask for an invasive permission like that. Probably they added it for a future release that possibly could allow the user to send feedback with speech recognition(?).

EDIT: Instabug recently added a new feature that allows to add voice notes as an attachment to a bug report. They guarantee me that next release of their SDK will have this feature as an opt-in, instead of being opt-out. Thanks guys :)

So how can you get rid of that?

Just declare the incriminated permission in your (main) Manifest with the

tools:node="remove"

attribute (yes, that’s exactly how we fixed it).

For example:

<uses-permission android:name=”android.permission.RECORD_AUDIO” tools:node=”remove” />

Even if another library is asking for this specific permission, the build will be forced to not merge it in your final Manifest file.

There is another general tip though. Big libraries like Google Play Services generally requires tons of permissions to work well. That’s why you should never include the generic Google Play Services dependency in your app. Instead, Google offers you more targeted libraries, like play-services-analytics or play-services-maps that will limit the number of permission required and make your final apk smaller as well.