Disable vendor id filtering for OS X.
Companion patch for change I2bf583a27f9a3f98ef006ea62b906a4f89960507.
Due to the use of USB class 0xff it's not possible to register a listener
which uses the OS methods for filtering notifications, so this patch
also introduces a check in the notification listener which checks the
class, subclass, and protocol for the interface each notification relates
to.
Change-Id: I380cc80f96addc5057660efb2179b35f9378886a
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index ee893f5..ba157f1 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -28,12 +28,11 @@
#define TRACE_TAG TRACE_USB
#include "adb.h"
-#include "usb_vendors.h"
#define DBG D
static IONotificationPortRef notificationPort = 0;
-static io_iterator_t* notificationIterators;
+static io_iterator_t notificationIterator;
struct usb_handle
{
@@ -61,8 +60,6 @@
{
CFMutableDictionaryRef matchingDict;
CFRunLoopSourceRef runLoopSource;
- SInt32 vendor, if_subclass, if_protocol;
- unsigned i;
//* To set up asynchronous notifications, create a notification port and
//* add its run loop event source to the program's run loop
@@ -70,47 +67,33 @@
runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
- memset(notificationIterators, 0, sizeof(notificationIterators));
+ //* Create our matching dictionary to find the Android device's
+ //* adb interface
+ //* IOServiceAddMatchingNotification consumes the reference, so we do
+ //* not need to release this
+ matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
- //* loop through all supported vendors
- for (i = 0; i < vendorIdCount; i++) {
- //* Create our matching dictionary to find the Android device's
- //* adb interface
- //* IOServiceAddMatchingNotification consumes the reference, so we do
- //* not need to release this
- matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
-
- if (!matchingDict) {
- DBG("ERR: Couldn't create USB matching dictionary.\n");
- return -1;
- }
-
- //* Match based on vendor id, interface subclass and protocol
- vendor = vendorIds[i];
- if_subclass = ADB_SUBCLASS;
- if_protocol = ADB_PROTOCOL;
- CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID),
- CFNumberCreate(kCFAllocatorDefault,
- kCFNumberSInt32Type, &vendor));
- CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass),
- CFNumberCreate(kCFAllocatorDefault,
- kCFNumberSInt32Type, &if_subclass));
- CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol),
- CFNumberCreate(kCFAllocatorDefault,
- kCFNumberSInt32Type, &if_protocol));
- IOServiceAddMatchingNotification(
- notificationPort,
- kIOFirstMatchNotification,
- matchingDict,
- AndroidInterfaceAdded,
- NULL,
- ¬ificationIterators[i]);
-
- //* Iterate over set of matching interfaces to access already-present
- //* devices and to arm the notification
- AndroidInterfaceAdded(NULL, notificationIterators[i]);
+ if (!matchingDict) {
+ DBG("ERR: Couldn't create USB matching dictionary.\n");
+ return -1;
}
+ //* We have to get notifications for all potential candidates and test them
+ //* at connection time because the matching rules don't allow for a
+ //* USB interface class of 0xff for class+subclass+protocol matches
+ //* See https://developer.apple.com/library/mac/qa/qa1076/_index.html
+ IOServiceAddMatchingNotification(
+ notificationPort,
+ kIOFirstMatchNotification,
+ matchingDict,
+ AndroidInterfaceAdded,
+ NULL,
+ ¬ificationIterator);
+
+ //* Iterate over set of matching interfaces to access already-present
+ //* devices and to arm the notification
+ AndroidInterfaceAdded(NULL, notificationIterator);
+
return 0;
}
@@ -126,6 +109,7 @@
HRESULT result;
SInt32 score;
UInt32 locationId;
+ UInt8 class, subclass, protocol;
UInt16 vendor;
UInt16 product;
UInt8 serialIndex;
@@ -156,6 +140,16 @@
continue;
}
+ kr = (*iface)->GetInterfaceClass(iface, &class);
+ kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
+ kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
+ if(class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
+ // Ignore non-ADB devices.
+ DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", class, subclass, protocol);
+ (*iface)->Release(iface);
+ continue;
+ }
+
//* this gets us an ioservice, with which we will find the actual
//* device; after getting a plugin, and querying the interface, of
//* course.
@@ -192,7 +186,6 @@
//* Now after all that, we actually have a ref to the device and
//* the interface that matched our criteria
-
kr = (*dev)->GetDeviceVendor(dev, &vendor);
kr = (*dev)->GetDeviceProduct(dev, &product);
kr = (*dev)->GetLocationID(dev, &locationId);
@@ -385,8 +378,6 @@
void* RunLoopThread(void* unused)
{
- unsigned i;
-
InitUSB();
currentRunLoop = CFRunLoopGetCurrent();
@@ -399,9 +390,7 @@
CFRunLoopRun();
currentRunLoop = 0;
- for (i = 0; i < vendorIdCount; i++) {
- IOObjectRelease(notificationIterators[i]);
- }
+ IOObjectRelease(notificationIterator);
IONotificationPortDestroy(notificationPort);
DBG("RunLoopThread done\n");
@@ -416,9 +405,6 @@
{
adb_thread_t tid;
- notificationIterators = (io_iterator_t*)malloc(
- vendorIdCount * sizeof(io_iterator_t));
-
adb_mutex_init(&start_lock, NULL);
adb_cond_init(&start_cond, NULL);
@@ -443,11 +429,6 @@
close_usb_devices();
if (currentRunLoop)
CFRunLoopStop(currentRunLoop);
-
- if (notificationIterators != NULL) {
- free(notificationIterators);
- notificationIterators = NULL;
- }
}
int usb_write(usb_handle *handle, const void *buf, int len)