28 May 2019

Knox Deep Dive: Changes to runtime permission in Android Q

By Sabrina (Portal Administrator)

What are dangerous permissions?

With Android Q comes a critical change to how dangerous permissions are handled in Knox framework. Dangerous permissions involve resources that either concern the user’s private information and stored data, or could affect the operation of other apps. For example, access to the Camera API falls under the dangerous permissions category. Users must first approve the requested permission before any app can use the feature.
 

How are they currently handled?

From Android M (API level 23) onwards, developers can prompt users for permission to use these dangerous permissions. The app can be set to request a permission during runtime, which prompts the user with a dialog box containing options to “Deny” or “Allow”.
 
 
 
An example of a user prompt for access to the camera API
 

What changes are coming in Android Q?

MDM apps were not equipped to handle dangerous permissions in Android M (version 6.0). Because of this, a change was made in Knox framework to automatically grant dangerous permissions to enterprise (licensed/signed) admin apps.
 
Starting with the upcoming Android Q release, the Knox framework no longer automatically grants dangerous permissions to enterprise admin apps. To ensure that your app retains its current functionality and avoids runtime errors, it’s crucial that you leverage Android’s requestPermissions() and setPermissionGrantState() API methods to grant and revoke dangerous permissions.
 
Please note that Knox SDK’s applyRuntimePermissions() and getRuntimePermissions() APIs and related constants will no longer be supported from Android Q.
 

Requesting user permissions with Android’s requestPermissions() API method

You can choose to provide users with the option to approve or deny dangerous permissions on their end. Doing so will prompt the user with a dialog box, as shown earlier. The following code snippet illustrates the algorithm used to check for and request permission from a user:
 
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity, 
        Manifest.permission.READ_CONTACTS) 
        != PackageManager.PERMISSION_GRANTED) { 

    // Permission is not granted 
    // Is it necessary to show an explanation to the user? 
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, 
            Manifest.permission.READ_CONTACTS)) { 
        // Show an explanation to the user *asynchronously* -- don't block 
        // this thread waiting for the user's response! After the user 
        // sees the explanation, try again to request the permission. 
    } else { 
        // No explanation needed; request the permission 
        ActivityCompat.requestPermissions(thisActivity, 
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS); 

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an 
        // app-defined int constant. The callback method gets the 
        // result of the request. 
    } 
} else { 
    // Permission has already been granted 
}

 

Using Android’s setPermissionGrantState() API method

setPermissionGrantState() allows you to set the grant state of a specific application to default, denied, or granted. The denied and granted permission states bypass the need for explicit user approval, which are especially useful for MDM applications.
 

If you’d like to learn more about this method, the API reference on the Android Developers website is a good resource.

 
Note: If your app is built on a version lower than Android Q, you cannot grant and revoke permissions for apps built on versions lower than Android M (API level 23).
 
Regardless of how you decide to handle dangerous permissions in your apps, be sure to update them in time for the upcoming Android Q release so you can proactively avoid user issues with app functionality.
 

Next steps