Overview
Delegation Scopes is a method by which the Android Device Policy Manager (DPM) APIs allow a device owner (DO) such as an Enterprise Mobility Management (EMM) agent to enable other apps to use some DPM functions. Apps targeting Android 11 (API 30) and later can declare that access to one or more of their interfaces should be controlled, and that an administrator can be allowed to delegate access to other apps within a given scope. The Android DPM implementation of Delegation Scopes covers package and certificate management and a few other categories. Zebra has adopted and expanded Delegation Scopes to allow applications to control access to their interfaces by limiting their use to applications to which the administrator has granted a suitable Delegation Scope. Zebra Device Manager (ZDM), a new service developed as part of the transition to Android 11 and 13, handles Delegation Scopes on the device.
Required Actions:
- Developers that currently protect their app interfaces using MX/AccessMgr must switch to using Delegation Scopes and ZDM.
- Administrators formerly granting access using MX/AccessMgr must switch to using Delegation Scopes and Zebra OEMConfig.
NOTE: Apps that use protected services require NO modifications for these changes.
Delegation Scopes and ZDM
Click images to enlarge; ESC to exit.
The relationship between Delegation Scopes and ZDM is usually transparent to the developer. Apps calling for access to another app's interface(s) must be explicitly granted permission by the implementing app; ZDM manages those permissions. When an app attempts to use an interface that the implementing app has chosen to protect using a Delegation Scope, the implementing app must query ZDM to determine whether the calling app has been granted (by the administrator) a Delegation Scope that allows access to that interface. When a given function supported by ZDM or a Zebra app is controlled by a Delegation Scope, it allows only direct use of that function by a genuine instance of an app that has been explicitly granted that Delegation Scope.
The exception is when the calling app attempts to access an interface indirectly, such as through an intent. As in the MX/AccessMgr model, the calling app must acquire a token, which in the new model comes from ZDM. The token is sent by the calling app via intent to the implementing app, which checks with ZDM to determine whether the token was issued to an app entitled to access the protected API. When a genuine instance of an app is allowed direct use of a function controlled by a Delegation Scope, that app might choose to allow indirect use of that function by another application through a defined interface such as AIDL or a JavaScript callback. In such cases, the app that's allowed to use the function becomes responsible for ensuring that any use of that by another app is appropriately controlled.
Usage Notes
- Each Delegation Scope must have a unique name.
- Delegation Scope names must be in the form
delegation-zebra-[app name]-[API, component or service]
. - The underlined section above is a mandatory prefix that must remain unchanged.
Example:delegation-zebra-bind-zebradevicemanager-config-service
. - Delegation Scope status can be determined using ZDM queries,
- Apps with functions controlled by Delegation Scopes are assumed to be trustworthy for identifying apps trusted to use them.
- Apps created using EMDK are automatically trusted to access Zebra apps.
- Customer apps created using EMDK must be granted access to non-Zebra apps by an EMM administrator.
Communicating with ZDM
By default, only Zebra apps (e.g. DataWedge, Enterprise Browser, etc.) can bind with ZDM without obtaining permission separately. All other apps must be expressly granted access by an administrator, a concept similar to using MX/Access Manager to add apps to a "whitelist."
To communicate with ZDM, the calling app must do the following:
Obtain access to ZDM through an administrator for the app(s) that need to use it.
Add the following line to the
manifest.xml
file of the app(s):<uses-permission android:name=”com.symbol.zdm.ACCESS_DEVICE_MANAGER_SERVICE”>
Bind app(s) with the ZDM service:
private static final String ZDM_PACKAGE "com.zebra.devicemanager"; private static final String ZDM_SERVICE_CLASS = "com.zebra.devicemanager.ZebraDeviceMgr"; Intent bindZDMServiceIntent = new Intent(); bindZDMServiceIntent.setComponent(new ComponentName(ZDM_PACKAGE,ZDM_SERVICE_CLASS)); try { bindService(bindZDMServiceIntent,ZDMServiceConnection,Context.BIND_AUTO_CREATE); }catch (SecurityException e){ } Messenger mService; private ServiceConnection ZDMServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = new Messenger(service);
}}
Send message(s) to ZDM for processing:
Message msg = Message.obtain(); IncomingHandler incomingHandler = new IncomingHandler(); msg.replyTo = new Messenger(incomingHandler); Bundle bundle = new Bundle(); bundle.putString("data",”JS function/js file path in device”); msg.setData(bundle); mService.send(msg);
Implement an
IncomingHandler
to receive ZDM responses:public static final int TASK_COMPLETED = 5; public static final int TASK_FAILED = 6; private class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) {
//Parse the json to get all the details //Response json format mentioned below in the docs } }String response = msg.getData().getString(Constant.RESPONSE);
Be aware that responses come in JsonString format, as below:
{ "status": "COMPLETED", "IN_PROGRESS" "msg": "TASK_COMPLETED", "TASK_IN_PROGRESS" "result": "[{\"command\":\"js callback name\",\"message\":\"detail about execution\",\"status\":\"SUCCESS", "ERROR", "EXCEPTION" or "IN_PROGRESS\"}]" }
Parse responses:
JSONObject resObj = new JSONObject(response.trim()); String status = resObj.getString(STATUS); String message = resObj.getString(MSG); String result = resObj.getString(RESULT); JSONArray jsonArray = new JSONArray(result); for (int i = 0 ; i<jsonArray.length();i++){ JSONObject obj = jsonArray.getJSONObject(i); Log.i(TAG,"callback result = "+obj.toString()); }
Feedback Channel
In accordance with Google's published practices, ZDM supports a feedback channel. Feedback responses are sent as a broadcast for registered authorized apps.
Register the feedback channel
To configure an app to receive broadcast feedback responses, register the following action name in the app's manifest.xml
file:
FEEDBACK_ACTION_NAME = "com.zebra.feedback.action.APP_STATES";
Example
<receiver android:name="FeedbackReceiver"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="com.zebra.feedback.action.APP_STATES" />
</intent-filter>
</receiver>
Retrieve Feedback
Feedback broadcast details are received as an intent. Some of the most common are shown in the table below.
Description | Code |
---|---|
Name of bundle (stored as a parcelable) containing feedback details | static final String APP_STATES = "app_states"; |
Name of keyed app state key for a given bundle | static final String APP_STATE_KEY = "app_state_key"; |
Name of severity of the app state | static final String APP_STATE_SEVERITY = "app_state_severity"; |
Name of optional app state message for a given bundle | static final String APP_STATE_MESSAGE = "app_state_message"; |
Package name that submitted the app state | static final String APP_STATE_PKG = "app_state_pkg"; |
Time stamp of app state | static final String APP_STATE_TIME_STAMP = "app_state_time_stamp"; |
Name of optional app state data for a given bundle | static final String APP_STATE_DATA = "app_state_data"; |
Example
public class FeedbackReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, final Intent intent) {
ArrayList<Bundle> bundles = intent.getParcelableArrayListExtra(APP_STATES);
if(bundles != null) {
for (Bundle feedbackDetails : bundles) {
String key = feedbackDetails.getString(APP_STATE_KEY);
int severity = feedbackDetails.getInt(APP_STATE_SEVERITY);
String message = feedbackDetails.getString(APP_STATE_MESSAGE);
String pkgName = feedbackDetails.getString(APP_STATE_PKG);
String data = feedbackDetails.getString(APP_STATE_DATA);
Long timestamp = feedbackDetails.getLong(APP_STATE_TIME_STAMP);
}
}
}
}
Delegation Scopes - Zebra Apps
The following Delegation Scopes can be used to grant third-party apps access to Zebra-app interfaces designated as accessible for use by non-Zebra apps.
Zebra App to Access | Delegation Scope Name |
---|---|
DataWedge Configuration (intent APIs for Set Config, Create Profile, etc.) | delegation-zebra-datawedge-api-access-config |
DataWedge Notification (intent APIs for Scanner Status, Profile Switch, etc.) | delegation-zebra-datawedge-api-access-notification |
DataWedge Query (intent APIs for Enumerate Scanners, Get DataWedge Status, etc.) | delegation-zebra-datawedge-api-access-query |
DataWedge Runtime (intent APIs for Enable/Disable DataWedge, Soft Scan Trigger, etc.) | delegation-zebra-datawedge-api-access-control |
EMDK-built customer apps* | delegation-zebra-emdk-access |
Secure Storage Manager | delegation-zebra-file-deployment |
Wi-Fi API Access Service Provider | delegation-zebra-wifi-api-access-control |
Zebra Workstation Connect | delegation-zebra-workstationconnect-api-access-configuration-service |
* All EMDK Delegation Scopes are currently allowed by default. A future version of EMDK will allow only EMDK-built apps with an EMDK Delegation Scope to be allowed to submit JavaScript/JSON to ZDM using EMDK ProfileManager APIs.
Delegation Scopes - Third-party Apps
The following Delegation Scopes can be used to grant EMM agents and other third-party apps permission to access other apps and app resources running on Zebra devices.
App Function | Delegation Scope Name |
---|---|
Key Touch Injection**: Grants permission to an app on the device (i.e. an EMM agent) to access KTI services and APIs | delegation-zebra-kti-eventinjection |
Key Touch Injection**: Grants permission to an app to search and delete files in sandboxes of other apps on the device | delegation-zebra-kti-fileops |
Key Touch Injection**: Grants permission to an app to suppress display of the media projection pop-up message on the device, which might otherwise prevent remote control of an unattended device | delegation-zebra-kti-remotedisplay |
Key Touch Injection**: Grants permission to an app on the device to list the tasks and services of third-party apps running on the device, and to force-stop those apps | delegation-zebra-kti-remotetroubleshooting |
** All four (4) KTI Delegation Scopes are required for remote control operation.
Also See
Android Developer Docs
- Android Content Provider Basics | An Introduction
- Creating a content provider | Why and how to share an app's data
- Android Cursor docs | How to interface with a result data set
- Content Observer | Get a callback when data changes
Articles by Zebra Engineers
- How to display serial and IMEI numbers on device | Sample app, instructions, source code
- Save OEM identifiers to a file on the device | Sample app, source code