diff options
author | reillyg@chromium.org <reillyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-13 20:53:00 +0000 |
---|---|---|
committer | reillyg@chromium.org <reillyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-13 20:54:17 +0000 |
commit | 4a9d240b2e59fcfca5fe8dca408a9a33077f210a (patch) | |
tree | 527dbe99a9d451025cd9d3b845c7d2d985e249af | |
parent | 312e33116c0916b89cf831aa95464028d559690e (diff) | |
download | chromium_src-4a9d240b2e59fcfca5fe8dca408a9a33077f210a.zip chromium_src-4a9d240b2e59fcfca5fe8dca408a9a33077f210a.tar.gz chromium_src-4a9d240b2e59fcfca5fe8dca408a9a33077f210a.tar.bz2 |
Add usb_service::UsbDeviceFilter class for device matching.
This class stores criteria for selecting USB devices. A device can be
matched by its vendor and product IDs, and the interfaces that it
implements.
BUG=346953
TBR=satorux@chromium.org
Review URL: https://codereview.chromium.org/462753002
Cr-Commit-Position: refs/heads/master@{#289370}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289370 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/devtools/device/usb/android_usb_browsertest.cc | 2 | ||||
-rw-r--r-- | chrome/browser/devtools/device/usb/android_usb_device.cc | 4 | ||||
-rw-r--r-- | chromeos/dbus/permission_broker_client.h | 4 | ||||
-rw-r--r-- | components/components_tests.gyp | 2 | ||||
-rw-r--r-- | components/usb_service.gypi | 2 | ||||
-rw-r--r-- | components/usb_service/usb_device.h | 2 | ||||
-rw-r--r-- | components/usb_service/usb_device_filter.cc | 128 | ||||
-rw-r--r-- | components/usb_service/usb_device_filter.h | 48 | ||||
-rw-r--r-- | components/usb_service/usb_device_filter_unittest.cc | 239 | ||||
-rw-r--r-- | components/usb_service/usb_device_impl.cc | 2 | ||||
-rw-r--r-- | components/usb_service/usb_device_impl.h | 2 | ||||
-rw-r--r-- | extensions/browser/api/usb/usb_api.cc | 26 | ||||
-rw-r--r-- | extensions/browser/api/usb/usb_apitest.cc | 2 |
13 files changed, 441 insertions, 22 deletions
diff --git a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc index 6baed7e..be1f167 100644 --- a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc +++ b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc @@ -464,7 +464,7 @@ class MockUsbDevice : public UsbDevice { // permission broker can change the owner of the device so that the unclaimed // interfaces can be used. If this argument is missing, permission broker will // not be used and this method fails if the device is claimed. - virtual void RequestUsbAcess( + virtual void RequestUsbAccess( int interface_id, const base::Callback<void(bool success)>& callback) OVERRIDE { callback.Run(true); diff --git a/chrome/browser/devtools/device/usb/android_usb_device.cc b/chrome/browser/devtools/device/usb/android_usb_device.cc index fd40fad..b4d24d7 100644 --- a/chrome/browser/devtools/device/usb/android_usb_device.cc +++ b/chrome/browser/devtools/device/usb/android_usb_device.cc @@ -277,8 +277,8 @@ static void EnumerateOnFileThread( // Request permission on Chrome OS. #if defined(OS_CHROMEOS) - (*it)->RequestUsbAcess(j, base::Bind(&OpenAndroidDeviceOnFileThread, - devices, rsa_key, barrier, *it, j)); + (*it)->RequestUsbAccess(j, base::Bind(&OpenAndroidDeviceOnFileThread, + devices, rsa_key, barrier, *it, j)); #else OpenAndroidDeviceOnFileThread(devices, rsa_key, barrier, *it, j, true); #endif // defined(OS_CHROMEOS) diff --git a/chromeos/dbus/permission_broker_client.h b/chromeos/dbus/permission_broker_client.h index 17e215a..9ee953a 100644 --- a/chromeos/dbus/permission_broker_client.h +++ b/chromeos/dbus/permission_broker_client.h @@ -24,8 +24,8 @@ namespace chromeos { class CHROMEOS_EXPORT PermissionBrokerClient : public DBusClient { public: // The ResultCallback is used for both the RequestPathAccess and - // RequestUsbAcess methods. Its boolean parameter represents the result of the - // operation that it was submitted alongside. + // RequestUsbAccess methods. Its boolean parameter represents the result of + // the operation that it was submitted alongside. typedef base::Callback<void(bool)> ResultCallback; virtual ~PermissionBrokerClient(); diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 6b5a7e9..543beca57 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -404,6 +404,7 @@ 'autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc', 'dom_distiller/content/dom_distiller_viewer_source_unittest.cc', 'usb_service/usb_context_unittest.cc', + 'usb_service/usb_device_filter_unittest.cc', ], 'dependencies': [ # Dependencies of autofill @@ -553,6 +554,7 @@ 'storage_monitor/storage_info_unittest.cc', 'storage_monitor/storage_monitor_unittest.cc', 'usb_service/usb_context_unittest.cc', + 'usb_service/usb_device_filter_unittest.cc', 'web_modal/web_contents_modal_dialog_manager_unittest.cc', ], 'dependencies': [ diff --git a/components/usb_service.gypi b/components/usb_service.gypi index 5f85452..ed165f7 100644 --- a/components/usb_service.gypi +++ b/components/usb_service.gypi @@ -27,6 +27,8 @@ 'usb_service/usb_device_impl.cc', 'usb_service/usb_device_impl.h', 'usb_service/usb_device.h', + 'usb_service/usb_device_filter.cc', + 'usb_service/usb_device_filter.h', 'usb_service/usb_device_handle_impl.cc', 'usb_service/usb_device_handle_impl.h', 'usb_service/usb_device_handle.h', diff --git a/components/usb_service/usb_device.h b/components/usb_service/usb_device.h index 076af18..48ca516 100644 --- a/components/usb_service/usb_device.h +++ b/components/usb_service/usb_device.h @@ -31,7 +31,7 @@ class USB_SERVICE_EXPORT UsbDevice // permission broker can change the owner of the device so that the unclaimed // interfaces can be used. If this argument is missing, permission broker will // not be used and this method fails if the device is claimed. - virtual void RequestUsbAcess( + virtual void RequestUsbAccess( int interface_id, const base::Callback<void(bool success)>& callback) = 0; #endif // OS_CHROMEOS diff --git a/components/usb_service/usb_device_filter.cc b/components/usb_service/usb_device_filter.cc new file mode 100644 index 0000000..45f8d12 --- /dev/null +++ b/components/usb_service/usb_device_filter.cc @@ -0,0 +1,128 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/usb_service/usb_device_filter.h" + +#include "base/values.h" +#include "components/usb_service/usb_device.h" +#include "components/usb_service/usb_device_handle.h" +#include "components/usb_service/usb_interface.h" + +namespace usb_service { + +namespace { + +const char kProductIdKey[] = "productId"; +const char kVendorIdKey[] = "vendorId"; +const char kInterfaceClassKey[] = "interfaceClass"; +const char kInterfaceSubclassKey[] = "interfaceSubclass"; +const char kInterfaceProtocolKey[] = "interfaceProtocol"; + +} // namespace + +UsbDeviceFilter::UsbDeviceFilter() + : vendor_id_set_(false), + product_id_set_(false), + interface_class_set_(false), + interface_subclass_set_(false), + interface_protocol_set_(false) { +} + +UsbDeviceFilter::~UsbDeviceFilter() { +} + +void UsbDeviceFilter::SetVendorId(uint16 vendor_id) { + vendor_id_set_ = true; + vendor_id_ = vendor_id; +} + +void UsbDeviceFilter::SetProductId(uint16 product_id) { + product_id_set_ = true; + product_id_ = product_id; +} + +void UsbDeviceFilter::SetInterfaceClass(uint8 interface_class) { + interface_class_set_ = true; + interface_class_ = interface_class; +} + +void UsbDeviceFilter::SetInterfaceSubclass(uint8 interface_subclass) { + interface_subclass_set_ = true; + interface_subclass_ = interface_subclass; +} + +void UsbDeviceFilter::SetInterfaceProtocol(uint8 interface_protocol) { + interface_protocol_set_ = true; + interface_protocol_ = interface_protocol; +} + +bool UsbDeviceFilter::Matches(scoped_refptr<UsbDevice> device) { + if (vendor_id_set_) { + if (device->vendor_id() != vendor_id_) { + return false; + } + + if (product_id_set_ && device->product_id() != product_id_) { + return false; + } + } + + if (interface_class_set_) { + bool foundMatch = false; + scoped_refptr<const UsbConfigDescriptor> config = device->ListInterfaces(); + + // TODO(reillyg): Check device configuration if the class is not defined at + // a per-interface level. This is not really important because most devices + // have per-interface classes. The only counter-examples I know of are hubs. + + for (size_t i = 0; i < config->GetNumInterfaces() && !foundMatch; ++i) { + scoped_refptr<const UsbInterfaceDescriptor> iface = + config->GetInterface(i); + + for (size_t j = 0; j < iface->GetNumAltSettings() && !foundMatch; ++j) { + scoped_refptr<const UsbInterfaceAltSettingDescriptor> altSetting = + iface->GetAltSetting(j); + + if (altSetting->GetInterfaceClass() == interface_class_ && + (!interface_subclass_set_ || + (altSetting->GetInterfaceSubclass() == interface_subclass_ && + (!interface_protocol_set_ || + altSetting->GetInterfaceProtocol() == interface_protocol_)))) { + foundMatch = true; + } + } + } + + if (!foundMatch) { + return false; + } + } + + return true; +} + +base::Value* UsbDeviceFilter::ToValue() const { + scoped_ptr<base::DictionaryValue> obj(new base::DictionaryValue()); + + if (vendor_id_set_) { + obj->SetInteger(kVendorIdKey, vendor_id_); + if (product_id_set_) { + obj->SetInteger(kProductIdKey, product_id_); + } + } + + if (interface_class_set_) { + obj->SetInteger(kInterfaceClassKey, interface_class_); + if (interface_subclass_set_) { + obj->SetInteger(kInterfaceSubclassKey, interface_subclass_); + if (interface_protocol_set_) { + obj->SetInteger(kInterfaceProtocolKey, interface_protocol_); + } + } + } + + return obj.release(); +} + +} // namespace usb_service diff --git a/components/usb_service/usb_device_filter.h b/components/usb_service/usb_device_filter.h new file mode 100644 index 0000000..76a3b2c --- /dev/null +++ b/components/usb_service/usb_device_filter.h @@ -0,0 +1,48 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_USB_SERVICE_USB_DEVICE_FILTER_H_ +#define COMPONENTS_USB_SERVICE_USB_DEVICE_FILTER_H_ + +#include "base/memory/ref_counted.h" +#include "components/usb_service/usb_service_export.h" + +namespace base { +class Value; +} + +namespace usb_service { + +class UsbDevice; + +class USB_SERVICE_EXPORT UsbDeviceFilter { + public: + UsbDeviceFilter(); + ~UsbDeviceFilter(); + + void SetVendorId(uint16 vendor_id); + void SetProductId(uint16 product_id); + void SetInterfaceClass(uint8 interface_class); + void SetInterfaceSubclass(uint8 interface_subclass); + void SetInterfaceProtocol(uint8 interface_protocol); + + bool Matches(scoped_refptr<UsbDevice> device); + base::Value* ToValue() const; + + private: + uint16 vendor_id_; + uint16 product_id_; + uint8 interface_class_; + uint8 interface_subclass_; + uint8 interface_protocol_; + bool vendor_id_set_ : 1; + bool product_id_set_ : 1; + bool interface_class_set_ : 1; + bool interface_subclass_set_ : 1; + bool interface_protocol_set_ : 1; +}; + +} // namespace usb_service + +#endif // COMPONENTS_USB_SERVICE_USB_DEVICE_FILTER_H_ diff --git a/components/usb_service/usb_device_filter_unittest.cc b/components/usb_service/usb_device_filter_unittest.cc new file mode 100644 index 0000000..a812068 --- /dev/null +++ b/components/usb_service/usb_device_filter_unittest.cc @@ -0,0 +1,239 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <vector> + +#include "base/memory/ref_counted.h" +#include "components/usb_service/usb_device.h" +#include "components/usb_service/usb_device_filter.h" +#include "components/usb_service/usb_device_handle.h" +#include "components/usb_service/usb_interface.h" +#include "testing/gtest/include/gtest/gtest.h" + +using usb_service::UsbConfigDescriptor; +using usb_service::UsbDevice; +using usb_service::UsbDeviceFilter; +using usb_service::UsbDeviceHandle; +using usb_service::UsbEndpointDescriptor; +using usb_service::UsbInterfaceAltSettingDescriptor; +using usb_service::UsbInterfaceDescriptor; + +namespace { + +class MockUsbInterfaceAltSettingDescriptor + : public UsbInterfaceAltSettingDescriptor { + public: + MockUsbInterfaceAltSettingDescriptor(int interface_number, + int alternate_setting, + int interface_class, + int interface_subclass, + int interface_protocol) + : interface_number_(interface_number), + alternate_setting_(alternate_setting), + interface_class_(interface_class), + interface_subclass_(interface_subclass), + interface_protocol_(interface_protocol) {} + + virtual size_t GetNumEndpoints() const OVERRIDE { return 0; } + virtual scoped_refptr<const UsbEndpointDescriptor> GetEndpoint( + size_t index) const OVERRIDE { + return NULL; + } + virtual int GetInterfaceNumber() const OVERRIDE { return interface_number_; } + virtual int GetAlternateSetting() const OVERRIDE { + return alternate_setting_; + } + virtual int GetInterfaceClass() const OVERRIDE { return interface_class_; } + virtual int GetInterfaceSubclass() const OVERRIDE { + return interface_subclass_; + } + virtual int GetInterfaceProtocol() const OVERRIDE { + return interface_protocol_; + } + + protected: + virtual ~MockUsbInterfaceAltSettingDescriptor() {} + + private: + int interface_number_; + int alternate_setting_; + int interface_class_; + int interface_subclass_; + int interface_protocol_; +}; + +typedef std::vector<scoped_refptr<UsbInterfaceAltSettingDescriptor> > + UsbInterfaceAltSettingDescriptorList; + +class MockUsbInterfaceDescriptor : public UsbInterfaceDescriptor { + public: + MockUsbInterfaceDescriptor( + const UsbInterfaceAltSettingDescriptorList& alt_settings) + : alt_settings_(alt_settings) {} + + virtual size_t GetNumAltSettings() const OVERRIDE { + return alt_settings_.size(); + } + virtual scoped_refptr<const UsbInterfaceAltSettingDescriptor> GetAltSetting( + size_t index) const OVERRIDE { + return alt_settings_[index]; + } + + protected: + virtual ~MockUsbInterfaceDescriptor() {} + + private: + UsbInterfaceAltSettingDescriptorList alt_settings_; +}; + +typedef std::vector<scoped_refptr<UsbInterfaceDescriptor> > + UsbInterfaceDescriptorList; + +class MockUsbConfigDescriptor : public UsbConfigDescriptor { + public: + MockUsbConfigDescriptor(const UsbInterfaceDescriptorList& interfaces) + : interfaces_(interfaces) {} + + virtual size_t GetNumInterfaces() const OVERRIDE { + return interfaces_.size(); + } + virtual scoped_refptr<const UsbInterfaceDescriptor> GetInterface( + size_t index) const OVERRIDE { + return interfaces_[index]; + } + + protected: + virtual ~MockUsbConfigDescriptor() {} + + private: + UsbInterfaceDescriptorList interfaces_; +}; + +class MockUsbDevice : public UsbDevice { + public: + MockUsbDevice(uint16 vendor_id, + uint16 product_id, + uint32 unique_id, + scoped_refptr<UsbConfigDescriptor> config_desc) + : UsbDevice(vendor_id, product_id, unique_id), + config_desc_(config_desc) {} + + virtual scoped_refptr<UsbDeviceHandle> Open() OVERRIDE { return NULL; } + virtual bool Close(scoped_refptr<UsbDeviceHandle> handle) OVERRIDE { + NOTREACHED(); + return true; + } +#if defined(OS_CHROMEOS) + virtual void RequestUsbAccess( + int interface_id, + const base::Callback<void(bool success)>& callback) OVERRIDE { + NOTREACHED(); + } +#endif // OS_CHROMEOS + virtual scoped_refptr<UsbConfigDescriptor> ListInterfaces() OVERRIDE { + return config_desc_; + } + + protected: + virtual ~MockUsbDevice() {} + + private: + scoped_refptr<UsbConfigDescriptor> config_desc_; +}; + +class UsbFilterTest : public testing::Test { + public: + virtual void SetUp() OVERRIDE { + UsbInterfaceAltSettingDescriptorList alt_settings; + alt_settings.push_back(make_scoped_refptr( + new MockUsbInterfaceAltSettingDescriptor(1, 0, 0xFF, 0x42, 1))); + + UsbInterfaceDescriptorList interfaces; + interfaces.push_back( + make_scoped_refptr(new MockUsbInterfaceDescriptor(alt_settings))); + + scoped_refptr<UsbConfigDescriptor> config_desc( + new MockUsbConfigDescriptor(interfaces)); + + android_phone_ = new MockUsbDevice(0x18d1, 0x4ee2, 0, config_desc); + } + + protected: + scoped_refptr<UsbDevice> android_phone_; +}; + +} // namespace + +TEST_F(UsbFilterTest, MatchAny) { + UsbDeviceFilter filter; + ASSERT_TRUE(filter.Matches(android_phone_)); +} + +TEST_F(UsbFilterTest, MatchVendorId) { + UsbDeviceFilter filter; + filter.SetVendorId(0x18d1); + ASSERT_TRUE(filter.Matches(android_phone_)); +} + +TEST_F(UsbFilterTest, MatchVendorIdNegative) { + UsbDeviceFilter filter; + filter.SetVendorId(0x1d6b); + ASSERT_FALSE(filter.Matches(android_phone_)); +} + +TEST_F(UsbFilterTest, MatchProductId) { + UsbDeviceFilter filter; + filter.SetVendorId(0x18d1); + filter.SetProductId(0x4ee2); + ASSERT_TRUE(filter.Matches(android_phone_)); +} + +TEST_F(UsbFilterTest, MatchProductIdNegative) { + UsbDeviceFilter filter; + filter.SetVendorId(0x18d1); + filter.SetProductId(0x4ee1); + ASSERT_FALSE(filter.Matches(android_phone_)); +} + +TEST_F(UsbFilterTest, MatchInterfaceClass) { + UsbDeviceFilter filter; + filter.SetInterfaceClass(0xff); + ASSERT_TRUE(filter.Matches(android_phone_)); +} + +TEST_F(UsbFilterTest, MatchInterfaceClassNegative) { + UsbDeviceFilter filter; + filter.SetInterfaceClass(0xe0); + ASSERT_FALSE(filter.Matches(android_phone_)); +} + +TEST_F(UsbFilterTest, MatchInterfaceSubclass) { + UsbDeviceFilter filter; + filter.SetInterfaceClass(0xff); + filter.SetInterfaceSubclass(0x42); + ASSERT_TRUE(filter.Matches(android_phone_)); +} + +TEST_F(UsbFilterTest, MatchInterfaceSubclassNegative) { + UsbDeviceFilter filter; + filter.SetInterfaceClass(0xff); + filter.SetInterfaceSubclass(0x01); + ASSERT_FALSE(filter.Matches(android_phone_)); +} + +TEST_F(UsbFilterTest, MatchInterfaceProtocol) { + UsbDeviceFilter filter; + filter.SetInterfaceClass(0xff); + filter.SetInterfaceSubclass(0x42); + filter.SetInterfaceProtocol(0x01); + ASSERT_TRUE(filter.Matches(android_phone_)); +} + +TEST_F(UsbFilterTest, MatchInterfaceProtocolNegative) { + UsbDeviceFilter filter; + filter.SetInterfaceClass(0xff); + filter.SetInterfaceSubclass(0x42); + filter.SetInterfaceProtocol(0x02); + ASSERT_FALSE(filter.Matches(android_phone_)); +} diff --git a/components/usb_service/usb_device_impl.cc b/components/usb_service/usb_device_impl.cc index 98c3a49..aaba7e3 100644 --- a/components/usb_service/usb_device_impl.cc +++ b/components/usb_service/usb_device_impl.cc @@ -61,7 +61,7 @@ UsbDeviceImpl::~UsbDeviceImpl() { #if defined(OS_CHROMEOS) -void UsbDeviceImpl::RequestUsbAcess( +void UsbDeviceImpl::RequestUsbAccess( int interface_id, const base::Callback<void(bool success)>& callback) { DCHECK(thread_checker_.CalledOnValidThread()); diff --git a/components/usb_service/usb_device_impl.h b/components/usb_service/usb_device_impl.h index db84f5e..e27a692 100644 --- a/components/usb_service/usb_device_impl.h +++ b/components/usb_service/usb_device_impl.h @@ -27,7 +27,7 @@ class UsbDeviceImpl : public UsbDevice { public: // UsbDevice implementation: #if defined(OS_CHROMEOS) - virtual void RequestUsbAcess( + virtual void RequestUsbAccess( int interface_id, const base::Callback<void(bool success)>& callback) OVERRIDE; #endif // OS_CHROMEOS diff --git a/extensions/browser/api/usb/usb_api.cc b/extensions/browser/api/usb/usb_api.cc index 7490f10..18b0e53 100644 --- a/extensions/browser/api/usb/usb_api.cc +++ b/extensions/browser/api/usb/usb_api.cc @@ -325,12 +325,12 @@ void RequestUsbDevicesAccessHelper( callback.Run(devices.Pass()); return; } - (*i)->RequestUsbAcess(interface_id, - base::Bind(RequestUsbDevicesAccessHelper, - base::Passed(devices.Pass()), - i, - interface_id, - callback)); + (*i)->RequestUsbAccess(interface_id, + base::Bind(RequestUsbDevicesAccessHelper, + base::Passed(devices.Pass()), + i, + interface_id, + callback)); } void RequestUsbDevicesAccess( @@ -342,12 +342,12 @@ void RequestUsbDevicesAccess( return; } std::vector<scoped_refptr<UsbDevice> >::iterator i = devices->begin(); - (*i)->RequestUsbAcess(interface_id, - base::Bind(RequestUsbDevicesAccessHelper, - base::Passed(devices.Pass()), - i, - interface_id, - callback)); + (*i)->RequestUsbAccess(interface_id, + base::Bind(RequestUsbDevicesAccessHelper, + base::Passed(devices.Pass()), + i, + interface_id, + callback)); } #endif // OS_CHROMEOS @@ -680,7 +680,7 @@ void UsbRequestAccessFunction::AsyncWorkStart() { if (!device) return; - device->RequestUsbAcess( + device->RequestUsbAccess( parameters_->interface_id, base::Bind(&UsbRequestAccessFunction::OnCompleted, this)); #else diff --git a/extensions/browser/api/usb/usb_apitest.cc b/extensions/browser/api/usb/usb_apitest.cc index 8d6fb55..215475f 100644 --- a/extensions/browser/api/usb/usb_apitest.cc +++ b/extensions/browser/api/usb/usb_apitest.cc @@ -131,7 +131,7 @@ class MockUsbDevice : public UsbDevice { } #if defined(OS_CHROMEOS) - virtual void RequestUsbAcess( + virtual void RequestUsbAccess( int interface_id, const base::Callback<void(bool success)>& callback) OVERRIDE { BrowserThread::PostTask( |