vendredi 20 février 2015

10 things to know about Device Owner Apps in Android 5

Device Owner Apps is another key feature of Android for Enterprise available in Android 5 (API 21). Device Owner app is a special kind of Admin app that help you create users, and configure global settings without the need to be a privileged system app.

Let’s see 10 facts to know about Device Owner Apps.

1. It can be set via NFC

Because this app has some special “power”, it can only be set using special means.

The official way of setting a Device Owner App is by using a NFC message. You could use a classic NFC tag, or Android Beam.
This message has a special MIME type (application/com.android.managedprovisioning) and contains at least 3 properties :

For instance, on an Android Beam, you could create an Activity implementing NfcAdapter.CreateNdefMessageCallback and NfcAdapter.OnNdefPushCompleteCallback, and have the following code in your createNdefMessage()

import static android.app.admin.DevicePolicyManager.*;
... 
 Properties p = new Properties();
 p.setProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, "com.test.my_device_owner_app");
 p.setProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION, "https://raw.githubusercontent.com/.../MY_APP.apk");
 p.setProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM,AGt-"ELmIalMx6tdNKWbKBZ4YdGo"); 
 ByteArrayOutputStream bos = new ByteArrayOutputStream();
 OutputStream out = new ObjectOutputStream(bos);
 p.store(out, "");
 final byte[] bytes = bos.toByteArray();

 NdefMessage msg = new NdefMessage(NdefRecord.createMime("application/com.android.managedprovisioning", bytes));

Some additionnal information may also be provided like Wifi informations, proxy, locale, time zone, email address, etc. All other options are available under the EXTRA_PROVISIONING_XXXXconstants in DevicePolicyManager

The checksum of the APK is calculated with :

cat MY_APP.apk | openssl dgst -binary -sha1 | openssl base64 | tr '+/' '-_' | tr -d '='

(Under Windows, you could use a cygwin-like bash (like Babun for instance) to provide these commands.)

Important thing to know : It has to be done on an unprovisioned device , on the FIRST step, once your device is booted (if your device is already provisionned, go to Settings > Backup & Reset > Factory data reset to reset it. Beware : all your data will be lost). Once the NFC message is delivered, the second step will ask you to setup the Wifi connection. Once the Wifi connection is validated, the APK is donwloaded and your device is provisioned.
Also make sure the device screen are unlocked. NFC is not working when the screen is locked on Android.

see also http://stackoverflow.com/questions/21183328/how-to-make-my-app-a-device-owner

2. it can also be set via a shell command

Another way to set a Device Owner App on your device is by using the dpm command line tool. It’s useful when you are developping or when you have a full access on a rooted device.
In this case, your app will have to be installed first, like any other casual app, and then you could set it as a Device Owner App using the shell (mostly through adb if you are developing)

for instance :

$adh shell dpm set-device-owner com.test.my_device_owner_app/.MyDeviceAdminReceiver

The dpm utility is really simple actually. Its goal is to create a new file called device_owner.xml under /data/system/device_owner.xml (if the storage is not encrypted) that references the Device/Profile owner apps.

The android platform is then reading this file to check which application is considered as Device Owner or Profile Owner App.

On a rooted device, you could indeed, create this file by yourself, but since the dpm tool is doing it, you’d better use it (DRY principle) :

Runtime.getRuntime().exec(dpm set-device-owner com.test.my_device_owner_app);

Also notice that this tool is working only if no account is set for the user (make sure no account is set in Settings > Accounts) before its use.

More information on this tool is provided in a previous post.

3. There can be only one Device Owner App per device…

Once the Device Admin app is set, it’s absolutely possible to update new versions of this app in a normal way, without re-provisioning it through NFC or the dpm tool).

The file /data/system/device_owner.xml contains the package name of applications registered as Device Owner / Profile Owner apps. Updating these apps won’t infer on this file since the package name stays the same. Just make sure you’re always using the same certificate as the one you previously used when first setting you device owner for the first time (which is a standard rule of security for every application update in Android anyway).
Permissions can also be updated without the need to re-provision it through NFC, nor dpm.

you could also take a look at this question on SO.

4. … but there may be a Profile Owner for each user.

A Profile Owner App is, like Device Owner App, a specific kind of Admin App.
By definition there can be only one Device Owner app, but there may be a Profile Owner for each user.

The difference with the Device Owner App is that a Device Owner App is per-device basis, while a Profile Owner app is on a per profile basis. That means that while only one Device Owner App can be set, multiple Profile Owner app can be set, one on each user profile.

A Profile Owner App, is a subset of Device Owner App, that allows only certain API specific to users and profile. Profile Owner Apps can typically restrict the applications accessible or configure the settings for a specific user.

Setting a Profile Owner App can be done from a Device Owner App, when creating a new user, using the createAndInitializeUser() method where the DeviceAdminReceiver’s implementation represents the component that handle the Profile Owner.

When the user is created with createandInitializeUser(), the application corresponding to the package associated to the DeviceAdminReceiver is installer in the user’s profile. Internally, the API IPackageManager.installExistingPackageAsUser and the user is then started in background. The profile’s DeviceAdminReceiver and its associated package are considered as admin and Profile Owner for this user

When developping, you could also use dpm and specify for which user you want to set this app as a Profile Owner.

$adh shell dpm set-profile-owner com.test.my_device_owner_app/.MyDeviceAdminReceiver <USER_ID>

Notice that the use of dpm set-profile-owner is only possible for a user that is not set up (not yet initialized).

There’s also a way to set an application as a profile owner, without the need of a Device Owner App, or dpm. In this case, the user will be prompted to accept this application as a profile owner by sending a specific Intent (not detailed here though).

5. They can not be unset by any user …

… even the owner is not allowed to unset the Device Owner app!

Because a Device Owner app has full control over the device. The Device Owner app can not be modified by the user and the only way of removing this app is to do a factory reset.

You could reset your device, by going into Settings > Backup & Reset > Factory data reset. If this option is disabled, you’ll have to reboot your device in Recovery Mode and factory reset from here (depending on your hardware).

dpm utility offers no way to unset the Device Owner application.

Fortunately, there ‘s a way a unset it programmatically : ask the app to unset by itself. You can use DevicePolicyManager.clearDeviceOwnerApp() to make sure your app is not set as a Device Owner app anymore.

For example, in one of your Device Owner App’s activity :

DevicePolicyManager mDPM = (DevicePolicyManager) this.getSystemService(Context.DEVICE_POLICY_SERVICE);
mDPM.clearDeviceOwnerApp(getPackage());

6. They can dynamically manage users

A Device Owner app can create a new user, swith to its session, remove it.
This is a big advantage over other normal apps which are not autorized to do this.

2 methods are available to create users :

  • createUser() creates a new user, but this user which is not provisionned nor restricted. In a programmatic sense, no Profile Owner app is associated to it.
  • createAndInitializeUser() creates a new user and associate a Profile Owner app which is used to provision and restrict the user programmatically.

Device Owner apps also provides a way to switch to a user session from its handle.
This is particulary useful when you create a user and want to switch directly to its session.
A Device Owner App can also remove a specific user from its handle.

DevicePolicyManager mDPM = (DevicePolicyManager) this.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName mDeviceAdminRcvr = new ComponentName(this, DeviceAdminRcvr.class);
UserHandle newUserHandle = mDPM.createUser(mDeviceAdminRcvr, "Temporary user");
mDPM.switchUser(mDeviceAdminRcvr, newUserHandle);

...
// once done with the user
mDPM.removeUser(mDeviceAdminRcvr, newUserHandle);

7. They can restrict the apps accessible for a user

You can easily limit the applications accessible for your user by “hiding” them using setApplicationHidden.

Example of use to hide the Google+ app :

DevicePolicyManager mDPM = (DevicePolicyManager) this.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName mDeviceAdminRcvr = new ComponentName(this, DeviceAdminRcvr.class);
mDPM.setApplicationHidden(mDeviceAdminRcvr, "com.google.android.apps.plus", false)

You can set them visible in a same way by placing the last flag to true.
Also notice that, you will not see notifications of hidden applications.

Bad thing is that you cannot, programmatically and silently, install new applications for a user. To do this, you’ll need to have the permission INSTALL_PACKAGES, and this permission is not given for third party apps. You could still use it if your app is a system app or on a rooted device.

8. They can restrict the device and configure its settings

Device Owner App and Profile Owner App ARE Admin Apps. Everything you were used to do with Admin apps, can also be done with a Device Owner app. That includes restricting the security policy (password policies, lock policies, encryption policies, camera policies) and also wipe its data, lock the device or prompt for a password.

A Device Owner app is going further by offering some settings customization, through DevicePolicyManager.addUserRestriction, DevicePolicyManager.setSecureSetting, DevicePolicyManager.setGlobalSetting

You should know that you can :

  • Disallow some settings modifications with DevicePolicyManager.addUserRestriction. The list of settings that could be disallowed is provided in the UserManager.DISALLOW_XXX constants with some specific cases depending if you are calling from a Device Owner App, Profile Owner App, or from the Owner user.
  • Modifiy Global device settings with DevicePolicyManage.setGlobalSetting like auto time, adb enabled (Only a subset of Global Settings is available though). Only a Device Owner App can call this method.
  • Modify User settings with DevicePolicyManager.setSecureSetting. Only 2 settings are modifiable like the default input method and the skipping of the first use hint. These settings can be set from a Device Owner App or a Profile Owner App.

Sadly the documentation is not clear about what settings you can set or value to use, so I’won’t go in more detail here (I’m preparing a complete article on these).

9. They can make a your app a real Kiosk app

Screen Pinning is another great feature of Android for Workplace and Education. And when it’s configured from a Device Owner App through setLockTaskPackages, it offers a real Kiosk App.

Here are some screen pinning behavior that could be set when a Device Owner App autorizes an app to be pinned :

  • Only the Back(enter image description here) button remains visible in the navigation bar. Home(enter image description here) and Overview(enter image description here) buttons are not visible
  • … and because of this, it’s impossible to unpin the application manually
  • You can enter the pin mode without user confirmation.

You can have more details in my blog post Android 5 Screen Pinning.

10. Create Restricted Profile is impossible once a Device Owner App is set

The Android source code indicates that the creation a restricted profile is not allowed from Settings on tablets with a device owner or phones.

Programmatically, it’s not possible to create a new profile based on an existing one. The API exists but hidden (UserManager.createProfileForUser(String, int, int)). Accessing this API via reflection cannot be done because it needs the system permission MANAGE_USERS.

You should be aware of that and because you have more power, means you’ll have to restrict your user by yourself when a Device Owner App is set. You could use all restrictions API explained earlier to do that.

Going further

For now, because the documentation is very light on these subjets, and no book is out, The best way to go further is by browsing the Android Source Code base.

Some classes are particularly interesting : LauncherApps, DevicePolicyManager, DevicePolicyManagerService, deviceAdminReceiver, UserManager