Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae0b9628 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I72688f65,I2dd8d439 into pi-dev

* changes:
  UsbHostManager: Restore inserted device logging
  UsbDescriptorParser: always parse in constructor
parents d41fad71 608ec66d
Loading
Loading
Loading
Loading
+69 −37
Original line number Original line Diff line number Diff line
@@ -54,6 +54,7 @@ import java.util.LinkedList;
public class UsbHostManager {
public class UsbHostManager {
    private static final String TAG = UsbHostManager.class.getSimpleName();
    private static final String TAG = UsbHostManager.class.getSimpleName();
    private static final boolean DEBUG = false;
    private static final boolean DEBUG = false;
    private static final int LINUX_FOUNDATION_VID = 0x1d6b;


    private final Context mContext;
    private final Context mContext;


@@ -267,7 +268,6 @@ public class UsbHostManager {
    }
    }


    private boolean isBlackListed(String deviceAddress) {
    private boolean isBlackListed(String deviceAddress) {
        Slog.i(TAG, "isBlackListed(" + deviceAddress + ")");
        int count = mHostBlacklist.length;
        int count = mHostBlacklist.length;
        for (int i = 0; i < count; i++) {
        for (int i = 0; i < count; i++) {
            if (deviceAddress.startsWith(mHostBlacklist[i])) {
            if (deviceAddress.startsWith(mHostBlacklist[i])) {
@@ -279,7 +279,6 @@ public class UsbHostManager {


    /* returns true if the USB device should not be accessible by applications */
    /* returns true if the USB device should not be accessible by applications */
    private boolean isBlackListed(int clazz, int subClass) {
    private boolean isBlackListed(int clazz, int subClass) {
        Slog.i(TAG, "isBlackListed(" + clazz + ", " + subClass + ")");
        // blacklist hubs
        // blacklist hubs
        if (clazz == UsbConstants.USB_CLASS_HUB) return true;
        if (clazz == UsbConstants.USB_CLASS_HUB) return true;


@@ -302,6 +301,40 @@ public class UsbHostManager {
        }
        }
    }
    }


    private void logUsbDevice(UsbDescriptorParser descriptorParser) {
        int vid = 0;
        int pid = 0;
        String mfg = "<unknown>";
        String product = "<unknown>";
        String version = "<unknown>";
        String serial = "<unknown>";

        UsbDeviceDescriptor deviceDescriptor = descriptorParser.getDeviceDescriptor();
        if (deviceDescriptor != null) {
            vid = deviceDescriptor.getVendorID();
            pid = deviceDescriptor.getProductID();
            mfg = deviceDescriptor.getMfgString(descriptorParser);
            product = deviceDescriptor.getProductString(descriptorParser);
            version = deviceDescriptor.getDeviceReleaseString();
            serial = deviceDescriptor.getSerialString(descriptorParser);
        }

        if (vid == LINUX_FOUNDATION_VID) {
            return;  // don't care about OS-constructed virtual USB devices.
        }
        boolean hasAudio = descriptorParser.hasAudioInterface();
        boolean hasHid = descriptorParser.hasHIDInterface();
        boolean hasStorage = descriptorParser.hasStorageInterface();

        String attachedString = "USB device attached: ";
        attachedString += String.format("vidpid %04x:%04x", vid, pid);
        attachedString += String.format(" mfg/product/ver/serial %s/%s/%s/%s",
                                        mfg, product, version, serial);
        attachedString += String.format(" hasAudio/HID/Storage: %b/%b/%b",
                                        hasAudio, hasHid, hasStorage);
        Slog.d(TAG, attachedString);
    }

    /* Called from JNI in monitorUsbHostBus() to report new USB devices
    /* Called from JNI in monitorUsbHostBus() to report new USB devices
       Returns true if successful, i.e. the USB Audio device descriptors are
       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.
       correctly parsed and the unique device is added to the audio device list.
@@ -313,10 +346,18 @@ public class UsbHostManager {
            Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
            Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
        }
        }


        // check class/subclass first as it is more likely to be blacklisted
        if (isBlackListed(deviceAddress)) {
        if (isBlackListed(deviceClass, deviceSubclass) || isBlackListed(deviceAddress)) {
            if (DEBUG) {
                Slog.d(TAG, "device address is black listed");
            }
            return false;
        }
        UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
        logUsbDevice(parser);

        if (isBlackListed(deviceClass, deviceSubclass)) {
            if (DEBUG) {
            if (DEBUG) {
                Slog.d(TAG, "device is black listed");
                Slog.d(TAG, "device class is black listed");
            }
            }
            return false;
            return false;
        }
        }
@@ -329,9 +370,6 @@ public class UsbHostManager {
                return false;
                return false;
            }
            }


            UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress);
            if (parser.parseDescriptors(descriptors)) {

            UsbDevice newDevice = parser.toAndroidUsbDevice();
            UsbDevice newDevice = parser.toAndroidUsbDevice();
            if (newDevice == null) {
            if (newDevice == null) {
                Slog.e(TAG, "Couldn't create UsbDevice object.");
                Slog.e(TAG, "Couldn't create UsbDevice object.");
@@ -340,6 +378,7 @@ public class UsbHostManager {
                        parser.getRawDescriptors());
                        parser.getRawDescriptors());
            } else {
            } else {
                mDevices.put(deviceAddress, newDevice);
                mDevices.put(deviceAddress, newDevice);
                Slog.d(TAG, "Added device " + newDevice);


                // It is fine to call this only for the current user as all broadcasts are
                // 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.
                // sent to all profiles of the user and the dialogs should only show once.
@@ -357,13 +396,6 @@ public class UsbHostManager {
                addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
                addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
                        parser.getRawDescriptors());
                        parser.getRawDescriptors());
            }
            }
            } else {
                Slog.e(TAG, "Error parsing USB device descriptors for " + deviceAddress);
                // Tracking
                addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADPARSE,
                        parser.getRawDescriptors());
                return false;
            }
        }
        }


        if (DEBUG) {
        if (DEBUG) {
@@ -376,18 +408,18 @@ public class UsbHostManager {
    /* Called from JNI in monitorUsbHostBus to report USB device removal */
    /* Called from JNI in monitorUsbHostBus to report USB device removal */
    @SuppressWarnings("unused")
    @SuppressWarnings("unused")
    private void usbDeviceRemoved(String deviceAddress) {
    private void usbDeviceRemoved(String deviceAddress) {
        if (DEBUG) {
            Slog.d(TAG, "usbDeviceRemoved(" + deviceAddress + ") - start");
        }
        synchronized (mLock) {
        synchronized (mLock) {
            UsbDevice device = mDevices.remove(deviceAddress);
            UsbDevice device = mDevices.remove(deviceAddress);
            if (device != null) {
            if (device != null) {
                Slog.d(TAG, "Removed device at " + deviceAddress + ": " + device.getProductName());
                mUsbAlsaManager.usbDeviceRemoved(deviceAddress/*device*/);
                mUsbAlsaManager.usbDeviceRemoved(deviceAddress/*device*/);
                mSettingsManager.usbDeviceRemoved(device);
                mSettingsManager.usbDeviceRemoved(device);
                getCurrentUserSettings().usbDeviceRemoved(device);
                getCurrentUserSettings().usbDeviceRemoved(device);


                // Tracking
                // Tracking
                addConnectionRecord(deviceAddress, ConnectionRecord.DISCONNECT, null);
                addConnectionRecord(deviceAddress, ConnectionRecord.DISCONNECT, null);
            } else {
                Slog.d(TAG, "Removed device at " + deviceAddress + " was already gone");
            }
            }
        }
        }
    }
    }
+22 −20
Original line number Original line Diff line number Diff line
@@ -43,11 +43,6 @@ public final class UsbDescriptorParser {
    // Obtained from the first AudioClass Header descriptor.
    // Obtained from the first AudioClass Header descriptor.
    private int mACInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0;
    private int mACInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0;


    public UsbDescriptorParser(String deviceAddr) {
        mDeviceAddr = deviceAddr;
        mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE);
    }

    /**
    /**
     * Connect this parser to an existing set of already parsed descriptors.
     * Connect this parser to an existing set of already parsed descriptors.
     * This is useful for reporting.
     * This is useful for reporting.
@@ -214,7 +209,7 @@ public final class UsbDescriptorParser {
    /**
    /**
     * @hide
     * @hide
     */
     */
    public boolean parseDescriptors(byte[] descriptors) {
    public void parseDescriptors(byte[] descriptors) {
        if (DEBUG) {
        if (DEBUG) {
            Log.d(TAG, "parseDescriptors() - start");
            Log.d(TAG, "parseDescriptors() - start");
        }
        }
@@ -248,17 +243,6 @@ public final class UsbDescriptorParser {
        if (DEBUG) {
        if (DEBUG) {
            Log.d(TAG, "parseDescriptors() - end " + mDescriptors.size() + " descriptors.");
            Log.d(TAG, "parseDescriptors() - end " + mDescriptors.size() + " descriptors.");
        }
        }
        return true;
    }

    /**
     * @hide
     */
    public boolean parseDevice() {
        byte[] rawDescriptors = getRawDescriptors();

        return rawDescriptors != null
            ? parseDescriptors(rawDescriptors) : false;
    }
    }


    public byte[] getRawDescriptors() {
    public byte[] getRawDescriptors() {
@@ -493,12 +477,30 @@ public final class UsbDescriptorParser {
    /**
    /**
     *@ hide
     *@ hide
     */
     */
    public boolean hasHIDDescriptor() {
    public boolean hasAudioInterface() {
        ArrayList<UsbDescriptor> descriptors =
                getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_AUDIO);
        return !descriptors.isEmpty();
    }

    /**
     * @hide
     */
    public boolean hasHIDInterface() {
        ArrayList<UsbDescriptor> descriptors =
        ArrayList<UsbDescriptor> descriptors =
                getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_HID);
                getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_HID);
        return !descriptors.isEmpty();
        return !descriptors.isEmpty();
    }
    }


    /**
     * @hide
     */
    public boolean hasStorageInterface() {
        ArrayList<UsbDescriptor> descriptors =
                getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_STORAGE);
        return !descriptors.isEmpty();
    }

    /**
    /**
     * @hide
     * @hide
     */
     */
@@ -540,7 +542,7 @@ public final class UsbDescriptorParser {
            probability += 0.75f;
            probability += 0.75f;
        }
        }


        if (hasMic && hasHIDDescriptor()) {
        if (hasMic && hasHIDInterface()) {
            probability += 0.25f;
            probability += 0.25f;
        }
        }


@@ -593,7 +595,7 @@ public final class UsbDescriptorParser {
            probability += 0.75f;
            probability += 0.75f;
        }
        }


        if (hasSpeaker && hasHIDDescriptor()) {
        if (hasSpeaker && hasHIDInterface()) {
            probability += 0.25f;
            probability += 0.25f;
        }
        }


+29 −10
Original line number Original line Diff line number Diff line
@@ -48,7 +48,7 @@ public final class UsbDeviceDescriptor extends UsbDescriptor {
    private int mDeviceRelease; // 12:2 Device Release number - BCD
    private int mDeviceRelease; // 12:2 Device Release number - BCD
    private byte mMfgIndex;     // 14:1 Index of Manufacturer String Descriptor
    private byte mMfgIndex;     // 14:1 Index of Manufacturer String Descriptor
    private byte mProductIndex; // 15:1 Index of Product String Descriptor
    private byte mProductIndex; // 15:1 Index of Product String Descriptor
    private byte mSerialNum;    // 16:1 Index of Serial Number String Descriptor
    private byte mSerialIndex;  // 16:1 Index of Serial Number String Descriptor
    private byte mNumConfigs;   // 17:1 Number of Possible Configurations
    private byte mNumConfigs;   // 17:1 Number of Possible Configurations


    private ArrayList<UsbConfigDescriptor> mConfigDescriptors =
    private ArrayList<UsbConfigDescriptor> mConfigDescriptors =
@@ -91,16 +91,37 @@ public final class UsbDeviceDescriptor extends UsbDescriptor {
        return mDeviceRelease;
        return mDeviceRelease;
    }
    }


    // mDeviceRelease is binary-coded decimal, format DD.DD
    public String getDeviceReleaseString() {
        int hundredths = mDeviceRelease & 0xF;
        int tenths = (mDeviceRelease & 0xF0) >> 4;
        int ones = (mDeviceRelease & 0xF00) >> 8;
        int tens = (mDeviceRelease & 0xF000) >> 12;
        return String.format("%d.%d%d", tens * 10 + ones, tenths, hundredths);
    }

    public byte getMfgIndex() {
    public byte getMfgIndex() {
        return mMfgIndex;
        return mMfgIndex;
    }
    }


    public String getMfgString(UsbDescriptorParser p) {
        return p.getDescriptorString(mMfgIndex);
    }

    public byte getProductIndex() {
    public byte getProductIndex() {
        return mProductIndex;
        return mProductIndex;
    }
    }


    public byte getSerialNum() {
    public String getProductString(UsbDescriptorParser p) {
        return mSerialNum;
        return p.getDescriptorString(mProductIndex);
    }

    public byte getSerialIndex() {
        return mSerialIndex;
    }

    public String getSerialString(UsbDescriptorParser p) {
        return p.getDescriptorString(mSerialIndex);
    }
    }


    public byte getNumConfigs() {
    public byte getNumConfigs() {
@@ -119,16 +140,14 @@ public final class UsbDeviceDescriptor extends UsbDescriptor {
            Log.d(TAG, "toAndroid()");
            Log.d(TAG, "toAndroid()");
        }
        }


        String mfgName = parser.getDescriptorString(mMfgIndex);
        String mfgName = getMfgString(parser);
        String prodName = parser.getDescriptorString(mProductIndex);
        String prodName = getProductString(parser);
        if (DEBUG) {
        if (DEBUG) {
            Log.d(TAG, "  mfgName:" + mfgName + " prodName:" + prodName);
            Log.d(TAG, "  mfgName:" + mfgName + " prodName:" + prodName);
        }
        }


        // Create version string in "%.%" format
        String versionString = getDeviceReleaseString();
        String versionString =
        String serialStr = getSerialString(parser);
                Integer.toString(mDeviceRelease >> 8) + "." + (mDeviceRelease & 0xFF);
        String serialStr = parser.getDescriptorString(mSerialNum);
        if (DEBUG) {
        if (DEBUG) {
            Log.d(TAG, "  versionString:" + versionString + " serialStr:" + serialStr);
            Log.d(TAG, "  versionString:" + versionString + " serialStr:" + serialStr);
        }
        }
@@ -159,7 +178,7 @@ public final class UsbDeviceDescriptor extends UsbDescriptor {
        mDeviceRelease = stream.unpackUsbShort();
        mDeviceRelease = stream.unpackUsbShort();
        mMfgIndex = stream.getByte();
        mMfgIndex = stream.getByte();
        mProductIndex = stream.getByte();
        mProductIndex = stream.getByte();
        mSerialNum = stream.getByte();
        mSerialIndex = stream.getByte();
        mNumConfigs = stream.getByte();
        mNumConfigs = stream.getByte();


        return mLength;
        return mLength;
+50 B

File added.

No diff preview for this file type.

+89 −8
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.usb;


import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.junit.Assert.fail;


import android.content.Context;
import android.content.Context;
@@ -28,6 +29,7 @@ import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.runner.AndroidJUnit4;


import com.android.server.usb.descriptors.UsbDescriptorParser;
import com.android.server.usb.descriptors.UsbDescriptorParser;
import com.android.server.usb.descriptors.UsbDeviceDescriptor;
import com.google.common.io.ByteStreams;
import com.google.common.io.ByteStreams;


import java.io.InputStream;
import java.io.InputStream;
@@ -61,14 +63,24 @@ public class UsbDescriptorParserTests {
        }
        }


        // Testing same codepath as UsbHostManager.java:usbDeviceAdded
        // Testing same codepath as UsbHostManager.java:usbDeviceAdded
        UsbDescriptorParser parser = new UsbDescriptorParser("test-usb-addr");
        UsbDescriptorParser parser = new UsbDescriptorParser("test-usb-addr", descriptors);
        if (!parser.parseDescriptors(descriptors)) {
            fail("failed to parse descriptors.");
        }
        return parser;
        return parser;
    }
    }


    // A Headset has a microphone and a speaker and is a headset.
    /** A Headset has a microphone and a speaker and is a headset.
     * Descriptors for this example show up on lsusb -v with:
     *   bcdDevice           22.80
     * and a UAC1 audio device with the following control interface:
     *       bInterfaceClass         1 Audio
     * ...
     *       bDescriptorSubtype      2 (INPUT_TERMINAL)
     *       bTerminalID             1
     *       wTerminalType      0x0201 Microphone
     * ...
     *       bDescriptorSubtype      3 (OUTPUT_TERMINAL)
     *       bTerminalID            15
     *       wTerminalType      0x0302 Headphones
     */
    @Test
    @Test
    @SmallTest
    @SmallTest
    public void testHeadsetDescriptorParser() {
    public void testHeadsetDescriptorParser() {
@@ -77,9 +89,24 @@ public class UsbDescriptorParserTests {
        assertTrue(parser.hasOutput());
        assertTrue(parser.hasOutput());
        assertTrue(parser.isInputHeadset());
        assertTrue(parser.isInputHeadset());
        assertTrue(parser.isOutputHeadset());
        assertTrue(parser.isOutputHeadset());

        assertTrue(parser.hasAudioInterface());
        assertTrue(parser.hasHIDInterface());
        assertFalse(parser.hasStorageInterface());

        assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
    }
    }


    // Headphones have no microphones but are considered a headset.
    /** Headphones have no microphones but are considered a headset.
     * Descriptors for this example show up on lsusb -v with:
     *   bcdDevice           22.80
     * and a UAC1 audio device with the following control interface:
     *       bInterfaceClass         1 Audio
     * ...
     *       bDescriptorSubtype      3 (OUTPUT_TERMINAL)
     *       bTerminalID            15
     *       wTerminalType      0x0302 Headphones
     */
    @Test
    @Test
    @SmallTest
    @SmallTest
    public void testHeadphoneDescriptorParser() {
    public void testHeadphoneDescriptorParser() {
@@ -88,9 +115,24 @@ public class UsbDescriptorParserTests {
        assertTrue(parser.hasOutput());
        assertTrue(parser.hasOutput());
        assertFalse(parser.isInputHeadset());
        assertFalse(parser.isInputHeadset());
        assertTrue(parser.isOutputHeadset());
        assertTrue(parser.isOutputHeadset());

        assertTrue(parser.hasAudioInterface());
        assertTrue(parser.hasHIDInterface());
        assertFalse(parser.hasStorageInterface());

        assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
    }
    }


    // Line out has no microphones and aren't considered a headset.
    /** Line out with no microphones aren't considered a headset.
     * Descriptors for this example show up on lsusb -v with:
     *     bcdDevice           22.80
     * and the following UAC1 audio control interface
     *  bInterfaceClass         1 Audio
     *  ...
     *   bDescriptorSubtype      3 (OUTPUT_TERMINAL)
     *   bTerminalID            15
     *   wTerminalType      0x0603 Line Connector
     */
    @Test
    @Test
    @SmallTest
    @SmallTest
    public void testLineoutDescriptorParser() {
    public void testLineoutDescriptorParser() {
@@ -99,9 +141,20 @@ public class UsbDescriptorParserTests {
        assertTrue(parser.hasOutput());
        assertTrue(parser.hasOutput());
        assertFalse(parser.isInputHeadset());
        assertFalse(parser.isInputHeadset());
        assertFalse(parser.isOutputHeadset());
        assertFalse(parser.isOutputHeadset());

        assertTrue(parser.hasAudioInterface());
        assertTrue(parser.hasHIDInterface());
        assertFalse(parser.hasStorageInterface());

        assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
    }
    }


    // An HID-only device shouldn't be considered anything at all.
    /** An HID-only device shouldn't be considered anything at all.
    /* Descriptors show up on lsusb -v with:
     *   bcdDevice           22.80
     * and a single HID interface,
     *   bInterfaceClass         3 Human Interface Device
     */
    @Test
    @Test
    @SmallTest
    @SmallTest
    public void testNothingDescriptorParser() {
    public void testNothingDescriptorParser() {
@@ -110,6 +163,34 @@ public class UsbDescriptorParserTests {
        assertFalse(parser.hasOutput());
        assertFalse(parser.hasOutput());
        assertFalse(parser.isInputHeadset());
        assertFalse(parser.isInputHeadset());
        assertFalse(parser.isOutputHeadset());
        assertFalse(parser.isOutputHeadset());

        assertFalse(parser.hasAudioInterface());
        assertTrue(parser.hasHIDInterface());
        assertFalse(parser.hasStorageInterface());

        assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
    }

    /** A USB mass-storage device.
     * Shows up on lsusb -v with:
     *    bcdDevice            2.08
     * and a single interface descriptor,
     *    bInterfaceClass         8 Mass Storage
     */
    @Test
    @SmallTest
    public void testMassStorageDescriptorParser() {
        UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_massstorage);
        assertFalse(parser.hasInput());
        assertFalse(parser.hasOutput());
        assertFalse(parser.isInputHeadset());
        assertFalse(parser.isOutputHeadset());

        assertFalse(parser.hasAudioInterface());
        assertFalse(parser.hasHIDInterface());
        assertTrue(parser.hasStorageInterface());

        assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "2.08");
    }
    }


}
}