Previous  | Next  | Home

Runtime Permissions


 

Beginning with Android 6 (API 23), the Android permission system was modified to provide more transparency and flexibility to the user. While this undoubtedly improves the user experience, it presents new problems to developers, who must now account for a more diverse set of options concerning permissions, and must do this in code executed at runtime, not just in the static manifest file for the project (though that is still required).

 

Permissions the Old Way

Prior to Android 6, required permissions were all presented to the user at installation and all had to be accepted or rejected as a block. If accepted the app was installed with those permissions. If rejected, the app was not installed. Furthermore, once installed, the same permissions remained in effect through subsequent updates of the app, unless permissions changed in an update, in which case the user was required to explicitly approve (as a block) all changed permissions. In this scheme, permissions were a fairly straightforward issue for developers: you just included in the manifest file declarations for permissions your app would require.

 

Permissions the New Way

Under Android 6 and beyond, the permission system was changed in three significant ways:

  1. Some permissions are now given on an individual basis at the time they are required in using the app, not just at installation.

  2. Permissions are now a la carte, with the user able to pick and choose which to approve. For example, a user might approve location permissions but not approve permission to write to the device SD card.

  3. Permissions are not eternal, but can be added or revoked by using the Settings > Apps > "app name" > Permissions menu on the device.

Thus the programmer still must declare permissions that will be required in the AndroidManifest.xml file just like in the old way, but in addition must add new code in the class files that deals with acceptance and revocation of runtime permissions. Here we give an example at a general level of how to handle such runtime permissions.

The bad news is that this adds additional complication to code development. The good news is that much of this is handled by system-level black boxes and it can be implemented in a very systematic way. Thus, it is not hard to incorporate once one has the hang of it.


Apps written under versions of Android earlier than API 23 will continue to function in the old way regarding permissions, so no existing apps should break when running on newer devices or through operating system upgrades for installed apps on older devices. However, apps developed under API 23 or later must implement the new runtime permissions capabilities. Your app won't even compile without errors using Android Studio if you do not, so going forward this will be a necessary part of Android development, unless you choose to limit the functionality of your app to earlier versions of Android. However, be aware that even in that case a user of your app on a device running Android 6 or later still has the capability to revoke permissions granted at install using the device Settings > Apps > "app name" > Permissions menu, so you need to consider the effect of that capability on your app. All in all, it is probabily better to bite the bullet and incorporate code for runtime permissions in your app.

 

Normal and Dangerous Permissions

Implementing the new permissions system is described in Requesting Permissions at Runtime The first point concerning permissions done the new way is that permissions are now divided into two classes, normal permissions and dangerous permissions:

  1. Normal permissions involve those actions that require access outside the app's security sandbox, but that present little danger to the functioning of other apps or to the user's privacy. An example is permission to set the timezone. A normal permission declared in the manifest is granted automatically by the system.

  2. Dangerous permissions involve those actions that have the potential to read or modify a user's private data, or that potentially could affect the functionality of other apps or the operating system. For example, permission to write to the SD card is a dangerous permission, since it presents the potential to compromise data not belonging to the app, and determining location is another, since it has the potential to infringe upon user privacy. Permissions for dangerous operations must be granted explicitly by the user, and for API 23 and beyond permission is typically requested when the user first attempts to use a functionality of the app requiring a dangerous permission.

Of course "dangerous" is an apt but somewhat colorful descriptor in this context. Most such permissions pose no real danger to the user for a legitimate app, and each individual has to decide whether (say) allowing an app to determine location for the user presents unacceptable privacy concerns relative to the potential benefit. But in a viable security model one must guard against the worst possible behavior of any app, and users must be able to make informed decisions about what they permit apps on their mobile devices to do, particularly for actions that are deemed "dangerous" by the above classification.

Permissions are organized into permission groups. This is not relevant in the present discussion for normal permissions, but it is for dangerous permissions because runtime permissions for them are given for their entire group. For example, the permission for coarse location and fine location determination are in the same permission group, so granting runtime permission for one implicitly grants permission for the other.

 

Best Practices for Runtime Permissions

There are some best practice guidelines for requesting runtime permissions to ensure optimal user experience while satisfying the security model. Basically they fall into three categories: (1) Don't annoy your user by requesting permissions that are not essential. (For example, an app may require a runtime permission only for one part of its functionality, so a user not employing that functionality does not need to grant the permission.) (2) Try to avoid annoying the user with multiple permissions request at the same time. (3) Be certain that your app handles seamlessly all possible combinations of adding and revoking permissions at runtime.

Much of this can be realized by keeping your list of required runtime permissions as small as practical, asking for those permissions only where they are needed in the app, and extensive testing on multiple platforms of the user giving, revoking, and then giving again a runtime permission.


One way to reduce the number of runtime permissions required by your app is to use intents to have another app perform a required task. For example, suppose your app needs to take a picture. One option is to request permission to access the camera from the user and build the functionality directly into your app. But you also could use an ACTION_IMAGE_CAPTURE intent to request that the system take a picture with the camera and return it to your app in the onActivityResult() method. The latter give less direct control but does not require your app to request a user permission.

 

Runtime Permissions Examples

The project Map Example gives a detailed discussion of implementing runtime permissions for location services. The project Read Your Contacts illustrates implementation of similar runtime permissions for reading contacts. Other runtime permissions can be implemented largely by cloning these examples and changing the specifics.

Last modified: August 9, 2016


Previous  | Next  | Home