diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index e76d2113a62e6..7a352a4dc69dd 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -28,6 +28,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.usb.descriptors.UsbDescriptor; import com.android.server.usb.descriptors.UsbDescriptorParser; import com.android.server.usb.descriptors.UsbDeviceDescriptor; import com.android.server.usb.descriptors.report.TextReportCanvas; @@ -84,7 +85,10 @@ public class UsbHostManager { String mDeviceAddress; static final int CONNECT = 0; - static final int DISCONNECT = 1; + static final int CONNECT_BADPARSE = 1; + static final int CONNECT_BADDEVICE = 2; + static final int DISCONNECT = -1; + final int mMode; final byte[] mDescriptors; @@ -100,8 +104,8 @@ public class UsbHostManager { } void dumpShort(IndentingPrintWriter pw) { - if (mMode == CONNECT) { - pw.println(formatTime() + " Connect " + mDeviceAddress); + if (mMode != DISCONNECT) { + pw.println(formatTime() + " Connect " + mDeviceAddress + " mode:" + mMode); UsbDescriptorParser parser = new UsbDescriptorParser(mDeviceAddress, mDescriptors); UsbDeviceDescriptor deviceDescriptor = parser.getDeviceDescriptor(); @@ -115,9 +119,9 @@ public class UsbHostManager { } } - void dumpLong(IndentingPrintWriter pw) { - if (mMode == CONNECT) { - pw.println(formatTime() + " Connect " + mDeviceAddress); + void dumpTree(IndentingPrintWriter pw) { + if (mMode != DISCONNECT) { + pw.println(formatTime() + " Connect " + mDeviceAddress + " mode:" + mMode); UsbDescriptorParser parser = new UsbDescriptorParser(mDeviceAddress, mDescriptors); StringBuilder stringBuilder = new StringBuilder(); UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree(); @@ -131,6 +135,55 @@ public class UsbHostManager { pw.println(formatTime() + " Disconnect " + mDeviceAddress); } } + + void dumpList(IndentingPrintWriter pw) { + if (mMode != DISCONNECT) { + pw.println(formatTime() + " Connect " + mDeviceAddress + " mode:" + mMode); + UsbDescriptorParser parser = new UsbDescriptorParser(mDeviceAddress, mDescriptors); + StringBuilder stringBuilder = new StringBuilder(); + TextReportCanvas canvas = new TextReportCanvas(parser, stringBuilder); + for (UsbDescriptor descriptor : parser.getDescriptors()) { + descriptor.report(canvas); + } + pw.println(stringBuilder.toString()); + + pw.println("isHeadset[in: " + parser.isInputHeadset() + + " , out: " + parser.isOutputHeadset() + "]"); + } else { + pw.println(formatTime() + " Disconnect " + mDeviceAddress); + } + } + + private static final int kDumpBytesPerLine = 16; + + void dumpRaw(IndentingPrintWriter pw) { + if (mMode != DISCONNECT) { + pw.println(formatTime() + " Connect " + mDeviceAddress + " mode:" + mMode); + int length = mDescriptors.length; + pw.println("Raw Descriptors " + length + " bytes"); + int dataOffset = 0; + for (int line = 0; line < length / kDumpBytesPerLine; line++) { + StringBuilder sb = new StringBuilder(); + for (int offset = 0; offset < kDumpBytesPerLine; offset++) { + sb.append("0x") + .append(String.format("0x%02X", mDescriptors[dataOffset++])) + .append(" "); + } + pw.println(sb.toString()); + } + + // remainder + StringBuilder sb = new StringBuilder(); + while (dataOffset < length) { + sb.append("0x") + .append(String.format("0x%02X", mDescriptors[dataOffset++])) + .append(" "); + } + pw.println(sb.toString()); + } else { + pw.println(formatTime() + " Disconnect " + mDeviceAddress); + } + } } /* @@ -205,7 +258,7 @@ public class UsbHostManager { ConnectionRecord rec = new ConnectionRecord(deviceAddress, mode, rawDescriptors); mConnections.add(rec); - if (mode == ConnectionRecord.CONNECT) { + if (mode != ConnectionRecord.DISCONNECT) { mLastConnect = rec; } } @@ -241,31 +294,41 @@ public class UsbHostManager { if (parser.parseDescriptors(descriptors)) { 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(newDevice); + if (newDevice == null) { + Slog.e(TAG, "Couldn't create UsbDevice object."); + // Tracking + addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADDEVICE, + parser.getRawDescriptors()); } else { - getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice, - usbDeviceConnectionHandler); + 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(newDevice); + } else { + getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice, + usbDeviceConnectionHandler); + } + + // Headset? + boolean isInputHeadset = parser.isInputHeadset(); + boolean isOutputHeadset = parser.isOutputHeadset(); + Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset + + " , out: " + isOutputHeadset + "]"); + + mUsbAlsaManager.usbDeviceAdded(newDevice, isInputHeadset, isOutputHeadset); + + // Tracking + addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT, + parser.getRawDescriptors()); } - - // Headset? - boolean isInputHeadset = parser.isInputHeadset(); - boolean isOutputHeadset = parser.isOutputHeadset(); - Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset - + " , out: " + isOutputHeadset + "]"); - - mUsbAlsaManager.usbDeviceAdded(newDevice, isInputHeadset, isOutputHeadset); - - // Tracking - addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT, - parser.getRawDescriptors()); } else { Slog.e(TAG, "Error parsing USB device descriptors for " + deviceAddress); + // Tracking + addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADPARSE, + parser.getRawDescriptors()); return false; } } @@ -330,7 +393,11 @@ public class UsbHostManager { } } - public void dump(IndentingPrintWriter pw) { + /** + * Dump out various information about the state of USB device connections. + * + */ + public void dump(IndentingPrintWriter pw, String[] args) { pw.println("USB Host State:"); synchronized (mHandlerLock) { if (mUsbDeviceConnectionHandler != null) { @@ -342,21 +409,38 @@ public class UsbHostManager { pw.println(" " + name + ": " + mDevices.get(name)); } + // Connections pw.println("" + mNumConnects + " total connects/disconnects"); pw.println("Last " + mConnections.size() + " connections/disconnections"); for (ConnectionRecord rec : mConnections) { rec.dumpShort(pw); } - if (mLastConnect != null) { - pw.println("Last Connected USB Device:"); - mLastConnect.dumpLong(pw); - } } mUsbAlsaManager.dump(pw); } + /** + * Dump various descriptor data. + */ + public void dumpDescriptors(IndentingPrintWriter pw, String[] args) { + if (mLastConnect != null) { + pw.println("Last Connected USB Device:"); + if (args.length <= 1 || args[1].equals("-dump-short")) { + mLastConnect.dumpShort(pw); + } else if (args[1].equals("-dump-tree")) { + mLastConnect.dumpTree(pw); + } else if (args[1].equals("-dump-list")) { + mLastConnect.dumpList(pw); + } else if (args[1].equals("-dump-raw")) { + mLastConnect.dumpRaw(pw); + } + } else { + pw.println("No USB Devices have been connected."); + } + } + private native void monitorUsbHostBus(); private native ParcelFileDescriptor nativeOpenDevice(String deviceAddress); } diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java index 17de83f0cac98..8554cf7b186f9 100644 --- a/services/usb/java/com/android/server/usb/UsbService.java +++ b/services/usb/java/com/android/server/usb/UsbService.java @@ -496,7 +496,7 @@ public class UsbService extends IUsbManager.Stub { mDeviceManager.dump(pw); } if (mHostManager != null) { - mHostManager.dump(pw); + mHostManager.dump(pw, args); } if (mPortManager != null) { mPortManager.dump(pw); @@ -504,7 +504,7 @@ public class UsbService extends IUsbManager.Stub { mAlsaManager.dump(pw); mSettingsManager.dump(pw); - } else if (args.length == 4 && "set-port-roles".equals(args[0])) { + } else if ("set-port-roles".equals(args[0]) && args.length == 4) { final String portId = args[1]; final int powerRole; switch (args[2]) { @@ -546,7 +546,7 @@ public class UsbService extends IUsbManager.Stub { pw.println(); mPortManager.dump(pw); } - } else if (args.length == 3 && "add-port".equals(args[0])) { + } else if ("add-port".equals(args[0]) && args.length == 3) { final String portId = args[1]; final int supportedModes; switch (args[2]) { @@ -571,7 +571,7 @@ public class UsbService extends IUsbManager.Stub { pw.println(); mPortManager.dump(pw); } - } else if (args.length == 5 && "connect-port".equals(args[0])) { + } else if ("connect-port".equals(args[0]) && args.length == 5) { final String portId = args[1]; final int mode; final boolean canChangeMode = args[2].endsWith("?"); @@ -618,30 +618,32 @@ public class UsbService extends IUsbManager.Stub { pw.println(); mPortManager.dump(pw); } - } else if (args.length == 2 && "disconnect-port".equals(args[0])) { + } else if ("disconnect-port".equals(args[0]) && args.length == 2) { final String portId = args[1]; if (mPortManager != null) { mPortManager.disconnectSimulatedPort(portId, pw); pw.println(); mPortManager.dump(pw); } - } else if (args.length == 2 && "remove-port".equals(args[0])) { + } else if ("remove-port".equals(args[0]) && args.length == 2) { final String portId = args[1]; if (mPortManager != null) { mPortManager.removeSimulatedPort(portId, pw); pw.println(); mPortManager.dump(pw); } - } else if (args.length == 1 && "reset".equals(args[0])) { + } else if ("reset".equals(args[0]) && args.length == 1) { if (mPortManager != null) { mPortManager.resetSimulation(pw); pw.println(); mPortManager.dump(pw); } - } else if (args.length == 1 && "ports".equals(args[0])) { + } else if ("ports".equals(args[0]) && args.length == 1) { if (mPortManager != null) { mPortManager.dump(pw); } + } else if ("dump-descriptors".equals(args[0])) { + mHostManager.dumpDescriptors(pw, args); } else { pw.println("Dump current USB state or issue command:"); pw.println(" ports"); @@ -678,6 +680,12 @@ public class UsbService extends IUsbManager.Stub { pw.println(" dumpsys usb add-port \"matrix\" ufp"); pw.println(" dumpsys usb connect-port \"matrix\" ufp sink device"); pw.println(" dumpsys usb reset"); + pw.println(); + pw.println("Example USB device descriptors:"); + pw.println(" dumpsys usb dump-descriptors -dump-short"); + pw.println(" dumpsys usb dump-descriptors -dump-tree"); + pw.println(" dumpsys usb dump-descriptors -dump-list"); + pw.println(" dumpsys usb dump-descriptors -dump-raw"); } } finally { Binder.restoreCallingIdentity(ident); 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 993778fa39916..639aa4e03849d 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java @@ -17,6 +17,7 @@ package com.android.server.usb.descriptors; import android.hardware.usb.UsbConfiguration; import android.hardware.usb.UsbInterface; +import android.util.Log; import com.android.server.usb.descriptors.report.ReportCanvas; @@ -29,6 +30,7 @@ import java.util.ArrayList; */ public final class UsbConfigDescriptor extends UsbDescriptor { private static final String TAG = "UsbConfigDescriptor"; + private static final boolean DEBUG = false; private int mTotalLength; // 2:2 Total length in bytes of data returned private byte mNumInterfaces; // 4:1 Number of Interfaces @@ -77,10 +79,16 @@ public final class UsbConfigDescriptor extends UsbDescriptor { } UsbConfiguration toAndroid(UsbDescriptorParser parser) { + if (DEBUG) { + Log.d(TAG, " toAndroid()"); + } String name = parser.getDescriptorString(mConfigIndex); UsbConfiguration config = new UsbConfiguration(mConfigValue, name, mAttribs, mMaxPower); UsbInterface[] interfaces = new UsbInterface[mInterfaceDescriptors.size()]; + if (DEBUG) { + Log.d(TAG, " " + mInterfaceDescriptors.size() + " interfaces."); + } for (int index = 0; index < mInterfaceDescriptors.size(); index++) { interfaces[index] = mInterfaceDescriptors.get(index).toAndroid(parser); } 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 78c7fdc915265..7a1e9e2f9896e 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java @@ -26,7 +26,7 @@ import java.util.ArrayList; */ public final class UsbDescriptorParser { private static final String TAG = "UsbDescriptorParser"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; private final String mDeviceAddr; @@ -289,10 +289,15 @@ public final class UsbDescriptorParser { */ public UsbDevice toAndroidUsbDevice() { if (mDeviceDescriptor == null) { + Log.e(TAG, "toAndroidUsbDevice() ERROR - No Device Descriptor"); return null; } - return mDeviceDescriptor.toAndroid(this); + UsbDevice device = mDeviceDescriptor.toAndroid(this); + if (device == null) { + Log.e(TAG, "toAndroidUsbDevice() ERROR Creating Device"); + } + return device; } /** 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 8e7f0fde15377..e31e3a3126489 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java @@ -17,6 +17,7 @@ package com.android.server.usb.descriptors; import android.hardware.usb.UsbConfiguration; import android.hardware.usb.UsbDevice; +import android.util.Log; import com.android.server.usb.descriptors.report.ReportCanvas; import com.android.server.usb.descriptors.report.UsbStrings; @@ -30,6 +31,7 @@ import java.util.ArrayList; */ public final class UsbDeviceDescriptor extends UsbDescriptor { private static final String TAG = "UsbDeviceDescriptor"; + private static final boolean DEBUG = false; public static final int USBSPEC_1_0 = 0x0100; public static final int USBSPEC_1_1 = 0x0110; @@ -113,19 +115,30 @@ public final class UsbDeviceDescriptor extends UsbDescriptor { * @hide */ public UsbDevice toAndroid(UsbDescriptorParser parser) { + if (DEBUG) { + Log.d(TAG, "toAndroid()"); + } + String mfgName = parser.getDescriptorString(mMfgIndex); String prodName = parser.getDescriptorString(mProductIndex); + if (DEBUG) { + Log.d(TAG, " mfgName:" + mfgName + " prodName:" + prodName); + } // Create version string in "%.%" format String versionString = Integer.toString(mDeviceRelease >> 8) + "." + (mDeviceRelease & 0xFF); String serialStr = parser.getDescriptorString(mSerialNum); + if (DEBUG) { + Log.d(TAG, " versionString:" + versionString + " serialStr:" + serialStr); + } UsbDevice device = new UsbDevice(parser.getDeviceAddr(), mVendorID, mProductID, mDevClass, mDevSubClass, mProtocol, mfgName, prodName, versionString, serialStr); UsbConfiguration[] configs = new UsbConfiguration[mConfigDescriptors.size()]; + Log.d(TAG, " " + configs.length + " configs"); for (int index = 0; index < mConfigDescriptors.size(); index++) { configs[index] = mConfigDescriptors.get(index).toAndroid(parser); } 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 11302380b5898..4da31ea469c39 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java @@ -16,6 +16,7 @@ package com.android.server.usb.descriptors; import android.hardware.usb.UsbEndpoint; +import android.util.Log; import com.android.server.usb.descriptors.report.ReportCanvas; @@ -26,6 +27,7 @@ import com.android.server.usb.descriptors.report.ReportCanvas; */ public class UsbEndpointDescriptor extends UsbDescriptor { private static final String TAG = "UsbEndpointDescriptor"; + private static final boolean DEBUG = false; public static final int MASK_ENDPOINT_ADDRESS = 0b000000000001111; public static final int MASK_ENDPOINT_DIRECTION = (byte) 0b0000000010000000; @@ -108,6 +110,12 @@ public class UsbEndpointDescriptor extends UsbDescriptor { } /* package */ UsbEndpoint toAndroid(UsbDescriptorParser parser) { + if (DEBUG) { + Log.d(TAG, "toAndroid() type:" + + Integer.toHexString(mAttributes & MASK_ATTRIBS_TRANSTYPE) + + " sync:" + Integer.toHexString(mAttributes & MASK_ATTRIBS_SYNCTYPE) + + " usage:" + Integer.toHexString(mAttributes & MASK_ATTRIBS_USEAGE)); + } return new UsbEndpoint(mEndpointAddress, mAttributes, mPacketSize, mInterval); } 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 d87b1afba79a5..632e3dc500fac 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java @@ -17,6 +17,7 @@ package com.android.server.usb.descriptors; import android.hardware.usb.UsbEndpoint; import android.hardware.usb.UsbInterface; +import android.util.Log; import com.android.server.usb.descriptors.report.ReportCanvas; import com.android.server.usb.descriptors.report.UsbStrings; @@ -30,6 +31,7 @@ import java.util.ArrayList; */ public class UsbInterfaceDescriptor extends UsbDescriptor { private static final String TAG = "UsbInterfaceDescriptor"; + private static final boolean DEBUG = false; protected int mInterfaceNumber; // 2:1 Number of Interface protected byte mAlternateSetting; // 3:1 Value used to select alternative setting @@ -93,6 +95,11 @@ public class UsbInterfaceDescriptor extends UsbDescriptor { } UsbInterface toAndroid(UsbDescriptorParser parser) { + if (DEBUG) { + Log.d(TAG, "toAndroid() class:" + Integer.toHexString(mUsbClass) + + " subclass:" + Integer.toHexString(mUsbSubclass) + + " " + mEndpointDescriptors.size() + " endpoints."); + } String name = parser.getDescriptorString(mDescrIndex); UsbInterface ntrface = new UsbInterface( mInterfaceNumber, mAlternateSetting, name, mUsbClass, mUsbSubclass, mProtocol);