Android Enterprise OEMConfig Setup

Guide to help OEM developers create OEMConfig applications to enforce proprietary and privileged APIs.

OEMConfig

Use case

To help meet advanced customer use cases that are not directly supported through the Android platform today, OEMConfig enables OEMs and EMMs to build support for custom OEM APIs (e.g. barcode scanning hardware) in a consistent and reusable way.

Prior to Android Enterprise, OEMs had created SDKs which EMMs added into their applications to support all of the additional APIs built by the OEM. However, this then relied on the EMM to add additional support for any new APIs while also maintaining support for every OEMs SDK in their applications. This lead to a great deal of duplicated effort across OEMs and EMMs, and overall lower adoption of OEM APIs with fewer use cases supported for customers.
With the introduction of Android Enterprise features into the Android operating system in Android 5.0, EMMs can now leverage the managed configurations communication channel to pass any OEM configurations to applications built by the OEMs themselves. These configuration bundles can be passed by any EMM to the designated OEMConfig application, which greatly reduces the investment required by an EMM to support an OEMs APIs.

For additional information on how managed configurations works, OEMs and EMMs should review the “App Configuration” section above.

How it works
  1. Requires Android 5.0+ device
  2. OEMConfig application built by OEM and uploaded to Google Play
  3. OEMConfig application whitelisted by Google Play team with expanded restrictions EMM support for managed configurations

Developer requirements

OEMs

Before you begin to build your OEMConfig application, you should first review the managed configuration guidance.

Step 1

By default, Managed Google Play enforces certain limitations for managed configuration schemas submitted to the Play store. While these limitations are appropriate for a typical use case of managed configurations, OEMConfig applications may require a more robust schema to be able to include all of the necessary key-value pairs to map to OEM APIs.
To accommodate for this, OEMs can request for their OEMConfig application to be whitelisted by Google. This whitelist extends the standard limits imposed on managed configurations (e.g. bundles can exist outside of bundle arrays) to help with schema structure for IT admin configuration. Whitelist requests can be submitted to OEMConfig-integration@google.com
and must contain the following information:

  • OEM name
  • Application package name
  • Sample restriction schema structure

Note: EMMs must modify their managed configurations UI within their EMM console in order to properly render the OEMConfig schema. Please check with your EMMs to determine if they support the OEMConfig schema.

Bundle within bundle schema layout (Using “Steps”):
Each API that is built into your OEMConfig application acts as an individual key-value pair. To ensure that your schema can be properly configured by an IT admin, you must be considerate of how you organize these key-value pairs. One way to do this is to group them as a series of steps correlated to feature groups of key-value pairs.

The best way to organize these steps is a single restriction configured as a bundle_array at the top layer of your restrictions. Since bundle_array can only have one child bundle, you will need to have a nested bundle. Beneath that, you will have bundles that correspond with a step of OEMConfig.
Structurally, steps should be organized as:

    L1. Steps (bundle_array)

      L2. Step (bundle)

        L3. Clock Configuration (bundle)

          L4. Clock Configuration -Manual Time
          L4. Clock Configuration -Manual Date
          L4. Clock Configuration -Time Zone Mode
        L3. Camera Configuration (bundle)

          L4. Camera Configuration -Front Camera
          L4. Camera Configuration -Back Camera

Additionally, you should keep the following in mind when building your OEMConfig schema:

  • You should have a bundle (L2) that contains your step bundles (L3)
  • In each step bundle (L3), you must set restrictions (L4) for components of that step.
    • You can set bundle_arrays with additional substeps within each step.
    • Nest only as deep as is needed to prevent overcomplicating your schema.
  • Each time an IT admin modifies a key-value pair, the full schema will be sent to your application.
    • OEMConfig should only act on the key-value pairs that have changed.

You can review the example code in the code reference section to see how to properly nest steps.

Best practices for naming restrictions:

Use clear and concise names for your top layers
To define the parent bundle array for steps, use the title ‘Steps’. For each step within, define each feature set by what it will control followed by the suffix ‘Configuration’ or ‘Step’. This will help ensure that each title is consistent and descriptive within the schema. For example, you would have ‘Analytics Configuration’, ‘Bluetooth Configuration’, or ‘Blacklist Configuration’ to help clarify the contents of what each step will configure. These should be concise and descriptive to clearly define what each step accomplishes for the admin.

Keep titles consistent within each step
If the step for clock configuration is titled ‘Clock Configuration’ then each substep will be derivative of that. In the example below, you would have a substep called ‘Clock Configuration -Manual Time’ that would be used for setting the time to manual or automatic. The description should also concisely reflect what the responsibilities of the individual APIs are within the substep. This clarifies the functionality of the APIs, what that section of the step is responsible for, and what to expect when modifying the key-value pair.

Level Type Title Description Key
L1 bundle_array Steps OEM Config Steps steps
L2 bundle Step OEM Config Step step
L3 bundle Clock Configuration Clock configuration of OEMConfig Step clockStep
L4 bool/choice/multi.select/integer/string Clock Configuration – Manual Time Specifies if the time is configured manually or automatically clockManualTime
Step 2

Since the managed configuration channel is a one-way transaction from the server to the application, DPCs don’t have a way to know when your OEMConfig application has completed its operations. This can be particularly problematic when the APIs called by the DPC rely on certain settings being configured. For example, the date and time for a device must first be set before a certificate can be installed to the device.

Google is currently building backward-compatible support for a standardized communication channel between any app and any EMM. In the meantime, OEMs can optionally add additional restrictions to enable this transaction between an OEMConfig application and the DPC. These restrictions should map to intent values that will be sent by the OEMConfig application to the intended recipient, as specified in the restrictions. These restrictions should be of type hidden to prevent the admin from making modifications, and the EMM should instead configure these values themselves. OEMs should map to the intent structure as outlined in the
Android developer documentation.

Note: EMMs must support modifying the managed configuration with these hidden restrictions and their DPC must be equipped to handle the intent sent by the OEMConfig application. Please check with your EMMs to determine if they support this transaction model.

Step 3

Allow your OEMConfig application to execute the required API correlating to key-value pairs within your configuration schema. While there is no industry standard for this implementation, there is some public
documentation on existing methods used by OEMs.

EMM

Before EMMs can support configuring an OEMConfig application through Play, they must first be validated for at least one of the Android Enterprise solution sets.

Step 1

The UI used within an EMM’s console to dynamically display the key-value pairs for application configuration must support the flexible nature of an OEMConfig application. In particular, EMMs should be able to properly read the step structure to allow for configuration of the restrictions in the bundle and bundle arrays within the UI for configuration. We recommend reviewing the “Code reference” section to see an example of the XML schema your UI should be able to render.

Step 2

While not required to enable an OEMConfig application to execute the APIs on a users device, there are a few optional features that EMMs can choose to implement:

  • Offline environment support
    • EMMs can choose to call setApplicationRestriction directly from the device owner DPC, rather than delegating to Play, to support offline environments where Google Play may not be available.
  • Intent resolution for configuration feedback
    • EMMs can specify an intent to be sent from the OEMConfig application to their DPC to notify them of completion. See Step 2 of the OEM section for more details.

Code reference

This section features an example XML schema of a OEMConfig application and it’s JSON output received by an EMM when calling Products.getAppRestrictionsSchema.

OEMConfig XML schema
<restrictions>
	<restriction 
		description="Specifies the type of intent that will be sent by OEMConfig"
		title="resultIntentType_title"
		key="resultIntentType"
		defaultValue="{resultIntentType}"
		restrictionType="hidden" /> 
	
	<restriction 
		description="Specifies the action name for the intent that will be sent by OEMConfig"
		title="resultIntentAction_title"
		key="resultIntentAction"
		defaultValue="{resultIntentAction}"
		restrictionType="hidden" /> 
	
	<restriction 
		description="Specifies the component name to which the intent will be sent by OEMConfig"
		title="resultIntentComponent_title"
		key="resultIntentComponent"
		defaultValue="{resultIntentComponent}"
		restrictionType="hidden" /> 
	
	<restriction 
		description="Specifies the name of the string extra to be attached to the intent"
		title="resultIntentExtraName_title"
		key="resultIntentExtraName"
		defaultValue="{resultIntentExtraName}"
		restrictionType="hidden" />

	<restriction 
		description="Specifies the value of a string extra to be attached to the intent"
		title="resultIntentExtraValue_title"
		key="resultIntentExtraValue"
		defaultValue="{resultIntentExtraValue}"
		restrictionType="hidden" /> 
	
	<restriction 
		description="Specifies a series of steps to be performed by OEMConfig"
		title="Steps"
		key="steps"
		restrictionType="bundle_array"> 
		
		<restriction 
			description="Specifies an OemConfig Step by specifying an unordered set of operations"
			title="Step” key="step"
			restrictionType="bundle"> 
			
			<restriction 
				description="Clock configuration of OEMConfig Step"
				title="Clock Configuration"
				key="clockStep"
				restrictionType="bundle">
				
				<restriction 
					description="Specifies if the time is configured manually or automatically" entries="clockTimeMode_entries"
					title="Clock Configuration - Time Mode"
					key="clockTimeMode"
					defaultValue="true" entryValues="clockTimeMode_values"
					restrictionType="choice" />

				<restriction 
					description="Specifies the date in manual date mode"
					title="Clock Configuration - Manual Date"
					key="clockManualDate"
					restrictionType="string" />

				<restriction 
					description="Specifies the time in manual time mode"
					title="Clock Configuration - Manual Time"
					key="clockManualTime"
					restrictionType="string" /> 

				<restriction 
					description="Specifies if the time zone is configured manually or automatically" entries="clockTimeZoneMode_entries"
					title="Clock Configuration - Time Zone Mode"
					key="clockTimeZoneMode"
					defaultValue="Auto" entryValues="clockTimeZoneMode_values"
					restrictionType="choice" />

				<restriction 
					description="Specifies the time zone in manual time zone mode"
					title="Clock Configuration - Manual Time Zone"
					key="clockManualTimeZone"
					restrictionType="string" />

				<restriction 
					description="Specifies whether time is 12 hour or 24 hour" entries="clockTimeFormat_entries"
					title="Clock Configuration - Time Format"
					key="clockTimeFormat"
					defaultValue="12" entryValues="clockTimeFormat_values"
					restrictionType="choice" /> 
			</restriction> 
				
			<restriction 
				description=”Camera configuration of OEMConfig Step"
				title="Camera Configuration"
				key="cameraStep"
				restrictionType="bundle">

				<restriction 
					description="Enables the use of the back camera" entries="cameraUseOfBack_entries"
					title="Camera Configuration - Back Camera"
					key="cameraUseOfBack" entryValues="cameraUseOfBack_values"
					restrictionType="choice" />

				<restriction 
					description="Enables the use of the front camera" entries="cameraUseOfFront_entries"
					title="Camera Configuration - Front Camera"
					key="cameraUseOfFront" entryValues="cameraUseOfFront_values"
					restrictionType="choice" /> 	
			</restriction> 
		</restriction> 
	</restriction> 
</restrictions> 
Products.getAppRestrictionsSchema JSON output
{ 
	"result": { 
	"kind": "androidenterprise#appRestrictionsSchema", 
		"restrictions": [ 
			{ 
				"restrictionType": "hidden", 
				"defaultValue": { 
					"valueString": "{resultIntentType}", 
					"type": "hidden" 
				}, 
				"description": "Specifies the type of intent that will be sent by OEMConfig", 
				"entryValue": [ 
					"startActivity", 
					"startService", 
					"sendBroadcast" 
				], 
				"title": "write", 
				"key": "resultIntentType" 
			}, 
			{ 
				"restrictionType": "hidden", 
				"defaultValue": { 
					"valueString": "{resultIntentAction}", 
					"type": "hidden" 
				}, 
				"description": "Specifies the action name for the Intent that will be sent by OEMConfig", 
				"title": "write", 
				"key": "resultIntentAction" 
			}, 
			{ 
				"restrictionType": "hidden", 
				"defaultValue": { 
					"valueString": "{resultIntentComponent}", 
					"type": "hidden" 
				}, 
				"description": "Specifies the component name to which the Intent will be sent by OEMConfig", 
				"title": "write", 
				"key": "resultIntentComponent" 
			}, 
			{ 
			"restrictionType": "hidden", 
			"defaultValue": { 
				"valueString": "{resultIntentExtraName}", 
				"type": "hidden" 
			}, 
				"description": "Specifies the name of a string extra to be attached the Intent", 
				"title": "write", 
				"key": "resultIntentExtraName" 
			}, 
			{ 
			"restrictionType": "hidden", 
			"defaultValue": { 
				"valueString": "{resultIntentExtraValue}", 
				"type": "hidden" 
			}, 
				"description": "Specifies the value of a string extra to be attached the Intent", 
				"title": "write", 
				"key": "resultIntentExtraValue" 
			}, 
			{ 
			"restrictionType": "bundleArray", 
			"nestedRestriction": [
		 		{ 
		 		"restrictionType": "bundle", 
		 		"nestedRestriction": [ 
					{ 
					"restrictionType": "bundle", 
					"nestedRestriction": [
		 				{ 
						"entry": [ "Off", 
						"On" 
					], 
						"restrictionType": "choice", 
						"description": "Enables the use of the back camera", 
						"entryValue": [ 
							"2", 
							"1" 
						], 
						"title": "Camera Configuration - Back Camera", 
						"key": "cameraUseOfBack" 
					}, 
					{ 
						"entry": [ "Off", 
						"On" 
					], 
					"restrictionType": "choice", 
					"description": "Enables the use of the front camera", 
					"entryValue": [ 
						"2", 
						"1" 
					], 
					"title": "Camera Configuration - Front Camera", 
					"key": "cameraUseOfFront" 
					} 
				], 
				"description": "Camera configuration of OEMConfig Step", 
				"title": "Camera Configuration", 
				"key": "cameraStep" 
				}, 
				{ 
				"restrictionType": "bundle", "nestedRestriction": [
		 			{ "entry": [ 
						"Manual", 
						"Auto" 
					], 
					"restrictionType": "choice", 
					"defaultValue": { 
						"valueString": "0xffffffff", 
						"type": "choice" 
					}, 
					"description": "Specifies if the time is configured manually or automatically", 
					"entryValue": [ 
						"false", 
						"true" 
					], 
					"title": "Clock Configuration - Time Mode", 
					"key": "clockTimeMode" 
					},
		 			{ 
		 			"restrictionType": "string", 
		 			"description": "Specifies the date in manual date mode", 
		 			"title": "Clock Configuration - Manual Date", 
		 			"key": "clockManualDate" 
					},
		 			{ 
		 			"restrictionType": "string", 
		 			"description": "Specifies the time in manual time mode", 
		 			"title": "Clock Configuration - Manual Time", 
		 			"key": "clockManualTime" 
					}, 
					{ 
					"entry": [ 
					"Manual", 
					"Auto" 
					], 
					"restrictionType": "choice", 
					"defaultValue": { 
						"valueString": "Auto", 
						"type": "choice" 
					}, 
					"description": "Specifies if the time zone is configured manually or automatically", 
					"entryValue": [ 
						"false", 
						"true" 
					], 
					"title": "Clock Configuration - Time Zone Mode", 
					"key": "clockTimeZoneMode" 
					},
		 			{ 
		 				"restrictionType": "string", 
		 				"description": "Specifies the time zone in manual time zone mode", 
		 				"title": "Clock Configuration - Manual Time Zone", 
		 				"key": "clockManualTimeZone" 
					}, 
					{ 
						"entry": [ 
						"12", 
						"24" 
					], 
					"restrictionType": "choice", 
					"defaultValue": { 
						"valueString": "12", 
						"type": "choice" 
					}, 
					"description": "Specifies whether time is 12 hour or 24 hour", 
					"entryValue": [ 
						"2", 
						"1" 
					], 
					"title": "Clock Configuration - Time Format", 
					"key": "clockTimeFormat" 
					} 
				], 
				"description": "Clock configuration of OEMConfig Step", 
				"title": "Clock Configuration", 
				"key": "clockStep" 
				} 
			], 
			"description": "Specifies an OEMConfig Step by specifying an unordered set of operations to be performed as 
		part of that Step", 
			"title": "OEMConfig Step",
			"key": "step" 
			} 
		], 
		"description": "Specifies a series of Steps to be performed by OEMConfig", 
		"title": "Steps", 
		"key": "steps" 
		}
		]
	}
} 

© 2018 Google Inc. All rights reserved. Google and the Google logo are trademarks of Google Inc. All other company and product names may be trademarks of the respective companies with which they are associated. [03-2018-en-002.01]