Asking Permission: Getting your head around Marshmallow's Runtime Permissions

Yossi Elkrief

February 2016

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 should give out a security exception (using a SecurityException class), informing you about the missing permission in most cases.

The sendBroadcast(Intent) method is exceptional as it checks permissions after the method call has returned, so you 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.

(For more resources related to this topic, see here.)

Understanding Android Marshmallow permissions

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

An overview

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 the 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 the 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.

    If an app targets an Android Marshmallow version, it must use the new permissions model.

Permission groups

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[GS1] .

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.

Apps cannot request signature permissions at runtime.

System components automatically receive all the permissions listed in their manifests.

Runtime permissions

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.

Taking coding permissions into account

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 the methods used for coding permissions:

  • Context.checkSelfPermission(): This checks whether your app has been granted a permission
  • Activity.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.

Testing permissions

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 following adb command:
    adb install -g <path_to_apk>

Coding for runtime permissions

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() and onActivityResult() 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 return false.

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.

Your app cannot assume user interaction has taken place because the user can choose to reject granting a permission along with the do not show again option; your permission request is automatically rejected and onRequestPermissionsResult gets the result back.

Summary

To learn more about Android 6 Essentials, the following books published by Packt Publishing (https://www.packtpub.com/) are recommended:

Android User Interface Development: Beginner's Guide (https://www.packtpub.com/application-development/android-user-interface-...)

Android Native Development Kit Cookbook (https://www.packtpub.com/application-development/android-native-developm...)

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Android 6 Essentials

Explore Title