OSDN Git Service

Saving USB Device connect/disconnect info.
authorPaul McLean <pmclean@google.com>
Thu, 30 Nov 2017 00:37:35 +0000 (17:37 -0700)
committerPaul McLean <pmclean@google.com>
Wed, 6 Dec 2017 17:49:22 +0000 (09:49 -0800)
Test: Manual testing with Skylab, Mir, HTC dongle & Presonus AudioBox 22VSL
  (and various others)

Change-Id: Ice1bb889bc4655805d6b117988a5ebc4baa48cde

services/usb/java/com/android/server/usb/UsbHostManager.java
services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java

index dd2e192..e76d211 100644 (file)
@@ -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<ConnectionRecord> mConnections = new LinkedList<ConnectionRecord>();
+    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<UsbDevice> 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);
             }
         }
 
index 6c6bd01..78c7fdc 100644 (file)
@@ -32,7 +32,7 @@ public final class UsbDescriptorParser {
 
     // Descriptor Objects
     private static final int DESCRIPTORS_ALLOC_SIZE = 128;
-    private ArrayList<UsbDescriptor> mDescriptors = new ArrayList<UsbDescriptor>();
+    private final ArrayList<UsbDescriptor> mDescriptors;
 
     private UsbDeviceDescriptor mDeviceDescriptor;
     private UsbConfigDescriptor mCurConfigDescriptor;
@@ -45,6 +45,28 @@ public final class UsbDescriptorParser {
 
     public UsbDescriptorParser(String deviceAddr) {
         mDeviceAddr = deviceAddr;
+        mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE);
+    }
+
+    /**
+     * Connect this parser to an existing set of already parsed descriptors.
+     * This is useful for reporting.
+     */
+    public UsbDescriptorParser(String deviceAddr, ArrayList<UsbDescriptor> 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<UsbDescriptor>(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<UsbDescriptor>(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);
     }