From 2b3ae20bfc52c72266ff846a451eaac2259ebaeb Mon Sep 17 00:00:00 2001 From: Paul McLean Date: Wed, 29 Nov 2017 17:37:35 -0700 Subject: [PATCH] Saving USB Device connect/disconnect info. Test: Manual testing with Skylab, Mir, HTC dongle & Presonus AudioBox 22VSL (and various others) Change-Id: Ice1bb889bc4655805d6b117988a5ebc4baa48cde --- .../com/android/server/usb/UsbHostManager.java | 126 +++++++++++++++++---- .../usb/descriptors/UsbDescriptorParser.java | 28 ++++- 2 files changed, 128 insertions(+), 26 deletions(-) diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index dd2e19297272..e76d2113a62e 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -29,18 +29,21 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.usb.descriptors.UsbDescriptorParser; +import com.android.server.usb.descriptors.UsbDeviceDescriptor; import com.android.server.usb.descriptors.report.TextReportCanvas; import com.android.server.usb.descriptors.tree.UsbDescriptorsTree; -import java.util.Collection; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.HashMap; +import java.util.LinkedList; /** * UsbHostManager manages USB state in host mode. */ public class UsbHostManager { private static final String TAG = UsbHostManager.class.getSimpleName(); - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; private final Context mContext; @@ -63,6 +66,76 @@ public class UsbHostManager { @GuardedBy("mHandlerLock") private ComponentName mUsbDeviceConnectionHandler; + /* + * Member used for tracking connections & disconnections + */ + static final SimpleDateFormat sFormat = new SimpleDateFormat("MM-dd HH:mm:ss:SSS"); + private static final int MAX_CONNECT_RECORDS = 32; + private int mNumConnects; // TOTAL # of connect/disconnect + private final LinkedList mConnections = new LinkedList(); + private ConnectionRecord mLastConnect; + + /* + * ConnectionRecord + * Stores connection/disconnection data. + */ + class ConnectionRecord { + long mTimestamp; // Same time-base as system log. + String mDeviceAddress; + + static final int CONNECT = 0; + static final int DISCONNECT = 1; + final int mMode; + final byte[] mDescriptors; + + ConnectionRecord(String deviceAddress, int mode, byte[] descriptors) { + mTimestamp = System.currentTimeMillis(); + mDeviceAddress = deviceAddress; + mMode = mode; + mDescriptors = descriptors; + } + + private String formatTime() { + return (new StringBuilder(sFormat.format(new Date(mTimestamp)))).toString(); + } + + void dumpShort(IndentingPrintWriter pw) { + if (mMode == CONNECT) { + pw.println(formatTime() + " Connect " + mDeviceAddress); + UsbDescriptorParser parser = new UsbDescriptorParser(mDeviceAddress, mDescriptors); + + UsbDeviceDescriptor deviceDescriptor = parser.getDeviceDescriptor(); + + pw.println("manfacturer:0x" + Integer.toHexString(deviceDescriptor.getVendorID()) + + " product:" + Integer.toHexString(deviceDescriptor.getProductID())); + pw.println("isHeadset[in: " + parser.isInputHeadset() + + " , out: " + parser.isOutputHeadset() + "]"); + } else { + pw.println(formatTime() + " Disconnect " + mDeviceAddress); + } + } + + void dumpLong(IndentingPrintWriter pw) { + if (mMode == CONNECT) { + pw.println(formatTime() + " Connect " + mDeviceAddress); + UsbDescriptorParser parser = new UsbDescriptorParser(mDeviceAddress, mDescriptors); + StringBuilder stringBuilder = new StringBuilder(); + UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree(); + descriptorTree.parse(parser); + descriptorTree.report(new TextReportCanvas(parser, stringBuilder)); + + stringBuilder.append("isHeadset[in: " + parser.isInputHeadset() + + " , out: " + parser.isOutputHeadset() + "]"); + pw.println(stringBuilder.toString()); + } else { + pw.println(formatTime() + " Disconnect " + mDeviceAddress); + } + } + } + + /* + * UsbHostManager + */ public UsbHostManager(Context context, UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) { mContext = context; @@ -124,6 +197,19 @@ public class UsbHostManager { } + private void addConnectionRecord(String deviceAddress, int mode, byte[] rawDescriptors) { + mNumConnects++; + while (mConnections.size() >= MAX_CONNECT_RECORDS) { + mConnections.removeFirst(); + } + ConnectionRecord rec = + new ConnectionRecord(deviceAddress, mode, rawDescriptors); + mConnections.add(rec); + if (mode == ConnectionRecord.CONNECT) { + mLastConnect = rec; + } + } + /* Called from JNI in monitorUsbHostBus() to report new USB devices 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. @@ -174,6 +260,10 @@ public class UsbHostManager { + " , 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); return false; @@ -196,6 +286,9 @@ public class UsbHostManager { mUsbAlsaManager.usbDeviceRemoved(device); mSettingsManager.usbDeviceRemoved(device); getCurrentUserSettings().usbDeviceRemoved(device); + + // Tracking + addConnectionRecord(deviceAddress, ConnectionRecord.DISCONNECT, null); } } } @@ -249,26 +342,15 @@ public class UsbHostManager { pw.println(" " + name + ": " + mDevices.get(name)); } - Collection devices = mDevices.values(); - if (devices.size() != 0) { - pw.println("USB Peripheral Descriptors"); - for (UsbDevice device : devices) { - StringBuilder stringBuilder = new StringBuilder(); - - UsbDescriptorParser parser = new UsbDescriptorParser(device.getDeviceName()); - if (parser.parseDevice()) { - UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree(); - descriptorTree.parse(parser); - - descriptorTree.report(new TextReportCanvas(parser, stringBuilder)); - - stringBuilder.append("isHeadset[in: " + parser.isInputHeadset() - + " , out: " + parser.isOutputHeadset() + "]"); - } else { - stringBuilder.append("Error Parsing USB Descriptors"); - } - pw.println(stringBuilder.toString()); - } + 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); } } 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 6c6bd01316af..78c7fdc91526 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java @@ -32,7 +32,7 @@ public final class UsbDescriptorParser { // Descriptor Objects private static final int DESCRIPTORS_ALLOC_SIZE = 128; - private ArrayList mDescriptors = new ArrayList(); + private final ArrayList mDescriptors; private UsbDeviceDescriptor mDeviceDescriptor; private UsbConfigDescriptor mCurConfigDescriptor; @@ -45,6 +45,28 @@ public final class UsbDescriptorParser { public UsbDescriptorParser(String deviceAddr) { mDeviceAddr = deviceAddr; + mDescriptors = new ArrayList(DESCRIPTORS_ALLOC_SIZE); + } + + /** + * Connect this parser to an existing set of already parsed descriptors. + * This is useful for reporting. + */ + public UsbDescriptorParser(String deviceAddr, ArrayList descriptors) { + mDeviceAddr = deviceAddr; + mDescriptors = descriptors; + //TODO some error checking here.... + mDeviceDescriptor = (UsbDeviceDescriptor) descriptors.get(0); + } + + /** + * Connect this parser to an byte array containing unparsed (raw) device descriptors + * to be parsed (and parse them). Useful for parsing a stored descriptor buffer. + */ + public UsbDescriptorParser(String deviceAddr, byte[] rawDescriptors) { + mDeviceAddr = deviceAddr; + mDescriptors = new ArrayList(DESCRIPTORS_ALLOC_SIZE); + parseDescriptors(rawDescriptors); } public String getDeviceAddr() { @@ -196,8 +218,6 @@ public final class UsbDescriptorParser { if (DEBUG) { Log.d(TAG, "parseDescriptors() - start"); } - // This will allow us to (probably) alloc mDescriptors just once. - mDescriptors = new ArrayList(DESCRIPTORS_ALLOC_SIZE); ByteStream stream = new ByteStream(descriptors); while (stream.available() > 0) { @@ -241,7 +261,7 @@ public final class UsbDescriptorParser { ? parseDescriptors(rawDescriptors) : false; } - private byte[] getRawDescriptors() { + public byte[] getRawDescriptors() { return getRawDescriptors_native(mDeviceAddr); } -- 2.11.0