Cracking Android Open Accessory transactions

This post aims to help the readers with two key learning , first to give an insight into  how the  Linux USB sniffer tools provided data can help in the analysis of complex interactions between USB devices . Second by deciding to use it to understand the flow of events between the Accessory and Android devices ,following this post one can gain a better understanding of how the Android Open Accessory protocol implementation works.

Big Buzz around AOA!!!

Android allows connections of Accessories (usb hosts) to Android powered devices by implementing the Android Open Accessory APIs for Android. These APIs allow USB accessories to connect to Android devices running Android 3.1 or Android 2.3.4 without special licensing or fees. The new “accessory mode” does not require the Android device to support USB Host mode. But Android also has the USB Host mode APIs for devices with hardware capable of supporting it.

The USB protocol defines the participants capability as either “HOST”   or “DEVICES”. USB is an asymmetric protocol in that one participant acts as a USB Host and all other participants are USB Devices. In the PC world, a laptop or desktop acts as Host and your printer, mouse, webcam, etc., is the USB Device.The USB host servers as the master for the bus and is responsible for enumeration of the devices connected to the bus and to control the way the devices sends the data over the bus. USB being a powered bus ,the USB host has to supply the power to the bus.   While working with accessories ,the android powered devices such as Android phones or tablet act as the USB device and the accessory is something like a PC or an infotainment head unit implementing Android Auto and wants to control the device act as USB host.

Android Auto as accessory

The following section will explain the highlights of interactions between the Accessory and device for the Android Auto ,the remote screen projection protocol v1.0 implemented by Google on AoA v2.0. The intention of this is to explain how to see the  USB data flow traces from  usbmon log and compare them with the sequences that being explained in the Android Open Accessory interaction scneario . Thus for this learning setup , you need to have the Android Head Unit Simulator on your workstation (Windows/ or Linux) ,Android names it as, DHU ( Desktop Head Unit ) which makes the workstation as accessory to work with the Android powered device (smartphone or tablets ) . The smartphone should have Android Auto application .If you are new to Google Android Auto ,then you may need to start from here to understand Android Auto aswell as the capabilities of the simulator and the test setup.

Thus in my verification setup I connected the Android phone from HTC , and the model, which support the android Accessory .The phone is connected to the Android Head Unit simulator running on the PC which simulates the android accessory functions . Then ran the USB sniffing tools to capture the logs of the interactions.

Setup the USB bus sniffing tools

Now setup the usbmon and capture the logs as explained in the post USB sniffing methods in linux.

Once the trace is complete ,it captures the data trace in the .pcap format .The following section list the details of the interactions as seen by analyzing the log using wire shark.

Android Accessory Protocol

The Accessory protocol establishes the bi-directional connection between the device and accessory by performing a handshake.  In the collaboration model,accessory has the role to detect the connection of the device and way to exchange the commands and query the status to ascertain whether the device is capable of supporting the accessory driven functionality.

While sequencing the handshaking operations  , The Android device will identify itself with the VID/PID that is appropriate based on the manufacturer and model of the device. The accessory then sends a control transaction to the Android device asking if it supports accessory mode. Once the accessory confirms the Android device supports accessory mode, sets the device with appropriate address and start to query the capabilities of the device to understand the interface classes and the end points for data exchange. The accessory sends a  series of request as  strings as per the supported AoA protocol version to the Android device using control transactions. These strings allow the Android device to identify compatible applications as well as provide a URL that Android will use if a suitable app is not found. Next the accessory sends a control transaction to the Android device telling it to enter accessory mode.

The Android device then drops off the bus and reappears with a new VID/PID combination. The new VID/PID corresponds to a device in accessory mode, which is Google’s VID 0x18D1, and PID 0x2D01 or 0x2D00. Once an appropriate application is started on the Android side, the accessory can now communicate with it using the first Bulk IN and Bulk OUT endpoints.

So when the Android device is plugged to a host running Linux OS ,the device properties are shown as Vendor ID and property ID of the original equipment manufacturer ,when the accessory first detects the device. To verify the properties of the device,the easiest way in Linux systems is to get the info using udevadm ,the control utility of the udev device manager shows a log as similar given  below.

$ udevadm moniotor -u –property

UDEV  [140.867635] add      /devices/soc0/soc.1/2100000.aips-bus/2184200.usb/ci_hdrc.1/usb1/1-1 (usb)

ACTION=add

BUSNUM=001

DEVNAME=/dev/bus/usb/001/002

DEVNUM=002

DEVPATH=/devices/soc0/soc.1/2100000.aips-bus/2184200.usb/ci_hdrc.1/usb1/1-1

DEVTYPE=usb_device

ID_BUS=usb

ID_FOR_SEAT=usb-platform-ci_hdrc_1-usb-0_1

ID_MODEL=Android_Phone

ID_MODEL_ENC=Android\x20Phone

ID_MODEL_ID=0f25

ID_PATH=platform-ci_hdrc.1-usb-0:1

ID_PATH_TAG=platform-ci_hdrc_1-usb-0_1

ID_REVISION=0232

ID_SERIAL=HTC_Android_Phone_HT485WM02462

ID_SERIAL_SHORT=HT485WM02462

ID_USB_INTERFACES=:060101:080650:

ID_VENDOR=HTC

ID_VENDOR_ENC=HTC

ID_VENDOR_FROM_DATABASE=HTC (High Tech Computer Corp.)

ID_VENDOR_ID=0bb4

MAJOR=189

MINOR=1

PRODUCT=bb4/f25/232

SEQNUM=1455

SUBSYSTEM=usb

TAGS=:seat:uaccess:

TYPE=0/0/0

USEC_INITIALIZED=742946

Thus from the log , one can infer the device connected is recognized as Android device , manufactured by HTC with the Vendor ID 0x0bb4.  Subsequently the HOST erforms the verification to decide whether the device supports accessory and initiate a role switch to device accessory mode.

The protocol is easy to implement on your accessory  with the ADK but any accessory that has the required hardware and speaks the protocol described here and laid out in detail in the documentation can function as an Android Open Accessory.

Once the Accessory establish successful connection with the device upon sensing the device connection as stable,the subsequent response to the GET_STATUS query from the device is shows up as Connection status , device enabled and power status as TRUE.

Protocol Length Info199 19.261952   1.0                   host                  USBHUB   68     GET_STATUS Response    [Port 1]

Frame 199: 68 bytes on wire (544 bits), 68 bytes captured (544 bits)

USB URB

URB id: 0x00000000a05d5280

URB type: URB_COMPLETE (‘C’)

URB transfer type: URB_CONTROL (0x02)

Endpoint: 0x80, Direction: IN

1… …. = Direction: IN (1)

.000 0000 = Endpoint value: 0

Device: 1

URB bus id: 1

[bInterfaceClass: Unknown (0xffff)]

Port Status: 0x0503, PORT_CONNECTION, PORT_ENABLE, PORT_POWER, PORT_HIGH_SPEED

    …. …. …. …1 = PORT_CONNECTION: True

    …. …. …. ..1. = PORT_ENABLE: True

    …. …. …. .0.. = PORT_SUSPEND: False

    …. …. …. 0… = PORT_OVER_CURRENT: False

    …. …. …0 …. = PORT_RESET: False

    …. …1 …. …. = PORT_POWER: True

    …. ..0. …. …. = PORT_LOW_SPEED: False

    …. .1.. …. …. = PORT_HIGH_SPEED: True

    …. 0… …. …. = PORT_TEST: False

    …0 …. …. …. = PORT_INDICATOR: Default colors

Determine The Device’s Accessory Mode Support

Once after the device is connected , the accessory need to verify the support of accessory mode in the device, send a “Get Device Descriptor” request to address “0” and then a “Set Address” command to set the address of the device to the desired value.

USB      64     SET ADDRESS Request

Frame 202: 64 bytes on wire (512 bits), 64 bytes captured (512 bits)

USB URB

Device: 0

URB bus id: 1

[…]

URB setup

bmRequestType: 0x00

 bRequest: SET ADDRESS (5)

    Device: 15

Subsequently ,accessory , send all subsequent USB requests to this new address to see if the device is responding to the new address. Send the “Get Device Descriptor” and “Get Configuration” requests. This is not a mandatory step.

Seventh, check if the PID_VID of the attached device matches with the Google PID_VID. After sending the “Get Device Descriptor” request, fetch the PID_VID details of the device from the descriptor received. The product ID (PID) and vendor ID (VID) of the device will typically be the device manufacturer’s IDs.

USB      82     GET DESCRIPTOR Response DEVICE

Frame 205: 82 bytes on wire (656 bits), 82 bytes captured (656 bits)

USB URB

Endpoint: 0x80, Direction: IN

1… …. = Direction: IN (1)

.000 0000 = Endpoint value: 0

Device: 15

URB bus id: 1

Device setup request: not relevant (‘-‘)

Data: present (0)

DEVICE DESCRIPTOR

bMaxPacketSize0: 64

 idVendor: Google Inc. (0x18d1)

    idProduct: Android-powered device in accessory mode (0x2d00)

bcdDevice: 0x0232

iManufacturer: 1

iProduct: 2

iSerialNumber: 3

bNumConfigurations: 1

How can you confirm device supports accessory mode?

If the device supports and is active in AOA mode, it will respond with Google’s VID (VID==0x18D1) and PID (PID==0x2D00||PID==0x2D01) instead of the device manufacturer’s IDs. If the device is detected with the Google ID, the accessory can conclude that the found Android device supports AOA and it can establish communication with the device.

Frame 130: 64 bytes on wire (512 bits), 64 bytes captured (512 bits)USB URB

URB id: 0x00000000a9251500

URB type: URB_SUBMIT (‘S’)

URB transfer type: URB_CONTROL (0x02)

[Response in: 131]

URB setup

bmRequestType: 0xc0

   bRequest: 51

wValue: 0x0000

This request returns a non-zero number if the AOA protocol is supported, with the exact value representing the version of the protocol that the device supports (AOA 1 or AOA 2). If zero is returned, the device is not AOA compliant and the accessory should wait for the next device to be connected. Attempt to start the device in accessory mode if needed.

For this device responded as 0200 => A0A v2 protocol.

Start The Device In Accessory Mode If Needed

Now in this stage the accessory present the device with its services or capabilities, by sending identifying string information to the device. This information allows the device to figure out an appropriate application (installed on the device) for the accessory or present the user with a uniform resource identifier (URI) if an appropriate application does not exist. These requests are control requests on endpoint 0 to the device

Here the request : 0x53 send from the accessory to the device in the format Index : Data ,  where the index indicate the string index [0-5] and the associated data . For example the String index 2 ,corresponds to the protocol description. For my setup which has initiated with the Android Auto Accessory, the transactions are read as…

USB      97     URB_CONTROL outFrame 136: 97 bytes on wire (776 bits), 97 bytes captured (776 bits)

USB URB

URB id: 0x00000000a9251500

URB type: URB_SUBMIT (‘S’)

URB transfer type: URB_CONTROL (0x02)

Endpoint: 0x00, Direction: OUT

0… …. = Direction: OUT (0)

.000 0000 = Endpoint value: 0

Device: 14

URB bus id: 1

Device setup request: relevant (0)

Data: present (0)

URB sec: 1420098547

URB usec: 121529

URB status: Operation now in progress (-EINPROGRESS) (-115)

URB length [bytes]: 33

Data length [bytes]: 33

[Response in: 137]

URB setup

bmRequestType: 0x40

 bRequest: 52

wValue: 0x0000

wIndex: 2

    wLength: 33

Leftover Capture Data: 416e64726f6964204f70656e204175746f6d6f7469766520…

The hex string 416e6472……..is the data string reading “Android Open Automotive Protocol”

Once this is done, the device is started in the accessory mode by issuing the request 0x53.

USB      64     URB_CONTROL outFrame 144: 64 bytes on wire (512 bits), 64 bytes captured (512 bits)

USB URB

URB id: 0x00000000a9251500

URB type: URB_SUBMIT (‘S’)

URB transfer type: URB_CONTROL (0x02)

Endpoint: 0x00, Direction: OUT

0… …. = Direction: OUT (0)

.000 0000 = Endpoint value: 0

Device: 14

URB bus id: 1

[Response in: 145]

URB setup

bmRequestType: 0x40

bRequest: 53

wValue: 0x0000

wIndex: 0

wLength: 0

Complete endpoint configuration using the “Get Configuration” request. The AOA Protocol communicates over 1 Bulk In and 1 Bulk Out endpoint only. An Android device that has a PID of 0x2D00 has one interface with two bulk endpoints for input and output communication. The PID of 0x2D01 provides an extra interface for ADB (Android Debug Bridge) communication. For devices with either PID, configuration 1 should be active, and communication can happen over the first Bulk In and first Bulk Out endpoint.

Finally, start your application on the accessory to communicate with the Android device as the USB slave. This concludes the process.

USB      82     GET DESCRIPTOR Response DEVICEPacket comments

Frame 251: 82 bytes on wire (656 bits), 82 bytes captured (656 bits)

USB URB

URB id: 0x00000000a05d5400

URB type: URB_COMPLETE (‘C’)

URB transfer type: URB_CONTROL (0x02)

Endpoint: 0x80, Direction: IN

1… …. = Direction: IN (1)

.000 0000 = Endpoint value: 0

Device: 15

URB bus id: 1

Device setup request: not relevant (‘-‘)

Data: present (0)

URB sec: 1420098550

URB usec: 470024

URB status: Success (0)

URB length [bytes]: 18

Data length [bytes]: 18

[Request in: 250]

[Time from request: 0.000179000 seconds]

[bInterfaceClass: Unknown (0xffff)]

DEVICE DESCRIPTOR

bLength: 18

bDescriptorType: DEVICE (1)

bcdUSB: 0x0210

bDeviceClass: Device (0x00)

bDeviceSubClass: 0

bDeviceProtocol: 0 (Use class code info from Interface Descriptors)

bMaxPacketSize0: 64

idVendor: Google Inc. (0x18d1)

idProduct: Android-powered device in accessory mode (0x2d00)

bcdDevice: 0x0232

iManufacturer: 1

iProduct: 2

iSerialNumber: 3

bNumConfigurations: 1

Frame 257: 96 bytes on wire (768 bits), 96 bytes captured (768 bits)

USB URB

URB id: 0x00000000a05d5400

URB type: URB_COMPLETE (‘C’)

URB transfer type: URB_CONTROL (0x02)

Endpoint: 0x80, Direction: IN

1… …. = Direction: IN (1)

.000 0000 = Endpoint value: 0

Device: 15

URB bus id: 1

Device setup request: not relevant (‘-‘)

Data: present (0)

URB sec: 1420098550

URB usec: 470648

URB status: Success (0)

URB length [bytes]: 32

Data length [bytes]: 32

[Request in: 256]

[Time from request: 0.000218000 seconds]

[bInterfaceClass: Unknown (0xffff)]

CONFIGURATION DESCRIPTOR

bLength: 9

bDescriptorType: CONFIGURATION (2)

wTotalLength: 32

 bNumInterfaces: 1

bConfigurationValue: 1

iConfiguration: 0

Configuration bmAttributes: 0xc0  SELF-POWERED  NO REMOTE-WAKEUP

bMaxPower: 250  (500mA)

INTERFACE DESCRIPTOR (0.0): class Vendor Specific

bLength: 9

bDescriptorType: INTERFACE (4)

bInterfaceNumber: 0

bAlternateSetting: 0

bNumEndpoints: 2

bInterfaceClass: Vendor Specific (0xff)

bInterfaceSubClass: 0xff

bInterfaceProtocol: 0x00

iInterface: 6

ENDPOINT DESCRIPTOR

bLength: 7

bDescriptorType: ENDPOINT (5)

 bEndpointAddress: 0x81  IN  Endpoint:1

bmAttributes: 0x02

wMaxPacketSize: 512

bInterval: 0

ENDPOINT DESCRIPTOR

bLength: 7

bDescriptorType: ENDPOINT (5)

 bEndpointAddress: 0x02  OUT  Endpoint:2

bmAttributes: 0x02

wMaxPacketSize: 512

bInterval: 0

The accessory and device now exchange the data via these endpoints.

A sample transaction is shown

Frame 275: 72 bytes on wire (576 bits), 72 bytes captured (576 bits)USB URB

URB id: 0x00000000a896e800

URB type: URB_SUBMIT (‘S’)

URB transfer type: URB_BULK (0x03)

Endpoint: 0x02, Direction: OUT

0… …. = Direction: OUT (0)

        .000 0010 = Endpoint value: 2

Device: 15

URB bus id: 1

Device setup request: not relevant (‘-‘)

Data: present (0)

URB sec: 1420098551

URB usec: 254348

URB status: Operation now in progress (-EINPROGRESS) (-115)

URB length [bytes]: 8

Data length [bytes]: 8

[Response in: 277]

[bInterfaceClass: Vendor Specific (0xff)]

Leftover Capture Data: 0003000400040800

No.     Time        Source                Destination           Protocol Length Info

276 22.736617   15.2                  host                  USB      64     URB_BULK out

Frame 276: 64 bytes on wire (512 bits), 64 bytes captured (512 bits)

USB URB

URB id: 0x00000000a896e800

  URB type: URB_COMPLETE (‘C’)

    URB transfer type: URB_BULK (0x03)

Endpoint: 0x02, Direction: OUT

0… …. = Direction: OUT (0)

.000 0010 = Endpoint value: 2

Device: 15

URB bus id: 1

Device setup request: not relevant (‘-‘)

Data: not present (‘>’)

URB sec: 1420098551

URB usec: 254528

URB status: Success (0)

URB length [bytes]: 8

Data length [bytes]: 0

[Request in: 275]

[Time from request: 0.000180000 seconds]

[bInterfaceClass: Vendor Specific (0xff)]

No.     Time        Source                Destination           Protocol Length Info

277 22.776379   15.1                  host                  USB      4160   URB_BULK in

Frame 277: 4160 bytes on wire (33280 bits), 4160 bytes captured (33280 bits)

USB URB

URB id: 0x00000000a9b04900

 URB type: URB_COMPLETE (‘C’)

    URB transfer type: URB_BULK (0x03)

Endpoint: 0x81, Direction: IN

1… …. = Direction: IN (1)

.000 0001 = Endpoint value: 1

Device: 15

URB bus id: 1

Device setup request: not relevant (‘-‘)

Data: present (0)

URB sec: 1420098551

URB usec: 294290

URB status: Success (0)

URB length [bytes]: 4096

Data length [bytes]: 4096

[Request in: 275]

[Time from request: 0.039942000 seconds]

[bInterfaceClass: Vendor Specific (0xff)]

Leftover Capture Data: 000b1431170303142c9ac18a0ae46424c80948c1227375f8…

Hope this helped you to gain some insight of Android Accessories behavior and the approach to crack the complex transactions happening through the USB .

Meanwhile you are either waiting for your USB-Host board or deciding if you even want to get one at all. At that point we would like to share a way of how to write your first “Hello World” application using your Linux Desktop/Laptop (we use Ubuntu …).

Your Desktop/Laptop probably has a USB host controller. This opens you all doors to write accessory applications using “libusb”. The link has reference to some C code as a template that let’s you act as Accessory on Linux side.

simplectrl.c

Leave a comment