Android permissions have been there for as long as we can remember—since Android 1.0, to be exact. Through the years and with the evolvement of platforms, the Android permissions model has been modified by adding new permissions and trying to allow more granular control over the part of the device hardware/data the application has.
In this chapter, we will review a bit of the Android permissions model that was prior to Android Marshmallow, and we'll focus on the changes it brings to the table. We will also explain the changes that you as a developer must do in order to handle all the other changes and make sure your applications work as intended on Android Marshmallow.
In this chapter, we will cover the following:
An overview of Android permissions
Understanding Android Marshmallow permissions
Handling code permissions with best practices
In Android, each application runs with distinct system IDs known as Linux user ID and Group ID. The system parts are also separated into distinct IDs, forming isolated zones for applications—from each other and from the system. As part of this isolated life cycle scheme, accessing services or other applications' data requires that you declare this desire in advance by requesting a permission.
This is done by adding the uses-permission
element to your AndroidManifest.xml
file. Your manifest may have zero or more uses-permission
elements, and all of them must be the direct children of the root <manifest>
element.
Trying to access data or features without proper permission would give out a security exception (using a SecurityException
class), informing us about the missing permission in most cases.
The
sendBroadcast(Intent)
method is exceptional as it checks permissions after the method call has returned, so we will not receive an exception if there are permission failures. A permission failure
should be printed to the system log. Note that in Android versions prior to Marshmallow, missing permissions were due to missing declarations in the manifest. Hence, it is important that you keep permissions in mind when you come up with the feature list for your app.
When using Android platform as an app, you have restrictions preventing access to some hardware, system APIs, private user data, and application data.
Permission is needed in order to allow access to a specific API, data, or hardware; it was asked upon the installation of your app up until Android Marshmallow. Most permissions are used to restrict access. When a permission is granted, you then have access to that specific restricted area. A feature can be protected by one permission at most.
The uses-permission
element takes a name attribute, android:name
, which is the name of the permission your application requires:
<uses-permission android:name="string" android:maxSdkVersion="integer" />
Did you know that the android:maxSdkVersion
attribute, added in API level 19, is used to notify the version of the API from which this permission should not be granted? This is useful if a permission is no longer needed on higher versions of the API. For example, take a look at the following:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
In API 19, your app doesn't need to ask for this permission—it's granted to you.
Your application can also protect its own components, such as activities, services, broadcast receivers, and content providers with permissions.
It can employ any of the permissions defined by Android and declared by other applications, or it can define its own.
For more information on permissions, you can read http://developer.android.com/reference/android/Manifest.permission.html.
Permissions are divided into groups. According to Google, we can say that a permission group puts together related permissions in a single name/tag. You can group permissions together using the permissionGroup
attribute inside the <permission>
element.
Permissions grouped in the same permission group are shown as one group when approving permissions or when checking an app for its permissions.
The permission group is what you see when installing an application from the Play Store; for example, take a look at the following screenshot:

Let's take a look at the structure of the permission-group
tag:
<permission-group android:description="string resource" android:icon="drawable resource" android:label="string resource" android:name="string" />
The elements of the preceding structure can be explained as follows:
android:description
: This refers to simple text used to describe the group.android:icon
: This refers to an icon from a drawable resource that represents the permission.android:label
: This refers to a simple text name for the group.android:name
: This is the name of the group. It is used to assign permissions to a specific group.
The following table shows you the various categories of permissions that are there in a permissions group:
Permissions group | |
---|---|
In-app purchases |
Device and app history |
Contacts |
Calendar |
Phone |
Photos, media, and files |
Wi-Fi connection information |
Bluetooth connection information |
Identity |
Cellular data settings |
SMS |
Location |
Microphone |
Camera |
Device ID and call information |
Wearable sensors/activity data |
Other |
Some permissions are implied by feature requirements; we will cover this next.
When declaring a feature in the manifest, we must also request the permissions that we need.
Let's say, for example, that we want to have a feature that sets pictures for our contacts. If we want to take a picture via the Camera
API, then we must request a Camera
permission.
The <users-feature>
tag makes sure we declare that we need devices that support the required feature for our application to work and use that feature. If this feature is not a required feature and our app can work without it but with fewer features, we can use android:required="false"
, keeping it in mind that this feature is optional.
The <uses-feature>
declarations always take precedence over features implied by permissions. The complete list of permission categories that imply feature requirements can be found at http://developer.android.com/guide/topics/manifest/uses-feature-element.html#permissions.
You can look at the permissions for each app using the settings app or the adb
shell command.
To use the settings app, go to Settings | Apps. Pick an app and scroll down to see the permissions that the app uses You can see the Lollipop version in the following screenshot:

In Android Marshmallow, the UI is different.

The second option is to use the adb
shell commands with the aapt
command:
List all the applications along with their installation paths. As an example, let's try to find out Facebook groups' app permissions using the following command:
adb shell pm list packages –f
We can use the
-3
flag to just show the third-party apps instead of the entire list.Once we get the package location (
apk
), we need to pull it from the device via theadb
pull:adb pull /data/app/com.facebook.groups-1/base.apk
Our final step to show permissions is to use
aapt
found in thebuild-tools
folder of your specific build tools version:aapt d permissions base.apk
This gives us the following screenshot as a result:
To view the permissions for the entire device, take a look at the following screenshot:
Using an adb
command, you can print all known permissions on the device. The package manager (pm
) command inside the adb
command looks something like the following:
$ adb shell pm list permissions [options] <GROUP>
List permissions get the [options]
and <GROUP>
arguments (both optional).
Here, options
can be as follows:
-g
: This refers to a list of permissions organized by a group-f
: This prints all the information-s
: This prints a short summary, and this is what the user sees on screen when checking permissions or approving them-d
: This looks up and prints only permissions that are considered dangerous-u
: This lists permissions visible to the user only
Android Marshmallow introduces a new application permissions model, allowing a simpler process for users when installing and/or upgrading applications. Applications running on Marshmallow should work according to a new permissions model, where the user can grant or revoke permissions after the installation—permissions are not given until there is user acceptance.
Supporting the new permissions model is backward-compatible, which means your apps can still be installed and run on devices running older versions of Android using the old permissions model on those devices.
With the Android Marshmallow version, a new application permissions model has been introduced.
Let's review it a bit more thoroughly:
Declaring permissions: All permissions an app needs are declared in the manifest, which is done to preserve backward compatibility in a manner similar to earlier Android platform versions.
Permission groups: As discussed previously, permissions are divided into permission groups based on their functionalities:
PROTECTION_NORMAL permissions: Some of the permissions are granted when users install the app. Upon installation, the system checks your app's manifest and automatically grants permissions that match the
PROTECTION_NORMAL
group.INTERNET permission: One important permission is the
INTERNET
permission, which will be granted upon installation, and the user can't revoke it.
App signature permissions granted: The user is not prompted to grant any permissions at the time of installation.
Permissions granted by users at runtime: You as an app developer need to request a permission in your app; a system dialog is shown to the user, and the user response is passed back to your app, notifying whether the permission is granted.
Permissions can be revoked: Users can revoke permissions that were granted previously. We must learn how to handle these cases, as we'll learn later on.
When working with permissions, we divide them into groups. This division is done for fast user interaction when reviewing and approving permissions. Granting is done only once per permission group. If you add a new permission or request a new permission from the same permission group and the user has already approved that group, the system will grant you the added permission without bothering the user about the approval.
For more information on this, visit https://developer.android.com/reference/android/content/pm/PermissionInfo.html#constants.
When the user installs an app, the app is granted only those permissions that are listed in the manifest that belongs to the PROTECTION_NORMAL
group.
Requesting permissions from the PROTECTION_SIGNATURE
group will be granted only if the application is signed with the same certificate as the app with the declared permission.
System components automatically receive all the permissions listed in their manifests.
Android Marshmallow showcased a new permissions model where users were able to directly manage app permissions at application runtime. Google has altered the old permissions model, mostly to enable easier and frictionless installations and auto-updates for users as well as for app developers. This allows users to install the app without the need to preapprove each permission the application needs. The user can install the app without going through the phase of checking each permission and declining the installation due to a single permission.
Users can grant or revoke permissions for installed apps, leaving the tweaking and the freedom of choice in the users' hands.
Most of the applications will need to address these issues when updating the target API to 23.
Well, after all the explanations, we've reached the coding part, and this is where we will get our coding hands dirty. The following are key methods used for handling permissions:
Context.checkSelfPermission()
: This checks whether your app has been granted a permissionActivity.requestPermission()
: This requests a permission at runtime
Even if your app is not yet targeting Android Marshmallow, you should test your app and prepare to support it.
In the Android Marshmallow permissions model, your app must ask the user for individual permissions at runtime. There is limited compatibility support for legacy apps, and you should test your app and also test a version to make sure it's supported.
You can use the following test guide and conduct app testing with the new behavior:
Map your app's permissions
Test flows with permissions granted and revoked
The adb
command shell can be quite helpful to check for permissions:
Listing application permissions and status by group can be done using the following
adb
command:adb shell pm list permissions -g
You can grant or revoke permissions using the following
adb
syntax:adb shell pm [grant|revoke] <permission.name>
You can grant permissions and install
apk
using the followingadb
command:adb install -g <path_to_apk>
When we want to adjust our application to the new model, we need to make sure that we organize our steps and leave no permission stranded:
Check what platform the app is running on: When running a piece of code that is sensitive at the API level, we start by checking the version/API level that we are running on.
By now, you should be familiar with
Build.VERSION.SDK_INT
.Check whether the app has the required permission: Here, we get ourselves a brand new API call:
Context.checkSelfPermission(String permission_name)
.With this, we silently check whether permissions are granted or not.
This method returns immediately, so any permission-related controls/flows should be dealt with by checking this first.
Prompting for permissions: We have a new API call,
Activity.requestPermissions (String[] permissions, int requestCode)
. This call triggers the system to show the dialog requesting a permission. This method functions asynchronously.You can request more than one permission at once. The second argument is a simple request code returned in the callback so that you can recognize the calls. This is just like how we've been dealing with
startActivityForResult()
andonActivityResult()
for years.Another new API is
Activity.shouldShowRequestPermissionRationale(String permission)
.This method returns
true
when you have requested a permission and the user denied the request. It's considered a good practice after verifying that you explain to the user why you need that exact permission. The user can decide to turn down the permission request and select the Don't ask again option; then, this method will returnfalse
.
The following sample code checks whether the app has permission to read the user's contacts. It requests the permission if required, and the result callback returns to onRequestPermissionsResult
:
if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, SAMPLE_MATRIXY_READ_CONTACTS); } //Now this is our callback @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case SAMPLE_MATRIXY_READ_CONTACTS: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission granted - we can continue the feature flow. } else { // permission denied! - we should disable the functionality that depends on this permission. } } }
Just to make sure we all know the constants used, here's the explanation:
public static final int PERMISSION_DENIED=-1
:Since it's API level 1, permission has not been granted to the given package
public static final int PERMISSION_GRANTED=0
:Since it's API level 1, permission has been granted to the given package.
If the user denies your permission request, your app should take the appropriate action, such as notifying the user why this permission is required or explaining that the feature can't work without it.
The new permissions model has brought to life a smoother experience for users and a bit more code-handling for developers. It makes it easier to install and update apps and feel comfortable with what the apps are doing.
Don't be a permission hog! In our application life cycle, we should try to minimize our permission requests. Asking for a lot of permissions and maintaining them can seem hazardous for some, and we should try and make the feature smooth and ask for the smallest number of permissions as far as possible in order to allow relaxed, undisturbed usage. Consider using intents whenever possible—rely on other applications doing some of the work for us (fewer permissions means less friction, turning a good app into a great one).
Users can get distracted by too many dialogs popping up, asking them for more and more permissions. Instead, you should ask for permissions as and when you need them.
However, we have some exceptions to every rule. Your app may require a few permissions to begin with, such as a camera application showing the camera permissions right at the beginning. However, setting the photo to your contact can be done and requested only when the user triggers that specific action. Try to map your flow and make it easier for users to understand what is going on. Users will understand that you've requested permissions for contacts if they have asked to set information to a contact via your app.
One more suggestion: apps with a tutorial can integrate the essential permissions' request in the tutorial, allowing the users to better understand the flow and why each permission is used.
When asking for a permission, the system shows a dialog stating which permission your app wants, but it doesn't say why. Consider users who hate being left in the dark thinking why this permission is needed now or users who deny the permissions due to speculation. Things can be even worse: sometimes, a user's cursor may be 2 cm away from the 1-star rating or the uninstall button.
This is why it's a good idea to explain why your app wants the permissions before calling requestPermissions()
.
Keep in mind that most developers will choose a tutorial but a lot of users may choose to skip tutorials whenever possible, so you must make sure that you can provide information about permissions, apart from the ones in the tutorial.
Managing permissions is easier with the latest revision of the v4 or v13 support libraries (23, which is the same as the Android Marshmallow API version, so it's easy to remember)
The support libraries now provide several new methods to manage permissions and work properly on any device that can use these libraries. This, for instance, saves you the time required to check for a sufficient API level regardless of whether the device runs Android Marshmallow or not. If an app is installed on a device running Android Marshmallow, proper behavior is achieved—as if you're running the same framework calls. Even when running on lower versions, you get the expected behavior from the support library methods.
The v4 support library has the following methods:
ActivityCompat.checkSelfPermission (Context context, String permission)
:This checks whether your app has a permission.
PERMISSION_GRANTED
is returned if the app has the permission; otherwise,PERMISSION_DENIED
is returned.ActivityCompat.requestPermissions (Activity activity, String[] permissions, int requestCode
:This requests permissions, if required. If the device is not running Android 6.0, you will get a callback.
ActivityCompat.OnRequestPermissionsResultCallback(int requestCode, String[] permissions, int[] grantResults)
:This passes
PERMISSION_GRANTED
if the app already has the specified permission andPERMISSION_DENIED
if it does not.ActivityCompat.shouldShowRequestPermissionRationale (Activity activity, String permission)
:This returns
true
if the user has denied a permission request at least once and has not yet selected the Don't ask again option.
According to the design patterns, we should now give our users more information about the feature and why these permissions are so important to the app.
Note
If the device is not running Android Marshmallow, shouldShowRequestPermissionRationale
will always return false
.
The PermissionChecker
class is also included in v4.
This class provides several methods for apps that use IPC to check whether a particular package has a specified permission when IPC calls are made.
Android has a compatibility mode, allowing users to revoke access to permission-protected methods for legacy apps. When a user revokes access in the compatibility mode, the app's permissions remain the same but access to the APIs is restricted.
The PermissionChecker
method verifies app permissions in normal as well as legacy modes.
Note
If your app acts as a middleman on behalf of other apps and needs to call platform methods that require runtime permissions, you should use the appropriate PermissionChecker
method in order to ensure that the other app is allowed to perform the operation.
The v13 support library provides the following permission methods:
FragmentCompat.requestPermissions()
:This requests permissions, if required. If the device is not running Android 6.0, you will get a callback.
FragmentCompat.OnRequestPermissionsResultCallback
:This passes
PERMISSION_GRANTED
if the app already has the specified permission andPERMISSION_DENIED
if it does not.FragmentCompat.shouldShowRequestPermissionRationale()
:This returns
true
if the user has denied a permission request at least once and has not yet selected the Don't ask again option.
According to the design patterns, we should now give our users more information about the feature and why this permission is so important to the app.
You can check out the sample project for the three ways to handle permissions:
https://github.com/MaTriXy/PermissionMigrationGuide
For more information on permission design patterns, read Patterns – Permissions by Google at https://www.google.com/design/spec/patterns/permissions.html.
The Android system flags permissions according to their protection levels. The levels are describes at http://developer.android.com/reference/android/content/pm/PermissionInfo.html.
The level that is relevant to our discussion is PROTECTION_NORMAL
, in which permissions are considered to have little or no risk when applications have them.
Let's say you want to build a flashlight app; allowing your app to turn on the flash is not considered a huge risk to privacy or security, and this is why flashlight permission is flagged PROTECTION_NORMAL
.
When you declare normal permissions in the manifest, the system grants these permissions automatically at the time of installation. There is no prompt to grant permissions for a normal permissions group, and these permissions can't be revoked by users.
This means that you can be sure that normal permissions are granted at the time of installation.
Currently, the permissions classified as PROTECTION_NORMAL
are as follows:
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.PERSISTENT_ACTIVITY
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.READ_USER_DICTIONARY
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SETTINGS
android.permission.WRITE_SYNC_SETTINGS
android.permission.WRITE_USER_DICTIONARY
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
As you saw, the Android permission system and model is vast and has introduced a few changes that can help app developers and applications gain more traction and installations and give the users the ability to decide when your applications will be able to use each permission-dependent feature. Keep in mind, though, that this is just a starting point and Android Marshmallow still needs to gain market share and get adopted by OEMs, enabling users with freedom of choice. You as an app developer must prepare in advance and make sure your application development is forward-facing, allowing new users to enjoy the latest updates as soon as possible while maintaining a high level of performance for your applications.
In the next chapter, we will go over a small yet important feature in the Android Marshmallow version: app linking.