Merge changes I72688f65,I2dd8d439 into pi-dev
* changes: UsbHostManager: Restore inserted device logging UsbDescriptorParser: always parse in constructor
This commit is contained in:
committed by
Android (Google) Code Review
commit
ae0b962865
@@ -54,6 +54,7 @@ import java.util.LinkedList;
|
||||
public class UsbHostManager {
|
||||
private static final String TAG = UsbHostManager.class.getSimpleName();
|
||||
private static final boolean DEBUG = false;
|
||||
private static final int LINUX_FOUNDATION_VID = 0x1d6b;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
@@ -267,7 +268,6 @@ public class UsbHostManager {
|
||||
}
|
||||
|
||||
private boolean isBlackListed(String deviceAddress) {
|
||||
Slog.i(TAG, "isBlackListed(" + deviceAddress + ")");
|
||||
int count = mHostBlacklist.length;
|
||||
for (int i = 0; i < count; 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 */
|
||||
private boolean isBlackListed(int clazz, int subClass) {
|
||||
Slog.i(TAG, "isBlackListed(" + clazz + ", " + subClass + ")");
|
||||
// blacklist hubs
|
||||
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
|
||||
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.
|
||||
@@ -313,10 +346,18 @@ public class UsbHostManager {
|
||||
Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
|
||||
}
|
||||
|
||||
// check class/subclass first as it is more likely to be blacklisted
|
||||
if (isBlackListed(deviceClass, deviceSubclass) || isBlackListed(deviceAddress)) {
|
||||
if (isBlackListed(deviceAddress)) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "device is black listed");
|
||||
Slog.d(TAG, "device address is black listed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
|
||||
logUsbDevice(parser);
|
||||
|
||||
if (isBlackListed(deviceClass, deviceSubclass)) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "device class is black listed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -329,40 +370,31 @@ public class UsbHostManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress);
|
||||
if (parser.parseDescriptors(descriptors)) {
|
||||
|
||||
UsbDevice newDevice = parser.toAndroidUsbDevice();
|
||||
if (newDevice == null) {
|
||||
Slog.e(TAG, "Couldn't create UsbDevice object.");
|
||||
// Tracking
|
||||
addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADDEVICE,
|
||||
parser.getRawDescriptors());
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
mUsbAlsaManager.usbDeviceAdded(deviceAddress, newDevice, parser);
|
||||
|
||||
// Tracking
|
||||
addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
|
||||
parser.getRawDescriptors());
|
||||
}
|
||||
} else {
|
||||
Slog.e(TAG, "Error parsing USB device descriptors for " + deviceAddress);
|
||||
UsbDevice newDevice = parser.toAndroidUsbDevice();
|
||||
if (newDevice == null) {
|
||||
Slog.e(TAG, "Couldn't create UsbDevice object.");
|
||||
// Tracking
|
||||
addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADPARSE,
|
||||
addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADDEVICE,
|
||||
parser.getRawDescriptors());
|
||||
} else {
|
||||
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
|
||||
// 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);
|
||||
}
|
||||
|
||||
mUsbAlsaManager.usbDeviceAdded(deviceAddress, newDevice, parser);
|
||||
|
||||
// Tracking
|
||||
addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
|
||||
parser.getRawDescriptors());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,18 +408,18 @@ public class UsbHostManager {
|
||||
/* Called from JNI in monitorUsbHostBus to report USB device removal */
|
||||
@SuppressWarnings("unused")
|
||||
private void usbDeviceRemoved(String deviceAddress) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "usbDeviceRemoved(" + deviceAddress + ") - start");
|
||||
}
|
||||
synchronized (mLock) {
|
||||
UsbDevice device = mDevices.remove(deviceAddress);
|
||||
if (device != null) {
|
||||
Slog.d(TAG, "Removed device at " + deviceAddress + ": " + device.getProductName());
|
||||
mUsbAlsaManager.usbDeviceRemoved(deviceAddress/*device*/);
|
||||
mSettingsManager.usbDeviceRemoved(device);
|
||||
getCurrentUserSettings().usbDeviceRemoved(device);
|
||||
|
||||
// Tracking
|
||||
addConnectionRecord(deviceAddress, ConnectionRecord.DISCONNECT, null);
|
||||
} else {
|
||||
Slog.d(TAG, "Removed device at " + deviceAddress + " was already gone");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,11 +43,6 @@ public final class UsbDescriptorParser {
|
||||
// Obtained from the first AudioClass Header descriptor.
|
||||
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.
|
||||
* This is useful for reporting.
|
||||
@@ -214,7 +209,7 @@ public final class UsbDescriptorParser {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public boolean parseDescriptors(byte[] descriptors) {
|
||||
public void parseDescriptors(byte[] descriptors) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "parseDescriptors() - start");
|
||||
}
|
||||
@@ -248,17 +243,6 @@ public final class UsbDescriptorParser {
|
||||
if (DEBUG) {
|
||||
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() {
|
||||
@@ -490,15 +474,33 @@ public final class UsbDescriptorParser {
|
||||
return hasSpeaker;
|
||||
}
|
||||
|
||||
/**
|
||||
*@ hide
|
||||
*/
|
||||
public boolean hasAudioInterface() {
|
||||
ArrayList<UsbDescriptor> descriptors =
|
||||
getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_AUDIO);
|
||||
return !descriptors.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public boolean hasHIDDescriptor() {
|
||||
public boolean hasHIDInterface() {
|
||||
ArrayList<UsbDescriptor> descriptors =
|
||||
getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_HID);
|
||||
return !descriptors.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public boolean hasStorageInterface() {
|
||||
ArrayList<UsbDescriptor> descriptors =
|
||||
getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_STORAGE);
|
||||
return !descriptors.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -540,7 +542,7 @@ public final class UsbDescriptorParser {
|
||||
probability += 0.75f;
|
||||
}
|
||||
|
||||
if (hasMic && hasHIDDescriptor()) {
|
||||
if (hasMic && hasHIDInterface()) {
|
||||
probability += 0.25f;
|
||||
}
|
||||
|
||||
@@ -593,7 +595,7 @@ public final class UsbDescriptorParser {
|
||||
probability += 0.75f;
|
||||
}
|
||||
|
||||
if (hasSpeaker && hasHIDDescriptor()) {
|
||||
if (hasSpeaker && hasHIDInterface()) {
|
||||
probability += 0.25f;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public final class UsbDeviceDescriptor extends UsbDescriptor {
|
||||
private int mDeviceRelease; // 12:2 Device Release number - BCD
|
||||
private byte mMfgIndex; // 14:1 Index of Manufacturer 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 ArrayList<UsbConfigDescriptor> mConfigDescriptors =
|
||||
@@ -91,16 +91,37 @@ public final class UsbDeviceDescriptor extends UsbDescriptor {
|
||||
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() {
|
||||
return mMfgIndex;
|
||||
}
|
||||
|
||||
public String getMfgString(UsbDescriptorParser p) {
|
||||
return p.getDescriptorString(mMfgIndex);
|
||||
}
|
||||
|
||||
public byte getProductIndex() {
|
||||
return mProductIndex;
|
||||
}
|
||||
|
||||
public byte getSerialNum() {
|
||||
return mSerialNum;
|
||||
public String getProductString(UsbDescriptorParser p) {
|
||||
return p.getDescriptorString(mProductIndex);
|
||||
}
|
||||
|
||||
public byte getSerialIndex() {
|
||||
return mSerialIndex;
|
||||
}
|
||||
|
||||
public String getSerialString(UsbDescriptorParser p) {
|
||||
return p.getDescriptorString(mSerialIndex);
|
||||
}
|
||||
|
||||
public byte getNumConfigs() {
|
||||
@@ -119,16 +140,14 @@ public final class UsbDeviceDescriptor extends UsbDescriptor {
|
||||
Log.d(TAG, "toAndroid()");
|
||||
}
|
||||
|
||||
String mfgName = parser.getDescriptorString(mMfgIndex);
|
||||
String prodName = parser.getDescriptorString(mProductIndex);
|
||||
String mfgName = getMfgString(parser);
|
||||
String prodName = getProductString(parser);
|
||||
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);
|
||||
String versionString = getDeviceReleaseString();
|
||||
String serialStr = getSerialString(parser);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, " versionString:" + versionString + " serialStr:" + serialStr);
|
||||
}
|
||||
@@ -159,7 +178,7 @@ public final class UsbDeviceDescriptor extends UsbDescriptor {
|
||||
mDeviceRelease = stream.unpackUsbShort();
|
||||
mMfgIndex = stream.getByte();
|
||||
mProductIndex = stream.getByte();
|
||||
mSerialNum = stream.getByte();
|
||||
mSerialIndex = stream.getByte();
|
||||
mNumConfigs = stream.getByte();
|
||||
|
||||
return mLength;
|
||||
|
||||
BIN
tests/UsbTests/res/raw/usbdescriptors_massstorage.bin
Normal file
BIN
tests/UsbTests/res/raw/usbdescriptors_massstorage.bin
Normal file
Binary file not shown.
@@ -18,6 +18,7 @@ package com.android.server.usb;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -28,6 +29,7 @@ import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.usb.descriptors.UsbDescriptorParser;
|
||||
import com.android.server.usb.descriptors.UsbDeviceDescriptor;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
import java.io.InputStream;
|
||||
@@ -61,14 +63,24 @@ public class UsbDescriptorParserTests {
|
||||
}
|
||||
|
||||
// Testing same codepath as UsbHostManager.java:usbDeviceAdded
|
||||
UsbDescriptorParser parser = new UsbDescriptorParser("test-usb-addr");
|
||||
if (!parser.parseDescriptors(descriptors)) {
|
||||
fail("failed to parse descriptors.");
|
||||
}
|
||||
UsbDescriptorParser parser = new UsbDescriptorParser("test-usb-addr", descriptors);
|
||||
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
|
||||
@SmallTest
|
||||
public void testHeadsetDescriptorParser() {
|
||||
@@ -77,9 +89,24 @@ public class UsbDescriptorParserTests {
|
||||
assertTrue(parser.hasOutput());
|
||||
assertTrue(parser.isInputHeadset());
|
||||
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
|
||||
@SmallTest
|
||||
public void testHeadphoneDescriptorParser() {
|
||||
@@ -88,9 +115,24 @@ public class UsbDescriptorParserTests {
|
||||
assertTrue(parser.hasOutput());
|
||||
assertFalse(parser.isInputHeadset());
|
||||
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
|
||||
@SmallTest
|
||||
public void testLineoutDescriptorParser() {
|
||||
@@ -99,9 +141,20 @@ public class UsbDescriptorParserTests {
|
||||
assertTrue(parser.hasOutput());
|
||||
assertFalse(parser.isInputHeadset());
|
||||
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
|
||||
@SmallTest
|
||||
public void testNothingDescriptorParser() {
|
||||
@@ -110,6 +163,34 @@ public class UsbDescriptorParserTests {
|
||||
assertFalse(parser.hasOutput());
|
||||
assertFalse(parser.isInputHeadset());
|
||||
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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user