Adding ability to control how the USB data is dumped.

Also added tracing to android.UsbDevice creation.

Test: Try each dump command with CALYX Pat USB DAC & Dragonfly Red USB DAC

Change-Id: I2ec05dfa9c544d0c50ee59e3b990e9010cbe0aa0
This commit is contained in:
Paul McLean
2017-12-11 08:36:41 -07:00
parent 7310f4f35b
commit f25c4eb7fd
7 changed files with 176 additions and 43 deletions

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;
}
/**

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);