[Android Tutorial] Master Android Device Owner Permissions, Enterprise Management Made Easy!
In this series of articles, I will share the problems I encountered in Android development,
and the notes on how I solved these problems.
This article will explore the Device Owner permissions provided in Android, including how to obtain and use these permissions.
Have you ever encountered needs that cannot be met by ordinary permissions? What should you do?
For example,
if you need to enforce a specific screen on the device,
or prevent users from uninstalling specific applications, you will need Device Owner permissions.
In short,
Device Owner permissions can help developers achieve needs that cannot be met by ordinary permissions,
but whether you need to use them depends on the specific application scenario.
This permission allows you to use the APIs within the DevicePolicyManager provided by Android.
You can refer to the DevicePolicyManager documentation provided by Android to understand which APIs are available.
DevicePolicyManager Documentation
1. After a Factory Reset, enter the welcome page, click the Welcome text seven times, and use the opened camera to scan the QR Code.
2. After a Factory Reset, click eight times, and use GMS to scan the QR Code (requires GMS).
Please note that different manufacturers may adopt different methods.
However, in practice, almost all of them can be used, unless it is a specially customized OTA that might not work.
Next, you need to create a QR code scan to implement these two steps.
1. Use the following command apk_download_link to input your apk download URL
curl -s [apk_download_link] | openssl dgst -binary -sha256 | openssl base64 | tr '+/' '-_' | tr -d '='
2. Use the following JSON format to fill in your values
android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME: Enter the path of your packageName/AdminReceiver
android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM: Enter the hash code generated in step 1
android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION: Enter your download URL
3. Use the JSON format from step 2 to generate a QR code.
Afterwards, simply open the QR code scanner on the device after a Factory Reset using one of the two methods mentioned earlier.
Let the user scan the QR code you generated.
Once the system is set up,
the app will automatically install and become the Device Owner.
This method is usually intended for non-developers.
For example: Developers from various platforms can first upload the APK.
After obtaining the APK download URL,
use the steps above to generate the hash code and create the JSON format data, then make the QR code.
This makes it convenient for non-developers to generate the Device Owner app through UI operations.
Here, you just need to input the path of your app’s Admin Receiver into the command below
to make the app the device owner.
adb shell dpm set-device-owner com.your.package/com.your.package.receivers.AdminReceiver
- However, this command has some limitations:
- There must not be any GMS account on the current OS.
This means you need to remove any Google account from the settings that you use for Google services. - Only one user-configured Device Owner can exist in the system. If there is one, you can delete it first and then reset the required app.
adb shell dumpsys device_policy
This command allows you to check the current device owner status on your OS.
- There must not be any GMS account on the current OS.
adb shell dpm remove-active-admin com.your.package/.receivers.AdminReceiver
- This command requires:
Addingandroid:testOnly="true"
within the<application>
tag inAndroidManifest.xml
to remove the Device Owner. -
Apps with device owner permissions
usually cannot be removed or installed via adb install.
You can use-r -f
to force overwrite:adb install -r -f ../xxx.apk
or force remove and then install. -
Removing via Official API
Within the device owner app,
useclearDeviceOwnerApp
inDevicePolicyManager
to remove the permissions. - Directly Factory Reset the phone
If none of the above methods work, you can use the ultimate solution: Factory Reset XD
-
This works in conjunction with Admin permissions.
You need to create an Admin Receiver within the app that will be the Device Owner.
This way, when you use adb to obtain permissions,
the subsequent Receiver can be activated.
In other words,
adb shell dpm remove-active-admin com.your.package/.receivers.AdminReceiver
-
Admin permissions mean:
Adding the necessary Receiver for Admin permissions within the app.
So the user
can also find theDevice Administrators
permissions in the settings and enable it.
However, this is actuallydifferent
from Device Owner permissions.
Do not confuse the two.
-
For the method, refer to the official documentation: Documentation
The documentation also mentions some practical examples for reference.
The process is simple and only requires creating
a subclass ofDeviceAdminReceiver
and adding it to the Manifest.xml. -
Quick steps:
- Extend a
DeviceAdminReceiver
- Extend a
class AdminReceiver : DeviceAdminReceiver() {
override fun onEnabled(context: Context, intent: Intent) {
}
override fun onDisabled(context: Context, intent: Intent) {
}
}
2.
Implement the permission declaration in device_admin.xml
under the path res/xml
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<limit-password />
<watch-login />
<reset-password />
</uses-policies>
</device-admin>
- Add the first two items to the manifest
<receiver
android:name=".MyAdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
- Request through code
fun startAskActiveAdmin() {
if (!isAdminActive) {
val intent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, deviceAdmin)
this.activity.startActivityForResult(intent, KnoxManager.DEVICE_ADMIN_ADD_RESULT_ENABLE)
}
}
- Handle the return result
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == KnoxManager.DEVICE_ADMIN_ADD_RESULT_ENABLE) {
when (resultCode) {
RESULT_CANCELED -> {
logger.debug("RESULT_CANCELED")
}
RESULT_OK -> {
logger.debug("RESULT_OK ")
}
}
}
}
Here are some examples encountered in previous implementations
Mainly discussing the concepts and some parts of the code
Personally, I think it’s not too difficult to understand
So I won’t go into too much detail
-
First, you need to get instances of DevicePolicyManager and AdminReceiver
-
Once you have them, you can call them as needed. The implementation methods are quite similar, so here are just a few examples
Hide App
- Add
User Restriction
-
For more examples, you can refer to Google’s github which has sample apps using Device Owner
Supplement:
Besides Device Owner
The following command can also modify the configuration of a specified app through adb
adb shell pm grant com.your.package android.permission.CHANGE_CONFIGURATION
Or you can directly add it to AndroidManifest.xml
However, because its protectLevel on the system is declared as signature|privileged
(Now looking at the documentation, signature|privileged
has been changed to signatureOrSystem
, with the same effect as before)
At this time, to use this permission to change app configuration, you need to obtain a system signature or have device owner permissions
You can check the official permission documentation to understand signature|privileged