Add configuration and interface permission checks to DeviceImpl.
New methods to check whether a client has permission to access a device
configuration or interface have been added to the PermissionProvider
interface. DeviceManagerImpl then uses the new Bind() method to give
DeviceImpl a new pointer to the object it has been using for permission
checks. Permission checks are not required for bulk, interrupt and
isochronous transfers because they require the interface to be claimed
first.
BUG=492204
Review URL: https://codereview.chromium.org/1369643002
Cr-Commit-Position: refs/heads/master@{#351408}
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 4961292c..6c8277a 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -112,6 +112,8 @@
sources += [
"devices_app/usb/device_impl_unittest.cc",
"devices_app/usb/device_manager_impl_unittest.cc",
+ "devices_app/usb/fake_permission_provider.cc",
+ "devices_app/usb/fake_permission_provider.h",
"test/test_device_client.cc",
"test/test_device_client.h",
"test/usb_test_gadget_impl.cc",
diff --git a/device/device_tests.gyp b/device/device_tests.gyp
index 864a320..051703a 100644
--- a/device/device_tests.gyp
+++ b/device/device_tests.gyp
@@ -62,6 +62,8 @@
'bluetooth/test/test_bluetooth_adapter_observer.h',
'devices_app/usb/device_impl_unittest.cc',
'devices_app/usb/device_manager_impl_unittest.cc',
+ 'devices_app/usb/fake_permission_provider.cc',
+ 'devices_app/usb/fake_permission_provider.h',
'hid/hid_connection_unittest.cc',
'hid/hid_device_filter_unittest.cc',
'hid/hid_report_descriptor_unittest.cc',
diff --git a/device/devices_app/usb/device_impl.cc b/device/devices_app/usb/device_impl.cc
index 1516c76..7f64cc6 100644
--- a/device/devices_app/usb/device_impl.cc
+++ b/device/devices_app/usb/device_impl.cc
@@ -31,38 +31,26 @@
return base::Bind(&CallMojoCallback<Args...>, callback);
}
+void OnPermissionCheckComplete(
+ const base::Callback<void(bool)>& callback,
+ const base::Callback<void(const base::Callback<void(bool)>&)>& action,
+ bool allowed) {
+ if (allowed)
+ action.Run(callback);
+ else
+ callback.Run(false);
+}
+
scoped_refptr<net::IOBuffer> CreateTransferBuffer(size_t size) {
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(
std::max(static_cast<size_t>(1u), static_cast<size_t>(size)));
return buffer;
}
-} // namespace
-
-DeviceImpl::DeviceImpl(scoped_refptr<UsbDevice> device,
- mojo::InterfaceRequest<Device> request)
- : binding_(this, request.Pass()), device_(device), weak_factory_(this) {}
-
-DeviceImpl::~DeviceImpl() {
- CloseHandle();
-}
-
-void DeviceImpl::CloseHandle() {
- if (device_handle_)
- device_handle_->Close();
- device_handle_ = nullptr;
-}
-
-void DeviceImpl::OnOpen(const OpenCallback& callback,
- scoped_refptr<UsbDeviceHandle> handle) {
- device_handle_ = handle;
- callback.Run(handle ? OPEN_DEVICE_ERROR_OK : OPEN_DEVICE_ERROR_ACCESS_DENIED);
-}
-
-void DeviceImpl::OnTransferIn(const MojoTransferInCallback& callback,
- UsbTransferStatus status,
- scoped_refptr<net::IOBuffer> buffer,
- size_t buffer_size) {
+void OnTransferIn(const DeviceImpl::MojoTransferInCallback& callback,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t buffer_size) {
mojo::Array<uint8_t> data;
if (buffer) {
// TODO(rockot/reillyg): We should change UsbDeviceHandle to use a
@@ -75,15 +63,58 @@
callback.Run(mojo::ConvertTo<TransferStatus>(status), data.Pass());
}
-void DeviceImpl::OnTransferOut(const MojoTransferOutCallback& callback,
- UsbTransferStatus status,
- scoped_refptr<net::IOBuffer> buffer,
- size_t buffer_size) {
+void OnControlTransferInPermissionCheckComplete(
+ scoped_refptr<UsbDeviceHandle> device_handle,
+ ControlTransferParamsPtr params,
+ int length,
+ int timeout,
+ const Device::ControlTransferInCallback& callback,
+ bool allowed) {
+ if (allowed) {
+ scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(length);
+ device_handle->ControlTransfer(
+ USB_DIRECTION_INBOUND,
+ mojo::ConvertTo<UsbDeviceHandle::TransferRequestType>(params->type),
+ mojo::ConvertTo<UsbDeviceHandle::TransferRecipient>(params->recipient),
+ params->request, params->value, params->index, buffer, length, timeout,
+ base::Bind(&OnTransferIn, callback));
+ } else {
+ mojo::Array<uint8_t> data;
+ callback.Run(TRANSFER_STATUS_PERMISSION_DENIED, data.Pass());
+ }
+}
+
+void OnTransferOut(const DeviceImpl::MojoTransferOutCallback& callback,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t buffer_size) {
callback.Run(mojo::ConvertTo<TransferStatus>(status));
}
-void DeviceImpl::OnIsochronousTransferIn(
- const IsochronousTransferInCallback& callback,
+void OnControlTransferOutPermissionCheckComplete(
+ scoped_refptr<UsbDeviceHandle> device_handle,
+ ControlTransferParamsPtr params,
+ mojo::Array<uint8_t> data,
+ int timeout,
+ const Device::ControlTransferOutCallback& callback,
+ bool allowed) {
+ if (allowed) {
+ scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(data.size());
+ const std::vector<uint8_t>& storage = data.storage();
+ std::copy(storage.begin(), storage.end(), buffer->data());
+ device_handle->ControlTransfer(
+ USB_DIRECTION_OUTBOUND,
+ mojo::ConvertTo<UsbDeviceHandle::TransferRequestType>(params->type),
+ mojo::ConvertTo<UsbDeviceHandle::TransferRecipient>(params->recipient),
+ params->request, params->value, params->index, buffer, data.size(),
+ timeout, base::Bind(&OnTransferOut, callback));
+ } else {
+ callback.Run(TRANSFER_STATUS_PERMISSION_DENIED);
+ }
+}
+
+void OnIsochronousTransferIn(
+ const Device::IsochronousTransferInCallback& callback,
uint32_t packet_size,
UsbTransferStatus status,
scoped_refptr<net::IOBuffer> buffer,
@@ -102,14 +133,81 @@
callback.Run(mojo::ConvertTo<TransferStatus>(status), packets.Pass());
}
-void DeviceImpl::OnIsochronousTransferOut(
- const MojoTransferOutCallback& callback,
+void OnIsochronousTransferOut(
+ const Device::IsochronousTransferOutCallback& callback,
UsbTransferStatus status,
scoped_refptr<net::IOBuffer> buffer,
size_t buffer_size) {
callback.Run(mojo::ConvertTo<TransferStatus>(status));
}
+} // namespace
+
+DeviceImpl::DeviceImpl(scoped_refptr<UsbDevice> device,
+ PermissionProviderPtr permission_provider,
+ mojo::InterfaceRequest<Device> request)
+ : binding_(this, request.Pass()),
+ device_(device),
+ permission_provider_(permission_provider.Pass()),
+ weak_factory_(this) {
+ // This object owns itself and will be destroyed if either the message pipe
+ // it is bound to is closed or the PermissionProvider it depends on is
+ // unavailable.
+ binding_.set_connection_error_handler([this]() { delete this; });
+ permission_provider_.set_connection_error_handler([this]() { delete this; });
+}
+
+DeviceImpl::~DeviceImpl() {
+ CloseHandle();
+}
+
+void DeviceImpl::CloseHandle() {
+ if (device_handle_)
+ device_handle_->Close();
+ device_handle_ = nullptr;
+}
+
+void DeviceImpl::HasControlTransferPermission(
+ ControlTransferRecipient recipient,
+ uint16_t index,
+ const base::Callback<void(bool)>& callback) {
+ DCHECK(device_handle_);
+ const UsbConfigDescriptor* config = device_->GetActiveConfiguration();
+
+ if (recipient == CONTROL_TRANSFER_RECIPIENT_INTERFACE ||
+ recipient == CONTROL_TRANSFER_RECIPIENT_ENDPOINT) {
+ if (!config) {
+ callback.Run(false);
+ return;
+ }
+
+ uint8_t interface_number = index & 0xff;
+ if (recipient == CONTROL_TRANSFER_RECIPIENT_ENDPOINT) {
+ if (!device_handle_->FindInterfaceByEndpoint(index & 0xff,
+ &interface_number)) {
+ callback.Run(false);
+ return;
+ }
+ }
+
+ permission_provider_->HasInterfacePermission(
+ interface_number, config->configuration_value,
+ DeviceInfo::From(*device_), callback);
+ } else if (config) {
+ permission_provider_->HasConfigurationPermission(
+ config->configuration_value, DeviceInfo::From(*device_), callback);
+ } else {
+ // Client must already have device permission to have gotten this far.
+ callback.Run(true);
+ }
+}
+
+void DeviceImpl::OnOpen(const OpenCallback& callback,
+ scoped_refptr<UsbDeviceHandle> handle) {
+ device_handle_ = handle;
+ callback.Run(handle ? OPEN_DEVICE_ERROR_OK : OPEN_DEVICE_ERROR_ACCESS_DENIED);
+}
+
void DeviceImpl::GetDeviceInfo(const GetDeviceInfoCallback& callback) {
callback.Run(DeviceInfo::From(*device_));
}
@@ -136,7 +234,12 @@
return;
}
- device_handle_->SetConfiguration(value, WrapMojoCallback(callback));
+ auto set_configuration =
+ base::Bind(&UsbDeviceHandle::SetConfiguration, device_handle_, value);
+ permission_provider_->HasConfigurationPermission(
+ value, DeviceInfo::From(*device_),
+ base::Bind(&OnPermissionCheckComplete, WrapMojoCallback(callback),
+ set_configuration));
}
void DeviceImpl::ClaimInterface(uint8_t interface_number,
@@ -146,7 +249,18 @@
return;
}
- device_handle_->ClaimInterface(interface_number, WrapMojoCallback(callback));
+ const UsbConfigDescriptor* config = device_->GetActiveConfiguration();
+ if (!config) {
+ callback.Run(false);
+ return;
+ }
+
+ auto claim_interface = base::Bind(&UsbDeviceHandle::ClaimInterface,
+ device_handle_, interface_number);
+ permission_provider_->HasInterfacePermission(
+ interface_number, config->configuration_value, DeviceInfo::From(*device_),
+ base::Bind(&OnPermissionCheckComplete, WrapMojoCallback(callback),
+ claim_interface));
}
void DeviceImpl::ReleaseInterface(uint8_t interface_number,
@@ -200,14 +314,12 @@
return;
}
- scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(length);
- device_handle_->ControlTransfer(
- USB_DIRECTION_INBOUND,
- mojo::ConvertTo<UsbDeviceHandle::TransferRequestType>(params->type),
- mojo::ConvertTo<UsbDeviceHandle::TransferRecipient>(params->recipient),
- params->request, params->value, params->index, buffer, length, timeout,
- base::Bind(&DeviceImpl::OnTransferIn, weak_factory_.GetWeakPtr(),
- callback));
+ ControlTransferRecipient recipient = params->recipient;
+ uint16_t index = params->index;
+ HasControlTransferPermission(
+ recipient, index,
+ base::Bind(&OnControlTransferInPermissionCheckComplete, device_handle_,
+ base::Passed(¶ms), length, timeout, callback));
}
void DeviceImpl::ControlTransferOut(
@@ -220,16 +332,12 @@
return;
}
- scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(data.size());
- const std::vector<uint8_t>& storage = data.storage();
- std::copy(storage.begin(), storage.end(), buffer->data());
- device_handle_->ControlTransfer(
- USB_DIRECTION_OUTBOUND,
- mojo::ConvertTo<UsbDeviceHandle::TransferRequestType>(params->type),
- mojo::ConvertTo<UsbDeviceHandle::TransferRecipient>(params->recipient),
- params->request, params->value, params->index, buffer, data.size(),
- timeout, base::Bind(&DeviceImpl::OnTransferOut,
- weak_factory_.GetWeakPtr(), callback));
+ ControlTransferRecipient recipient = params->recipient;
+ uint16_t index = params->index;
+ HasControlTransferPermission(
+ recipient, index, base::Bind(&OnControlTransferOutPermissionCheckComplete,
+ device_handle_, base::Passed(¶ms),
+ base::Passed(&data), timeout, callback));
}
void DeviceImpl::GenericTransferIn(uint8_t endpoint_number,
@@ -243,10 +351,9 @@
uint8_t endpoint_address = endpoint_number | 0x80;
scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(length);
- device_handle_->GenericTransfer(
- USB_DIRECTION_INBOUND, endpoint_address, buffer, length, timeout,
- base::Bind(&DeviceImpl::OnTransferIn, weak_factory_.GetWeakPtr(),
- callback));
+ device_handle_->GenericTransfer(USB_DIRECTION_INBOUND, endpoint_address,
+ buffer, length, timeout,
+ base::Bind(&OnTransferIn, callback));
}
void DeviceImpl::GenericTransferOut(
@@ -263,10 +370,9 @@
scoped_refptr<net::IOBuffer> buffer = CreateTransferBuffer(data.size());
const std::vector<uint8_t>& storage = data.storage();
std::copy(storage.begin(), storage.end(), buffer->data());
- device_handle_->GenericTransfer(
- USB_DIRECTION_OUTBOUND, endpoint_address, buffer, data.size(), timeout,
- base::Bind(&DeviceImpl::OnTransferOut, weak_factory_.GetWeakPtr(),
- callback));
+ device_handle_->GenericTransfer(USB_DIRECTION_OUTBOUND, endpoint_address,
+ buffer, data.size(), timeout,
+ base::Bind(&OnTransferOut, callback));
}
void DeviceImpl::IsochronousTransferIn(
@@ -286,8 +392,7 @@
device_handle_->IsochronousTransfer(
USB_DIRECTION_INBOUND, endpoint_address, buffer, transfer_size,
num_packets, packet_length, timeout,
- base::Bind(&DeviceImpl::OnIsochronousTransferIn,
- weak_factory_.GetWeakPtr(), callback, packet_length));
+ base::Bind(&OnIsochronousTransferIn, callback, packet_length));
}
void DeviceImpl::IsochronousTransferOut(
@@ -318,8 +423,7 @@
device_handle_->IsochronousTransfer(
USB_DIRECTION_OUTBOUND, endpoint_address, buffer, transfer_size,
static_cast<uint32_t>(packets.size()), packet_size, timeout,
- base::Bind(&DeviceImpl::OnIsochronousTransferOut,
- weak_factory_.GetWeakPtr(), callback));
+ base::Bind(&OnIsochronousTransferOut, callback));
}
} // namespace usb
diff --git a/device/devices_app/usb/device_impl.h b/device/devices_app/usb/device_impl.h
index 9a7bac4..12d6b90 100644
--- a/device/devices_app/usb/device_impl.h
+++ b/device/devices_app/usb/device_impl.h
@@ -10,10 +10,11 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "device/devices_app/usb/public/interfaces/device.mojom.h"
+#include "device/devices_app/usb/public/interfaces/permission_provider.mojom.h"
#include "device/usb/usb_device_handle.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
#include "third_party/mojo/src/mojo/public/cpp/bindings/callback.h"
#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
namespace net {
class IOBuffer;
@@ -27,51 +28,30 @@
// lifetime.
class DeviceImpl : public Device {
public:
- DeviceImpl(scoped_refptr<UsbDevice> device,
- mojo::InterfaceRequest<Device> request);
- ~DeviceImpl() override;
-
- private:
using MojoTransferInCallback =
mojo::Callback<void(TransferStatus, mojo::Array<uint8_t>)>;
using MojoTransferOutCallback = mojo::Callback<void(TransferStatus)>;
+ DeviceImpl(scoped_refptr<UsbDevice> device,
+ PermissionProviderPtr permission_provider,
+ mojo::InterfaceRequest<Device> request);
+ ~DeviceImpl() override;
+
+ private:
// Closes the device if it's open. This will always set |device_handle_| to
// null.
void CloseHandle();
+ // Checks interface permissions for control transfers.
+ void HasControlTransferPermission(ControlTransferRecipient recipient,
+ uint16_t index,
+ const base::Callback<void(bool)>& callback);
+
// Handles completion of an open request.
void OnOpen(const OpenCallback& callback,
scoped_refptr<device::UsbDeviceHandle> handle);
- // Handles completion of an inbound transfer on the UsbDeviceHandle.
- void OnTransferIn(const MojoTransferInCallback& callback,
- UsbTransferStatus status,
- scoped_refptr<net::IOBuffer> data,
- size_t size);
-
- // Handles completion of an outbound transfer on the UsbDeviceHandle.
- void OnTransferOut(const MojoTransferOutCallback& callback,
- UsbTransferStatus status,
- scoped_refptr<net::IOBuffer> data,
- size_t size);
-
- // Handles completion of an inbound isochronous transfer on the
- // UsbDeviceHandle.
- void OnIsochronousTransferIn(const IsochronousTransferInCallback& callback,
- uint32_t packet_length,
- UsbTransferStatus status,
- scoped_refptr<net::IOBuffer> data,
- size_t size);
-
- // Handles completion of an outbound isochronous transfer on the
- // UsbDeviceHandle.
- void OnIsochronousTransferOut(const MojoTransferOutCallback& callback,
- UsbTransferStatus status,
- scoped_refptr<net::IOBuffer> data,
- size_t size);
-
// Device implementation:
void GetDeviceInfo(const GetDeviceInfoCallback& callback) override;
void GetConfiguration(const GetConfigurationCallback& callback) override;
@@ -117,12 +97,13 @@
uint32_t timeout,
const IsochronousTransferOutCallback& callback) override;
- mojo::StrongBinding<Device> binding_;
+ mojo::Binding<Device> binding_;
scoped_refptr<UsbDevice> device_;
// The device handle. Will be null before the device is opened and after it
// has been closed.
scoped_refptr<UsbDeviceHandle> device_handle_;
+ PermissionProviderPtr permission_provider_;
base::WeakPtrFactory<DeviceImpl> weak_factory_;
diff --git a/device/devices_app/usb/device_impl_unittest.cc b/device/devices_app/usb/device_impl_unittest.cc
index 5868a17..2b41912 100644
--- a/device/devices_app/usb/device_impl_unittest.cc
+++ b/device/devices_app/usb/device_impl_unittest.cc
@@ -13,6 +13,7 @@
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "device/devices_app/usb/device_impl.h"
+#include "device/devices_app/usb/fake_permission_provider.h"
#include "device/usb/mock_usb_device.h"
#include "device/usb/mock_usb_device_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -150,13 +151,19 @@
new MockUsbDevice(vendor_id, product_id, manufacturer, product, serial);
mock_handle_ = new MockUsbDeviceHandle(mock_device_.get());
+ PermissionProviderPtr permission_provider;
+ permission_provider_.Bind(mojo::GetProxy(&permission_provider));
DevicePtr proxy;
- new DeviceImpl(mock_device_, mojo::GetProxy(&proxy));
+ new DeviceImpl(mock_device_, permission_provider.Pass(),
+ mojo::GetProxy(&proxy));
// Set up mock handle calls to respond based on mock device configs
// established by the test.
ON_CALL(mock_device(), Open(_))
.WillByDefault(Invoke(this, &USBDeviceImplTest::OpenMockHandle));
+ ON_CALL(mock_device(), GetActiveConfiguration())
+ .WillByDefault(
+ Invoke(this, &USBDeviceImplTest::GetActiveConfiguration));
ON_CALL(mock_handle(), Close())
.WillByDefault(Invoke(this, &USBDeviceImplTest::CloseMockHandle));
ON_CALL(mock_handle(), SetConfiguration(_, _))
@@ -210,6 +217,16 @@
is_device_open_ = false;
}
+ const UsbConfigDescriptor* GetActiveConfiguration() {
+ if (current_config_ == 0) {
+ return nullptr;
+ } else {
+ const auto it = mock_configs_.find(current_config_);
+ EXPECT_TRUE(it != mock_configs_.end());
+ return &it->second;
+ }
+ }
+
void SetConfiguration(uint8_t value,
const UsbDeviceHandle::ResultCallback& callback) {
if (mock_configs_.find(value) != mock_configs_.end()) {
@@ -342,6 +359,8 @@
std::set<uint8_t> claimed_interfaces_;
+ FakePermissionProvider permission_provider_;
+
DISALLOW_COPY_AND_ASSIGN(USBDeviceImplTest);
};
@@ -503,8 +522,18 @@
}
// Now add a mock interface #1.
- AddMockConfig(ConfigBuilder(0).AddInterface(1, 0, 1, 2, 3));
+ AddMockConfig(ConfigBuilder(1).AddInterface(1, 0, 1, 2, 3));
+ EXPECT_CALL(mock_handle(), SetConfiguration(1, _));
+
+ {
+ base::RunLoop loop;
+ device->SetConfiguration(
+ 1, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure()));
+ loop.Run();
+ }
+
+ EXPECT_CALL(mock_device(), GetActiveConfiguration());
EXPECT_CALL(mock_handle(), ClaimInterface(2, _));
{
@@ -515,6 +544,7 @@
loop.Run();
}
+ EXPECT_CALL(mock_device(), GetActiveConfiguration());
EXPECT_CALL(mock_handle(), ClaimInterface(1, _));
{
@@ -559,7 +589,7 @@
loop.Run();
}
- AddMockConfig(ConfigBuilder(0)
+ AddMockConfig(ConfigBuilder(1)
.AddInterface(1, 0, 1, 2, 3)
.AddInterface(1, 42, 1, 2, 3)
.AddInterface(2, 0, 1, 2, 3));
@@ -597,6 +627,18 @@
loop.Run();
}
+ AddMockConfig(ConfigBuilder(1).AddInterface(7, 0, 1, 2, 3));
+
+ EXPECT_CALL(mock_device(), GetActiveConfiguration());
+ EXPECT_CALL(mock_handle(), SetConfiguration(1, _));
+
+ {
+ base::RunLoop loop;
+ device->SetConfiguration(
+ 1, base::Bind(&ExpectResultAndThen, true, loop.QuitClosure()));
+ loop.Run();
+ }
+
std::vector<uint8_t> fake_data;
fake_data.push_back(41);
fake_data.push_back(42);
@@ -623,9 +665,9 @@
loop.Run();
}
- AddMockConfig(ConfigBuilder(0).AddInterface(7, 0, 1, 2, 3));
AddMockOutboundData(fake_data);
+ EXPECT_CALL(mock_device(), GetActiveConfiguration());
EXPECT_CALL(mock_handle(),
ControlTransfer(USB_DIRECTION_OUTBOUND, UsbDeviceHandle::STANDARD,
UsbDeviceHandle::INTERFACE, 5, 6, 7, _, _, 0, _));
@@ -668,7 +710,7 @@
std::vector<uint8_t> fake_inbound_data(message2.size());
std::copy(message2.begin(), message2.end(), fake_inbound_data.begin());
- AddMockConfig(ConfigBuilder(0).AddInterface(7, 0, 1, 2, 3));
+ AddMockConfig(ConfigBuilder(1).AddInterface(7, 0, 1, 2, 3));
AddMockOutboundData(fake_outbound_data);
AddMockInboundData(fake_inbound_data);
@@ -721,7 +763,7 @@
std::copy(inbound_packet_data.begin(), inbound_packet_data.end(),
fake_inbound_packets.begin());
- AddMockConfig(ConfigBuilder(0).AddInterface(7, 0, 1, 2, 3));
+ AddMockConfig(ConfigBuilder(1).AddInterface(7, 0, 1, 2, 3));
AddMockOutboundData(fake_outbound_packets);
AddMockInboundData(fake_inbound_packets);
diff --git a/device/devices_app/usb/device_manager_impl.cc b/device/devices_app/usb/device_manager_impl.cc
index 333df78..0fc287da 100644
--- a/device/devices_app/usb/device_manager_impl.cc
+++ b/device/devices_app/usb/device_manager_impl.cc
@@ -204,7 +204,9 @@
return;
DCHECK(allowed_guids.size() == 1);
- new DeviceImpl(device, device_request.Pass());
+ PermissionProviderPtr permission_provider;
+ permission_provider_->Bind(mojo::GetProxy(&permission_provider));
+ new DeviceImpl(device, permission_provider.Pass(), device_request.Pass());
}
void DeviceManagerImpl::OnGetDevices(EnumerationOptionsPtr options,
diff --git a/device/devices_app/usb/device_manager_impl_unittest.cc b/device/devices_app/usb/device_manager_impl_unittest.cc
index 2f25dc0..d4e43c88 100644
--- a/device/devices_app/usb/device_manager_impl_unittest.cc
+++ b/device/devices_app/usb/device_manager_impl_unittest.cc
@@ -14,11 +14,11 @@
#include "device/core/device_client.h"
#include "device/devices_app/usb/device_impl.h"
#include "device/devices_app/usb/device_manager_impl.h"
+#include "device/devices_app/usb/fake_permission_provider.h"
#include "device/usb/mock_usb_device.h"
#include "device/usb/mock_usb_device_handle.h"
#include "device/usb/mock_usb_service.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
using ::testing::Invoke;
using ::testing::_;
@@ -28,26 +28,6 @@
namespace {
-class TestPermissionProvider : public PermissionProvider {
- public:
- TestPermissionProvider(mojo::InterfaceRequest<PermissionProvider> request)
- : binding_(this, request.Pass()) {}
- ~TestPermissionProvider() override {}
-
- void HasDevicePermission(
- mojo::Array<DeviceInfoPtr> requested_devices,
- const HasDevicePermissionCallback& callback) override {
- // Permission to access all devices granted.
- mojo::Array<mojo::String> allowed_guids(requested_devices.size());
- for (size_t i = 0; i < requested_devices.size(); ++i)
- allowed_guids[i] = requested_devices[i]->guid;
- callback.Run(allowed_guids.Pass());
- }
-
- private:
- mojo::StrongBinding<PermissionProvider> binding_;
-};
-
class TestDeviceClient : public DeviceClient {
public:
TestDeviceClient() {}
@@ -76,7 +56,7 @@
DeviceManagerPtr ConnectToDeviceManager() {
PermissionProviderPtr permission_provider;
- new TestPermissionProvider(mojo::GetProxy(&permission_provider));
+ permission_provider_.Bind(mojo::GetProxy(&permission_provider));
DeviceManagerPtr device_manager;
new DeviceManagerImpl(mojo::GetProxy(&device_manager),
permission_provider.Pass(),
@@ -85,6 +65,7 @@
}
private:
+ FakePermissionProvider permission_provider_;
scoped_ptr<TestDeviceClient> device_client_;
scoped_ptr<base::MessageLoop> message_loop_;
};
diff --git a/device/devices_app/usb/fake_permission_provider.cc b/device/devices_app/usb/fake_permission_provider.cc
new file mode 100644
index 0000000..b4760f2
--- /dev/null
+++ b/device/devices_app/usb/fake_permission_provider.cc
@@ -0,0 +1,43 @@
+// Copyright 2015 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 "device/devices_app/usb/fake_permission_provider.h"
+
+namespace device {
+namespace usb {
+
+FakePermissionProvider::FakePermissionProvider() {}
+
+FakePermissionProvider::~FakePermissionProvider() {}
+
+void FakePermissionProvider::HasDevicePermission(
+ mojo::Array<DeviceInfoPtr> requested_devices,
+ const HasDevicePermissionCallback& callback) {
+ mojo::Array<mojo::String> allowed_guids(requested_devices.size());
+ for (size_t i = 0; i < requested_devices.size(); ++i)
+ allowed_guids[i] = requested_devices[i]->guid;
+ callback.Run(allowed_guids.Pass());
+}
+
+void FakePermissionProvider::HasConfigurationPermission(
+ uint8_t requested_configuration,
+ device::usb::DeviceInfoPtr device,
+ const HasInterfacePermissionCallback& callback) {
+ callback.Run(true);
+}
+void FakePermissionProvider::HasInterfacePermission(
+ uint8_t requested_interface,
+ uint8_t configuration_value,
+ device::usb::DeviceInfoPtr device,
+ const HasInterfacePermissionCallback& callback) {
+ callback.Run(true);
+}
+
+void FakePermissionProvider::Bind(
+ mojo::InterfaceRequest<PermissionProvider> request) {
+ bindings_.AddBinding(this, request.Pass());
+}
+
+} // namespace usb
+} // namespace device
diff --git a/device/devices_app/usb/fake_permission_provider.h b/device/devices_app/usb/fake_permission_provider.h
new file mode 100644
index 0000000..738ecbc
--- /dev/null
+++ b/device/devices_app/usb/fake_permission_provider.h
@@ -0,0 +1,42 @@
+// Copyright 2015 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 DEVICE_USB_FAKE_PERMISSION_PROVIDER_H_
+#define DEVICE_USB_FAKE_PERMISSION_PROVIDER_H_
+
+#include "device/devices_app/usb/public/interfaces/permission_provider.mojom.h"
+#include "mojo/common/weak_binding_set.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/array.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+
+namespace device {
+namespace usb {
+
+class FakePermissionProvider : public PermissionProvider {
+ public:
+ FakePermissionProvider();
+ ~FakePermissionProvider() override;
+
+ void HasDevicePermission(
+ mojo::Array<DeviceInfoPtr> requested_devices,
+ const HasDevicePermissionCallback& callback) override;
+ void HasConfigurationPermission(
+ uint8_t requested_configuration,
+ device::usb::DeviceInfoPtr device,
+ const HasInterfacePermissionCallback& callback) override;
+ void HasInterfacePermission(
+ uint8_t requested_interface,
+ uint8_t configuration_value,
+ device::usb::DeviceInfoPtr device,
+ const HasInterfacePermissionCallback& callback) override;
+ void Bind(mojo::InterfaceRequest<PermissionProvider> request) override;
+
+ private:
+ mojo::WeakBindingSet<PermissionProvider> bindings_;
+};
+
+} // namespace usb
+} // namespace device
+
+#endif // DEVICE_USB_FAKE_PERMISSION_PROVIDER_H_
diff --git a/device/devices_app/usb/public/interfaces/device.mojom b/device/devices_app/usb/public/interfaces/device.mojom
index 45797b7..5382ce37 100644
--- a/device/devices_app/usb/public/interfaces/device.mojom
+++ b/device/devices_app/usb/public/interfaces/device.mojom
@@ -115,6 +115,9 @@
// The transfer failed due to a non-specific error.
ERROR,
+ // The transfer was not allowed.
+ PERMISSION_DENIED,
+
// The transfer timed out.
TIMEOUT,
diff --git a/device/devices_app/usb/public/interfaces/permission_provider.mojom b/device/devices_app/usb/public/interfaces/permission_provider.mojom
index 1ed6d6e..f5d7111 100644
--- a/device/devices_app/usb/public/interfaces/permission_provider.mojom
+++ b/device/devices_app/usb/public/interfaces/permission_provider.mojom
@@ -11,4 +11,19 @@
// that should be accessible to clients of the DeviceManager instance.
HasDevicePermission(array<DeviceInfo> requested_devices)
=> (array<string> allowed_guids);
+
+ // Returns whether or not the client has permission to access
+ // |requested_configuration| on |device|.
+ HasConfigurationPermission(uint8 requested_configuration,
+ DeviceInfo device) => (bool allowed);
+
+ // Returns whether or not the client has permission to access
+ // |requested_interface| on |device| when it is in configuration
+ // |configuration_value|.
+ HasInterfacePermission(uint8 requested_interface,
+ uint8 configuration_value,
+ DeviceInfo device) => (bool allowed);
+
+ // Requests a new binding to this service.
+ Bind(PermissionProvider& request);
};
diff --git a/device/usb/mock_usb_device_handle.h b/device/usb/mock_usb_device_handle.h
index c3742b3..30b23d9 100644
--- a/device/usb/mock_usb_device_handle.h
+++ b/device/usb/mock_usb_device_handle.h
@@ -15,7 +15,19 @@
public:
MockUsbDeviceHandle(UsbDevice* device);
+ scoped_refptr<UsbDevice> GetDevice() const override;
MOCK_METHOD0(Close, void());
+ MOCK_METHOD2(SetConfiguration,
+ void(int configuration_value, const ResultCallback& callback));
+ MOCK_METHOD2(ClaimInterface,
+ void(int interface_number, const ResultCallback& callback));
+ MOCK_METHOD1(ReleaseInterface, bool(int interface_number));
+ MOCK_METHOD3(SetInterfaceAlternateSetting,
+ void(int interface_number,
+ int alternate_setting,
+ const ResultCallback& callback));
+ MOCK_METHOD1(ResetDevice, void(const ResultCallback& callback));
+ MOCK_METHOD2(ClearHalt, void(uint8 endpoint, const ResultCallback& callback));
MOCK_METHOD10(ControlTransfer,
void(UsbEndpointDirection direction,
TransferRequestType request_type,
@@ -43,21 +55,8 @@
size_t length,
unsigned int timeout,
const TransferCallback& callback));
- MOCK_METHOD1(ResetDevice, void(const ResultCallback& callback));
- MOCK_METHOD2(GetStringDescriptor, bool(uint8_t, base::string16*));
- MOCK_METHOD2(SetConfiguration,
- void(int configuration_value, const ResultCallback& callback));
- MOCK_METHOD2(ClaimInterface,
- void(int interface_number, const ResultCallback& callback));
- MOCK_METHOD1(ReleaseInterface, bool(int interface_number));
- MOCK_METHOD3(SetInterfaceAlternateSetting,
- void(int interface_number,
- int alternate_setting,
- const ResultCallback& callback));
- MOCK_METHOD2(ClearHalt,
- void(uint8_t endpoint, const ResultCallback& callback));
-
- scoped_refptr<UsbDevice> GetDevice() const override;
+ MOCK_METHOD2(FindInterfaceByEndpoint,
+ bool(uint8_t endpoint_address, uint8_t* interface_number));
private:
~MockUsbDeviceHandle() override;
diff --git a/device/usb/usb_device.h b/device/usb/usb_device.h
index 64fa6810..beb78036 100644
--- a/device/usb/usb_device.h
+++ b/device/usb/usb_device.h
@@ -44,6 +44,9 @@
return webusb_allowed_origins_.get();
}
const GURL& webusb_landing_page() const { return webusb_landing_page_; }
+ const std::vector<UsbConfigDescriptor>& configurations() const {
+ return configurations_;
+ }
// On ChromeOS the permission_broker service is used to change the ownership
// of USB device nodes so that Chrome can open them. On other platforms these
@@ -61,11 +64,6 @@
// if the device is unconfigured.
virtual const UsbConfigDescriptor* GetActiveConfiguration() = 0;
- // Gets all of the device's UsbConfigDescriptors.
- const std::vector<UsbConfigDescriptor>& configurations() const {
- return configurations_;
- }
-
protected:
UsbDevice(uint16_t vendor_id,
uint16_t product_id,
diff --git a/device/usb/usb_device_handle.h b/device/usb/usb_device_handle.h
index 0597378..23d2fd5c 100644
--- a/device/usb/usb_device_handle.h
+++ b/device/usb/usb_device_handle.h
@@ -90,6 +90,11 @@
unsigned int timeout,
const TransferCallback& callback) = 0;
+ // Gets the interface containing |endpoint_address|. Returns false if no
+ // claimed interface contains that endpoint.
+ virtual bool FindInterfaceByEndpoint(uint8_t endpoint_address,
+ uint8_t* interface_number) = 0;
+
protected:
friend class base::RefCountedThreadSafe<UsbDeviceHandle>;
diff --git a/device/usb/usb_device_handle_impl.cc b/device/usb/usb_device_handle_impl.cc
index c02895b..cdb0210 100644
--- a/device/usb/usb_device_handle_impl.cc
+++ b/device/usb/usb_device_handle_impl.cc
@@ -671,6 +671,17 @@
}
}
+bool UsbDeviceHandleImpl::FindInterfaceByEndpoint(uint8_t endpoint_address,
+ uint8_t* interface_number) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ const auto endpoint_it = endpoint_map_.find(endpoint_address);
+ if (endpoint_it != endpoint_map_.end()) {
+ *interface_number = endpoint_it->second.interface_number;
+ return true;
+ }
+ return false;
+}
+
UsbDeviceHandleImpl::UsbDeviceHandleImpl(
scoped_refptr<UsbContext> context,
scoped_refptr<UsbDeviceImpl> device,
@@ -815,9 +826,10 @@
scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer>
UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(uint8_t endpoint) {
- if (ContainsKey(endpoint_map_, endpoint))
- return claimed_interfaces_[endpoint_map_[endpoint].interface_number];
- return NULL;
+ const auto endpoint_it = endpoint_map_.find(endpoint);
+ if (endpoint_it != endpoint_map_.end())
+ return claimed_interfaces_[endpoint_it->second.interface_number];
+ return nullptr;
}
void UsbDeviceHandleImpl::ControlTransferInternal(
diff --git a/device/usb/usb_device_handle_impl.h b/device/usb/usb_device_handle_impl.h
index 1dff965..6d45e1e 100644
--- a/device/usb/usb_device_handle_impl.h
+++ b/device/usb/usb_device_handle_impl.h
@@ -82,6 +82,8 @@
size_t length,
unsigned int timeout,
const TransferCallback& callback) override;
+ bool FindInterfaceByEndpoint(uint8_t endpoint_address,
+ uint8_t* interface_number) override;
protected:
friend class UsbDeviceImpl;