Setting up device administration policies

First introduced in Android 2.2, the Device Admin policies grant abilities to apps to gain a greater level of device control. These features are primarily aimed at enterprise app developers given their controlling, restrictive, and potentially destructive nature, and offer an alternative to a third-party Mobile Device Management (MDM) solution. In general, this is not aimed at consumer apps unless a trust relationship already exists, for example, a bank and a banking app.

This recipe will define two device policies designed to strengthen the device that could be part of an enterprise's mobile security policy:

  • Enforce device encryption (which also ensures that a device pin/password is set)
  • Enforce maximum screen lock timeout

Although device encryption is no replacement for ensuring that the app data is encrypted properly, it does add to the overall device security. Reducing the maximum screen lock timeout helps protect the device if left unattended.

There is no restriction on the number of apps enforcing device policies. If there is a conflict on policy, the system defaults to the most secure policy. For example, if there was a conflict on the password strength requirement's policy, the strongest policy would be applied to satisfy all policies.

Getting ready

The Device Admin policies were added in Version 2.2; however, this feature and the specific restriction for device encryption were not added until Android 3.0. Therefore, for this recipe, ensure that you are building against a SDK above API 11.

How to do it...

Let's get started.

  1. Define a device administration policy by creating a new .xml file called admin_policy_encryption_and_lock_timeout.xml in the res/xml folder with the following content:
    <device-admin xmlns:android="http://schemas.android.com/apk/res/android" >
        <uses-policies>
            <force-lock />
            <encrypted-storage />
        </uses-policies>
    </device-admin>
  2. Create a class that extends the DeviceAdminReceiver class. This is the app entry point for system broadcasts relating to device administration:
    public class AppPolicyReceiver extends DeviceAdminReceiver {
    
      // Called when the app is about to be deactivated as a device administrator.
      @Override
      public void onDisabled(Context context, Intent intent) {
        // depending on your requirements, you may want to disable the // app or wipe stored data e.g clear prefs
        context.getSharedPreferences(context.getPackageName(),
            Context.MODE_PRIVATE).edit().clear().apply();
        super.onDisabled(context, intent);
      }
    
      @Override
      public void onEnabled(Context context, Intent intent) {
        super.onEnabled(context, intent);
    
        // once enabled enforce
        AppPolicyController controller = new AppPolicyController();
        controller.enforceTimeToLock(context);
    
        controller.shouldPromptToEnableDeviceEncrpytion(context);
      }
    
      @Override
      public CharSequence onDisableRequested(Context context, Intent intent) {
        // issue warning to the user before disable e.g. app prefs // will be wiped
        return context.getText(R.string.device_admin_disable_policy);
      }
    }
  3. Add receiver definition to your Android manifest file:
    <receiver
           android:name="YOUR_APP_PGK.AppPolicyReceiver"
           android:permission="android.permission.BIND_DEVICE_ADMIN" >
           <meta-data
             android:name="android.app.device_admin"
             android:resource="@xml/admin_policy_encryption_and_lock_timeout" />
    
           <intent-filter>
             <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
             <action android:name="android.app.action.DEVICE_ADMIN_DISABLED" />
             <action android:name="android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED" />
           </intent-filter>
    </receiver>

    Defining the receiver allows AppPolicyReceiver to receive system broadcast intents to disable/request disabling of the admin settings. You should also notice that this is where we reference the policy XML file in the metadata via the filename admin_policy_encryption_and_lock_timeout.

  4. A device policy controller handles communication with DevicePolicyManager with any additional application-specific logic. The first method that we defined is for other application components (such as an activity) to validate device admin status and to get intents that are specific to device admin:
    public class AppPolicyController {
    
      public boolean isDeviceAdminActive(Context context) {
        DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context
            .getSystemService(Context.DEVICE_POLICY_SERVICE);
    
        ComponentName appPolicyReceiver = new ComponentName(context,
            AppPolicyReceiver.class);
    
        return devicePolicyManager.isAdminActive(appPolicyReceiver);
      }
      public Intent getEnableDeviceAdminIntent(Context context) {
    
        ComponentName appPolicyReceiver = new ComponentName(context,
            AppPolicyReceiver.class);
    
        Intent activateDeviceAdminIntent = new Intent(
            DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
    
        activateDeviceAdminIntent.putExtra(
            DevicePolicyManager.EXTRA_DEVICE_ADMIN, appPolicyReceiver);
    
        // include optional explanation message
        activateDeviceAdminIntent.putExtra(
            DevicePolicyManager.EXTRA_ADD_EXPLANATION,
            context.getString(R.string.device_admin_activation_
    message));
    
        return activateDeviceAdminIntent;
      }
    
    public Intent getEnableDeviceEncryptionIntent() {
        return new Intent(DevicePolicyManager.ACTION_START_ENCRYPTION);
      }
  5. In AppPolicyController, we now define the method that actually enforces the lock screen timeout. We've arbitrarily chosen a maximum lock time of 3 minutes, but this should align with an enterprise's security policy:
      private static final long MAX_TIME_TILL_LOCK = 3 * 60 * 1000;
    
      public void enforceTimeToLock(Context context) {
        DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context
            .getSystemService(Context.DEVICE_POLICY_SERVICE);
    
        ComponentName appPolicyReceiver = new ComponentName(context,
            AppPolicyReceiver.class);
    
        devicePolicyManager.setMaximumTimeToLock(appPolicyReceiver,
            MAX_TIME_TILL_LOCK);
      }
  6. Encrypting the device may take some time depending on the device's hardware and external storage size. As part of enforcing the device encryption policy, we need a way to check whether the device is encrypted or encryption is in progress:
    public boolean shouldPromptToEnableDeviceEncryption(Context context) {
        DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context
            .getSystemService(Context.DEVICE_POLICY_SERVICE);
        int currentStatus = devicePolicyManager.getStorageEncryptionStatus();
        if (currentStatus == DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE) {
          return true;
        }
        return false;
      }
    }
  7. We define an example activity to show how it's possible to integrate AppPolicyController to help direct the user to enable system settings and handle the responses:
    public class AppPolicyDemoActivity extends Activity {
    
      private static final int ENABLE_DEVICE_ADMIN_REQUEST_CODE = 11;
      private static final int ENABLE_DEVICE_ENCRYPT_REQUEST_CODE = 12;
      private AppPolicyController controller;
      private TextView mStatusTextView;
    
      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_app_policy);
        mStatusTextView = (TextView) findViewById(R.id.deviceAdminStatus);
    
        controller = new AppPolicyController();
    
        if (!controller.isDeviceAdminActive(getApplicationContext())) {
          // Launch the activity to have the user enable our admin.
          startActivityForResult(
              controller
                  .getEnableDeviceAdminIntent(getApplicationContext()),
              ENABLE_DEVICE_ADMIN_REQUEST_CODE);
        } else {
          mStatusTextView.setText("Device admin enabled, yay!");
          // admin is already activated so ensure policies are set
          controller.enforceTimeToLock(getApplicationContext());
          if (controller.shouldPromptToEnableDeviceEncrpytion(this)) {
            startActivityForResult(
                controller.getEnableDeviceEncrpytionIntent(),
                ENABLE_DEVICE_ENCRYPT_REQUEST_CODE);
          }
        }
    
      }
  8. Here, we implement the onActivityResult(…) activity lifecycle method to handle the results from the system activities when enabling device administration and encryption:
      @Override
      protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == ENABLE_DEVICE_ADMIN_REQUEST_CODE) {
          if (resultCode != RESULT_OK) {
            handleDevicePolicyNotActive();
          } else {
            mStatusTextView.setText("Device admin enabled");
            if (controller.shouldPromptToEnableDeviceEncrpytion(this)) {
              startActivityForResult(
                  controller.getEnableDeviceEncryptionIntent(),
                  ENABLE_DEVICE_ENCRYPT_REQUEST_CODE);
            }
          }
    
        } else if (requestCode == ENABLE_DEVICE_ENCRYPT_REQUEST_CODE
            && resultCode != RESULT_OK) {
          handleDevicePolicyNotActive();
        }
      }
  9. Finally, we add a method to handle the process if users choose not to activate this app as a device administrator. In this sample, we simply post a message; however, it is likely that you would prevent the app from running as the device wouldn't compliment the enterprise security policy:
      private void handleDevicePolicyNotActive() {
        Toast.makeText(this, R.string.device_admin_policy_breach_message,
            Toast.LENGTH_SHORT).show();
      }
    }

How it works...

AppPolicyDemoActivity shows an example of handling user interactions and callbacks in onActivityResult(…) from the system activities for enabling the device administration and device encryption.

AppPolicyController encapsulates interactions with DevicePolicyManager and contains the logic to apply the policies. You could locate this code in your activity or fragment, but it's a better practice to keep it separate.

Defining the policies is as simple as defining them in the <uses-policies> element of the device admin file. This is referenced in the metadata element of the AppPolicyReceiver XML declaration in the Android manifest:

<meta-data  android:name="android.app.device_admin"                android:resource="@xml/admin_policy_encryption_and_lock_timeout" />

Given the elevated privileges of being a device administrator, apps are not enabled as device administrators on installation as a security precaution. This is achieved post install by using a build-in system activity that is requested using an intent with a special action AppPolicyController.getEnableDeviceAdminIntent() as shown. This activity is started with startActivityForResult(). This returns a callback to onActivityResult(…) where the users choose to activate or cancel. Nonactivation of the device administration could count as being in breach of the enterprise security policy. Therefore, if the user doesn't activate it, it might be enough to simply prevent the user from using the app until it is activated.

We use the DevicePolicyManager.isActive(…) method to check if the app is active as a device administrator. Typically, this check should be performed on the entry points to the application, such as the first activity.

The job of AppPolicyReceiver is to listen for device administration system events. To receive these events, firstly you have to extend DeviceAdminReceiver and define Receiver in the Android manifest file. The OnEnabled() callback is where we enforce the lock screen timeout as it requires no additional user input. Enabling device encryption requires user confirmation; therefore, we initiate this from the activity.

AppPolicyReceiver will also receive an onDisabled event if the user disables this application as a device administrator. What to do when a user disables your app as device administrator will vary between apps, as mentioned earlier it depends on enterprise security policy. There is also an onDisableRequested callback method that allows us to display a specific message to the user, detailing the consequences of disabling the application. In this example, we wipe the SharedPreferences to ensure that data is not at risk while the device is noncompliant.

There's more...

In addition to the policies used in this recipe, the device admin can enforce the following:

  • Password enabled
  • Password complexity (more control over this was added in 3.0)
  • Password history since 3.0
  • Maximum failed password attempts before factory reset
  • Wipe device (factory reset)
  • Lock device
  • Disable lock screen widgets (since 4.2)
  • Disable camera (since 4.0)

Users cannot uninstall apps that are active device administrators. To uninstall, they must first deactivate the app as a device administrator, and then uninstall it. This allows you to perform any necessary functions in DeviceAdminReceiver.onDisabled(), for example, reporting an incident to a remote server.

Android 4.4 saw the introduction of an optional device admin feature constant to be used in the <uses-feature> tag in the app's manifest.xml file. This declares that the app requires device admin feature and ensures correct filtering on the Google Play store.

Disabling device camera

An interesting feature added in Android 4.0 was the ability to disable camera use. This can be useful for organizations looking to limit data leakage. The following code snippet shows the policy to enable an app to disable camera use:

<device-admin xmlns:android="http://schemas.android.com/apk/res/android" >
    <uses-policies>
        <disable-camera />
    </uses-policies>
</device-admin>

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.78.145