Using Delegation Scopes

MX Transition

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 12, 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

image 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.
    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:
  1. Obtain access to ZDM through an administrator for the app(s) that need to use it.

  2. Add the following line to the manifest.xml file of the app(s):

    
    <uses-permission android:name=”com.symbol.zdm.ACCESS_DEVICE_MANAGER_SERVICE”>
    
  3. 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); 
    
    
         } 
    
    }
  4. 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); 
    
  5. 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) { 
    
    
        String response =   msg.getData().getString(Constant.RESPONSE); 
    
    //Parse the json to get all the details //Response json format mentioned below in the docs } }
  6. 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\"}]" 
    
    } 
    
  7. 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 for 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); 
                    } 
                } 
    } 
} 

Zebra-app Delegation Scopes

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 Query (intent APIs for Enumerate Scanners, Get DataWedge Status, etc.) delegation-zebra-datawedge-api-access-query
DataWedge Notification (intent APIs for Scanner Status, Profile Switch, etc.) delegation-zebra-datawedge-api-access-notification
DataWedge Runtime (intent APIs for Enable/Disable DataWedge, Soft Scan Trigger, etc.) delegation-zebra-datawedge-api-access-control
DataWedge Configuration (intent APIs for Set Config, Create Profile, etc.) delegation-zebra-datawedge-api-access-config
EMDK-built customer apps* delegation-zebra-emdk-access
Secure Storage Manager delegation-zebra-file-deployment
Zebra Workstation Connect delegation-zwc-developer-api-access-control

* 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.


Also See

Android Developer Docs

Articles by Zebra Engineers