What’s New in Android Marshmallow for Enterprise-Oriented Applications

With Android dominating the smartphone market, running on 82.8 percent of all mobile devices (IDC, Aug 2015), there is a lot of potential for mobile enterprise solutions in the workplace.
The Android for Work program, which Google announced earlier this year, is a set of initiatives involving software, hardware and corporate elements designed to help businesses better utilize the ever-growing ubiquity and computing power of mobile devices. With the idea that smartphones and tablets are, for the most part, largely underutilized in the workplace, the Android for Work program (along with its management, hardware, software and networking partners) aims to provide a number of solutions to ensure that Corporate-Owned, Single-Use (COSU) devices provide consistent management with secure business applications on innovative devices.
The Android for Work APIs released with Android 5.0 Lollipop kept those promises, and Lollipop’s follow up adds a number of new features to further assist businesses in bringing more devices to work.
Components of the Android for Work Program
Work profiles
Work profiles allow dedicated user profiles that isolate and protect work data by allowing its users to have their personal apps and data on their work devices, while knowing that their private data is secure, and their employers only manage and access the apps and data on their work profile.
Built-in productivity tools
These handle email, contacts and calendar functions. They also provide editing capabilities for documents, including spreadsheets and presentations.
Google Play for Work
Enables secure deployment of business-oriented applications in a way that is both simple and flexible. Apps can be managed across all users using Android for Work, streamlining the process of distributing apps for both employees and IT.
Android for Work app
With older devices not running Lollipop and above (but are running at least Android 4.0 Ice Cream Sandwich) or devices that can’t run native work profiles, the Android for Work app delivers secure mail, contacts, calendar, documents, internet browsing and access to work apps.
To use the Android for Work APIs your app must have a DeviceAdminReceiver
subclass:
This provides a way for your app to receive broadcast intents related to device administration sent by the Android system. Your DeviceAdminReceiver
must handle DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED
in its intent-filter — this is the primary action a device administrator must implement to manage a device. The system sends an intent with DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED
when the application is enabled as an administrator, and it is usually handled in the onEnabled(Context, Intent)
method of your DeviceAdminReceiver
subclass. Your DeviceAdminReceiver
must include the BIND_DEVICE_ADMIN
permission, to ensure that only the system is able to send broadcasts to the receiver. A typical DeviceAdminReceiver
manifest tag looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 |
<receiver android:name=".SampleDeviceAdminReceiver" android:description="@string/device_admin_description" android:label="@string/device_admin_label" android:permission="android.permission.BIND_DEVICE_ADMIN"> <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin_policies"/> <intent-filter> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/> </intent-filter> </receiver> |
The android:description
and android:label attributes
are user-readable texts shown to the user when enabling the device administrator, with the description attribute being longer and more descriptive. The android:resource
attribute in the meta-data
tag declares the security policies used by the application. Device admins can require that devices ask for PIN or passwords, determine the password requirements, require that the device storage be encrypted, disable cameras, wipe data, force lock the device, disable the keyboard (in Android Marshmallow and above), and more. These are obviously very powerful features and you should only include those that are relevant to your app.
After doing this you can now set up your app as either a Profile Owner or a Device Owner. A Profile Owner app creates a managed profile on the device. With this, users can have work-related instances of their apps, alongside personal app instances. The Android device administration badge identifies which apps are work apps.
Although Device Owners are more powerful than Profile Owners, I think due to the relative hassle required to set them up, and the potential security/privacy concerns they bring, Enterprise applications should be set up as Profile Owners only except in cases where very tight control over the devices is required (for example, Kiosk applications where a single app is always in the forefront). Device Owners can perform some operations that a work profile can’t, including wiping the device data, disabling Wifi and Bluetooth, allowing applications to pin themselves to the foreground and a number of other powerful features. Some of the new features added in Marshmallow can only be implemented using a Device Owner. However, Device Owner can only be provisioned at the device’s initial setup (usually via NFC) before any user account has been added. Note that both Profile Owners and Device Owners require an encrypted device. If the device is not encrypted, the user will be prompted to encrypt the device before provisioning.
To setup up a work profile, first find out if the device supports managed profiles by checking for the FEATURE_MANAGED_USERS
system feature:
1 2 3 4 5 6 |
PackageManager pm = getContext().getPackageManager(); if (pm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) { // This device supports native managed profiles! }else{ // We need to use an alternative like the Android for Work app } |
If your devices don’t support managed profiles, I recommend considering the Android for Work app from Google to manage your COSU devices.
Next, you must send an Intent
of action DeviceAdminReceiver.ACTION_PROVISION_MANAGED_PROFILE
to the system with an extra DeviceAdminReceiver.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME
containing a ComponentName
object representing your app’s DeviceAdminReceiver
.
1 2 3 4 5 6 7 8 9 10 |
Intent intent = new Intent(ACTION_PROVISION_MANAGED_PROFILE); intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, new ComponentName(context, SampleDeviceAdminReceiver.class)); if (intent.resolveActivity(activity.getPackageManager()) != null) { startActivityForResult(intent, REQUEST_PROVISION_MANAGED_PROFILE); activity.finish(); } else { Toast.makeText(activity, "Device provisioning is not enabled. Stopping.", Toast.LENGTH_SHORT).show(); } |
Note that if your app already has a managed profile set up on the device, an error dialog will be shown at this point.
Setting up a Device Owner requires a little bit more work — a device must be in an unprovisioned state, which can be achieved by performing a factory reset. Then, the Device Owner is typically provisioned using another device with NFC functionality. A NdefMessage
containing your app’s device admin component (your DeviceAdminReceiver
), its download location as a url string, and its package checksum is sent via NFC to your target device.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
@Override public NdefMessage createNdefMessage(NfcEvent event) { try { Properties properties = new Properties(); properties.setProperty( DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, SampleDeviceAdminReceiver.getComponentName(getContext()).flattenToShortString()); properties.setProperty( DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION, mPackageUrl); properties.setProperty( DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM, Utils.getCheckSum()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); OutputStream out = new ObjectOutputStream(bos); properties.store(out, ""); final byte[] bytes = bos.toByteArray(); return new NdefMessage(NdefRecord.createMime(DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC, bytes)); } catch (IOException e) { Log.e(DEVICE_OWNER_LOG, "Something went wrong!", e); throw new RuntimeException(e.getMessage()); } } |
In case you don’t have a NFC device nearby, you can also set up a Device Owner on an unprovisioned device by using the dpm
command line tool in an ADB shell.
adb shell
dpm set-device-owner com.example.android.androidforworksample/com.example.android.androidforworksample.SampleDeviceAdminReceiver
Where com.example.android.androidforworksample/com.example.android.androidforworksample.SampleDeviceAdminReceiver
is the device admin component.
Android has a new permission model in Marshmallow. With Runtime permissions Android users don’t grant any permissions when they install or upgrade apps. Instead, apps need to request permissions as they need them at runtime. A Profile or Device Owner can set a permission policy for the runtime requests of all applications. The default runtime permission policy in Marshmallow is DevicePolicyManager.PERMISSION_POLICY_PROMPT
; if an app requests a runtime permission, the system shows a dialog to the user asking for the permission. A Device Administrator can change this behavior. If DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT
is set, the system always grants runtime permissions to requesting applications. Conversely, if DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY
is set, the system always denies requests for runtime permissions. If you want to grant or deny a runtime permission to a specific application, use the DevicePolicyManager.setPermissionGrantState()
, passing in the package name of your target application and the intended permission as the String parameters.
Note that already granted or denied permissions are not affected.
1 2 3 4 5 6 7 8 9 10 |
DevicePolicyManager manager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); if(setPermissionForAll){ manager.setPermissionPolicy(SampleDeviceAdminReceiver.getComponentName(this), DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT); }else if (setPermissionForSample){ manager.setPermissionGrantState(SampleDeviceAdminReceiver.getComponentName(this), SAMPLE_THIRD_PARTY_APPLICATION, Manifest.permission.CAMERA, DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); } |
A Device Administrator can now also allow third-party applications to access privileged certificate manipulation APIs. More specifically, a third-party certificate installer app can:
- Get all CA certificates that are currently trusted, excluding system CA certificates, by calling
DevicePolicyManager.getInstalledCaCerts()
. - Check if a certificate is installed as a trusted CA by calling
DevicePolicyManager.hasCaCertInstalled()
. - Install or uninstall a certificate as a user CA by calling
DevicePolicyManager.installCaCert()
orDevicePolicyManager.uninstallCaCert()
. - Install a certificate and private key pair with
DevicePolicyManager.installKeyPair()
. - Uninstall all custom trusted CA certificates from the profile using
DevicePolicyManager.uninstallAllUserCaCerts()
.
In all cases a delegated third-party certificate installer should pass a null value as the ComponentName argument, if it has been set as a certificate installer package. Your application can set a certificate installer package by calling DevicePolicyManager.setCertInstallerPackage()
, passing in your DeviceAdminReceiver
, and your intended certificate installer package as a String.
1 2 3 4 |
DevicePolicyManager manager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); manager.setCertInstallerPackage(SampleDeviceAdminReceiver.getComponentName(this), SAMPLE_DELEGATED_CERTIFICATE_INSTALLER); |
Your enterprise application can now also silently grant managed apps access to certificates. By overriding the DeviceAdminReceiver.onChoosePrivateKeyAlias()
, your app can return the alias for a private key and certificate pair before the system shows a dialog to the user. This allows your application greater control over the apps your corporate application manages.
Device Owners have a lot more control over the devices they manage in Marshmallow. In a corporate environment it is important that there are as little distractions as possible — that’s why Android Marshmallow allows Device Owners the ability to disable the status bar (including notifications), quick settings and the swipe-up gestures that opens Google Now by calling the DevicePolicyManager.setStatusBarDisabled()
method, passing in their DeviceAdminReceiver
. This allows for more immersive corporate experiences. Device Owners now have the option to control when their users install system updates with the DevicePolicyManager.setSystemUpdatePolicy()
method, which can auto-accept, postpone or set system update windows to ensure that updates are installed during the most appropriate time. Device Owners can also disable a device’s lock screen by calling DevicePolicyManager.setKeyguardDisabled()
.
Note that this has no effect if a password, pattern or pin is already set, and the keyguard is re enabled if any of these are set after the method call.
Additional changes coming to the Android for Work APIs with Marshmallow include the ability to obtain data usage stats with the NetworkStatsManager
APIs, specific notifications for VPN apps, and the new briefcase icon that appears whenever an app from a managed profile is in the foreground. Profile or Device Owners can also change the photo of a current user by calling the DevicePolicyManager.setUserIcon()
method.
With IT management having a lot more tools to use in creating corporate applications for COSU devices, the changes brought to Android Marshmallow have been substantial. Furthermore, with Google’s hope of making the Android OS run on as many devices as possible, it seems Android For Work will continue to grow — adding new features along the way. One issue, though, is the fragmentation issue caused by the lack of backward compatibility with many of the new APIs. Not every company can afford to update their COSU devices to have the latest version of Android. Since most of the Android for Work APIs were introduced in Lollipop (and updated in Marshmallow), older devices may just have to make do with the Android for Work app by Google.