Eliminate native/JNI/callback USB Descriptor parsing mechanism

Also optimized connection mechanism.

Bug: 68008691
Bug: 68337205
Test: Manual
Devices - Skylab, Mir, HTC dongle, Presonus AudioBox 44VSL, HP mouse

Change-Id: I287bcdd251b38d2a5cbd37bca1a80bf7f7b0a265
diff --git a/services/core/jni/com_android_server_UsbDescriptorParser.cpp b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
index df85e31..35e65bc 100644
--- a/services/core/jni/com_android_server_UsbDescriptorParser.cpp
+++ b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
@@ -17,16 +17,18 @@
 #define LOG_TAG "UsbHostManagerJNI"
 #include "utils/Log.h"
 
+#include <stdlib.h>
+
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 
 #include <usbhost/usbhost.h>
 
-#define MAX_DESCRIPTORS_LENGTH 16384
+#define MAX_DESCRIPTORS_LENGTH 4096
 
 // com.android.server.usb.descriptors
 extern "C" {
-jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors(
+jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors_1native(
         JNIEnv* env, jobject thiz, jstring deviceAddr) {
     const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL);
     struct usb_device* device = usb_device_open(deviceAddrStr);
@@ -39,6 +41,7 @@
 
     int fd = usb_device_get_fd(device);
     if (fd < 0) {
+        usb_device_close(device);
         return NULL;
     }
 
@@ -46,17 +49,48 @@
     jbyte buffer[MAX_DESCRIPTORS_LENGTH];
     lseek(fd, 0, SEEK_SET);
     int numBytes = read(fd, buffer, sizeof(buffer));
-
+    jbyteArray ret = NULL;
     usb_device_close(device);
 
-    jbyteArray ret = NULL;
-    if (numBytes != 0) {
+    if (numBytes > 0) {
         ret = env->NewByteArray(numBytes);
         env->SetByteArrayRegion(ret, 0, numBytes, buffer);
+    } else {
+        ALOGE("error reading descriptors\n");
     }
+
     return ret;
 }
 
+jstring JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getDescriptorString_1native(
+        JNIEnv* env, jobject thiz, jstring deviceAddr, jint stringId) {
+
+    const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL);
+    struct usb_device* device = usb_device_open(deviceAddrStr);
+    env->ReleaseStringUTFChars(deviceAddr, deviceAddrStr);
+
+    if (!device) {
+        ALOGE("usb_device_open failed");
+        return NULL;
+    }
+
+    int fd = usb_device_get_fd(device);
+    if (fd < 0) {
+        ALOGE("usb_device_get_fd failed");
+        usb_device_close(device);
+        return NULL;
+    }
+
+    char* c_str = usb_device_get_string(device, stringId, 0 /*timeout*/);
+
+    jstring j_str = env->NewStringUTF(c_str);
+
+    free(c_str);
+    usb_device_close(device);
+
+    return j_str;
+}
+
 } // extern "C"
 
 
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index 88ae824..11f508b 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -22,8 +22,6 @@
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/Log.h"
 
-#include <usbhost/usbhost.h>
-
 #include <stdio.h>
 #include <asm/byteorder.h>
 #include <sys/types.h>
@@ -31,22 +29,20 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 
+#include <usbhost/usbhost.h>
+
+#define MAX_DESCRIPTORS_LENGTH 4096
+
 namespace android
 {
 
-static const int USB_CONTROL_TRANSFER_TIMEOUT_MS = 200;
-
 static struct parcel_file_descriptor_offsets_t
 {
     jclass mClass;
     jmethodID mConstructor;
 } gParcelFileDescriptorOffsets;
 
-static jmethodID method_beginUsbDeviceAdded;
-static jmethodID method_addUsbConfiguration;
-static jmethodID method_addUsbInterface;
-static jmethodID method_addUsbEndpoint;
-static jmethodID method_endUsbDeviceAdded;
+static jmethodID method_usbDeviceAdded;
 static jmethodID method_usbDeviceRemoved;
 
 static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
@@ -57,101 +53,63 @@
     }
 }
 
-static int usb_device_added(const char *devname, void* client_data) {
-    struct usb_descriptor_header* desc;
-    struct usb_descriptor_iter iter;
-
-    struct usb_device *device = usb_device_open(devname);
+static int usb_device_added(const char *devAddress, void* clientData) {
+    struct usb_device *device = usb_device_open(devAddress);
     if (!device) {
         ALOGE("usb_device_open failed\n");
         return 0;
     }
 
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jobject thiz = (jobject)client_data;
     const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device);
+    int classID = deviceDesc->bDeviceClass;
+    int subClassID = deviceDesc->bDeviceSubClass;
 
-    char *manufacturer = usb_device_get_manufacturer_name(device,
-            USB_CONTROL_TRANSFER_TIMEOUT_MS);
-    char *product = usb_device_get_product_name(device,
-            USB_CONTROL_TRANSFER_TIMEOUT_MS);
-    int version = usb_device_get_version(device);
-    char *serial = usb_device_get_serial(device,
-            USB_CONTROL_TRANSFER_TIMEOUT_MS);
-
-    jstring deviceName = env->NewStringUTF(devname);
-    jstring manufacturerName = AndroidRuntime::NewStringLatin1(env, manufacturer);
-    jstring productName = AndroidRuntime::NewStringLatin1(env, product);
-    jstring serialNumber = AndroidRuntime::NewStringLatin1(env, serial);
-
-    jboolean result = env->CallBooleanMethod(thiz, method_beginUsbDeviceAdded,
-            deviceName, usb_device_get_vendor_id(device), usb_device_get_product_id(device),
-            deviceDesc->bDeviceClass, deviceDesc->bDeviceSubClass, deviceDesc->bDeviceProtocol,
-            manufacturerName, productName, version, serialNumber);
-
-    env->DeleteLocalRef(serialNumber);
-    env->DeleteLocalRef(productName);
-    env->DeleteLocalRef(manufacturerName);
-    env->DeleteLocalRef(deviceName);
-    free(manufacturer);
-    free(product);
-    free(serial);
-
-    if (!result) goto fail;
-
-    usb_descriptor_iter_init(device, &iter);
-
-    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
-        if (desc->bDescriptorType == USB_DT_CONFIG) {
-            struct usb_config_descriptor *config = (struct usb_config_descriptor *)desc;
-            char *name = usb_device_get_string(device, config->iConfiguration,
-                    USB_CONTROL_TRANSFER_TIMEOUT_MS);
-            jstring configName = AndroidRuntime::NewStringLatin1(env, name);
-
-            env->CallVoidMethod(thiz, method_addUsbConfiguration,
-                    config->bConfigurationValue, configName, config->bmAttributes,
-                    config->bMaxPower);
-
-            env->DeleteLocalRef(configName);
-            free(name);
-        } else if (desc->bDescriptorType == USB_DT_INTERFACE) {
-            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
-            char *name = usb_device_get_string(device, interface->iInterface,
-                    USB_CONTROL_TRANSFER_TIMEOUT_MS);
-            jstring interfaceName = AndroidRuntime::NewStringLatin1(env, name);
-
-            env->CallVoidMethod(thiz, method_addUsbInterface,
-                    interface->bInterfaceNumber, interfaceName, interface->bAlternateSetting,
-                    interface->bInterfaceClass, interface->bInterfaceSubClass,
-                    interface->bInterfaceProtocol);
-
-            env->DeleteLocalRef(interfaceName);
-            free(name);
-        } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
-            struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)desc;
-
-            env->CallVoidMethod(thiz, method_addUsbEndpoint,
-                    endpoint->bEndpointAddress, endpoint->bmAttributes,
-                    __le16_to_cpu(endpoint->wMaxPacketSize), endpoint->bInterval);
-        }
+    // get the raw descriptors
+    int fd = usb_device_get_fd(device);
+    if (fd < 0) {
+        ALOGE("usb_device_get_fd failed\n");
+        usb_device_close(device);
+        // TODO return an error code here?
+        return 0;
     }
 
-    env->CallVoidMethod(thiz, method_endUsbDeviceAdded);
+    // from android_hardware_UsbDeviceConnection_get_desc()
+    jbyte rawdescriptors[MAX_DESCRIPTORS_LENGTH];
+    lseek(fd, 0, SEEK_SET);
+    int numBytes = read(fd, rawdescriptors, sizeof(rawdescriptors));
 
-fail:
     usb_device_close(device);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+    if (numBytes > 0) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        jobject thiz = (jobject)clientData;
+        jstring deviceAddress = env->NewStringUTF(devAddress);
+
+        jbyteArray descriptorsArray = env->NewByteArray(numBytes);
+        env->SetByteArrayRegion(descriptorsArray, 0, numBytes, rawdescriptors);
+
+        env->CallBooleanMethod(thiz, method_usbDeviceAdded,
+                deviceAddress, classID, subClassID, descriptorsArray);
+
+        env->DeleteLocalRef(descriptorsArray);
+        env->DeleteLocalRef(deviceAddress);
+
+        checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    } else {
+        // TODO return an error code here?
+        ALOGE("error reading descriptors\n");
+    }
 
     return 0;
 }
 
-static int usb_device_removed(const char *devname, void* client_data) {
+static int usb_device_removed(const char *devAddress, void* clientData) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jobject thiz = (jobject)client_data;
+    jobject thiz = (jobject)clientData;
 
-    jstring deviceName = env->NewStringUTF(devname);
-    env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceName);
-    env->DeleteLocalRef(deviceName);
+    jstring deviceAddress = env->NewStringUTF(devAddress);
+    env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceAddress);
+    env->DeleteLocalRef(deviceAddress);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return 0;
 }
@@ -168,11 +126,11 @@
 }
 
 static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* thiz */,
-                                                        jstring deviceName)
+                                                        jstring deviceAddress)
 {
-    const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
-    struct usb_device* device = usb_device_open(deviceNameStr);
-    env->ReleaseStringUTFChars(deviceName, deviceNameStr);
+    const char *deviceAddressStr = env->GetStringUTFChars(deviceAddress, NULL);
+    struct usb_device* device = usb_device_open(deviceAddressStr);
+    env->ReleaseStringUTFChars(deviceAddress, deviceAddressStr);
 
     if (!device)
         return NULL;
@@ -206,34 +164,12 @@
         ALOGE("Can't find com/android/server/usb/UsbHostManager");
         return -1;
     }
-    method_beginUsbDeviceAdded = env->GetMethodID(clazz, "beginUsbDeviceAdded",
-            "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;ILjava/lang/String;)Z");
-    if (method_beginUsbDeviceAdded == NULL) {
+    method_usbDeviceAdded =
+            env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;II[B)Z");
+    if (method_usbDeviceAdded == NULL) {
         ALOGE("Can't find beginUsbDeviceAdded");
         return -1;
     }
-    method_addUsbConfiguration = env->GetMethodID(clazz, "addUsbConfiguration",
-            "(ILjava/lang/String;II)V");
-    if (method_addUsbConfiguration == NULL) {
-        ALOGE("Can't find addUsbConfiguration");
-        return -1;
-    }
-    method_addUsbInterface = env->GetMethodID(clazz, "addUsbInterface",
-            "(ILjava/lang/String;IIII)V");
-    if (method_addUsbInterface == NULL) {
-        ALOGE("Can't find addUsbInterface");
-        return -1;
-    }
-    method_addUsbEndpoint = env->GetMethodID(clazz, "addUsbEndpoint", "(IIII)V");
-    if (method_addUsbEndpoint == NULL) {
-        ALOGE("Can't find addUsbEndpoint");
-        return -1;
-    }
-    method_endUsbDeviceAdded = env->GetMethodID(clazz, "endUsbDeviceAdded", "()V");
-    if (method_endUsbDeviceAdded == NULL) {
-        ALOGE("Can't find endUsbDeviceAdded");
-        return -1;
-    }
     method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved",
             "(Ljava/lang/String;)V");
     if (method_usbDeviceRemoved == NULL) {
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index d359b70..7bea8a1 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -255,6 +255,7 @@
     }
 
     private void alsaFileAdded(String name) {
+        Slog.i(TAG, "alsaFileAdded(" + name + ")");
         int type = AlsaDevice.TYPE_UNKNOWN;
         int card = -1, device = -1;
 
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 095fdc6..c29a335 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -19,13 +19,8 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
-import android.hardware.usb.UsbConfiguration;
 import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbDeviceConnection;
-import android.hardware.usb.UsbEndpoint;
-import android.hardware.usb.UsbInterface;
-import android.hardware.usb.UsbManager;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.text.TextUtils;
@@ -37,7 +32,6 @@
 import com.android.server.usb.descriptors.report.TextReportCanvas;
 import com.android.server.usb.descriptors.tree.UsbDescriptorsTree;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 
@@ -50,28 +44,23 @@
 
     private final Context mContext;
 
-    // contains all connected USB devices
-    private final HashMap<String, UsbDevice> mDevices = new HashMap<>();
-
     // USB busses to exclude from USB host support
     private final String[] mHostBlacklist;
 
-    private final Object mLock = new Object();
-
-    private UsbDevice mNewDevice;
-    private UsbConfiguration mNewConfiguration;
-    private UsbInterface mNewInterface;
-    private ArrayList<UsbConfiguration> mNewConfigurations;
-    private ArrayList<UsbInterface> mNewInterfaces;
-    private ArrayList<UsbEndpoint> mNewEndpoints;
-
     private final UsbAlsaManager mUsbAlsaManager;
     private final UsbSettingsManager mSettingsManager;
 
+    private final Object mLock = new Object();
     @GuardedBy("mLock")
+    // contains all connected USB devices
+    private final HashMap<String, UsbDevice> mDevices = new HashMap<>();
+
+    private Object mSettingsLock = new Object();
+    @GuardedBy("mSettingsLock")
     private UsbProfileGroupSettingsManager mCurrentSettings;
 
-    @GuardedBy("mLock")
+    private Object mHandlerLock = new Object();
+    @GuardedBy("mHandlerLock")
     private ComponentName mUsbDeviceConnectionHandler;
 
     public UsbHostManager(Context context, UsbAlsaManager alsaManager,
@@ -91,33 +80,33 @@
     }
 
     public void setCurrentUserSettings(UsbProfileGroupSettingsManager settings) {
-        synchronized (mLock) {
+        synchronized (mSettingsLock) {
             mCurrentSettings = settings;
         }
     }
 
     private UsbProfileGroupSettingsManager getCurrentUserSettings() {
-        synchronized (mLock) {
+        synchronized (mSettingsLock) {
             return mCurrentSettings;
         }
     }
 
     public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
-        synchronized (mLock) {
+        synchronized (mHandlerLock) {
             mUsbDeviceConnectionHandler = usbDeviceConnectionHandler;
         }
     }
 
     private @Nullable ComponentName getUsbDeviceConnectionHandler() {
-        synchronized (mLock) {
+        synchronized (mHandlerLock) {
             return mUsbDeviceConnectionHandler;
         }
     }
 
-    private boolean isBlackListed(String deviceName) {
+    private boolean isBlackListed(String deviceAddress) {
         int count = mHostBlacklist.length;
         for (int i = 0; i < count; i++) {
-            if (deviceName.startsWith(mHostBlacklist[i])) {
+            if (deviceAddress.startsWith(mHostBlacklist[i])) {
                 return true;
             }
         }
@@ -136,166 +125,73 @@
     }
 
     /* Called from JNI in monitorUsbHostBus() to report new USB devices
-       Returns true if successful, in which case the JNI code will continue adding configurations,
-       interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
-       have been processed
+       Returns true if successful, i.e. the USB Audio device descriptors are
+       correctly parsed and the unique device is added to the audio device list.
      */
     @SuppressWarnings("unused")
-    private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID,
-            int deviceClass, int deviceSubclass, int deviceProtocol,
-            String manufacturerName, String productName, int version, String serialNumber) {
-
+    private boolean usbDeviceAdded(String deviceAddress, int deviceClass, int deviceSubclass,
+            byte[] descriptors) {
         if (DEBUG) {
-            Slog.d(TAG, "usb:UsbHostManager.beginUsbDeviceAdded(" + deviceName + ")");
-            // Audio Class Codes:
-            // Audio: 0x01
-            // Audio Subclass Codes:
-            // undefined: 0x00
-            // audio control: 0x01
-            // audio streaming: 0x02
-            // midi streaming: 0x03
-
-            // some useful debugging info
-            Slog.d(TAG, "usb: nm:" + deviceName + " vnd:" + vendorID + " prd:" + productID + " cls:"
-                    + deviceClass + " sub:" + deviceSubclass + " proto:" + deviceProtocol);
+            Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
         }
 
-        // OK this is non-obvious, but true. One can't tell if the device being attached is even
-        // potentially an audio device without parsing the interface descriptors, so punt on any
-        // such test until endUsbDeviceAdded() when we have that info.
-
-        if (isBlackListed(deviceName) ||
-                isBlackListed(deviceClass, deviceSubclass)) {
+        // check class/subclass first as it is more likely to be blacklisted
+        if (isBlackListed(deviceClass, deviceSubclass) || isBlackListed(deviceAddress)) {
+            if (DEBUG) {
+                Slog.d(TAG, "device is black listed");
+            }
             return false;
         }
 
         synchronized (mLock) {
-            if (mDevices.get(deviceName) != null) {
-                Slog.w(TAG, "device already on mDevices list: " + deviceName);
+            if (mDevices.get(deviceAddress) != null) {
+                Slog.w(TAG, "device already on mDevices list: " + deviceAddress);
+                //TODO If this is the same peripheral as is being connected, replace
+                // it with the new connection.
                 return false;
             }
 
-            if (mNewDevice != null) {
-                Slog.e(TAG, "mNewDevice is not null in endUsbDeviceAdded");
-                return false;
-            }
+            UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress);
+            if (parser.parseDescriptors(descriptors)) {
 
-            // Create version string in "%.%" format
-            String versionString = Integer.toString(version >> 8) + "." + (version & 0xFF);
-
-            mNewDevice = new UsbDevice(deviceName, vendorID, productID,
-                    deviceClass, deviceSubclass, deviceProtocol,
-                    manufacturerName, productName, versionString, serialNumber);
-
-            mNewConfigurations = new ArrayList<>();
-            mNewInterfaces = new ArrayList<>();
-            mNewEndpoints = new ArrayList<>();
-        }
-
-        return true;
-    }
-
-    /* Called from JNI in monitorUsbHostBus() to report new USB configuration for the device
-       currently being added.  Returns true if successful, false in case of error.
-     */
-    @SuppressWarnings("unused")
-    private void addUsbConfiguration(int id, String name, int attributes, int maxPower) {
-        if (mNewConfiguration != null) {
-            mNewConfiguration.setInterfaces(
-                    mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
-            mNewInterfaces.clear();
-        }
-
-        mNewConfiguration = new UsbConfiguration(id, name, attributes, maxPower);
-        mNewConfigurations.add(mNewConfiguration);
-    }
-
-    /* Called from JNI in monitorUsbHostBus() to report new USB interface for the device
-       currently being added.  Returns true if successful, false in case of error.
-     */
-    @SuppressWarnings("unused")
-    private void addUsbInterface(int id, String name, int altSetting,
-            int Class, int subClass, int protocol) {
-        if (mNewInterface != null) {
-            mNewInterface.setEndpoints(
-                    mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
-            mNewEndpoints.clear();
-        }
-
-        mNewInterface = new UsbInterface(id, altSetting, name, Class, subClass, protocol);
-        mNewInterfaces.add(mNewInterface);
-    }
-
-    /* Called from JNI in monitorUsbHostBus() to report new USB endpoint for the device
-       currently being added.  Returns true if successful, false in case of error.
-     */
-    @SuppressWarnings("unused")
-    private void addUsbEndpoint(int address, int attributes, int maxPacketSize, int interval) {
-        mNewEndpoints.add(new UsbEndpoint(address, attributes, maxPacketSize, interval));
-    }
-
-    /* Called from JNI in monitorUsbHostBus() to finish adding a new device */
-    @SuppressWarnings("unused")
-    private void endUsbDeviceAdded() {
-        if (DEBUG) {
-            Slog.d(TAG, "usb:UsbHostManager.endUsbDeviceAdded()");
-        }
-        if (mNewInterface != null) {
-            mNewInterface.setEndpoints(
-                    mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
-        }
-        if (mNewConfiguration != null) {
-            mNewConfiguration.setInterfaces(
-                    mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
-        }
-
-
-        synchronized (mLock) {
-            if (mNewDevice != null) {
-                mNewDevice.setConfigurations(
-                        mNewConfigurations.toArray(
-                                new UsbConfiguration[mNewConfigurations.size()]));
-                mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
-                Slog.d(TAG, "Added device " + mNewDevice);
+                UsbDevice newDevice = parser.toAndroidUsbDevice();
+                mDevices.put(deviceAddress, newDevice);
 
                 // It is fine to call this only for the current user as all broadcasts are sent to
                 // all profiles of the user and the dialogs should only show once.
                 ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
                 if (usbDeviceConnectionHandler == null) {
-                    getCurrentUserSettings().deviceAttached(mNewDevice);
+                    getCurrentUserSettings().deviceAttached(newDevice);
                 } else {
-                    getCurrentUserSettings().deviceAttachedForFixedHandler(mNewDevice,
+                    getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
                             usbDeviceConnectionHandler);
                 }
-                // deviceName is something like: "/dev/bus/usb/001/001"
-                UsbDescriptorParser parser = new UsbDescriptorParser();
-                boolean isInputHeadset = false;
-                boolean isOutputHeadset = false;
-                if (parser.parseDevice(mNewDevice.getDeviceName())) {
-                    isInputHeadset = parser.isInputHeadset();
-                    isOutputHeadset = parser.isOutputHeadset();
-                    Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset
-                            + " , out: " + isOutputHeadset + "]");
-                }
-                mUsbAlsaManager.usbDeviceAdded(mNewDevice,
-                        isInputHeadset, isOutputHeadset);
+
+                // Headset?
+                boolean isInputHeadset = parser.isInputHeadset();
+                boolean isOutputHeadset = parser.isOutputHeadset();
+                Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset
+                        + " , out: " + isOutputHeadset + "]");
+
+                mUsbAlsaManager.usbDeviceAdded(newDevice, isInputHeadset, isOutputHeadset);
             } else {
-                Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
+                Slog.e(TAG, "Error parsing USB device descriptors for " + deviceAddress);
+                return false;
             }
-            mNewDevice = null;
-            mNewConfigurations = null;
-            mNewInterfaces = null;
-            mNewEndpoints = null;
-            mNewConfiguration = null;
-            mNewInterface = null;
         }
+
+        if (DEBUG) {
+            Slog.d(TAG, "beginUsbDeviceAdded(" + deviceAddress + ") end");
+        }
+
+        return true;
     }
 
     /* Called from JNI in monitorUsbHostBus to report USB device removal */
     @SuppressWarnings("unused")
-    private void usbDeviceRemoved(String deviceName) {
+    private void usbDeviceRemoved(String deviceAddress) {
         synchronized (mLock) {
-            UsbDevice device = mDevices.remove(deviceName);
+            UsbDevice device = mDevices.remove(deviceAddress);
             if (device != null) {
                 mUsbAlsaManager.usbDeviceRemoved(device);
                 mSettingsManager.usbDeviceRemoved(device);
@@ -322,32 +218,37 @@
         }
     }
 
-    /* Opens the specified USB device */
-    public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings) {
+    /**
+     * Opens the specified USB device
+     * @hide
+     */
+    public ParcelFileDescriptor openDevice(String deviceAddress, UsbUserSettingsManager settings) {
         synchronized (mLock) {
-            if (isBlackListed(deviceName)) {
+            if (isBlackListed(deviceAddress)) {
                 throw new SecurityException("USB device is on a restricted bus");
             }
-            UsbDevice device = mDevices.get(deviceName);
+            UsbDevice device = mDevices.get(deviceAddress);
             if (device == null) {
                 // if it is not in mDevices, it either does not exist or is blacklisted
                 throw new IllegalArgumentException(
-                        "device " + deviceName + " does not exist or is restricted");
+                        "device " + deviceAddress + " does not exist or is restricted");
             }
             settings.checkPermission(device);
-            return nativeOpenDevice(deviceName);
+            return nativeOpenDevice(deviceAddress);
         }
     }
 
     public void dump(IndentingPrintWriter pw) {
-        synchronized (mLock) {
-            pw.println("USB Host State:");
-            for (String name : mDevices.keySet()) {
-                pw.println("  " + name + ": " + mDevices.get(name));
-            }
+        pw.println("USB Host State:");
+        synchronized (mHandlerLock) {
             if (mUsbDeviceConnectionHandler != null) {
                 pw.println("Default USB Host Connection handler: " + mUsbDeviceConnectionHandler);
             }
+        }
+        synchronized (mLock) {
+            for (String name : mDevices.keySet()) {
+                pw.println("  " + name + ": " + mDevices.get(name));
+            }
 
             Collection<UsbDevice> devices = mDevices.values();
             if (devices.size() != 0) {
@@ -355,17 +256,12 @@
                 for (UsbDevice device : devices) {
                     StringBuilder stringBuilder = new StringBuilder();
 
-                    UsbDescriptorParser parser = new UsbDescriptorParser();
-                    if (parser.parseDevice(device.getDeviceName())) {
+                    UsbDescriptorParser parser = new UsbDescriptorParser(device.getDeviceName());
+                    if (parser.parseDevice()) {
                         UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree();
                         descriptorTree.parse(parser);
 
-                        UsbManager usbManager =
-                                (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
-                        UsbDeviceConnection connection = usbManager.openDevice(device);
-
-                        descriptorTree.report(new TextReportCanvas(connection, stringBuilder));
-                        connection.close();
+                        descriptorTree.report(new TextReportCanvas(parser, stringBuilder));
 
                         stringBuilder.append("isHeadset[in: " + parser.isInputHeadset()
                                 + " , out: " + parser.isOutputHeadset() + "]");
@@ -381,5 +277,5 @@
     }
 
     private native void monitorUsbHostBus();
-    private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
+    private native ParcelFileDescriptor nativeOpenDevice(String deviceAddress);
 }
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
index 75279c6..511e59a 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
@@ -15,8 +15,13 @@
  */
 package com.android.server.usb.descriptors;
 
+import android.hardware.usb.UsbConfiguration;
+import android.hardware.usb.UsbInterface;
+
 import com.android.server.usb.descriptors.report.ReportCanvas;
 
+import java.util.ArrayList;
+
 /**
  * @hide
  * An USB Config Descriptor.
@@ -35,6 +40,9 @@
                                 //     D4..0 Reserved, set to 0.
     private byte mMaxPower;     // 8:1 Maximum Power Consumption in 2mA units
 
+    private ArrayList<UsbInterfaceDescriptor> mInterfaceDescriptors =
+            new ArrayList<UsbInterfaceDescriptor>();
+
     UsbConfigDescriptor(int length, byte type) {
         super(length, type);
         mHierarchyLevel = 2;
@@ -64,6 +72,22 @@
         return mMaxPower;
     }
 
+    void addInterfaceDescriptor(UsbInterfaceDescriptor interfaceDesc) {
+        mInterfaceDescriptors.add(interfaceDesc);
+    }
+
+    UsbConfiguration toAndroid(UsbDescriptorParser parser) {
+        String name = parser.getDescriptorString(mConfigIndex);
+        UsbConfiguration config = new
+                UsbConfiguration(mConfigValue, name, mAttribs, mMaxPower);
+        UsbInterface[] interfaces = new UsbInterface[mInterfaceDescriptors.size()];
+        for (int index = 0; index < mInterfaceDescriptors.size(); index++) {
+            interfaces[index] = mInterfaceDescriptors.get(index).toAndroid(parser);
+        }
+        config.setInterfaces(interfaces);
+        return config;
+    }
+
     @Override
     public int parseRawDescriptors(ByteStream stream) {
         mTotalLength = stream.unpackUsbShort();
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index ad7bde5c..c5052c8 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.usb.descriptors;
 
+import android.hardware.usb.UsbDevice;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -25,11 +26,16 @@
  */
 public final class UsbDescriptorParser {
     private static final String TAG = "UsbDescriptorParser";
+    private static final boolean DEBUG = false;
+
+    private final String mDeviceAddr;
 
     // Descriptor Objects
+    private static final int DESCRIPTORS_ALLOC_SIZE = 128;
     private ArrayList<UsbDescriptor> mDescriptors = new ArrayList<UsbDescriptor>();
 
     private UsbDeviceDescriptor mDeviceDescriptor;
+    private UsbConfigDescriptor mCurConfigDescriptor;
     private UsbInterfaceDescriptor mCurInterfaceDescriptor;
 
     // The AudioClass spec implemented by the AudioClass Interfaces
@@ -37,7 +43,13 @@
     // Obtained from the first AudioClass Header descriptor.
     private int mACInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0;
 
-    public UsbDescriptorParser() {}
+    public UsbDescriptorParser(String deviceAddr) {
+        mDeviceAddr = deviceAddr;
+    }
+
+    public String getDeviceAddr() {
+        return mDeviceAddr;
+    }
 
     /**
      * @return the USB Spec value associated with the Device descriptor for the
@@ -60,6 +72,18 @@
     public int getACInterfaceSpec() {
         return mACInterfacesSpec;
     }
+
+    private class UsbDescriptorsStreamFormatException extends Exception {
+        String mMessage;
+        UsbDescriptorsStreamFormatException(String message) {
+            mMessage = message;
+        }
+
+        public String toString() {
+            return "Descriptor Stream Format Exception: " + mMessage;
+        }
+    }
+
     /**
      * The probability (as returned by getHeadsetProbability() at which we conclude
      * the peripheral is a headset.
@@ -67,7 +91,8 @@
     private static final float IN_HEADSET_TRIGGER = 0.75f;
     private static final float OUT_HEADSET_TRIGGER = 0.75f;
 
-    private UsbDescriptor allocDescriptor(ByteStream stream) {
+    private UsbDescriptor allocDescriptor(ByteStream stream)
+            throws UsbDescriptorsStreamFormatException {
         stream.resetReadCount();
 
         int length = stream.getUnsignedByte();
@@ -83,15 +108,38 @@
                 break;
 
             case UsbDescriptor.DESCRIPTORTYPE_CONFIG:
-                descriptor = new UsbConfigDescriptor(length, type);
+                descriptor = mCurConfigDescriptor = new UsbConfigDescriptor(length, type);
+                if (mDeviceDescriptor != null) {
+                    mDeviceDescriptor.addConfigDescriptor(mCurConfigDescriptor);
+                } else {
+                    Log.e(TAG, "Config Descriptor found with no associated Device Descriptor!");
+                    throw new UsbDescriptorsStreamFormatException(
+                            "Config Descriptor found with no associated Device Descriptor!");
+                }
                 break;
 
             case UsbDescriptor.DESCRIPTORTYPE_INTERFACE:
                 descriptor = mCurInterfaceDescriptor = new UsbInterfaceDescriptor(length, type);
+                if (mCurConfigDescriptor != null) {
+                    mCurConfigDescriptor.addInterfaceDescriptor(mCurInterfaceDescriptor);
+                } else {
+                    Log.e(TAG, "Interface Descriptor found with no associated Config Descriptor!");
+                    throw new UsbDescriptorsStreamFormatException(
+                            "Interface Descriptor found with no associated Config Descriptor!");
+                }
                 break;
 
             case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT:
                 descriptor = new UsbEndpointDescriptor(length, type);
+                if (mCurInterfaceDescriptor != null) {
+                    mCurInterfaceDescriptor.addEndpointDescriptor(
+                            (UsbEndpointDescriptor) descriptor);
+                } else {
+                    Log.e(TAG,
+                            "Endpoint Descriptor found with no associated Interface Descriptor!");
+                    throw new UsbDescriptorsStreamFormatException(
+                            "Endpoint Descriptor found with no associated Interface Descriptor!");
+                }
                 break;
 
             /*
@@ -144,8 +192,12 @@
     /**
      * @hide
      */
-    public void parseDescriptors(byte[] descriptors) {
-        mDescriptors.clear();
+    public boolean parseDescriptors(byte[] descriptors) {
+        if (DEBUG) {
+            Log.d(TAG, "parseDescriptors() - start");
+        }
+        // This will allow us to (probably) alloc mDescriptors just once.
+        mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE);
 
         ByteStream stream = new ByteStream(descriptors);
         while (stream.available() > 0) {
@@ -173,21 +225,36 @@
                 }
             }
         }
+        if (DEBUG) {
+            Log.d(TAG, "parseDescriptors() - end " + mDescriptors.size() + " descriptors.");
+        }
+        return true;
     }
 
     /**
      * @hide
      */
-    public boolean parseDevice(String deviceAddr) {
-        byte[] rawDescriptors = getRawDescriptors(deviceAddr);
-        if (rawDescriptors != null) {
-            parseDescriptors(rawDescriptors);
-            return true;
-        }
-        return false;
+    public boolean parseDevice() {
+        byte[] rawDescriptors = getRawDescriptors();
+
+        return rawDescriptors != null
+            ? parseDescriptors(rawDescriptors) : false;
     }
 
-    private native byte[] getRawDescriptors(String deviceAddr);
+    private byte[] getRawDescriptors() {
+        return getRawDescriptors_native(mDeviceAddr);
+    }
+
+    private native byte[] getRawDescriptors_native(String deviceAddr);
+
+    /**
+     * @hide
+     */
+    public String getDescriptorString(int stringId) {
+        return getDescriptorString_native(mDeviceAddr, stringId);
+    }
+
+    private native String getDescriptorString_native(String deviceAddr, int stringId);
 
     public int getParsingSpec() {
         return mDeviceDescriptor != null ? mDeviceDescriptor.getSpec() : 0;
@@ -200,6 +267,17 @@
     /**
      * @hide
      */
+    public UsbDevice toAndroidUsbDevice() {
+        if (mDeviceDescriptor == null) {
+            return null;
+        }
+
+        return mDeviceDescriptor.toAndroid(this);
+    }
+
+    /**
+     * @hide
+     */
     public ArrayList<UsbDescriptor> getDescriptors(byte type) {
         ArrayList<UsbDescriptor> list = new ArrayList<UsbDescriptor>();
         for (UsbDescriptor descriptor : mDescriptors) {
@@ -355,8 +433,6 @@
      * to count on the peripheral being a headset.
      */
     public boolean isInputHeadset() {
-        // TEMP
-        Log.i(TAG, "---- isInputHeadset() prob:" + (getInputHeadsetProbability() * 100f) + "%");
         return getInputHeadsetProbability() >= IN_HEADSET_TRIGGER;
     }
 
@@ -410,8 +486,6 @@
      * to count on the peripheral being a headset.
      */
     public boolean isOutputHeadset() {
-        // TEMP
-        Log.i(TAG, "---- isOutputHeadset() prob:" + (getOutputHeadsetProbability() * 100f) + "%");
         return getOutputHeadsetProbability() >= OUT_HEADSET_TRIGGER;
     }
 
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
index d5cb89e..c89d9b6 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
@@ -15,9 +15,14 @@
  */
 package com.android.server.usb.descriptors;
 
+import android.hardware.usb.UsbConfiguration;
+import android.hardware.usb.UsbDevice;
+
 import com.android.server.usb.descriptors.report.ReportCanvas;
 import com.android.server.usb.descriptors.report.UsbStrings;
 
+import java.util.ArrayList;
+
 /**
  * @hide
  * A USB Device Descriptor.
@@ -44,6 +49,9 @@
     private byte mSerialNum;    // 16:1 Index of Serial Number String Descriptor
     private byte mNumConfigs;   // 17:1 Number of Possible Configurations
 
+    private ArrayList<UsbConfigDescriptor> mConfigDescriptors =
+            new ArrayList<UsbConfigDescriptor>();
+
     UsbDeviceDescriptor(int length, byte type) {
         super(length, type);
         mHierarchyLevel = 1;
@@ -97,6 +105,35 @@
         return mNumConfigs;
     }
 
+    void addConfigDescriptor(UsbConfigDescriptor config) {
+        mConfigDescriptors.add(config);
+    }
+
+    /**
+     * @hide
+     */
+    public UsbDevice toAndroid(UsbDescriptorParser parser) {
+        String mfgName = parser.getDescriptorString(mMfgIndex);
+        String prodName = parser.getDescriptorString(mProductIndex);
+
+        // Create version string in "%.%" format
+        String versionString =
+                Integer.toString(mDeviceRelease >> 8) + "." + (mDeviceRelease & 0xFF);
+        String serialStr = parser.getDescriptorString(mSerialNum);
+
+        UsbDevice device = new UsbDevice(parser.getDeviceAddr(), mVendorID, mProductID,
+                mDevClass, mDevSubClass,
+                mProtocol, mfgName, prodName,
+                versionString, serialStr);
+        UsbConfiguration[] configs = new UsbConfiguration[mConfigDescriptors.size()];
+        for (int index = 0; index < mConfigDescriptors.size(); index++) {
+            configs[index] = mConfigDescriptors.get(index).toAndroid(parser);
+        }
+        device.setConfigurations(configs);
+
+        return device;
+    }
+
     @Override
     public int parseRawDescriptors(ByteStream stream) {
         mSpec = stream.unpackUsbShort();
@@ -134,12 +171,11 @@
                 + " Product ID: " + ReportCanvas.getHexString(getProductID())
                 + " Product Release: " + ReportCanvas.getBCDString(getDeviceRelease()));
 
+        UsbDescriptorParser parser = canvas.getParser();
         byte mfgIndex = getMfgIndex();
-        String manufacturer =
-                UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), mfgIndex);
+        String manufacturer = parser.getDescriptorString(mfgIndex);
         byte productIndex = getProductIndex();
-        String product =
-                UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), productIndex);
+        String product = parser.getDescriptorString(productIndex);
 
         canvas.writeListItem("Manufacturer " + mfgIndex + ": " + manufacturer
                 + " Product " + productIndex + ": " + product);
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
index 6322fbe..9cb8f05 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.usb.descriptors;
 
+import android.hardware.usb.UsbEndpoint;
+
 import com.android.server.usb.descriptors.report.ReportCanvas;
 
 /**
@@ -105,6 +107,10 @@
         return mSyncAddress;
     }
 
+    /* package */ UsbEndpoint toAndroid(UsbDescriptorParser parser) {
+        return new UsbEndpoint(mEndpointAddress, mAttributes, mPacketSize, mInterval);
+    }
+
     @Override
     public int parseRawDescriptors(ByteStream stream) {
         mEndpointAddress = stream.getByte();
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
index 4eef6ca..645807d 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
@@ -15,9 +15,14 @@
  */
 package com.android.server.usb.descriptors;
 
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+
 import com.android.server.usb.descriptors.report.ReportCanvas;
 import com.android.server.usb.descriptors.report.UsbStrings;
 
+import java.util.ArrayList;
+
 /**
  * @hide
  * A common super-class for all USB Interface Descritor subtypes.
@@ -34,6 +39,9 @@
     protected byte mProtocol;         // 7:1 Protocol Code
     protected byte mDescrIndex;       // 8:1 Index of String Descriptor Describing this interface
 
+    private ArrayList<UsbEndpointDescriptor> mEndpointDescriptors =
+            new ArrayList<UsbEndpointDescriptor>();
+
     UsbInterfaceDescriptor(int length, byte type) {
         super(length, type);
         mHierarchyLevel = 3;
@@ -80,6 +88,22 @@
         return mDescrIndex;
     }
 
+    void addEndpointDescriptor(UsbEndpointDescriptor endpoint) {
+        mEndpointDescriptors.add(endpoint);
+    }
+
+    UsbInterface toAndroid(UsbDescriptorParser parser) {
+        String name = parser.getDescriptorString(mDescrIndex);
+        UsbInterface ntrface = new UsbInterface(
+                mInterfaceNumber, mAlternateSetting, name, mUsbClass, mUsbSubclass, mProtocol);
+        UsbEndpoint[] endpoints = new UsbEndpoint[mEndpointDescriptors.size()];
+        for (int index = 0; index < mEndpointDescriptors.size(); index++) {
+            endpoints[index] = mEndpointDescriptors.get(index).toAndroid(parser);
+        }
+        ntrface.setEndpoints(endpoints);
+        return ntrface;
+    }
+
     @Override
     public void report(ReportCanvas canvas) {
         super.report(canvas);
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
index 99ebcca..adfc514 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
@@ -15,7 +15,7 @@
  */
 package com.android.server.usb.descriptors.report;
 
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
 
 /**
  * @hide
@@ -32,8 +32,8 @@
      * from the USB device.
      * @param stringBuilder Generated output gets written into this object.
      */
-    public HTMLReportCanvas(UsbDeviceConnection connection, StringBuilder stringBuilder) {
-        super(connection);
+    public HTMLReportCanvas(UsbDescriptorParser parser, StringBuilder stringBuilder) {
+        super(parser);
 
         mStringBuilder = stringBuilder;
     }
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
index 9e0adf5..c34dc98 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
@@ -15,7 +15,7 @@
  */
 package com.android.server.usb.descriptors.report;
 
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
 
 /**
  * @hide
@@ -24,22 +24,19 @@
 public abstract class ReportCanvas {
     private static final String TAG = "ReportCanvas";
 
-    private final UsbDeviceConnection mConnection;
+    private final UsbDescriptorParser mParser;
 
     /**
      * Constructor.
      * @param connection    The USB connection object used to retrieve strings
      * from the USB device.
      */
-    public ReportCanvas(UsbDeviceConnection connection) {
-        mConnection = connection;
+    public ReportCanvas(UsbDescriptorParser parser) {
+        mParser = parser;
     }
 
-    /**
-     * @returns the UsbDeviceConnection member (mConnection).
-     */
-    public UsbDeviceConnection getConnection() {
-        return mConnection;
+    public UsbDescriptorParser getParser() {
+        return mParser;
     }
 
     /**
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
index a43569d..1e19ea1 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
@@ -15,7 +15,7 @@
  */
 package com.android.server.usb.descriptors.report;
 
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
 
 /**
  * @hide
@@ -34,8 +34,8 @@
      * from the USB device.
      * @param stringBuilder Generated output gets written into this object.
      */
-    public TextReportCanvas(UsbDeviceConnection connection, StringBuilder stringBuilder) {
-        super(connection);
+    public TextReportCanvas(UsbDescriptorParser parser, StringBuilder stringBuilder) {
+        super(parser);
 
         mStringBuilder = stringBuilder;
     }