Menu

Android M permissions

The Android Marshmallow operating system introduces a new permissions model, which has a big impact on enterprise solutions—especially apps that require dangerous permissions. Android's original permissions model required a user to grant all of an app’s required permissions during installation. If the user did not do this, the app would not be installed. The user could not alter the permissions once they had been granted.

About Android M permissions

Under the new permissions model, users are asked to grant dangerous permissions at runtime as they are needed, and can deny these permissions at any time. For example, if an app wants to use the camera but has not been granted the Camera permission, then the app asks the user for permission to do so. After a permission has been granted, the app does not need to ask for it again. However, the user can change an app’s permissions settings at any time. There is no change in behavior for normal, signature, or signatureOrsystem permissions. These permissions are granted by the system during app installation time and cannot be revoked. Throughout this topic, all references to permissions are referring to dangerous permissions.

For additional information, refer to requesting permissions at runtime.

How Android M permissions work

There are various effects that Android M permissions can have on your app and Knox SDK.

How targetSdkVersion affects permissions on Marshmallow

The value that you use for targetSdkVersionwhen you build your app determines how your app behaves with respect to dangerouspermissions when it runs on Marshmallow.

The new run time model is used for apps whose targetSdkVersionis set to 23 or above. Apps whose targetSdkVersionis less than 23 use the old permissions model, and ask the user to grant permissions at installation time. However, the user can still revoke these abilities at any time, which can break pre-Marshmallow apps.

If your app's targetSdkVersion is >= 23, the following happens.
  • The system doesn't grant requested dangerous runtime permissions during app installation
  • The user can grantor revoke dangerous permissions at runtime
  • An application's dangerous permissions settings are user-specific on a multi-user supported device. That is, the state of a dangerous permission for one user is not shared across other Android users on the device.
If your app's targetSdkVersion is < 23:
  • The system grants all requested dangerouspermissions during app installation
  • The states of dangerous permissions for one user are not shared across other Android users on the device, but the UI state is shared across all users.

How the Marshmallow permissions model affects enterprise Knox-based apps

The Marshmallow permissions model affects enterprise apps in a few major ways as follows.

  • Users cannot pre-grant permissions to apps. Doing so can cause out-of-the-box (OOB) enterprise services to not work if apps do not have their required permissions.
  • Users grant app permissions at runtime, and can modify those permissions at any time. This functionality means that a user can deny a permission for a critical app, such as an app using the Knox SDK, which can break an enterprise solution.
  • Revoke a critical permission, which can disable a Knox SDK app or feature.

If you don’t ensure that your app has the required permissions, the solution may break. For example, if an app attempts to perform an operation that requires a permission that it doesn’t have, then the app throws an exception and the app crashes.

Android Marshmallow allows users to decide which permissions to grant to apps, but you might want to give this control to the enterprise IT admin instead. To grant this control to the admin, the SDK provides com.samsung.android.knox.application.ApplicationPolicy, which includes the following APIs to manage runtime permissions:

  • ApplicationPolicy.applyRuntimePermissions()
  • ApplicationPolicy.getRuntimePermissions()

Note: Applications that call the above APIs must be an active Android admin app that's built with a targetSdkVersionof at least 23. We recommend that you move all of your enterprise apps to have a targetSdkVersionof 23 or higher. Doing so protects against permissions issues that can have negative impacts on your solution. Additionally, stop using the APIs from ApplicationPermissionControlPolicy to control dangerous permissions in your app. Replace those APIs with the new APIs from com.samsung.android.knox.application.ApplicationPolicy, which were designed specifically for the new runtime permissions model.

How firmware over-the-air (FOTA) updates affect permissions

You can control whether to allow FOTA upgrades to your enterprise's devices by using the com.samsung.android.knox.restriction.RestrictionPolicy.allowOTAUpgrade() API. If you allow FOTA upgrades to Android Marshmallow, during the upgrade, the Knox framework detects if an MDM admin agent is present on the device. If so, the system grants all requested dangerous permissions to the MDM admin agent application.

Android M permission examples

Apply a permission state to a set of permissions for an app

You can apply a permission state to a list of one or more permissions for an app by calling applyRuntimePermissions(), which overrides the current permission settings. There are three permissions states: grant, deny, and default.

When an MDM applies either the 'grant' or 'deny' runtime permission state to an app using applyRuntimePermissions(), the app permissions settings in the device UI are grayed out, and the user can't modify the permission’s state.

When an MDM applies the 'default' runtime permission state to an app using applyRuntimePermissions(), the existing state (granted or denied) is used but the UI is enabled, which allows the user to modify the permission state.

You can also call applyRuntimePermissions() to set the permission state for apps that have yet to be installed. For example, you can call this API and set the permission states for the com.future.app app, which is not currently installed. When the app is installed, the permission states set by the call(s) to applyRuntimePermissions() are used.

You can either pass a list of permissions to applyRuntimePermissions() to specify which permissions to set, or pass NULL to use the runtime permissions specified by the app's manifest file.

For example, the following code demonstrates how to grant a set of dangerous permissions (specified by runtimePermissions) to the com.sta.test app:

List <String> runtimePermissions = {
    "android.permission.ACCESS_COARSE_LOCATION",
    "android.permission.CALL_PHONE"
};
// The admin can pass the package's signature to the AppIdentity() constructor to ensure that the
// permission state policy is applied to the correct package.
String packageSignature = "3082024d308201b6a00302010202044dc96abf30...";
AppIdentity appIdentity = new AppIdentity("com.sta.test", packageSignature);
EnterpriseDeviceManager edm = (EnterpriseDeviceManager) getSystemService(EnterpriseDeviceManager.ENTERPRISE_POLICY_SERVICE);
ApplicationPolicy appPolicy = edm.getApplicationPolicy();
try {
    boolean ret = appPolicy.applyRuntimePermissions(appIdentity, runtimePermissions, PERMISSION_POLICY_STATE_GRANT);
    if (ret) {
        Log.w(TAG, "Granted runtime permissions: " + runtimePermissions + " to com.sta.test");
    } else {
        Log.d(TAG, "Failed to grant runtime permissions " + runtimePermissions + " to com.sta.test");
    }
} catch (SecurityException e) {
    Log.w(TAG, "SecurityException: " + e);
}

Apps in a Knox Workspace, are granted all permissions during the Workspace creation. However, the enterprise's IT admin can call applyRuntimePermissions() to apply a permission state to a list permissions for an app in the Workspace:

List <String> runtimePermissions = {
    "android.permission.ACCESS_COARSE_LOCATION",
    "android.permission.CALL_PHONE"
};
AppIdentity appIdentity = new AppIdentity("com.sta.test", null);
// When you create the container successfully, containerID is returned using intent.
// Use this containerID in the following API.
EnterpriseKnoxManager ekm = EnterpriseKnoxManager.getInstance();
KnoxContainerManager kcm = ekm.getKnoxContainerManager(Context, containerID);
ApplicationPolicy appPolicy = kcm.getApplicationPolicy();

try {
    boolean ret = appPolicy.applyRuntimePermissions(appIdentity, null, PERMISSION_POLICY_STATE_GRANT);
    if (ret) {
        Log.w(TAG, "Granted runtime permissions " + runtimePermissions + " to package "
            com.sta.test " successfully");
    } else {
        Log.d(TAG, "Failed to grant runtime permissions " + runtimePermissions + " to package "
            com.sta.test "");
    }
} catch (SecurityException e) {
    Log.w(TAG, "SecurityException: " + e);
}

Get the runtime permissions of an app that have a particular state

You can call getRuntimePermissions() to retrieve a list of runtime permissions for an app, where the permissions have the specified permission state.

For example, the following code demonstrates how to use getRuntimePermissions() to retrieve the list of dangerous permissions that match the specified state for the com.sta.test app:

/** Retrieve the list of permissions that have been granted to "com.sta.test"
 *   PERMISSION_POLICY_STATE_GRANT   = permission state is "grant"
 *   PERMISSION_POLICY_STATE_DENY    = permission state is "deny"
 *   PERMISSION_POLICY_STATE_DEFAULT = permission state is "default"
 */
int permStateToMatch = PERMISSION_POLICY_STATE_GRANT;

EnterpriseKnoxManager ekm = EnterpriseKnoxManager.getInstance(context);
KnoxContainerManager kcm = ekm.getKnoxContainerManager(containerID);
ApplicationPolicy appPolicy = edm.getApplicationPolicy();
try {
    List <String> runtimePermissions = appPolicy.getRuntimePermissions("com.sta.test", permStateToMatch);
    Log.w(TAG, "The granted runtime permissions are: " + runtimePermissions);

} catch (SecurityException e) {
    Log.w(TAG, "SecurityException: " + e);
}

You can also retrieve a list of runtime permissions for an app that's in a Knox Workspace:

EnterpriseKnoxManager ekm = EnterpriseKnoxManager.getInstance();

// When you successfully create a container, containerID is returned using
// an intent. Use this ID to get the KnoxContainerManager for the container that has 
// the "com.sta.test" app.
KnoxContainerManager kcm = ekm.getKnoxContainerManager(Context, containerID);
ApplicationPolicy appPolicy = kcm.getApplicationPolicy();

try {
    List <String> runtimePermissions = appPolicy.getRuntimePermissions("com.sta.test", PERMISSION_POLICY_STATE_GRANT);
    Log.w(TAG, "The granted runtime permissions are: " + runtimePermissions);

} catch (SecurityException e) {
    Log.w(TAG, "SecurityException: " + e);
}
Share it: