Android USB accessories must adhere to the Android Open Accessory (AOA) protocol, which defines how an accessory detects and sets up communication with an Android-powered device. Accessories should carry out the following steps:
- Wait for and detect a connected device.
- Determine the device's accessory mode support.
- Attempt to start the device in accessory mode (if needed).
- If the device supports AOA, establish communication with the device.
The following sections explain how to implement these steps.
Wait for and detect connected devices
Accessories should continuously check for connected Android-powered devices. When a device is connected, the accessory should determine if the device supports accessory mode.
Determine accessory mode support
When an Android-powered device connects, it can be in one of three states:
- Supports Android accessory mode and is already in accessory mode.
- Supports Android accessory mode but it is not in accessory mode.
- Does not support Android accessory mode.
During the initial connection, the accessory should check the version, vendor ID,
and product ID of the connected device's USB device descriptor. The vendor ID
should match Google's ID (
0x18D1). If the device is already in
accessory mode, the product ID should be
0x2D01 and the accessory can
establish communication with
the device through bulk transfer endpoints using its own communication
protocol (the device does not need to be started in accessory mode).
0x2D00 is reserved for
Android-powered devices that support accessory mode.
reserved for devices that support accessory mode as well as the Android Debug
Bridge (ADB) protocol, which exposes a second interface with two bulk endpoints
for ADB. You can use these endpoints for debugging the accessory application if
you are simulating the accessory on a computer. In general, do not use this
interface unless the accessory implements a passthrough to ADB on the device.
If the version, vendor ID, or product ID in the USB device descriptor do not match expected values, the accessory cannot determine if the device supports Android accessory mode. The accessory should attempt to start the device in accessory mode (detailed below) to determine device support.
Key point: A USB accessory must send a header upon initial handshake. The header contains the manufacturer, model, and version. Though version is an optional field, if an Android app is installed that only matches on version, but the accessory doesn't send a version, Android devices running on Android 10 and below will reboot due to an exception being thrown in the system process.
Attempt to start in accessory mode
If the version, vendor, and product IDs do not correspond to an Android-powered device in accessory mode, the accessory cannot determine if the device supports (but is not in) accessory mode or if the device does not support accessory mode. This can occur because devices that support accessory mode (but are not in accessory mode) initially report the device manufacturer vendor and product IDs instead of the AOA vendor and product IDs.
The accessory should try to start the device in accessory mode to determine if the device supports that mode:
- Send a 51 control request ("Get Protocol") to determine if the device
supports the Android accessory protocol. If the device supports the protocol,
it returns a non-zero number that represents the supported protocol version.
The control request is on endpoint 0 with the following characteristics:
requestType: USB_DIR_IN | USB_TYPE_VENDOR request: 51 value: 0 index: 0 data: protocol version number (16 bits little endian sent from the device to the accessory)
- If the device returns a supported protocol version, send a control request
with identifying string information to the device. This information allows the
device to determine an appropriate application for the accessory (or present a
URL to the user if an appropriate application does not exist). The control
request is on endpoint 0 (for each string ID) with the following
requestType: USB_DIR_OUT | USB_TYPE_VENDOR request: 52 value: 0 index: string ID data zero terminated UTF8 string sent from accessory to device
The following string IDs are supported, with a maximum size of 256 bytes for each string (must be zero-terminated with
manufacturer name: 0 model name: 1 description: 2 version: 3 URI: 4 serial number: 5
- Send a control request to ask the device to start in accessory mode. The
control request is on endpoint 0 with the following characteristics:
requestType: USB_DIR_OUT | USB_TYPE_VENDOR request: 53 value: 0 index: 0 data: none
After completing these steps, the accessory should wait for the connected USB device to re-introduce itself on the bus in accessory mode, then re-enumerate connected devices. The algorithm determines accessory mode support by checking the vendor and product IDs, which should be correct (for example, correspond to Google's vendor and product IDs instead of to the device manufacturer's IDs) if the device successfully switched to accessory mode. If IDs and version are correct, the accessory moves to establish communication with the device.
Note: AOA does not currently support simultaneous AOA and MTP connections. To switch from AOA to MTP, the accessory must first disconnect the USB device (either physically or in an electrically equivalent way) and then reconnect using MTP.
If any step fails, the accessory determines the device does not support Android accessory mode and waits for the next device to connect.
Establish communication with the device
If the accessory detects an Android-powered device in accessory mode, the accessory can query the device interface and endpoint descriptors to obtain the bulk endpoints for communicating with the device.
The number of interfaces and bulk endpoints depends on the product ID. An Android-powered device with a product ID of:
0x2D00has one interface with two bulk endpoints for input and output communication.
0x2D01has two interfaces with two bulk endpoints each for input and output communication. The first interface handles standard communication and the second interface handles ADB communication. To use an interface, locate the first bulk input and output endpoints, set the device configuration to a value of 1 with a
0x09) device request, then communicate using the endpoints.