Commit 7c403e06 authored by reillyg's avatar reillyg Committed by Commit bot

Add more generic filters to the chrome.usb.getDevices API.

Instead of specifying each of the USB vendor and product ID pairs an
app has permission to open this API extension allows filtering of
devices by vendor and product IDs as well as USB interface classes, sub-
classes and protocols. The 'vendorId' and 'productId' properties of
EnumerateDevicesOptions are still supported for backwards compatibility.

BUG=

Review URL: https://codereview.chromium.org/517923002

Cr-Commit-Position: refs/heads/master@{#293032}
parent 95aa6b1a
......@@ -6,7 +6,6 @@
#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 {
......@@ -57,7 +56,7 @@ void UsbDeviceFilter::SetInterfaceProtocol(uint8 interface_protocol) {
interface_protocol_ = interface_protocol;
}
bool UsbDeviceFilter::Matches(scoped_refptr<UsbDevice> device) {
bool UsbDeviceFilter::Matches(scoped_refptr<UsbDevice> device) const {
if (vendor_id_set_) {
if (device->vendor_id() != vendor_id_) {
return false;
......@@ -125,4 +124,17 @@ base::Value* UsbDeviceFilter::ToValue() const {
return obj.release();
}
// static
bool UsbDeviceFilter::MatchesAny(scoped_refptr<UsbDevice> device,
const std::vector<UsbDeviceFilter>& filters) {
for (std::vector<UsbDeviceFilter>::const_iterator i = filters.begin();
i != filters.end();
++i) {
if (i->Matches(device)) {
return true;
}
}
return false;
}
} // namespace usb_service
......@@ -5,6 +5,8 @@
#ifndef COMPONENTS_USB_SERVICE_USB_DEVICE_FILTER_H_
#define COMPONENTS_USB_SERVICE_USB_DEVICE_FILTER_H_
#include <vector>
#include "base/memory/ref_counted.h"
#include "components/usb_service/usb_service_export.h"
......@@ -27,9 +29,12 @@ class USB_SERVICE_EXPORT UsbDeviceFilter {
void SetInterfaceSubclass(uint8 interface_subclass);
void SetInterfaceProtocol(uint8 interface_protocol);
bool Matches(scoped_refptr<UsbDevice> device);
bool Matches(scoped_refptr<UsbDevice> device) const;
base::Value* ToValue() const;
static bool MatchesAny(scoped_refptr<UsbDevice> device,
const std::vector<UsbDeviceFilter>& filters);
private:
uint16 vendor_id_;
uint16 product_id_;
......
......@@ -237,3 +237,20 @@ TEST_F(UsbFilterTest, MatchInterfaceProtocolNegative) {
filter.SetInterfaceProtocol(0x02);
ASSERT_FALSE(filter.Matches(android_phone_));
}
TEST_F(UsbFilterTest, MatchAnyEmptyListNegative) {
std::vector<UsbDeviceFilter> filters;
ASSERT_FALSE(UsbDeviceFilter::MatchesAny(android_phone_, filters));
}
TEST_F(UsbFilterTest, MatchesAnyVendorId) {
std::vector<UsbDeviceFilter> filters(1);
filters.back().SetVendorId(0x18d1);
ASSERT_TRUE(UsbDeviceFilter::MatchesAny(android_phone_, filters));
}
TEST_F(UsbFilterTest, MatchesAnyVendorIdNegative) {
std::vector<UsbDeviceFilter> filters(1);
filters.back().SetVendorId(0x1d6b);
ASSERT_FALSE(UsbDeviceFilter::MatchesAny(android_phone_, filters));
}
......@@ -52,6 +52,7 @@ using usb::TransferType;
using usb::UsageType;
using usb_service::UsbConfigDescriptor;
using usb_service::UsbDevice;
using usb_service::UsbDeviceFilter;
using usb_service::UsbDeviceHandle;
using usb_service::UsbEndpointDescriptor;
using usb_service::UsbEndpointDirection;
......@@ -417,35 +418,51 @@ bool UsbAsyncApiFunction::Respond() {
return error_.empty();
}
scoped_refptr<UsbDevice> UsbAsyncApiFunction::GetDeviceOrOrCompleteWithError(
const Device& input_device) {
const uint16_t vendor_id = input_device.vendor_id;
const uint16_t product_id = input_device.product_id;
UsbDevicePermission::CheckParam param(
vendor_id, product_id, UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
if (!extension()->permissions_data()->CheckAPIPermissionWithParam(
APIPermission::kUsbDevice, &param)) {
LOG(WARNING) << "Insufficient permissions to access device.";
CompleteWithError(kErrorPermissionDenied);
return NULL;
// static
void UsbAsyncApiFunction::CreateDeviceFilter(const usb::DeviceFilter& input,
UsbDeviceFilter* output) {
if (input.vendor_id) {
output->SetVendorId(*input.vendor_id);
}
if (input.product_id) {
output->SetProductId(*input.product_id);
}
if (input.interface_class) {
output->SetInterfaceClass(*input.interface_class);
}
if (input.interface_subclass) {
output->SetInterfaceSubclass(*input.interface_subclass);
}
if (input.interface_protocol) {
output->SetInterfaceProtocol(*input.interface_protocol);
}
}
bool UsbAsyncApiFunction::HasDevicePermission(
scoped_refptr<usb_service::UsbDevice> device) {
UsbDevicePermission::CheckParam param(
device->vendor_id(),
device->product_id(),
UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
return extension()->permissions_data()->CheckAPIPermissionWithParam(
APIPermission::kUsbDevice, &param);
}
scoped_refptr<UsbDevice> UsbAsyncApiFunction::GetDeviceOrCompleteWithError(
const Device& input_device) {
UsbService* service = device::DeviceClient::Get()->GetUsbService();
if (!service) {
CompleteWithError(kErrorInitService);
return NULL;
}
scoped_refptr<UsbDevice> device;
device = service->GetDeviceById(input_device.device);
scoped_refptr<UsbDevice> device = service->GetDeviceById(input_device.device);
if (!device.get()) {
CompleteWithError(kErrorNoDevice);
return NULL;
}
if (device->vendor_id() != input_device.vendor_id ||
device->product_id() != input_device.product_id) {
if (!HasDevicePermission(device)) {
// Must act as if there is no such a device.
// Otherwise can be used to finger print unauthorized devices.
CompleteWithError(kErrorNoDevice);
......@@ -624,17 +641,20 @@ bool UsbGetDevicesFunction::Prepare() {
}
void UsbGetDevicesFunction::AsyncWorkStart() {
scoped_ptr<base::ListValue> result(new base::ListValue());
const uint16_t vendor_id = parameters_->options.vendor_id;
const uint16_t product_id = parameters_->options.product_id;
UsbDevicePermission::CheckParam param(
vendor_id, product_id, UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
if (!extension()->permissions_data()->CheckAPIPermissionWithParam(
APIPermission::kUsbDevice, &param)) {
LOG(WARNING) << "Insufficient permissions to access device.";
CompleteWithError(kErrorPermissionDenied);
return;
std::vector<UsbDeviceFilter> filters;
if (parameters_->options.filters) {
filters.resize(parameters_->options.filters->size());
for (size_t i = 0; i < parameters_->options.filters->size(); ++i) {
CreateDeviceFilter(*parameters_->options.filters->at(i).get(),
&filters[i]);
}
}
if (parameters_->options.vendor_id) {
filters.resize(filters.size() + 1);
filters.back().SetVendorId(*parameters_->options.vendor_id);
if (parameters_->options.product_id) {
filters.back().SetProductId(*parameters_->options.product_id);
}
}
UsbService* service = device::DeviceClient::Get()->GetUsbService();
......@@ -646,18 +666,15 @@ void UsbGetDevicesFunction::AsyncWorkStart() {
DeviceVector devices;
service->GetDevices(&devices);
for (DeviceVector::iterator it = devices.begin(); it != devices.end();) {
if ((*it)->vendor_id() != vendor_id || (*it)->product_id() != product_id) {
it = devices.erase(it);
} else {
++it;
scoped_ptr<base::ListValue> result(new base::ListValue());
for (DeviceVector::iterator it = devices.begin(); it != devices.end(); ++it) {
scoped_refptr<UsbDevice> device = *it;
if ((filters.empty() || UsbDeviceFilter::MatchesAny(device, filters)) &&
HasDevicePermission(device)) {
result->Append(PopulateDevice(it->get()));
}
}
for (size_t i = 0; i < devices.size(); ++i) {
result->Append(PopulateDevice(devices[i].get()));
}
SetResult(result.release());
AsyncWorkCompleted();
}
......@@ -677,7 +694,7 @@ bool UsbRequestAccessFunction::Prepare() {
void UsbRequestAccessFunction::AsyncWorkStart() {
#if defined(OS_CHROMEOS)
scoped_refptr<UsbDevice> device =
GetDeviceOrOrCompleteWithError(parameters_->device);
GetDeviceOrCompleteWithError(parameters_->device);
if (!device)
return;
......@@ -709,7 +726,7 @@ bool UsbOpenDeviceFunction::Prepare() {
void UsbOpenDeviceFunction::AsyncWorkStart() {
scoped_refptr<UsbDevice> device =
GetDeviceOrOrCompleteWithError(parameters_->device);
GetDeviceOrCompleteWithError(parameters_->device);
if (!device.get())
return;
......
......@@ -11,6 +11,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.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 "extensions/browser/api/api_resource_manager.h"
#include "extensions/browser/api/async_api_function.h"
......@@ -31,7 +32,13 @@ class UsbAsyncApiFunction : public AsyncApiFunction {
virtual bool PrePrepare() OVERRIDE;
virtual bool Respond() OVERRIDE;
scoped_refptr<usb_service::UsbDevice> GetDeviceOrOrCompleteWithError(
static void CreateDeviceFilter(
const extensions::core_api::usb::DeviceFilter& input,
usb_service::UsbDeviceFilter* output);
bool HasDevicePermission(scoped_refptr<usb_service::UsbDevice> device);
scoped_refptr<usb_service::UsbDevice> GetDeviceOrCompleteWithError(
const extensions::core_api::usb::Device& input_device);
scoped_refptr<usb_service::UsbDeviceHandle>
......
......@@ -16,6 +16,7 @@
#include "device/usb/usb_ids.h"
#include "extensions/common/api/usb_private.h"
namespace usb = extensions::core_api::usb;
namespace usb_private = extensions::core_api::usb_private;
namespace GetDevices = usb_private::GetDevices;
namespace GetDeviceInfo = usb_private::GetDeviceInfo;
......@@ -26,6 +27,8 @@ using usb_service::UsbDeviceFilter;
using usb_service::UsbDeviceHandle;
using usb_service::UsbService;
typedef std::vector<scoped_refptr<UsbDevice> > DeviceVector;
namespace {
const char kErrorInitService[] = "Failed to initialize USB service.";
......@@ -58,46 +61,16 @@ void UsbPrivateGetDevicesFunction::AsyncWorkStart() {
std::vector<UsbDeviceFilter> filters;
filters.resize(parameters_->filters.size());
for (size_t i = 0; i < parameters_->filters.size(); ++i) {
UsbDeviceFilter& filter = filters[i];
const usb_private::DeviceFilter* filter_param =
parameters_->filters[i].get();
if (filter_param->vendor_id) {
filter.SetVendorId(*filter_param->vendor_id);
}
if (filter_param->product_id) {
filter.SetProductId(*filter_param->product_id);
}
if (filter_param->interface_class) {
filter.SetInterfaceClass(*filter_param->interface_class);
}
if (filter_param->interface_subclass) {
filter.SetInterfaceSubclass(*filter_param->interface_subclass);
}
if (filter_param->interface_protocol) {
filter.SetInterfaceProtocol(*filter_param->interface_protocol);
}
CreateDeviceFilter(*parameters_->filters[i].get(), &filters[i]);
}
std::vector<scoped_refptr<UsbDevice> > devices;
DeviceVector devices;
service->GetDevices(&devices);
scoped_ptr<base::ListValue> result(new base::ListValue());
for (size_t i = 0; i < devices.size(); ++i) {
scoped_refptr<UsbDevice> device = devices[i];
bool matched = false;
if (filters.empty()) {
matched = true;
} else {
for (size_t j = 0; !matched && j < filters.size(); ++j) {
if (filters[j].Matches(device)) {
matched = true;
}
}
}
if (matched) {
for (DeviceVector::iterator it = devices.begin(); it != devices.end(); ++it) {
scoped_refptr<UsbDevice> device = *it;
if (filters.empty() || UsbDeviceFilter::MatchesAny(device, filters)) {
result->Append(new base::FundamentalValue((int)device->unique_id()));
}
}
......
This diff is collapsed.
......@@ -7,22 +7,6 @@
// API which should only be available to trusted pages.
namespace usbPrivate {
// Properties for matching devices. A device matches of any of its interfaces
// match the given properties. An empty dictionary matches any device.
dictionary DeviceFilter {
// Device-level matching criteria:
long? vendorId;
// Checked only if the vendorId matches.
long? productId;
// Per-interface matching criteria:
long? interfaceClass;
// Checked only if the interfaceClass matches.
long? interfaceSubclass;
// Checked only if the interfaceSubclass matches.
long? interfaceProtocol;
};
dictionary DeviceInfo {
long vendorId; // idVendor from the device
long productId; // idProduct from the device
......@@ -44,7 +28,7 @@ namespace usbPrivate {
// Lists USB devices matching any of the given filters.
// |filters|: The properties to search for on target devices.
// |callback|: Invoked with a list of device IDs on complete.
static void getDevices(DeviceFilter[] filters,
static void getDevices(usb.DeviceFilter[] filters,
GetDevicesCallback callback);
// Gets basic display information about a device.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment