This guide describes how to develop a device policy controller (DPC) for devices in an Android enterprise deployment. A DPC app, previously known as a work policy controller, controls local device policies and system applications on devices.
About DPCs
In an Android enterprise deployment, an enterprise maintains control over various aspects of user devices, such as isolating work-related information from users' personal data, pre-configuring approved apps for the environment, or disabling device capabilities (for example, the camera).
As an EMM, you develop a DPC app that can be used by your customers in conjunction with your EMM console and server. Your customer deploys the DPC to the user devices that they manage. The DPC acts as the bridge between your EMM console (and server) and the device. An admin uses the EMM console to perform a range of tasks, including configuring device settings and apps.
The DPC creates and manages the work profile on the device on which it is installed. The work profile encrypts work-related information and keeps it separate from users' personal apps and data. Before creating the work profile, the DPC can also provision a managed Google Play Account for use on the device.
This guide shows you how to develop a DPC that can create and manage work profiles.
DPC Support Library for EMMs
The DPC Support Library for EMMs comprises utility and helper classes that facilitate provisioning and management of Android devices in an enterprise environment. The library lets you take advantage of important features in your DPC apps:
- Managed Google Play Accounts provisioning support: Provisioning managed Google Play Accounts from the DPC app requires that Google Play and Google Play services apps meet minimum version requirements. However, updating these apps can be complex. The DPC support library takes care of updating these apps, and also ensures compatibility with future updates to the managed Google Play Accounts provisioning process. See managed Google Play Accounts provisioning support for details.
- Managed Configurations support: Using Play EMM API to handle managed configurations for approved apps is the easiest way to implement managed configurations on your DPC. The DPC Support Library lets you delegate to Google Play the task of applying managed configurations (formerly, app restrictions) as set by the admin using your EMM console. Using the Play EMM API to handle managed configurations allows the app configuration to be applied atomically during the installation. See Apply managed configurations to work apps for more information about how to enable this capability in your DPC.
Follow the steps below to download the library. The tasks detailed in this guide assume the use of the DPC Support Library.
Download the DPC Support Library
To use the DPC Support Library, download the library from the Android Enterprise EMM Provider community. You must add the library to your build.gradle file and take care of other dependencies when you build your DPC app. For example, the library requires 11.4.0 Google Play Services auth client library.
- Add the library to the
build.gradle
file:
Groovy
implementation(name:'dpcsupport-yyyymmdd', ext:'aar')
Kotlin
implementation(name = "dpcsupport-yyyymmdd", ext = "aar")
- Add 11.4.0
Google Play Services auth client library to the build.gradle file:
Groovy
implementation 'com.google.android.gms:play-services-auth:11.4.0'
Kotlin
implementation("com.google.android.gms:play-services-auth:11.4.0")
The library requires certain permissions to run, so you must add these to your DPC app’s manifest when you upload to Google Play:
<uses-permission android:name= "android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/> <uses-permission android:name= "android.permission.GET_ACCOUNTS"/> <uses-permission android:name= "android.permission.MANAGE_ACCOUNTS"/> <uses-permission android:name= "android.permission.WRITE_SYNC_SETTINGS"/> <uses-permission android:name= "com.google.android.providers.gsf.permission.READ_GSERVICES"/>
In addition to these preliminary setup and deployment steps, you must also initialize the specific library functionality in your DPC code, depending on the capability you want to implement. The details are included in the relevant sections below.
Create a DPC
Build your DPC on the existing model used for device administration applications.
Specifically, your app must subclass
DeviceAdminReceiver
(a class from the android.app.admin
package) as described in
Device Administration.
Create a work profile
For a sample that demonstrates how to create a basic work profile, see BasicManagedProfile on GitHub.
To create a work profile on a device that already has a personal profile,
first find out if the device can support a work profile, by checking for the
existence of the
FEATURE_MANAGED_USERS
system feature:
Kotlin
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) { // This device does not support work profiles! }
Java
PackageManager pm = getPackageManager(); if (!pm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) { // This device does not support work profiles! }
If the device supports work profiles, create a work profile by sending an intent with an ACTION_PROVISION_MANAGED_PROFILE action. (In some documentation, managed profile is a general term that means the same thing as work profile in the context of Android in the enterprise.) Include the device admin package name as an extra:
Kotlin
val provisioningActivity = getActivity() // You'll need the package name for the DPC app. val myDPCPackageName = "com.example.myDPCApp" // Set up the provisioning intent val adminComponent = ComponentName(provisioningActivity.applicationContext, MyAdminReceiver::class.java) provisioningIntent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, adminComponent.flattenToString()) if (provisioningIntent.resolveActivity(provisioningActivity.packageManager) == null) { // No handler for intent! Can't provision this device. // Show an error message and cancel. } else { // REQUEST_PROVISION_MANAGED_PROFILE is defined // to be a suitable request code startActivityForResult(provisioningIntent, REQUEST_PROVISION_MANAGED_PROFILE) provisioningActivity.finish() }
Java
Activity provisioningActivity = getActivity(); // You'll need the package name for the DPC app. String myDPCPackageName = "com.example.myDPCApp"; // Set up the provisioning intent Intent provisioningIntent = new Intent("android.app.action.PROVISION_MANAGED_PROFILE"); ComponentName adminComponent = new ComponentName(provisioningActivity.getApplicationContext(), MyAdminReceiver.class); provisioningIntent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, adminComponent.flattenToString()); if (provisioningIntent.resolveActivity(provisioningActivity.getPackageManager()) == null) { // No handler for intent! Can't provision this device. // Show an error message and cancel. } else { // REQUEST_PROVISION_MANAGED_PROFILE is defined // to be a suitable request code startActivityForResult(provisioningIntent, REQUEST_PROVISION_MANAGED_PROFILE); provisioningActivity.finish(); }
The system responds to this intent by doing the following:
- Verifies that the device is encrypted. If it isn't, the system prompts the user to encrypt the device before proceeding.
- Creates a work profile.
- Removes non-required applications from the work profile.
- Copies the DPC app into the work profile and sets the DPC itself as the profile owner.
Override
onActivityResult()
to
see if provisioning was successful:
Kotlin
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { // Check if this is the result of the provisioning activity if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) { // If provisioning was successful, the result code is // Activity.RESULT_OK if (resultCode == Activity.RESULT_OK) { // Work profile created and provisioned. } else { // Provisioning failed. } return } else { // This is the result of some other activity. Call the superclass. super.onActivityResult(requestCode, resultCode, data) } }
Java
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { // Check if this is the result of the provisioning activity if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) { // If provisioning was successful, the result code is // Activity.RESULT_OK if (resultCode == Activity.RESULT_OK) { // Work profile created and provisioned. } else { // Provisioning failed. } return; } else { // This is the result of some other activity. Call the superclass. super.onActivityResult(requestCode, resultCode, data); } }
Finish enabling the work profile
When the profile has been provisioned, the system calls the DPC
app's
DeviceAdminReceiver.onProfileProvisioningComplete()
method. Override
this callback method to finish enabling the work profile.
A typical DeviceAdminReceiver.onProfileProvisioningComplete()
callback implementation does the following:
- Verifies that the device is complying with the EMM's device policies, as described in Set up device policies.
- Enables the system applications that the admin has made
available within the work profile using
DevicePolicyManager.enableSystemApp()
. - If the device uses managed Google Play, adds the appropriate account to
the work profile so that approved apps can be installed on the device.
- Managed Google Play Accounts: See Ensure the working environment for managed Google Play Accounts and Add a managed Google Play Account for details.
- Google Accounts: Use
AccountManager.addAccount()
.
Activate the work profile
Once you have completed these tasks, call the device policy manager's
setProfileEnabled()
method to activate the work profile:
Kotlin
// Get the device policy manager val myDevicePolicyMgr = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager val componentName = myDeviceAdminReceiver.getComponentName(this) // Set the name for the newly created work profile. myDevicePolicyMgr.setProfileName(componentName, "My New Work Profile") // ...and enable the profile myDevicePolicyMgr.setProfileEnabled(componentName)
Java
// Get the device policy manager DevicePolicyManager myDevicePolicyMgr = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); ComponentName componentName = myDeviceAdminReceiver.getComponentName(this); // Set the name for the newly created work profile. myDevicePolicyMgr.setProfileName(componentName, "My New Work Profile"); // ...and enable the profile myDevicePolicyMgr.setProfileEnabled(componentName);
Set up device policies
The DPC app applies the device policies as set by an admin to meet an organization's requirements and constraints. For example, security policy might require that devices lock after a certain number of failed password attempts. The DPC queries the EMM console for current policies then applies the policies using the Device Administration API.
For information on how to apply device policies, see Policies.
Apply managed configurations to work apps
Managed configurations let you provide your customers with the ability to pre-configure the apps that they’ve approved for deployment, and update those apps easily when the configuration needs to change. Configuring an app prior to deployment ensures that the organization’s security and other policies are met upon installation of the app on the target device.
The app capabilities are defined by the app developer in an XML schema (the managed configurations schema) that accompanies the app upon upload to Google Play (app developers, see Set Up Managed Configurations for details).
You retrieve this schema from the app to display for your customer admins in your EMM console, provide a UI in which the various options defined in the schema display, and enable admins to pre-configure the app’s settings. The resulting managed configuration set by the admin is typically stored on the EMM server which then uses the Play EMM API to set Managedconfigurationsfordevice or Managedconfigurationsforuser. See Managed Configurations through Play for details.
Managed configurations can be applied to the app by using the Play EMM API (recommended approach) or directly from the DPC (described in Apply managed configurations directly from the DPC). Using the Play EMM API has several advantages, including easy implementation because you can use the DPC Support Library to simplify DPC tasks. In addition, the Play EMM API:
- Sets the configuration atomically when a new app is installed, thus ensuring the app is ready the first time the user launches the app.
- Lets you manage configurations on a per-user basis, so you can avoid monitoring provisioning on a per-device basis.
Apply managed configurations using the Play EMM API
To use the Play EMM API for managed configurations, the DPC must allow the Google Play to set configurations. The DPC Support Library takes care of this task for you by proxying the configuration sent by Google Play.
To use the Play EMM API, download the DPC Support Library and then enable managed configurations support in your DPC.
Enable Managed Configurations support in your DPC
Import this class in your DPC:
com.google.android.apps.work.dpcsupport.ManagedConfigurationsSupport
Initialize the managed configurations library. In this example, "admin" is the ComponentName of the DeviceAdminReceiver.
Kotlin
var managedConfigurationsSupport = ManagedConfigurationsSupport(context, admin)
Java
ManagedConfigurationsSupport managedConfigurationsSupport = new ManagedConfigurationsSupport(context, admin);
Enable managed configurations:
Kotlin
managedConfigurationsSupport.enableManagedConfigurations()
Java
managedConfigurationsSupport.enableManagedConfigurations();
With this library initialized in your DPC, you can use the Google Play EMM API in your EMM console and server to apply managed configurations to approved apps, instead of coding these tasks directly in the DPC. See Managed Configurations through Play for details.
Apply managed configurations directly from the DPC
To change an app's configuration settings directly from the DPC, call the DevicePolicyManager.setApplicationRestrictions() method and pass parameters for the DPC app's DeviceAdminReceiver, the package name of the target app, and the Bundle comprising the app’s managed configuration as set by the admin. See How your DPC and EMM console interact and Set up Managed Configurations for details. However, note that this alternative approach to applying managed configurations is not recommended in managed Google Play Accounts deployments.
Managed Google Play Account provisioning support
The DPC Support Library includes support for provisioning managed Google Play Accounts. To use this support, you must first initialize the library, and then you can Ensure the working environment and Add a managed Google Play Account.
Initialize managed Google Play Accounts support in your DPC
Import this class in your DPC:
com.google.android.apps.work.dpcsupport.AndroidForWorkAccountSupport
Initialize the provisioning compatibility library. In this example, “admin” is
the ComponentName
of the
DeviceAdminReceiver
.
Kotlin
var androidForWorkAccountSupport = AndroidForWorkAccountSupport(context, admin)
Java
AndroidForWorkAccountSupport androidForWorkAccountSupport = new AndroidForWorkAccountSupport(context, admin);
Ensure the working environment for managed Google Play Accounts
After the DPC provisions a device in profile owner mode (ACTION_PROVISION_MANAGED_PROFILE
) or device
owner mode (ACTION_PROVISION_MANAGED_DEVICE
), make sure that the device can support managed Google Play Accounts by calling:
Kotlin
androidForWorkAccountSupport.ensureWorkingEnvironment(callback)
Java
androidForWorkAccountSupport.ensureWorkingEnvironment(callback);
The callback reports the success or failure of this process. When the callback returns successfully, a managed Google Play Account can be added. If the callback reports an error, prompt the user to make sure the device has a network connection (for example, if the download fails). In other cases, report the failure to Google.
Kotlin
object : WorkingEnvironmentCallback() { override fun onSuccess() { // Can now provision the managed Google Play Account } override fun onFailure(error: Error) { // Notify user, handle error (check network connection) } }
Java
new WorkingEnvironmentCallback() { @Override public void onSuccess() { // Can now provision the managed Google Play Account } @Override public void onFailure(Error error) { // Notify user, handle error (check network connection) } }
Add a managed Google Play Account
The Android framework's AccountManager
can add a managed Google Play Account to a device. To simplify interaction with
AccountManager
, use the helper function (shown in the example below)
from the DPC Support Library. The function
handles the token returned by Google Play server and facilitates provisioning
the managed Google Play Account. The function returns when the managed Google Play
Account is in a valid state:
Kotlin
androidForWorkAccountSupport.addAndroidForWorkAccount(token, accountAddedCallback)
Java
androidForWorkAccountSupport.addAndroidForWorkAccount(token, accountAddedCallback);
token
—The user authentication token generated by the Google Play EMM APIUsers.generateAuthenticationToken()
call.accountAddedCallback
—Returns the managed Google Play Account that was successfully added to the device. This callback should includeonAccountReady()
andonFailure()
methods.
Kotlin
val workAccountAddedCallback = object : WorkAccountAddedCallback() { override fun onAccountReady(account: Account, deviceHint: String) { // Device account was successfully added to the device // and is ready to be used. } override fun onFailure(error: Error) { // The account was not successfully added. Check that the token // provided was valid (it expires after a certain period of time). } }
Java
WorkAccountAddedCallback workAccountAddedCallback = new WorkAccountAddedCallback() { @Override public void onAccountReady(Account account, String deviceHint) { // Device account was successfully added to the device // and is ready to be used. } @Override public void onFailure(Error error) { // The account was not successfully added. Check that the token // provided was valid (it expires after a certain period of time). } };
Related documentation
- To learn more about the Device Administration API, see Device Administration.
- To learn about Android Enterprise provisioning methods, see Provision devices in the Android Enterprise developer's guide.
- For a GitHub sample that demonstrates how to create a basic work profile, see BasicManagedProfile.
- For a GitHub sample that demonstrates how to set configurations on other apps as a profile owner, see AppRestrictionEnforcer.