summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chrome_device_client.cc10
-rw-r--r--chrome/browser/devtools/device/usb/android_usb_browsertest.cc268
-rw-r--r--chrome/browser/devtools/device/usb/android_usb_device.cc402
-rw-r--r--chrome/browser/devtools/device/usb/android_usb_device.h7
-rw-r--r--chrome/browser/extensions/api/device_permissions_manager_unittest.cc288
-rw-r--r--device/hid/hid_connection_unittest.cc37
-rw-r--r--device/hid/hid_service.cc10
-rw-r--r--device/test/usb_test_gadget.h9
-rw-r--r--device/test/usb_test_gadget_impl.cc760
-rw-r--r--device/usb/usb_context.cc28
-rw-r--r--device/usb/usb_device.cc14
-rw-r--r--device/usb/usb_device.h45
-rw-r--r--device/usb/usb_device_filter_unittest.cc28
-rw-r--r--device/usb/usb_device_handle.h47
-rw-r--r--device/usb/usb_device_handle_impl.cc758
-rw-r--r--device/usb/usb_device_handle_impl.h137
-rw-r--r--device/usb/usb_device_handle_unittest.cc157
-rw-r--r--device/usb/usb_device_impl.cc205
-rw-r--r--device/usb/usb_device_impl.h45
-rw-r--r--device/usb/usb_service.cc46
-rw-r--r--device/usb/usb_service.h25
-rw-r--r--device/usb/usb_service_impl.cc614
-rw-r--r--device/usb/usb_service_impl.h93
-rw-r--r--device/usb/usb_service_unittest.cc27
-rw-r--r--extensions/browser/api/device_permissions_manager.cc113
-rw-r--r--extensions/browser/api/device_permissions_manager.h46
-rw-r--r--extensions/browser/api/device_permissions_prompt.cc141
-rw-r--r--extensions/browser/api/device_permissions_prompt.h41
-rw-r--r--extensions/browser/api/usb/usb_api.cc824
-rw-r--r--extensions/browser/api/usb/usb_api.h287
-rw-r--r--extensions/browser/api/usb/usb_apitest.cc134
-rw-r--r--extensions/browser/api/usb/usb_device_resource.h2
-rw-r--r--extensions/browser/api/usb/usb_event_router.cc75
-rw-r--r--extensions/browser/api/usb/usb_event_router.h17
-rw-r--r--extensions/shell/browser/shell_device_client.cc10
-rw-r--r--extensions/test/data/api_test/usb/reset_device/test.js6
36 files changed, 2887 insertions, 2869 deletions
diff --git a/chrome/browser/chrome_device_client.cc b/chrome/browser/chrome_device_client.cc
index f93fb90..835a4c3 100644
--- a/chrome/browser/chrome_device_client.cc
+++ b/chrome/browser/chrome_device_client.cc
@@ -9,18 +9,20 @@
#include "device/hid/hid_service.h"
#include "device/usb/usb_service.h"
+using content::BrowserThread;
+
ChromeDeviceClient::ChromeDeviceClient() {}
ChromeDeviceClient::~ChromeDeviceClient() {}
device::UsbService* ChromeDeviceClient::GetUsbService() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
return device::UsbService::GetInstance(
- content::BrowserThread::GetMessageLoopProxyForThread(
- content::BrowserThread::UI));
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
}
device::HidService* ChromeDeviceClient::GetHidService() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
return device::HidService::GetInstance(
- content::BrowserThread::GetMessageLoopProxyForThread(
- content::BrowserThread::FILE));
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
}
diff --git a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
index c7f99ed..1eab6e8 100644
--- a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
@@ -29,7 +29,6 @@ using device::UsbEndpointDirection;
using device::UsbInterfaceDescriptor;
using device::UsbService;
using device::UsbSynchronizationType;
-using device::UsbTransferCallback;
using device::UsbTransferType;
using device::UsbUsageType;
@@ -127,15 +126,22 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
virtual void Close() override { device_ = nullptr; }
- bool SetConfiguration(int configuration_value) override { return true; }
+ void SetConfiguration(int configuration_value,
+ const ResultCallback& callback) override {
+ NOTIMPLEMENTED();
+ }
- bool ClaimInterface(int interface_number) override {
- if (device_->claimed_interfaces_.find(interface_number) !=
- device_->claimed_interfaces_.end())
- return false;
+ void ClaimInterface(int interface_number,
+ const ResultCallback& callback) override {
+ bool success = false;
+ if (device_->claimed_interfaces_.find(interface_number) ==
+ device_->claimed_interfaces_.end()) {
+ device_->claimed_interfaces_.insert(interface_number);
+ success = true;
+ }
- device_->claimed_interfaces_.insert(interface_number);
- return true;
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(callback, success));
}
bool ReleaseInterface(int interface_number) override {
@@ -147,35 +153,34 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
return true;
}
- virtual bool SetInterfaceAlternateSetting(int interface_number,
- int alternate_setting) override {
- return true;
+ void SetInterfaceAlternateSetting(int interface_number,
+ int alternate_setting,
+ const ResultCallback& callback) override {
+ NOTIMPLEMENTED();
}
- virtual bool ResetDevice() override { return true; }
- bool GetStringDescriptor(uint8_t string_id,
- base::string16* content) override {
- return false;
+ void ResetDevice(const ResultCallback& callback) override {
+ NOTIMPLEMENTED();
}
// Async IO. Can be called on any thread.
- virtual void ControlTransfer(UsbEndpointDirection direction,
- TransferRequestType request_type,
- TransferRecipient recipient,
- uint8 request,
- uint16 value,
- uint16 index,
- net::IOBuffer* buffer,
- size_t length,
- unsigned int timeout,
- const UsbTransferCallback& callback) override {}
-
- virtual void BulkTransfer(UsbEndpointDirection direction,
- uint8 endpoint,
- net::IOBuffer* buffer,
- size_t length,
- unsigned int timeout,
- const UsbTransferCallback& callback) override {
+ void ControlTransfer(UsbEndpointDirection direction,
+ TransferRequestType request_type,
+ TransferRecipient recipient,
+ uint8 request,
+ uint16 value,
+ uint16 index,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int timeout,
+ const TransferCallback& callback) override {}
+
+ void BulkTransfer(UsbEndpointDirection direction,
+ uint8 endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int timeout,
+ const TransferCallback& callback) override {
if (direction == device::USB_DIRECTION_OUTBOUND) {
if (remaining_body_length_ == 0) {
std::vector<uint32> header(6);
@@ -201,11 +206,10 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
device::UsbTransferStatus status =
broken_ ? device::USB_TRANSFER_ERROR : device::USB_TRANSFER_COMPLETED;
base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(callback, status, scoped_refptr<net::IOBuffer>(), 0));
+ FROM_HERE, base::Bind(callback, status, nullptr, 0));
ProcessQueries();
} else if (direction == device::USB_DIRECTION_INBOUND) {
- queries_.push(Query(callback, make_scoped_refptr(buffer), length));
+ queries_.push(Query(callback, buffer, length));
ProcessQueries();
}
}
@@ -336,36 +340,34 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
}
- virtual void InterruptTransfer(UsbEndpointDirection direction,
- uint8 endpoint,
- net::IOBuffer* buffer,
- size_t length,
- unsigned int timeout,
- const UsbTransferCallback& callback) override {
- }
+ void InterruptTransfer(UsbEndpointDirection direction,
+ uint8 endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int timeout,
+ const TransferCallback& callback) override {}
- virtual void IsochronousTransfer(
- UsbEndpointDirection direction,
- uint8 endpoint,
- net::IOBuffer* buffer,
- size_t length,
- unsigned int packets,
- unsigned int packet_length,
- unsigned int timeout,
- const UsbTransferCallback& callback) override {}
+ void IsochronousTransfer(UsbEndpointDirection direction,
+ uint8 endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int packets,
+ unsigned int packet_length,
+ unsigned int timeout,
+ const TransferCallback& callback) override {}
protected:
virtual ~MockUsbDeviceHandle() {}
struct Query {
- UsbTransferCallback callback;
+ TransferCallback callback;
scoped_refptr<net::IOBuffer> buffer;
size_t size;
- Query(UsbTransferCallback callback,
+ Query(TransferCallback callback,
scoped_refptr<net::IOBuffer> buffer,
int size)
- : callback(callback), buffer(buffer), size(size) {};
+ : callback(callback), buffer(buffer), size(size) {}
};
scoped_refptr<MockUsbDevice<T> > device_;
@@ -381,7 +383,13 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
template <class T>
class MockUsbDevice : public UsbDevice {
public:
- MockUsbDevice() : UsbDevice(0, 0, 0) {
+ MockUsbDevice()
+ : UsbDevice(0,
+ 0,
+ 0,
+ base::UTF8ToUTF16(kDeviceManufacturer),
+ base::UTF8ToUTF16(kDeviceModel),
+ base::UTF8ToUTF16(kDeviceSerial)) {
UsbEndpointDescriptor bulk_in;
bulk_in.address = 0x81;
bulk_in.direction = device::USB_DIRECTION_INBOUND;
@@ -406,30 +414,17 @@ class MockUsbDevice : public UsbDevice {
config_desc_.interfaces.push_back(interface_desc);
}
- virtual scoped_refptr<UsbDeviceHandle> Open() override {
- return new MockUsbDeviceHandle<T>(this);
+ void Open(const OpenCallback& callback) override {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, make_scoped_refptr(
+ new MockUsbDeviceHandle<T>(this))));
}
- virtual const UsbConfigDescriptor* GetConfiguration() override {
+ const UsbConfigDescriptor* GetConfiguration() override {
return T::kConfigured ? &config_desc_ : nullptr;
}
- virtual bool GetManufacturer(base::string16* manufacturer) override {
- *manufacturer = base::UTF8ToUTF16(kDeviceManufacturer);
- return true;
- }
-
- virtual bool GetProduct(base::string16* product) override {
- *product = base::UTF8ToUTF16(kDeviceModel);
- return true;
- }
-
- virtual bool GetSerialNumber(base::string16* serial) override {
- *serial = base::UTF8ToUTF16(kDeviceSerial);
- return true;
- }
-
- virtual bool Close(scoped_refptr<UsbDeviceHandle> handle) override {
+ bool Close(scoped_refptr<UsbDeviceHandle> handle) override {
return true;
}
@@ -453,52 +448,34 @@ class MockUsbService : public UsbService {
return nullptr;
}
- void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override {
- STLClearObject(devices);
- std::copy(devices_.begin(), devices_.end(), back_inserter(*devices));
+ void GetDevices(const GetDevicesCallback& callback) override {
+ callback.Run(devices_);
}
std::vector<scoped_refptr<UsbDevice> > devices_;
};
-class MockBreakingUsbService : public UsbService {
+class MockBreakingUsbService : public MockUsbService {
public:
- scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override {
- NOTIMPLEMENTED();
- return nullptr;
- }
-
- void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override {
- STLClearObject(devices);
- devices->push_back(new MockUsbDevice<BreakingAndroidTraits>());
+ MockBreakingUsbService() {
+ devices_.clear();
+ devices_.push_back(new MockUsbDevice<BreakingAndroidTraits>());
}
};
-class MockNoConfigUsbService : public UsbService {
+class MockNoConfigUsbService : public MockUsbService {
public:
- scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override {
- NOTIMPLEMENTED();
- return nullptr;
- }
-
- void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override {
- STLClearObject(devices);
- devices->push_back(new MockUsbDevice<AndroidTraits>());
- devices->push_back(new MockUsbDevice<NoConfigTraits>());
+ MockNoConfigUsbService() {
+ devices_.push_back(new MockUsbDevice<NoConfigTraits>());
}
};
-class MockUsbServiceForCheckingTraits : public UsbService {
+class MockUsbServiceForCheckingTraits : public MockUsbService {
public:
MockUsbServiceForCheckingTraits() : step_(0) {}
- scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override {
- NOTIMPLEMENTED();
- return nullptr;
- }
-
- void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override {
- STLClearObject(devices);
+ void GetDevices(const GetDevicesCallback& callback) override {
+ std::vector<scoped_refptr<UsbDevice>> devices;
// This switch should be kept in sync with
// AndroidUsbBrowserTest::DeviceCountChanged.
switch (step_) {
@@ -507,19 +484,20 @@ class MockUsbServiceForCheckingTraits : public UsbService {
break;
case 1:
// Android device.
- devices->push_back(new MockUsbDevice<AndroidTraits>());
+ devices.push_back(new MockUsbDevice<AndroidTraits>());
break;
case 2:
// Android and non-android device.
- devices->push_back(new MockUsbDevice<AndroidTraits>());
- devices->push_back(new MockUsbDevice<NonAndroidTraits>());
+ devices.push_back(new MockUsbDevice<AndroidTraits>());
+ devices.push_back(new MockUsbDevice<NonAndroidTraits>());
break;
case 3:
// Non-android device.
- devices->push_back(new MockUsbDevice<NonAndroidTraits>());
+ devices.push_back(new MockUsbDevice<NonAndroidTraits>());
break;
}
step_++;
+ callback.Run(devices);
}
private:
@@ -548,15 +526,7 @@ class AndroidUsbDiscoveryTest : public InProcessBrowserTest {
: scheduler_invoked_(0) {
}
void SetUpOnMainThread() override {
- scoped_refptr<content::MessageLoopRunner> runner =
- new content::MessageLoopRunner;
-
- BrowserThread::PostTaskAndReply(
- BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&AndroidUsbDiscoveryTest::SetUpService, this),
- runner->QuitClosure());
- runner->Run();
+ mock_usb_service_.reset(CreateMockService());
adb_bridge_ =
DevToolsAndroidBridge::Factory::GetForProfile(browser()->profile());
@@ -579,23 +549,10 @@ class AndroidUsbDiscoveryTest : public InProcessBrowserTest {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, request);
}
- virtual void SetUpService() {
- UsbService::SetInstanceForTest(new MockUsbService());
- }
-
- void TearDownOnMainThread() override {
- scoped_refptr<content::MessageLoopRunner> runner =
- new content::MessageLoopRunner;
- UsbService* service = nullptr;
- BrowserThread::PostTaskAndReply(
- BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&UsbService::SetInstanceForTest, service),
- runner->QuitClosure());
- runner->Run();
- }
+ virtual MockUsbService* CreateMockService() { return new MockUsbService(); }
scoped_refptr<content::MessageLoopRunner> runner_;
+ scoped_ptr<MockUsbService> mock_usb_service_;
DevToolsAndroidBridge* adb_bridge_;
int scheduler_invoked_;
};
@@ -613,22 +570,22 @@ class AndroidUsbCountTest : public AndroidUsbDiscoveryTest {
class AndroidUsbTraitsTest : public AndroidUsbDiscoveryTest {
protected:
- void SetUpService() override {
- UsbService::SetInstanceForTest(new MockUsbServiceForCheckingTraits());
+ MockUsbService* CreateMockService() override {
+ return new MockUsbServiceForCheckingTraits();
}
};
class AndroidBreakingUsbTest : public AndroidUsbDiscoveryTest {
protected:
- void SetUpService() override {
- UsbService::SetInstanceForTest(new MockBreakingUsbService());
+ MockUsbService* CreateMockService() override {
+ return new MockBreakingUsbService();
}
};
class AndroidNoConfigUsbTest : public AndroidUsbDiscoveryTest {
protected:
- void SetUpService() override {
- UsbService::SetInstanceForTest(new MockNoConfigUsbService());
+ MockUsbService* CreateMockService() override {
+ return new MockNoConfigUsbService();
}
};
@@ -662,10 +619,7 @@ class MockListListener : public DevToolsAndroidBridge::DeviceListListener {
class MockCountListener : public DevToolsAndroidBridge::DeviceCountListener {
public:
explicit MockCountListener(DevToolsAndroidBridge* adb_bridge)
- : adb_bridge_(adb_bridge),
- reposts_left_(10),
- invoked_(0) {
- }
+ : adb_bridge_(adb_bridge), invoked_(0) {}
void DeviceCountChanged(int count) override {
++invoked_;
@@ -673,33 +627,9 @@ class MockCountListener : public DevToolsAndroidBridge::DeviceCountListener {
Shutdown();
}
- void Shutdown() {
- ShutdownOnUIThread();
- };
-
- void ShutdownOnUIThread() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (reposts_left_-- == 0) {
- base::MessageLoop::current()->Quit();
- } else {
- BrowserThread::PostTask(
- BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&MockCountListener::ShutdownOnFileThread,
- base::Unretained(this)));
- }
- }
-
- void ShutdownOnFileThread() {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- BrowserThread::PostTask(BrowserThread::UI,
- FROM_HERE,
- base::Bind(&MockCountListener::ShutdownOnUIThread,
- base::Unretained(this)));
- }
+ void Shutdown() { base::MessageLoop::current()->Quit(); }
DevToolsAndroidBridge* adb_bridge_;
- int reposts_left_;
int invoked_;
};
@@ -820,6 +750,7 @@ IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
runner_->Run();
EXPECT_EQ(1, listener.invoked_);
EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
+ EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
}
IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
@@ -829,6 +760,7 @@ IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
runner_->Run();
EXPECT_EQ(3, listener.invoked_);
EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
+ EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
}
IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
@@ -840,6 +772,7 @@ IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
runner_->Run();
EXPECT_EQ(1, listener.invoked_);
EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
+ EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
}
IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
@@ -849,6 +782,7 @@ IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
runner_->Run();
EXPECT_EQ(2, listener.invoked_);
EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
+ EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
}
IN_PROC_BROWSER_TEST_F(AndroidUsbTraitsTest, TestDeviceCounting) {
diff --git a/chrome/browser/devtools/device/usb/android_usb_device.cc b/chrome/browser/devtools/device/usb/android_usb_device.cc
index 9e5d700..5da4458 100644
--- a/chrome/browser/devtools/device/usb/android_usb_device.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_device.cc
@@ -9,11 +9,12 @@
#include "base/barrier_closure.h"
#include "base/base64.h"
#include "base/lazy_instance.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
#include "chrome/browser/devtools/device/usb/android_rsa.h"
#include "chrome/browser/devtools/device/usb/android_usb_socket.h"
#include "content/public/browser/browser_thread.h"
@@ -69,38 +70,22 @@ bool IsAndroidInterface(const UsbInterfaceDescriptor& interface) {
return true;
}
-scoped_refptr<AndroidUsbDevice> ClaimInterface(
- crypto::RSAPrivateKey* rsa_key,
- scoped_refptr<UsbDeviceHandle> usb_handle,
- const base::string16& serial,
- const UsbInterfaceDescriptor& interface) {
- int inbound_address = 0;
- int outbound_address = 0;
- int zero_mask = 0;
-
- for (const UsbEndpointDescriptor& endpoint : interface.endpoints) {
- if (endpoint.transfer_type != device::USB_TRANSFER_BULK)
- continue;
- if (endpoint.direction == device::USB_DIRECTION_INBOUND)
- inbound_address = endpoint.address;
- else
- outbound_address = endpoint.address;
- zero_mask = endpoint.maximum_packet_size - 1;
+void CountAndroidDevices(const base::Callback<void(int)>& callback,
+ const UsbDevices& devices) {
+ int device_count = 0;
+ for (const scoped_refptr<UsbDevice>& device : devices) {
+ const UsbConfigDescriptor* config = device->GetConfiguration();
+ if (config) {
+ for (const UsbInterfaceDescriptor& iface : config->interfaces) {
+ if (IsAndroidInterface(iface)) {
+ ++device_count;
+ }
+ }
+ }
}
- if (inbound_address == 0 || outbound_address == 0)
- return NULL;
-
- if (!usb_handle->ClaimInterface(interface.interface_number))
- return NULL;
-
- return new AndroidUsbDevice(rsa_key,
- usb_handle,
- base::UTF16ToASCII(serial),
- inbound_address,
- outbound_address,
- zero_mask,
- interface.interface_number);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, device_count));
}
uint32 Checksum(const std::string& data) {
@@ -147,23 +132,8 @@ void ReleaseInterface(scoped_refptr<UsbDeviceHandle> usb_device,
usb_device->Close();
}
-} // namespace
-
-AdbMessage::AdbMessage(uint32 command,
- uint32 arg0,
- uint32 arg1,
- const std::string& body)
- : command(command),
- arg0(arg0),
- arg1(arg1),
- body(body) {
-}
-
-AdbMessage::~AdbMessage() {
-}
-
-static void RespondOnCallerThread(const AndroidUsbDevicesCallback& callback,
- AndroidUsbDevices* new_devices) {
+void RespondOnCallerThread(const AndroidUsbDevicesCallback& callback,
+ AndroidUsbDevices* new_devices) {
scoped_ptr<AndroidUsbDevices> devices(new_devices);
// Add raw pointers to the newly claimed devices.
@@ -176,82 +146,115 @@ static void RespondOnCallerThread(const AndroidUsbDevicesCallback& callback,
callback.Run(result);
}
-static void RespondOnFileThread(
+void RespondOnUIThread(
const AndroidUsbDevicesCallback& callback,
AndroidUsbDevices* devices,
- scoped_refptr<base::MessageLoopProxy> caller_message_loop_proxy) {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- caller_message_loop_proxy->PostTask(
- FROM_HERE,
- base::Bind(&RespondOnCallerThread, callback, devices));
+ scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ caller_task_runner->PostTask(
+ FROM_HERE, base::Bind(&RespondOnCallerThread, callback, devices));
}
-static void OpenAndroidDeviceOnFileThread(
- AndroidUsbDevices* devices,
- crypto::RSAPrivateKey* rsa_key,
- const base::Closure& barrier,
- scoped_refptr<UsbDevice> device,
- int interface_id,
- bool success) {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+void CreateDeviceOnInterfaceClaimed(AndroidUsbDevices* devices,
+ crypto::RSAPrivateKey* rsa_key,
+ scoped_refptr<UsbDeviceHandle> usb_handle,
+ int inbound_address,
+ int outbound_address,
+ int zero_mask,
+ int interface_number,
+ const base::Closure& barrier,
+ bool success) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (success) {
- base::string16 serial;
- if (device->GetSerialNumber(&serial) && !serial.empty()) {
- const UsbConfigDescriptor* config = device->GetConfiguration();
- if (config) {
- scoped_refptr<UsbDeviceHandle> usb_handle = device->Open();
- if (usb_handle.get()) {
- scoped_refptr<AndroidUsbDevice> android_device = ClaimInterface(
- rsa_key, usb_handle, serial, config->interfaces[interface_id]);
- if (android_device.get())
- devices->push_back(android_device);
- else
- usb_handle->Close();
- }
- }
- }
+ devices->push_back(new AndroidUsbDevice(
+ rsa_key, usb_handle,
+ base::UTF16ToASCII(usb_handle->GetDevice()->serial_number()),
+ inbound_address, outbound_address, zero_mask, interface_number));
+ } else {
+ usb_handle->Close();
}
barrier.Run();
}
-static int CountOnFileThread() {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- UsbService* service = device::DeviceClient::Get()->GetUsbService();
- UsbDevices usb_devices;
- if (service != NULL)
- service->GetDevices(&usb_devices);
- int device_count = 0;
- for (const scoped_refptr<UsbDevice>& device : usb_devices) {
- const UsbConfigDescriptor* config = device->GetConfiguration();
- if (config) {
- for (const UsbInterfaceDescriptor& iface : config->interfaces) {
- if (IsAndroidInterface(iface)) {
- ++device_count;
- }
- }
- }
+void OnDeviceOpened(AndroidUsbDevices* devices,
+ crypto::RSAPrivateKey* rsa_key,
+ int inbound_address,
+ int outbound_address,
+ int zero_mask,
+ int interface_number,
+ const base::Closure& barrier,
+ scoped_refptr<UsbDeviceHandle> usb_handle) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (usb_handle.get()) {
+ usb_handle->ClaimInterface(
+ interface_number,
+ base::Bind(&CreateDeviceOnInterfaceClaimed, devices, rsa_key,
+ usb_handle, inbound_address, outbound_address, zero_mask,
+ interface_number, barrier));
+ } else {
+ barrier.Run();
}
- return device_count;
}
-static void EnumerateOnFileThread(
- crypto::RSAPrivateKey* rsa_key,
- const AndroidUsbDevicesCallback& callback,
- scoped_refptr<base::MessageLoopProxy> caller_message_loop_proxy) {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+void OpenAndroidDevice(AndroidUsbDevices* devices,
+ crypto::RSAPrivateKey* rsa_key,
+ const base::Closure& barrier,
+ scoped_refptr<UsbDevice> device,
+ int interface_id,
+ bool success) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!success) {
+ barrier.Run();
+ return;
+ }
- UsbService* service = device::DeviceClient::Get()->GetUsbService();
- UsbDevices usb_devices;
- if (service != NULL)
- service->GetDevices(&usb_devices);
+ if (device->serial_number().empty()) {
+ barrier.Run();
+ return;
+ }
+
+ const UsbConfigDescriptor* config = device->GetConfiguration();
+ if (!config) {
+ barrier.Run();
+ return;
+ }
+ const UsbInterfaceDescriptor& interface = config->interfaces[interface_id];
+ int inbound_address = 0;
+ int outbound_address = 0;
+ int zero_mask = 0;
+
+ for (const UsbEndpointDescriptor& endpoint : interface.endpoints) {
+ if (endpoint.transfer_type != device::USB_TRANSFER_BULK)
+ continue;
+ if (endpoint.direction == device::USB_DIRECTION_INBOUND)
+ inbound_address = endpoint.address;
+ else
+ outbound_address = endpoint.address;
+ zero_mask = endpoint.maximum_packet_size - 1;
+ }
+
+ if (inbound_address == 0 || outbound_address == 0) {
+ barrier.Run();
+ return;
+ }
+
+ device->Open(base::Bind(&OnDeviceOpened, devices, rsa_key, inbound_address,
+ outbound_address, zero_mask,
+ interface.interface_number, barrier));
+}
+
+void OpenAndroidDevices(
+ crypto::RSAPrivateKey* rsa_key,
+ const AndroidUsbDevicesCallback& callback,
+ scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
+ const UsbDevices& usb_devices) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Add new devices.
AndroidUsbDevices* devices = new AndroidUsbDevices();
base::Closure barrier = base::BarrierClosure(
- usb_devices.size(), base::Bind(&RespondOnFileThread,
- callback,
- devices,
- caller_message_loop_proxy));
+ usb_devices.size(),
+ base::Bind(&RespondOnUIThread, callback, devices, caller_task_runner));
for (const scoped_refptr<UsbDevice>& device : usb_devices) {
const UsbConfigDescriptor* config = device->GetConfiguration();
@@ -265,45 +268,73 @@ static void EnumerateOnFileThread(
continue;
}
- device->RequestUsbAccess(
- j, base::Bind(&OpenAndroidDeviceOnFileThread, devices, rsa_key,
- barrier, device, j));
+ device->RequestUsbAccess(j, base::Bind(&OpenAndroidDevice, devices,
+ rsa_key, barrier, device, j));
has_android_interface = true;
break;
}
- if (!has_android_interface)
+ if (!has_android_interface) {
barrier.Run();
+ }
+ }
+}
+
+void EnumerateOnUIThread(
+ crypto::RSAPrivateKey* rsa_key,
+ const AndroidUsbDevicesCallback& callback,
+ scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ UsbService* service = device::DeviceClient::Get()->GetUsbService();
+ if (service == NULL) {
+ caller_task_runner->PostTask(FROM_HERE,
+ base::Bind(callback, AndroidUsbDevices()));
+ } else {
+ service->GetDevices(
+ base::Bind(&OpenAndroidDevices, rsa_key, callback, caller_task_runner));
}
}
+} // namespace
+
+AdbMessage::AdbMessage(uint32 command,
+ uint32 arg0,
+ uint32 arg1,
+ const std::string& body)
+ : command(command), arg0(arg0), arg1(arg1), body(body) {
+}
+
+AdbMessage::~AdbMessage() {
+}
+
// static
-void AndroidUsbDevice::CountDevices(
- const base::Callback<void(int)>& callback) {
- BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&CountOnFileThread),
- callback);
+void AndroidUsbDevice::CountDevices(const base::Callback<void(int)>& callback) {
+ UsbService* service = device::DeviceClient::Get()->GetUsbService();
+ if (service != NULL) {
+ service->GetDevices(base::Bind(&CountAndroidDevices, callback));
+ } else {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback, 0));
+ }
}
// static
void AndroidUsbDevice::Enumerate(crypto::RSAPrivateKey* rsa_key,
const AndroidUsbDevicesCallback& callback) {
-
// Collect devices with closed handles.
for (AndroidUsbDevice* device : g_devices.Get()) {
if (device->usb_handle_.get()) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&AndroidUsbDevice::TerminateIfReleased, device,
- device->usb_handle_));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&AndroidUsbDevice::TerminateIfReleased,
+ device, device->usb_handle_));
}
}
// Then look for the new devices.
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&EnumerateOnFileThread, rsa_key, callback,
- base::MessageLoopProxy::current()));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&EnumerateOnUIThread, rsa_key, callback,
+ base::ThreadTaskRunnerHandle::Get()));
}
AndroidUsbDevice::AndroidUsbDevice(crypto::RSAPrivateKey* rsa_key,
@@ -313,8 +344,7 @@ AndroidUsbDevice::AndroidUsbDevice(crypto::RSAPrivateKey* rsa_key,
int outbound_address,
int zero_mask,
int interface_id)
- : message_loop_(NULL),
- rsa_key_(rsa_key->Copy()),
+ : rsa_key_(rsa_key->Copy()),
usb_handle_(usb_device),
serial_(serial),
inbound_address_(inbound_address),
@@ -328,9 +358,9 @@ AndroidUsbDevice::AndroidUsbDevice(crypto::RSAPrivateKey* rsa_key,
}
void AndroidUsbDevice::InitOnCallerThread() {
- if (message_loop_)
+ if (task_runner_)
return;
- message_loop_ = base::MessageLoop::current();
+ task_runner_ = base::ThreadTaskRunnerHandle::Get();
Queue(make_scoped_ptr(new AdbMessage(AdbMessage::kCommandCNXN, kVersion,
kMaxPayload, kHostConnectMessage)));
ReadHeader();
@@ -360,12 +390,12 @@ void AndroidUsbDevice::Send(uint32 command,
}
AndroidUsbDevice::~AndroidUsbDevice() {
- DCHECK(message_loop_ == base::MessageLoop::current());
+ DCHECK(task_runner_->BelongsToCurrentThread());
Terminate();
}
void AndroidUsbDevice::Queue(scoped_ptr<AdbMessage> message) {
- DCHECK(message_loop_ == base::MessageLoop::current());
+ DCHECK(task_runner_->BelongsToCurrentThread());
// Queue header.
std::vector<uint32> header;
@@ -407,7 +437,7 @@ void AndroidUsbDevice::Queue(scoped_ptr<AdbMessage> message) {
}
void AndroidUsbDevice::ProcessOutgoing() {
- DCHECK(message_loop_ == base::MessageLoop::current());
+ DCHECK(task_runner_->BelongsToCurrentThread());
if (outgoing_queue_.empty() || !usb_handle_.get())
return;
@@ -415,11 +445,9 @@ void AndroidUsbDevice::ProcessOutgoing() {
BulkMessage message = outgoing_queue_.front();
outgoing_queue_.pop();
DumpMessage(true, message->data(), message->size());
- usb_handle_->BulkTransfer(device::USB_DIRECTION_OUTBOUND,
- outbound_address_,
- message.get(),
- message->size(),
- kUsbTimeout,
+
+ usb_handle_->BulkTransfer(device::USB_DIRECTION_OUTBOUND, outbound_address_,
+ message, message->size(), kUsbTimeout,
base::Bind(&AndroidUsbDevice::OutgoingMessageSent,
weak_factory_.GetWeakPtr()));
}
@@ -427,25 +455,24 @@ void AndroidUsbDevice::ProcessOutgoing() {
void AndroidUsbDevice::OutgoingMessageSent(UsbTransferStatus status,
scoped_refptr<net::IOBuffer> buffer,
size_t result) {
- DCHECK(message_loop_ == base::MessageLoop::current());
-
- if (status != device::USB_TRANSFER_COMPLETED)
+ if (status != device::USB_TRANSFER_COMPLETED) {
return;
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&AndroidUsbDevice::ProcessOutgoing, this));
+ }
+
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&AndroidUsbDevice::ProcessOutgoing, this));
}
void AndroidUsbDevice::ReadHeader() {
- DCHECK(message_loop_ == base::MessageLoop::current());
+ DCHECK(task_runner_->BelongsToCurrentThread());
- if (!usb_handle_.get())
+ if (!usb_handle_.get()) {
return;
+ }
+
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kHeaderSize);
usb_handle_->BulkTransfer(
- device::USB_DIRECTION_INBOUND,
- inbound_address_,
- buffer.get(),
- kHeaderSize,
+ device::USB_DIRECTION_INBOUND, inbound_address_, buffer, kHeaderSize,
kUsbTimeout,
base::Bind(&AndroidUsbDevice::ParseHeader, weak_factory_.GetWeakPtr()));
}
@@ -453,11 +480,11 @@ void AndroidUsbDevice::ReadHeader() {
void AndroidUsbDevice::ParseHeader(UsbTransferStatus status,
scoped_refptr<net::IOBuffer> buffer,
size_t result) {
- DCHECK(message_loop_ == base::MessageLoop::current());
+ DCHECK(task_runner_->BelongsToCurrentThread());
if (status == device::USB_TRANSFER_TIMEOUT) {
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&AndroidUsbDevice::ReadHeader, this));
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&AndroidUsbDevice::ReadHeader, this));
return;
}
@@ -480,35 +507,31 @@ void AndroidUsbDevice::ParseHeader(UsbTransferStatus status,
}
if (data_length == 0) {
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&AndroidUsbDevice::HandleIncoming, this,
- base::Passed(&message)));
- return;
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&AndroidUsbDevice::HandleIncoming, this,
+ base::Passed(&message)));
+ } else {
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&AndroidUsbDevice::ReadBody, this,
+ base::Passed(&message), data_length, data_check));
}
-
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&AndroidUsbDevice::ReadBody, this,
- base::Passed(&message), data_length, data_check));
}
void AndroidUsbDevice::ReadBody(scoped_ptr<AdbMessage> message,
uint32 data_length,
uint32 data_check) {
- DCHECK(message_loop_ == base::MessageLoop::current());
+ DCHECK(task_runner_->BelongsToCurrentThread());
- if (!usb_handle_.get())
+ if (!usb_handle_.get()) {
return;
+ }
+
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_length);
- usb_handle_->BulkTransfer(device::USB_DIRECTION_INBOUND,
- inbound_address_,
- buffer.get(),
- data_length,
- kUsbTimeout,
- base::Bind(&AndroidUsbDevice::ParseBody,
- weak_factory_.GetWeakPtr(),
- base::Passed(&message),
- data_length,
- data_check));
+ usb_handle_->BulkTransfer(
+ device::USB_DIRECTION_INBOUND, inbound_address_, buffer, data_length,
+ kUsbTimeout,
+ base::Bind(&AndroidUsbDevice::ParseBody, weak_factory_.GetWeakPtr(),
+ base::Passed(&message), data_length, data_check));
}
void AndroidUsbDevice::ParseBody(scoped_ptr<AdbMessage> message,
@@ -517,12 +540,12 @@ void AndroidUsbDevice::ParseBody(scoped_ptr<AdbMessage> message,
UsbTransferStatus status,
scoped_refptr<net::IOBuffer> buffer,
size_t result) {
- DCHECK(message_loop_ == base::MessageLoop::current());
+ DCHECK(task_runner_->BelongsToCurrentThread());
if (status == device::USB_TRANSFER_TIMEOUT) {
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&AndroidUsbDevice::ReadBody, this,
- base::Passed(&message), data_length, data_check));
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&AndroidUsbDevice::ReadBody, this,
+ base::Passed(&message), data_length, data_check));
return;
}
@@ -539,13 +562,13 @@ void AndroidUsbDevice::ParseBody(scoped_ptr<AdbMessage> message,
return;
}
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&AndroidUsbDevice::HandleIncoming, this,
- base::Passed(&message)));
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&AndroidUsbDevice::HandleIncoming, this,
+ base::Passed(&message)));
}
void AndroidUsbDevice::HandleIncoming(scoped_ptr<AdbMessage> message) {
- DCHECK(message_loop_ == base::MessageLoop::current());
+ DCHECK(task_runner_->BelongsToCurrentThread());
switch (message->command) {
case AdbMessage::kCommandAUTH:
@@ -599,23 +622,24 @@ void AndroidUsbDevice::HandleIncoming(scoped_ptr<AdbMessage> message) {
}
void AndroidUsbDevice::TransferError(UsbTransferStatus status) {
- DCHECK(message_loop_ == base::MessageLoop::current());
+ DCHECK(task_runner_->BelongsToCurrentThread());
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&AndroidUsbDevice::Terminate, this));
+ Terminate();
}
void AndroidUsbDevice::TerminateIfReleased(
scoped_refptr<UsbDeviceHandle> usb_handle) {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- if (usb_handle->GetDevice().get())
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (usb_handle->GetDevice().get()) {
return;
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&AndroidUsbDevice::Terminate, this));
+ }
+
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&AndroidUsbDevice::Terminate, this));
}
void AndroidUsbDevice::Terminate() {
- DCHECK(message_loop_ == base::MessageLoop::current());
+ DCHECK(task_runner_->BelongsToCurrentThread());
std::vector<AndroidUsbDevice*>::iterator it =
std::find(g_devices.Get().begin(), g_devices.Get().end(), this);
@@ -639,12 +663,12 @@ void AndroidUsbDevice::Terminate() {
DCHECK(sockets_.empty());
BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
+ BrowserThread::UI, FROM_HERE,
base::Bind(&ReleaseInterface, usb_handle, interface_id_));
}
void AndroidUsbDevice::SocketDeleted(uint32 socket_id) {
- DCHECK(message_loop_ == base::MessageLoop::current());
+ DCHECK(task_runner_->BelongsToCurrentThread());
sockets_.erase(socket_id);
}
diff --git a/chrome/browser/devtools/device/usb/android_usb_device.h b/chrome/browser/devtools/device/usb/android_usb_device.h
index 3400a97..af976a0 100644
--- a/chrome/browser/devtools/device/usb/android_usb_device.h
+++ b/chrome/browser/devtools/device/usb/android_usb_device.h
@@ -15,7 +15,7 @@
#include "device/usb/usb_device_handle.h"
namespace base {
-class MessageLoop;
+class SingleThreadTaskRunner;
}
namespace crypto {
@@ -68,11 +68,10 @@ typedef base::Callback<void(const AndroidUsbDevices&)>
class AndroidUsbDevice : public base::RefCountedThreadSafe<AndroidUsbDevice> {
public:
+ static void CountDevices(const base::Callback<void(int)>& callback);
static void Enumerate(crypto::RSAPrivateKey* rsa_key,
const AndroidUsbDevicesCallback& callback);
- static void CountDevices(const base::Callback<void(int)>& callback);
-
AndroidUsbDevice(crypto::RSAPrivateKey* rsa_key,
scoped_refptr<device::UsbDeviceHandle> device,
const std::string& serial,
@@ -130,7 +129,7 @@ class AndroidUsbDevice : public base::RefCountedThreadSafe<AndroidUsbDevice> {
void SocketDeleted(uint32 socket_id);
- base::MessageLoop* message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
scoped_ptr<crypto::RSAPrivateKey> rsa_key_;
diff --git a/chrome/browser/extensions/api/device_permissions_manager_unittest.cc b/chrome/browser/extensions/api/device_permissions_manager_unittest.cc
index 0140bf6..32296bc 100644
--- a/chrome/browser/extensions/api/device_permissions_manager_unittest.cc
+++ b/chrome/browser/extensions/api/device_permissions_manager_unittest.cc
@@ -30,121 +30,86 @@ using testing::SetArgPointee;
int next_id;
+class MockDeviceClient : device::DeviceClient {
+ public:
+ MockDeviceClient() {}
+
+ // device::DeviceClient implementation:
+ UsbService* GetUsbService() override {
+ DCHECK(usb_service_);
+ return usb_service_;
+ }
+
+ void set_usb_service(UsbService* service) { usb_service_ = service; }
+
+ private:
+ UsbService* usb_service_ = nullptr;
+};
+
class MockUsbService : public UsbService {
public:
- MockUsbService() : mock_device_client(this) {}
+ MockUsbService() {}
MOCK_METHOD1(GetDeviceById, scoped_refptr<UsbDevice>(uint32));
- MOCK_METHOD1(GetDevices, void(std::vector<scoped_refptr<UsbDevice>>*));
+ MOCK_METHOD1(GetDevices, void(const GetDevicesCallback& callback));
// Public wrapper for the protected NotifyDeviceRemove function.
void NotifyDeviceRemoved(scoped_refptr<UsbDevice> device) {
UsbService::NotifyDeviceRemoved(device);
}
-
- private:
- class MockDeviceClient : device::DeviceClient {
- public:
- explicit MockDeviceClient(UsbService* usb_service)
- : usb_service_(usb_service) {}
-
- UsbService* GetUsbService() override { return usb_service_; }
-
- private:
- UsbService* usb_service_;
- };
-
- MockDeviceClient mock_device_client;
};
class MockUsbDevice : public UsbDevice {
public:
explicit MockUsbDevice(const std::string& serial_number)
- : UsbDevice(0, 0, next_id++) {
- if (serial_number.empty()) {
- EXPECT_CALL(*this, GetSerialNumber(_)).WillRepeatedly(Return(false));
- } else {
- EXPECT_CALL(*this, GetSerialNumber(_))
- .WillRepeatedly(
- DoAll(SetArgPointee<0>(base::ASCIIToUTF16(serial_number)),
- Return(true)));
- }
-
- EXPECT_CALL(*this, GetProduct(_))
- .WillRepeatedly(
- DoAll(SetArgPointee<0>(base::ASCIIToUTF16("Test Product")),
- Return(true)));
- EXPECT_CALL(*this, GetManufacturer(_))
- .WillRepeatedly(
- DoAll(SetArgPointee<0>(base::ASCIIToUTF16("Test Manufacturer")),
- Return(true)));
- }
-
- MOCK_METHOD0(Open, scoped_refptr<UsbDeviceHandle>());
+ : UsbDevice(0,
+ 0,
+ next_id++,
+ base::ASCIIToUTF16("Test Manufacturer"),
+ base::ASCIIToUTF16("Test Product"),
+ base::ASCIIToUTF16(serial_number)) {}
+
+ MOCK_METHOD1(Open, void(const OpenCallback&));
MOCK_METHOD1(Close, bool(scoped_refptr<UsbDeviceHandle>));
MOCK_METHOD0(GetConfiguration, const device::UsbConfigDescriptor*());
- MOCK_METHOD1(GetManufacturer, bool(base::string16*));
- MOCK_METHOD1(GetProduct, bool(base::string16*));
- MOCK_METHOD1(GetSerialNumber, bool(base::string16*));
private:
virtual ~MockUsbDevice() {}
};
-void AllowUsbDevice(DevicePermissionsManager* manager,
- const Extension* extension,
- scoped_refptr<UsbDevice> device) {
- // If the device cannot provide any of these strings they will simply by
- // empty.
- base::string16 product;
- device->GetProduct(&product);
- base::string16 manufacturer;
- device->GetManufacturer(&manufacturer);
- base::string16 serial_number;
- device->GetSerialNumber(&serial_number);
-
- manager->AllowUsbDevice(
- extension->id(), device, product, manufacturer, serial_number);
-}
-
-scoped_refptr<DevicePermissionEntry> FindEntry(
- DevicePermissions* device_permissions,
- scoped_refptr<UsbDevice> device) {
- base::string16 serial_number;
- device->GetSerialNumber(&serial_number);
-
- return device_permissions->FindEntry(device, serial_number);
-}
-
} // namespace
class DevicePermissionsManagerTest : public testing::Test {
protected:
void SetUp() override {
testing::Test::SetUp();
- env_.GetExtensionPrefs(); // Force creation before adding extensions.
- extension_ = env_.MakeExtension(*base::test::ParseJson(
- "{"
- " \"app\": {"
- " \"background\": {"
- " \"scripts\": [\"background.js\"]"
- " }"
- " },"
- " \"permissions\": ["
- " \"usb\""
- " ]"
- "}"));
+ env_.reset(new extensions::TestExtensionEnvironment());
+ env_->GetExtensionPrefs(); // Force creation before adding extensions.
+ extension_ =
+ env_->MakeExtension(*base::test::ParseJson(
+ "{"
+ " \"app\": {"
+ " \"background\": {"
+ " \"scripts\": [\"background.js\"]"
+ " }"
+ " },"
+ " \"permissions\": ["
+ " \"usb\""
+ " ]"
+ "}"));
device0_ = new MockUsbDevice("ABCDE");
device1_ = new MockUsbDevice("");
device2_ = new MockUsbDevice("12345");
device3_ = new MockUsbDevice("");
- usb_service_ = new MockUsbService();
- UsbService::SetInstanceForTest(usb_service_);
+ mock_device_client_.set_usb_service(&usb_service_);
}
- extensions::TestExtensionEnvironment env_;
+ void TearDown() override { env_.reset(nullptr); }
+
+ scoped_ptr<extensions::TestExtensionEnvironment> env_;
const extensions::Extension* extension_;
- MockUsbService* usb_service_;
+ MockDeviceClient mock_device_client_;
+ MockUsbService usb_service_;
scoped_refptr<MockUsbDevice> device0_;
scoped_refptr<MockUsbDevice> device1_;
scoped_refptr<MockUsbDevice> device2_;
@@ -153,20 +118,20 @@ class DevicePermissionsManagerTest : public testing::Test {
TEST_F(DevicePermissionsManagerTest, AllowAndClearDevices) {
DevicePermissionsManager* manager =
- DevicePermissionsManager::Get(env_.profile());
- AllowUsbDevice(manager, extension_, device0_);
- AllowUsbDevice(manager, extension_, device1_);
+ DevicePermissionsManager::Get(env_->profile());
+ manager->AllowUsbDevice(extension_->id(), device0_);
+ manager->AllowUsbDevice(extension_->id(), device1_);
- scoped_ptr<DevicePermissions> device_permissions =
+ DevicePermissions* device_permissions =
manager->GetForExtension(extension_->id());
scoped_refptr<DevicePermissionEntry> device0_entry =
- FindEntry(device_permissions.get(), device0_);
+ device_permissions->FindEntry(device0_);
ASSERT_TRUE(device0_entry.get());
scoped_refptr<DevicePermissionEntry> device1_entry =
- FindEntry(device_permissions.get(), device1_);
+ device_permissions->FindEntry(device1_);
ASSERT_TRUE(device1_entry.get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device2_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device3_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device2_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device3_).get());
ASSERT_EQ(2U, device_permissions->entries().size());
ASSERT_EQ(base::ASCIIToUTF16(
@@ -176,132 +141,123 @@ TEST_F(DevicePermissionsManagerTest, AllowAndClearDevices) {
device1_entry->GetPermissionMessageString());
manager->Clear(extension_->id());
-
+ // The device_permissions object is deleted by Clear.
device_permissions = manager->GetForExtension(extension_->id());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device0_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device1_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device2_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device3_).get());
+
+ ASSERT_FALSE(device_permissions->FindEntry(device0_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device1_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device2_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device3_).get());
ASSERT_EQ(0U, device_permissions->entries().size());
// After clearing device it should be possible to grant permission again.
- AllowUsbDevice(manager, extension_, device0_);
- AllowUsbDevice(manager, extension_, device1_);
+ manager->AllowUsbDevice(extension_->id(), device0_);
+ manager->AllowUsbDevice(extension_->id(), device1_);
- device_permissions = manager->GetForExtension(extension_->id());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device0_).get());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device1_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device2_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device3_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device0_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device1_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device2_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device3_).get());
}
TEST_F(DevicePermissionsManagerTest, SuspendExtension) {
DevicePermissionsManager* manager =
- DevicePermissionsManager::Get(env_.profile());
- AllowUsbDevice(manager, extension_, device0_);
- AllowUsbDevice(manager, extension_, device1_);
+ DevicePermissionsManager::Get(env_->profile());
+ manager->AllowUsbDevice(extension_->id(), device0_);
+ manager->AllowUsbDevice(extension_->id(), device1_);
- scoped_ptr<DevicePermissions> device_permissions =
+ DevicePermissions* device_permissions =
manager->GetForExtension(extension_->id());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device0_).get());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device1_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device2_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device3_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device0_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device1_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device2_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device3_).get());
manager->OnBackgroundHostClose(extension_->id());
- device_permissions = manager->GetForExtension(extension_->id());
// Device 0 is still registered because its serial number has been stored in
// ExtensionPrefs, it is "persistent".
- ASSERT_TRUE(FindEntry(device_permissions.get(), device0_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device0_).get());
// Device 1 does not have uniquely identifying traits and so permission to
// open it has been dropped when the app's windows have closed and the
// background page has been suspended.
- ASSERT_FALSE(FindEntry(device_permissions.get(), device1_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device2_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device3_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device1_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device2_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device3_).get());
}
-// TODO(reillyg): Until crbug.com/427985 is resolved device removal
-// notifications are delivered asynchronously and so this test must be disabled.
-TEST_F(DevicePermissionsManagerTest, DISABLED_DisconnectDevice) {
+TEST_F(DevicePermissionsManagerTest, DisconnectDevice) {
DevicePermissionsManager* manager =
- DevicePermissionsManager::Get(env_.profile());
- AllowUsbDevice(manager, extension_, device0_);
- AllowUsbDevice(manager, extension_, device1_);
+ DevicePermissionsManager::Get(env_->profile());
+ manager->AllowUsbDevice(extension_->id(), device0_);
+ manager->AllowUsbDevice(extension_->id(), device1_);
- scoped_ptr<DevicePermissions> device_permissions =
+ DevicePermissions* device_permissions =
manager->GetForExtension(extension_->id());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device0_).get());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device1_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device2_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device3_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device0_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device1_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device2_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device3_).get());
- usb_service_->NotifyDeviceRemoved(device0_);
- usb_service_->NotifyDeviceRemoved(device1_);
+ usb_service_.NotifyDeviceRemoved(device0_);
+ usb_service_.NotifyDeviceRemoved(device1_);
- device_permissions = manager->GetForExtension(extension_->id());
// Device 0 will be accessible when it is reconnected because it can be
// recognized by its serial number.
- ASSERT_TRUE(FindEntry(device_permissions.get(), device0_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device0_).get());
// Device 1 does not have a serial number and cannot be distinguished from
// any other device of the same model so the app must request permission again
// when it is reconnected.
- ASSERT_FALSE(FindEntry(device_permissions.get(), device1_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device2_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device3_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device1_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device2_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device3_).get());
}
TEST_F(DevicePermissionsManagerTest, RevokeAndRegrantAccess) {
DevicePermissionsManager* manager =
- DevicePermissionsManager::Get(env_.profile());
- AllowUsbDevice(manager, extension_, device0_);
- AllowUsbDevice(manager, extension_, device1_);
+ DevicePermissionsManager::Get(env_->profile());
+ manager->AllowUsbDevice(extension_->id(), device0_);
+ manager->AllowUsbDevice(extension_->id(), device1_);
- scoped_ptr<DevicePermissions> device_permissions =
+ DevicePermissions* device_permissions =
manager->GetForExtension(extension_->id());
scoped_refptr<DevicePermissionEntry> device0_entry =
- FindEntry(device_permissions.get(), device0_);
+ device_permissions->FindEntry(device0_);
ASSERT_TRUE(device0_entry.get());
scoped_refptr<DevicePermissionEntry> device1_entry =
- FindEntry(device_permissions.get(), device1_);
+ device_permissions->FindEntry(device1_);
ASSERT_TRUE(device1_entry.get());
manager->RemoveEntry(extension_->id(), device0_entry);
- device_permissions = manager->GetForExtension(extension_->id());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device0_).get());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device1_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device0_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device1_).get());
- AllowUsbDevice(manager, extension_, device0_);
- device_permissions = manager->GetForExtension(extension_->id());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device0_).get());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device1_).get());
+ manager->AllowUsbDevice(extension_->id(), device0_);
+ ASSERT_TRUE(device_permissions->FindEntry(device0_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device1_).get());
manager->RemoveEntry(extension_->id(), device1_entry);
- device_permissions = manager->GetForExtension(extension_->id());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device0_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device1_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device0_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device1_).get());
- AllowUsbDevice(manager, extension_, device1_);
- device_permissions = manager->GetForExtension(extension_->id());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device0_).get());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device1_).get());
+ manager->AllowUsbDevice(extension_->id(), device1_);
+ ASSERT_TRUE(device_permissions->FindEntry(device0_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device1_).get());
}
TEST_F(DevicePermissionsManagerTest, UpdateLastUsed) {
DevicePermissionsManager* manager =
- DevicePermissionsManager::Get(env_.profile());
- AllowUsbDevice(manager, extension_, device0_);
+ DevicePermissionsManager::Get(env_->profile());
+ manager->AllowUsbDevice(extension_->id(), device0_);
- scoped_ptr<DevicePermissions> device_permissions =
+ DevicePermissions* device_permissions =
manager->GetForExtension(extension_->id());
scoped_refptr<DevicePermissionEntry> device0_entry =
- FindEntry(device_permissions.get(), device0_);
+ device_permissions->FindEntry(device0_);
ASSERT_TRUE(device0_entry->last_used().is_null());
manager->UpdateLastUsed(extension_->id(), device0_entry);
- device_permissions = manager->GetForExtension(extension_->id());
- device0_entry = FindEntry(device_permissions.get(), device0_);
+ device0_entry = device_permissions->FindEntry(device0_);
ASSERT_FALSE(device0_entry->last_used().is_null());
}
@@ -315,17 +271,17 @@ TEST_F(DevicePermissionsManagerTest, LoadPrefs) {
" \"vendor_id\": 0"
" }"
"]");
- env_.GetExtensionPrefs()->UpdateExtensionPref(extension_->id(), "devices",
- prefs_value.release());
+ env_->GetExtensionPrefs()->UpdateExtensionPref(extension_->id(), "devices",
+ prefs_value.release());
DevicePermissionsManager* manager =
- DevicePermissionsManager::Get(env_.profile());
- scoped_ptr<DevicePermissions> device_permissions =
+ DevicePermissionsManager::Get(env_->profile());
+ DevicePermissions* device_permissions =
manager->GetForExtension(extension_->id());
- ASSERT_TRUE(FindEntry(device_permissions.get(), device0_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device1_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device2_).get());
- ASSERT_FALSE(FindEntry(device_permissions.get(), device3_).get());
+ ASSERT_TRUE(device_permissions->FindEntry(device0_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device1_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device2_).get());
+ ASSERT_FALSE(device_permissions->FindEntry(device3_).get());
}
} // namespace extensions
diff --git a/device/hid/hid_connection_unittest.cc b/device/hid/hid_connection_unittest.cc
index e474a62..b036198 100644
--- a/device/hid/hid_connection_unittest.cc
+++ b/device/hid/hid_connection_unittest.cc
@@ -10,10 +10,12 @@
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/scoped_observer.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/test/test_io_thread.h"
#include "device/hid/hid_connection.h"
#include "device/hid/hid_service.h"
#include "device/test/usb_test_gadget.h"
+#include "device/usb/usb_device.h"
#include "net/base/io_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,20 +25,6 @@ namespace {
using net::IOBufferWithSize;
-void ClaimTestDevice(scoped_ptr<UsbTestGadget>* gadget) {
- base::MessageLoop::ScopedNestableTaskAllower allow(
- base::MessageLoop::current());
- *gadget = UsbTestGadget::Claim();
- ASSERT_TRUE(*gadget);
- ASSERT_TRUE((*gadget)->SetType(UsbTestGadget::HID_ECHO));
-}
-
-void UnclaimTestDevice(scoped_ptr<UsbTestGadget> gadget) {
- base::MessageLoop::ScopedNestableTaskAllower allow(
- base::MessageLoop::current());
- ASSERT_TRUE(gadget->Unclaim());
-}
-
// Helper class that can be used to block until a HID device with a particular
// serial number is available. Example usage:
//
@@ -46,10 +34,8 @@ void UnclaimTestDevice(scoped_ptr<UsbTestGadget> gadget) {
//
class DeviceCatcher : HidService::Observer {
public:
- DeviceCatcher(const std::string& serial_number)
- : serial_number_(serial_number), observer_(this) {
- HidService* hid_service = HidService::GetInstance(
- base::MessageLoop::current()->message_loop_proxy());
+ DeviceCatcher(HidService* hid_service, const base::string16& serial_number)
+ : serial_number_(base::UTF16ToUTF8(serial_number)), observer_(this) {
observer_.Add(hid_service);
hid_service->GetDevices(base::Bind(&DeviceCatcher::OnEnumerationComplete,
base::Unretained(this)));
@@ -168,23 +154,16 @@ class HidConnectionTest : public testing::Test {
service_ = HidService::GetInstance(io_thread_->task_runner());
ASSERT_TRUE(service_);
- io_thread_->PostTaskAndWait(FROM_HERE,
- base::Bind(&ClaimTestDevice, &test_gadget_));
+ test_gadget_ = UsbTestGadget::Claim(io_thread_->task_runner());
ASSERT_TRUE(test_gadget_);
+ ASSERT_TRUE(test_gadget_->SetType(UsbTestGadget::HID_ECHO));
- DeviceCatcher device_catcher(test_gadget_->GetSerialNumber());
+ DeviceCatcher device_catcher(service_,
+ test_gadget_->GetDevice()->serial_number());
device_id_ = device_catcher.WaitForDevice();
ASSERT_NE(device_id_, kInvalidHidDeviceId);
}
- void TearDown() override {
- if (io_thread_) {
- io_thread_->PostTaskAndWait(
- FROM_HERE,
- base::Bind(&UnclaimTestDevice, base::Passed(&test_gadget_)));
- }
- }
-
scoped_ptr<base::MessageLoopForUI> message_loop_;
scoped_ptr<base::TestIOThread> io_thread_;
HidService* service_;
diff --git a/device/hid/hid_service.cc b/device/hid/hid_service.cc
index 4f20235..fc50a41 100644
--- a/device/hid/hid_service.cc
+++ b/device/hid/hid_service.cc
@@ -106,9 +106,11 @@ void HidService::AddDevice(scoped_refptr<HidDeviceInfo> device_info) {
HID_LOG(USER) << "HID device "
<< (enumeration_ready_ ? "added" : "detected")
- << ": vendorId = " << device_info->vendor_id()
- << ", productId = " << device_info->product_id()
- << ", deviceId = '" << device_info->device_id() << "'";
+ << ": vendorId=" << device_info->vendor_id()
+ << ", productId=" << device_info->product_id() << ", name='"
+ << device_info->product_name() << "', serial='"
+ << device_info->serial_number() << "', deviceId='"
+ << device_info->device_id() << "'";
if (enumeration_ready_) {
FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceAdded(device_info));
@@ -120,7 +122,7 @@ void HidService::RemoveDevice(const HidDeviceId& device_id) {
DCHECK(thread_checker_.CalledOnValidThread());
DeviceMap::iterator it = devices_.find(device_id);
if (it != devices_.end()) {
- HID_LOG(USER) << "HID device removed: deviceId = '" << device_id << "'";
+ HID_LOG(USER) << "HID device removed: deviceId='" << device_id << "'";
if (enumeration_ready_) {
FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceRemoved(it->second));
diff --git a/device/test/usb_test_gadget.h b/device/test/usb_test_gadget.h
index 99110a1..b1a8642 100644
--- a/device/test/usb_test_gadget.h
+++ b/device/test/usb_test_gadget.h
@@ -8,8 +8,13 @@
#include <string>
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+namespace base {
+class SingleThreadTaskRunner;
+}
+
namespace device {
class UsbDevice;
@@ -27,7 +32,8 @@ class UsbTestGadget {
virtual ~UsbTestGadget() {}
static bool IsTestEnabled();
- static scoped_ptr<UsbTestGadget> Claim();
+ static scoped_ptr<UsbTestGadget> Claim(
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
virtual bool Unclaim() = 0;
virtual bool Disconnect() = 0;
@@ -35,7 +41,6 @@ class UsbTestGadget {
virtual bool SetType(Type type) = 0;
virtual UsbDevice* GetDevice() const = 0;
- virtual const std::string& GetSerialNumber() const = 0;
protected:
UsbTestGadget() {}
diff --git a/device/test/usb_test_gadget_impl.cc b/device/test/usb_test_gadget_impl.cc
index d9371b4..2eea058 100644
--- a/device/test/usb_test_gadget_impl.cc
+++ b/device/test/usb_test_gadget_impl.cc
@@ -18,9 +18,10 @@
#include "base/path_service.h"
#include "base/process/process_handle.h"
#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
+#include "base/scoped_observer.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "device/usb/usb_device.h"
#include "device/usb/usb_device_handle.h"
@@ -33,28 +34,35 @@
#include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h"
-using ::base::PlatformThread;
-using ::base::TimeDelta;
-
namespace device {
+class UsbTestGadgetImpl : public UsbTestGadget {
+ public:
+ UsbTestGadgetImpl(
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ UsbService* usb_service,
+ scoped_refptr<UsbDevice> device);
+ ~UsbTestGadgetImpl() override;
+
+ bool Unclaim() override;
+ bool Disconnect() override;
+ bool Reconnect() override;
+ bool SetType(Type type) override;
+ UsbDevice* GetDevice() const override;
+
+ private:
+ std::string device_address_;
+ scoped_refptr<UsbDevice> device_;
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ UsbService* usb_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(UsbTestGadgetImpl);
+};
+
namespace {
static const char kCommandLineSwitch[] = "enable-gadget-tests";
-static const int kClaimRetries = 100; // 5 seconds
-static const int kDisconnectRetries = 100; // 5 seconds
-static const int kRetryPeriod = 50; // 0.05 seconds
-static const int kReconnectRetries = 100; // 5 seconds
-static const int kUpdateRetries = 100; // 5 seconds
-
-// Wait for the given time delta while still running the main loop. This is
-// necessary so that device add/remove events are processed by the UsbService.
-void SleepWithRunLoop(base::TimeDelta delta) {
- base::RunLoop run_loop;
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- run_loop.QuitClosure(), delta);
- run_loop.Run();
-}
+static const int kReenumeratePeriod = 100; // 0.1 seconds
struct UsbTestGadgetConfiguration {
UsbTestGadget::Type type;
@@ -70,131 +78,107 @@ static const struct UsbTestGadgetConfiguration kConfigurations[] = {
{UsbTestGadget::ECHO, "/echo/configure", 0x58F4},
};
-class UsbTestGadgetImpl : public UsbTestGadget {
- public:
- ~UsbTestGadgetImpl() override;
-
- bool Unclaim() override;
- bool Disconnect() override;
- bool Reconnect() override;
- bool SetType(Type type) override;
- UsbDevice* GetDevice() const override;
- const std::string& GetSerialNumber() const override;
-
- protected:
- UsbTestGadgetImpl();
-
- private:
- scoped_ptr<net::URLFetcher> CreateURLFetcher(
- const GURL& url,
- net::URLFetcher::RequestType request_type,
- net::URLFetcherDelegate* delegate);
- int SimplePOSTRequest(const GURL& url, const std::string& form_data);
- bool FindUnclaimed();
- bool GetVersion(std::string* version);
- bool Update();
- bool FindClaimed();
- bool ReadLocalVersion(std::string* version);
- bool ReadLocalPackage(std::string* package);
- bool ReadFile(const base::FilePath& file_path, std::string* content);
-
- class Delegate : public net::URLFetcherDelegate {
- public:
- Delegate() {}
- ~Delegate() override {}
-
- void WaitForCompletion() {
- run_loop_.Run();
- }
+bool ReadFile(const base::FilePath& file_path, std::string* content) {
+ base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+ if (!file.IsValid()) {
+ LOG(ERROR) << "Cannot open " << file_path.MaybeAsASCII() << ": "
+ << base::File::ErrorToString(file.error_details());
+ return false;
+ }
- void OnURLFetchComplete(const net::URLFetcher* source) override {
- run_loop_.Quit();
+ STLClearObject(content);
+ int rv;
+ do {
+ char buf[4096];
+ rv = file.ReadAtCurrentPos(buf, sizeof buf);
+ if (rv == -1) {
+ LOG(ERROR) << "Cannot read " << file_path.MaybeAsASCII() << ": "
+ << base::File::ErrorToString(file.error_details());
+ return false;
}
+ content->append(buf, rv);
+ } while (rv > 0);
- private:
- base::RunLoop run_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(Delegate);
- };
-
- scoped_refptr<UsbDevice> device_;
- std::string device_address_;
- scoped_ptr<net::URLRequestContext> request_context_;
- std::string session_id_;
- UsbService* usb_service_;
+ return true;
+}
- friend class UsbTestGadget;
+bool ReadLocalVersion(std::string* version) {
+ base::FilePath file_path;
+ CHECK(PathService::Get(base::DIR_EXE, &file_path));
+ file_path = file_path.AppendASCII("usb_gadget.zip.md5");
- DISALLOW_COPY_AND_ASSIGN(UsbTestGadgetImpl);
-};
+ return ReadFile(file_path, version);
+}
-} // namespace
+bool ReadLocalPackage(std::string* package) {
+ base::FilePath file_path;
+ CHECK(PathService::Get(base::DIR_EXE, &file_path));
+ file_path = file_path.AppendASCII("usb_gadget.zip");
-bool UsbTestGadget::IsTestEnabled() {
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- return command_line->HasSwitch(kCommandLineSwitch);
+ return ReadFile(file_path, package);
}
-scoped_ptr<UsbTestGadget> UsbTestGadget::Claim() {
- scoped_ptr<UsbTestGadgetImpl> gadget(new UsbTestGadgetImpl);
+scoped_ptr<net::URLFetcher> CreateURLFetcher(
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ const GURL& url,
+ net::URLFetcher::RequestType request_type,
+ net::URLFetcherDelegate* delegate) {
+ scoped_ptr<net::URLFetcher> url_fetcher(
+ net::URLFetcher::Create(url, request_type, delegate));
- int retries = kClaimRetries;
- while (!gadget->FindUnclaimed()) {
- if (--retries == 0) {
- LOG(ERROR) << "Failed to find an unclaimed device.";
- return scoped_ptr<UsbTestGadget>();
- }
- SleepWithRunLoop(TimeDelta::FromMilliseconds(kRetryPeriod));
- }
- VLOG(1) << "It took " << (kClaimRetries - retries)
- << " retries to find an unclaimed device.";
+ url_fetcher->SetRequestContext(request_context_getter.get());
- return gadget.Pass();
+ return url_fetcher;
}
-UsbTestGadgetImpl::UsbTestGadgetImpl() {
- net::URLRequestContextBuilder context_builder;
- context_builder.set_proxy_service(net::ProxyService::CreateDirect());
- request_context_.reset(context_builder.Build());
+class URLRequestContextGetter : public net::URLRequestContextGetter {
+ public:
+ URLRequestContextGetter(
+ scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)
+ : network_task_runner_(network_task_runner) {}
- base::ProcessId process_id = base::GetCurrentProcId();
- session_id_ = base::StringPrintf(
- "%s:%p", base::HexEncode(&process_id, sizeof(process_id)).c_str(), this);
+ private:
+ ~URLRequestContextGetter() override {}
- usb_service_ = UsbService::GetInstance(NULL);
-}
+ // net::URLRequestContextGetter implementation
+ net::URLRequestContext* GetURLRequestContext() override {
+ context_builder_.set_proxy_service(net::ProxyService::CreateDirect());
+ return context_builder_.Build();
+ }
-UsbTestGadgetImpl::~UsbTestGadgetImpl() {
- if (!device_address_.empty()) {
- Unclaim();
+ scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
+ const override {
+ return network_task_runner_;
}
-}
-UsbDevice* UsbTestGadgetImpl::GetDevice() const {
- return device_.get();
-}
+ net::URLRequestContextBuilder context_builder_;
+ scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
+};
-const std::string& UsbTestGadgetImpl::GetSerialNumber() const {
- return device_address_;
-}
+class URLFetcherDelegate : public net::URLFetcherDelegate {
+ public:
+ URLFetcherDelegate() {}
+ ~URLFetcherDelegate() override {}
-scoped_ptr<net::URLFetcher> UsbTestGadgetImpl::CreateURLFetcher(
- const GURL& url, net::URLFetcher::RequestType request_type,
- net::URLFetcherDelegate* delegate) {
- scoped_ptr<net::URLFetcher> url_fetcher(
- net::URLFetcher::Create(url, request_type, delegate));
+ void WaitForCompletion() { run_loop_.Run(); }
- url_fetcher->SetRequestContext(new net::TrivialURLRequestContextGetter(
- request_context_.get(), base::MessageLoop::current()->task_runner()));
+ void OnURLFetchComplete(const net::URLFetcher* source) override {
+ run_loop_.Quit();
+ }
- return url_fetcher;
-}
+ private:
+ base::RunLoop run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(URLFetcherDelegate);
+};
-int UsbTestGadgetImpl::SimplePOSTRequest(const GURL& url,
- const std::string& form_data) {
- Delegate delegate;
- scoped_ptr<net::URLFetcher> url_fetcher =
- CreateURLFetcher(url, net::URLFetcher::POST, &delegate);
+int SimplePOSTRequest(
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ const GURL& url,
+ const std::string& form_data) {
+ URLFetcherDelegate delegate;
+ scoped_ptr<net::URLFetcher> url_fetcher = CreateURLFetcher(
+ request_context_getter, url, net::URLFetcher::POST, &delegate);
url_fetcher->SetUploadData("application/x-www-form-urlencoded", form_data);
url_fetcher->Start();
@@ -203,230 +187,360 @@ int UsbTestGadgetImpl::SimplePOSTRequest(const GURL& url,
return url_fetcher->GetResponseCode();
}
-bool UsbTestGadgetImpl::FindUnclaimed() {
- std::vector<scoped_refptr<UsbDevice> > devices;
- usb_service_->GetDevices(&devices);
-
- for (std::vector<scoped_refptr<UsbDevice> >::const_iterator iter =
- devices.begin(); iter != devices.end(); ++iter) {
- const scoped_refptr<UsbDevice> &device = *iter;
- if (device->vendor_id() == 0x18D1 && device->product_id() == 0x58F0) {
- base::string16 serial_utf16;
- if (!device->GetSerialNumber(&serial_utf16)) {
- continue;
- }
+class UsbGadgetFactory : public UsbService::Observer,
+ public net::URLFetcherDelegate {
+ public:
+ UsbGadgetFactory(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
+ : observer_(this), weak_factory_(this) {
+ usb_service_ = UsbService::GetInstance(io_task_runner);
+ request_context_getter_ = new URLRequestContextGetter(io_task_runner);
- const std::string serial = base::UTF16ToUTF8(serial_utf16);
- const GURL url("http://" + serial + "/claim");
- const std::string form_data = base::StringPrintf(
- "session_id=%s",
- net::EscapeUrlEncodedData(session_id_, true).c_str());
- const int response_code = SimplePOSTRequest(url, form_data);
+ static uint32 next_session_id;
+ base::ProcessId process_id = base::GetCurrentProcId();
+ session_id_ = base::StringPrintf("%d-%d", process_id, next_session_id++);
- if (response_code == 200) {
- device_address_ = serial;
- device_ = device;
- break;
- }
+ observer_.Add(usb_service_);
+ }
- // The device is probably claimed by another process.
- if (response_code != 403) {
- LOG(WARNING) << "Unexpected HTTP " << response_code << " from /claim.";
- }
- }
+ ~UsbGadgetFactory() override {}
+
+ scoped_ptr<UsbTestGadget> WaitForDevice() {
+ EnumerateDevices();
+ run_loop_.Run();
+ return make_scoped_ptr(
+ new UsbTestGadgetImpl(request_context_getter_, usb_service_, device_));
}
- std::string local_version;
- std::string version;
- if (!ReadLocalVersion(&local_version) ||
- !GetVersion(&version)) {
- return false;
+ private:
+ void EnumerateDevices() {
+ if (!device_) {
+ usb_service_->GetDevices(base::Bind(
+ &UsbGadgetFactory::OnDevicesEnumerated, weak_factory_.GetWeakPtr()));
+ }
}
- if (version == local_version) {
- return true;
+ void OnDevicesEnumerated(
+ const std::vector<scoped_refptr<UsbDevice>>& devices) {
+ for (const scoped_refptr<UsbDevice>& device : devices) {
+ OnDeviceAdded(device);
+ }
+
+ if (!device_) {
+ // TODO(reillyg): This timer could be replaced by a way to use long-
+ // polling to wait for claimed devices to become unclaimed.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, base::Bind(&UsbGadgetFactory::EnumerateDevices,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kReenumeratePeriod));
+ }
}
- return Update();
-}
+ void OnDeviceAdded(scoped_refptr<UsbDevice> device) override {
+ if (device_.get()) {
+ // Already trying to claim a device.
+ return;
+ }
-bool UsbTestGadgetImpl::GetVersion(std::string* version) {
- Delegate delegate;
- const GURL url("http://" + device_address_ + "/version");
- scoped_ptr<net::URLFetcher> url_fetcher =
- CreateURLFetcher(url, net::URLFetcher::GET, &delegate);
+ if (device->vendor_id() != 0x18D1 || device->product_id() != 0x58F0 ||
+ device->serial_number().empty()) {
+ return;
+ }
- url_fetcher->Start();
- delegate.WaitForCompletion();
+ std::string serial_number = base::UTF16ToUTF8(device->serial_number());
+ if (serial_number == serial_number_) {
+ // We were waiting for the device to reappear after upgrade.
+ device_ = device;
+ run_loop_.Quit();
+ return;
+ }
- const int response_code = url_fetcher->GetResponseCode();
- if (response_code != 200) {
- VLOG(2) << "Unexpected HTTP " << response_code << " from /version.";
- return false;
+ device_ = device;
+ serial_number_ = serial_number;
+ Claim();
}
- STLClearObject(version);
- if (!url_fetcher->GetResponseAsString(version)) {
- VLOG(2) << "Failed to read body from /version.";
- return false;
- }
- return true;
-}
+ void Claim() {
+ VLOG(1) << "Trying to claim " << serial_number_ << ".";
-bool UsbTestGadgetImpl::Update() {
- std::string version;
- if (!ReadLocalVersion(&version)) {
- return false;
- }
- LOG(INFO) << "Updating " << device_address_ << " to " << version << "...";
-
- Delegate delegate;
- const GURL url("http://" + device_address_ + "/update");
- scoped_ptr<net::URLFetcher> url_fetcher =
- CreateURLFetcher(url, net::URLFetcher::POST, &delegate);
-
- const std::string mime_header =
- base::StringPrintf(
- "--foo\r\n"
- "Content-Disposition: form-data; name=\"file\"; "
- "filename=\"usb_gadget-%s.zip\"\r\n"
- "Content-Type: application/octet-stream\r\n"
- "\r\n", version.c_str());
- const std::string mime_footer("\r\n--foo--\r\n");
-
- std::string package;
- if (!ReadLocalPackage(&package)) {
- return false;
+ GURL url("http://" + serial_number_ + "/claim");
+ std::string form_data = base::StringPrintf(
+ "session_id=%s", net::EscapeUrlEncodedData(session_id_, true).c_str());
+ url_fetcher_ = CreateURLFetcher(request_context_getter_, url,
+ net::URLFetcher::POST, this);
+ url_fetcher_->SetUploadData("application/x-www-form-urlencoded", form_data);
+ url_fetcher_->Start();
}
- url_fetcher->SetUploadData("multipart/form-data; boundary=foo",
- mime_header + package + mime_footer);
- url_fetcher->Start();
- delegate.WaitForCompletion();
-
- const int response_code = url_fetcher->GetResponseCode();
- if (response_code != 200) {
- LOG(ERROR) << "Unexpected HTTP " << response_code << " from /update.";
- return false;
+ void GetVersion() {
+ GURL url("http://" + serial_number_ + "/version");
+ url_fetcher_ = CreateURLFetcher(request_context_getter_, url,
+ net::URLFetcher::GET, this);
+ url_fetcher_->Start();
}
- int retries = kUpdateRetries;
- std::string new_version;
- while (!GetVersion(&new_version) || new_version != version) {
- if (--retries == 0) {
- LOG(ERROR) << "Device not responding with new version.";
+ bool Update(const std::string& version) {
+ LOG(INFO) << "Updating " << serial_number_ << " to " << version << "...";
+
+ GURL url("http://" + serial_number_ + "/update");
+ url_fetcher_ = CreateURLFetcher(request_context_getter_, url,
+ net::URLFetcher::POST, this);
+ std::string mime_header = base::StringPrintf(
+ "--foo\r\n"
+ "Content-Disposition: form-data; name=\"file\"; "
+ "filename=\"usb_gadget-%s.zip\"\r\n"
+ "Content-Type: application/octet-stream\r\n"
+ "\r\n",
+ version.c_str());
+ std::string mime_footer("\r\n--foo--\r\n");
+
+ std::string package;
+ if (!ReadLocalPackage(&package)) {
return false;
}
- SleepWithRunLoop(TimeDelta::FromMilliseconds(kRetryPeriod));
+
+ url_fetcher_->SetUploadData("multipart/form-data; boundary=foo",
+ mime_header + package + mime_footer);
+ url_fetcher_->Start();
+ device_ = nullptr;
+ return true;
}
- VLOG(1) << "It took " << (kUpdateRetries - retries)
- << " retries to see the new version.";
- // Release the old reference to the device and try to open a new one.
- device_ = NULL;
- retries = kReconnectRetries;
- while (!FindClaimed()) {
- if (--retries == 0) {
- LOG(ERROR) << "Failed to find updated device.";
- return false;
+ void OnURLFetchComplete(const net::URLFetcher* source) override {
+ DCHECK(!serial_number_.empty());
+
+ int response_code = source->GetResponseCode();
+ if (!claimed_) {
+ // Just completed a /claim request.
+ if (response_code == 200) {
+ claimed_ = true;
+ GetVersion();
+ } else {
+ if (response_code != 403) {
+ LOG(WARNING) << "Unexpected HTTP " << response_code
+ << " from /claim.";
+ }
+ Reset();
+ }
+ } else if (version_.empty()) {
+ // Just completed a /version request.
+ if (response_code != 200) {
+ LOG(WARNING) << "Unexpected HTTP " << response_code
+ << " from /version.";
+ Reset();
+ return;
+ }
+
+ if (!source->GetResponseAsString(&version_)) {
+ LOG(WARNING) << "Failed to read body from /version.";
+ Reset();
+ return;
+ }
+
+ std::string local_version;
+ if (!ReadLocalVersion(&local_version)) {
+ Reset();
+ return;
+ }
+
+ if (version_ == local_version) {
+ run_loop_.Quit();
+ } else {
+ if (!Update(local_version)) {
+ Reset();
+ }
+ }
+ } else {
+ // Just completed an /update request.
+ if (response_code != 200) {
+ LOG(WARNING) << "Unexpected HTTP " << response_code << " from /update.";
+ Reset();
+ return;
+ }
+
+ // Must wait for the device to reconnect.
}
- SleepWithRunLoop(TimeDelta::FromMilliseconds(kRetryPeriod));
}
- VLOG(1) << "It took " << (kReconnectRetries - retries)
- << " retries to find the updated device.";
- return true;
-}
+ void Reset() {
+ device_ = nullptr;
+ serial_number_.clear();
+ claimed_ = false;
+ version_.clear();
+
+ // Wait a bit and then try again to find an available device.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, base::Bind(&UsbGadgetFactory::EnumerateDevices,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kReenumeratePeriod));
+ }
-bool UsbTestGadgetImpl::FindClaimed() {
- CHECK(!device_.get());
+ UsbService* usb_service_ = nullptr;
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ std::string session_id_;
+ scoped_ptr<net::URLFetcher> url_fetcher_;
+ scoped_refptr<UsbDevice> device_;
+ std::string serial_number_;
+ bool claimed_ = false;
+ std::string version_;
+ base::RunLoop run_loop_;
+ ScopedObserver<UsbService, UsbService::Observer> observer_;
+ base::WeakPtrFactory<UsbGadgetFactory> weak_factory_;
+};
- std::string expected_serial = GetSerialNumber();
+class DeviceAddListener : public UsbService::Observer {
+ public:
+ DeviceAddListener(UsbService* usb_service,
+ const std::string& serial_number,
+ int product_id)
+ : usb_service_(usb_service),
+ serial_number_(serial_number),
+ product_id_(product_id),
+ observer_(this),
+ weak_factory_(this) {
+ observer_.Add(usb_service_);
+ }
+ virtual ~DeviceAddListener() {}
- std::vector<scoped_refptr<UsbDevice> > devices;
- usb_service_->GetDevices(&devices);
+ scoped_refptr<UsbDevice> WaitForAdd() {
+ usb_service_->GetDevices(base::Bind(&DeviceAddListener::OnDevicesEnumerated,
+ weak_factory_.GetWeakPtr()));
+ run_loop_.Run();
+ return device_;
+ }
- for (std::vector<scoped_refptr<UsbDevice> >::iterator iter =
- devices.begin(); iter != devices.end(); ++iter) {
- scoped_refptr<UsbDevice> &device = *iter;
+ private:
+ void OnDevicesEnumerated(
+ const std::vector<scoped_refptr<UsbDevice>>& devices) {
+ for (const scoped_refptr<UsbDevice>& device : devices) {
+ OnDeviceAdded(device);
+ }
+ }
- if (device->vendor_id() == 0x18D1) {
+ void OnDeviceAdded(scoped_refptr<UsbDevice> device) override {
+ if (device->vendor_id() == 0x18D1 && !device->serial_number().empty()) {
const uint16 product_id = device->product_id();
- bool found = false;
- for (size_t i = 0; i < arraysize(kConfigurations); ++i) {
- if (product_id == kConfigurations[i].product_id) {
- found = true;
- break;
+ if (product_id_ == -1) {
+ bool found = false;
+ for (size_t i = 0; i < arraysize(kConfigurations); ++i) {
+ if (product_id == kConfigurations[i].product_id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return;
+ }
+ } else {
+ if (product_id_ != product_id) {
+ return;
}
- }
- if (!found) {
- continue;
}
- base::string16 serial_utf16;
- if (!device->GetSerialNumber(&serial_utf16)) {
- continue;
+ if (serial_number_ != base::UTF16ToUTF8(device->serial_number())) {
+ return;
}
- std::string serial = base::UTF16ToUTF8(serial_utf16);
- if (serial != expected_serial) {
- continue;
+ device_ = device;
+ run_loop_.Quit();
+ }
+ }
+
+ UsbService* usb_service_;
+ const std::string serial_number_;
+ const int product_id_;
+ base::RunLoop run_loop_;
+ scoped_refptr<UsbDevice> device_;
+ ScopedObserver<UsbService, UsbService::Observer> observer_;
+ base::WeakPtrFactory<DeviceAddListener> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceAddListener);
+};
+
+class DeviceRemoveListener : public UsbService::Observer {
+ public:
+ DeviceRemoveListener(UsbService* usb_service, scoped_refptr<UsbDevice> device)
+ : usb_service_(usb_service),
+ device_(device),
+ observer_(this),
+ weak_factory_(this) {
+ observer_.Add(usb_service_);
+ }
+ virtual ~DeviceRemoveListener() {}
+
+ void WaitForRemove() {
+ usb_service_->GetDevices(
+ base::Bind(&DeviceRemoveListener::OnDevicesEnumerated,
+ weak_factory_.GetWeakPtr()));
+ run_loop_.Run();
+ }
+
+ private:
+ void OnDevicesEnumerated(
+ const std::vector<scoped_refptr<UsbDevice>>& devices) {
+ bool found = false;
+ for (const scoped_refptr<UsbDevice>& device : devices) {
+ if (device_ == device) {
+ found = true;
}
+ }
+ if (!found) {
+ run_loop_.Quit();
+ }
+ }
- device_ = device;
- return true;
+ void OnDeviceRemoved(scoped_refptr<UsbDevice> device) override {
+ if (device_ == device) {
+ run_loop_.Quit();
}
}
- return false;
-}
+ UsbService* usb_service_;
+ base::RunLoop run_loop_;
+ scoped_refptr<UsbDevice> device_;
+ ScopedObserver<UsbService, UsbService::Observer> observer_;
+ base::WeakPtrFactory<DeviceRemoveListener> weak_factory_;
-bool UsbTestGadgetImpl::ReadLocalVersion(std::string* version) {
- base::FilePath file_path;
- CHECK(PathService::Get(base::DIR_EXE, &file_path));
- file_path = file_path.AppendASCII("usb_gadget.zip.md5");
+ DISALLOW_COPY_AND_ASSIGN(DeviceRemoveListener);
+};
- return ReadFile(file_path, version);
+} // namespace
+
+bool UsbTestGadget::IsTestEnabled() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ return command_line->HasSwitch(kCommandLineSwitch);
}
-bool UsbTestGadgetImpl::ReadLocalPackage(std::string* package) {
- base::FilePath file_path;
- CHECK(PathService::Get(base::DIR_EXE, &file_path));
- file_path = file_path.AppendASCII("usb_gadget.zip");
+scoped_ptr<UsbTestGadget> UsbTestGadget::Claim(
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
+ UsbGadgetFactory gadget_factory(io_task_runner);
+ return gadget_factory.WaitForDevice().Pass();
+}
- return ReadFile(file_path, package);
+UsbTestGadgetImpl::UsbTestGadgetImpl(
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_,
+ UsbService* usb_service,
+ scoped_refptr<UsbDevice> device)
+ : device_address_(base::UTF16ToUTF8(device->serial_number())),
+ device_(device),
+ request_context_getter_(request_context_getter_),
+ usb_service_(usb_service) {
}
-bool UsbTestGadgetImpl::ReadFile(const base::FilePath& file_path,
- std::string* content) {
- base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
- if (!file.IsValid()) {
- LOG(ERROR) << "Cannot open " << file_path.MaybeAsASCII() << ": "
- << base::File::ErrorToString(file.error_details());
- return false;
+UsbTestGadgetImpl::~UsbTestGadgetImpl() {
+ if (!device_address_.empty()) {
+ Unclaim();
}
+}
- STLClearObject(content);
- int rv;
- do {
- char buf[4096];
- rv = file.ReadAtCurrentPos(buf, sizeof buf);
- if (rv == -1) {
- LOG(ERROR) << "Cannot read " << file_path.MaybeAsASCII() << ": "
- << base::File::ErrorToString(file.error_details());
- return false;
- }
- content->append(buf, rv);
- } while (rv > 0);
-
- return true;
+UsbDevice* UsbTestGadgetImpl::GetDevice() const {
+ return device_.get();
}
bool UsbTestGadgetImpl::Unclaim() {
VLOG(1) << "Releasing the device at " << device_address_ << ".";
- const GURL url("http://" + device_address_ + "/unclaim");
- const int response_code = SimplePOSTRequest(url, "");
+ GURL url("http://" + device_address_ + "/unclaim");
+ int response_code = SimplePOSTRequest(request_context_getter_, url, "");
if (response_code != 200) {
LOG(ERROR) << "Unexpected HTTP " << response_code << " from /unclaim.";
@@ -446,8 +560,8 @@ bool UsbTestGadgetImpl::SetType(Type type) {
}
CHECK(config);
- const GURL url("http://" + device_address_ + config->http_resource);
- const int response_code = SimplePOSTRequest(url, "");
+ GURL url("http://" + device_address_ + config->http_resource);
+ int response_code = SimplePOSTRequest(request_context_getter_, url, "");
if (response_code != 200) {
LOG(ERROR) << "Unexpected HTTP " << response_code
@@ -456,75 +570,41 @@ bool UsbTestGadgetImpl::SetType(Type type) {
}
// Release the old reference to the device and try to open a new one.
- int retries = kReconnectRetries;
- while (true) {
- device_ = NULL;
- if (FindClaimed() && device_->product_id() == config->product_id) {
- break;
- }
- if (--retries == 0) {
- LOG(ERROR) << "Failed to find updated device.";
- return false;
- }
- SleepWithRunLoop(TimeDelta::FromMilliseconds(kRetryPeriod));
- }
- VLOG(1) << "It took " << (kReconnectRetries - retries)
- << " retries to find the updated device.";
-
+ DeviceAddListener add_listener(usb_service_, device_address_,
+ config->product_id);
+ device_ = add_listener.WaitForAdd();
+ DCHECK(device_.get());
return true;
}
bool UsbTestGadgetImpl::Disconnect() {
- const GURL url("http://" + device_address_ + "/disconnect");
- const int response_code = SimplePOSTRequest(url, "");
+ GURL url("http://" + device_address_ + "/disconnect");
+ int response_code = SimplePOSTRequest(request_context_getter_, url, "");
if (response_code != 200) {
- LOG(ERROR) << "Unexpected HTTP " << response_code << " from /disconnect.";
+ LOG(ERROR) << "Unexpected HTTP " << response_code << " from " << url << ".";
return false;
}
// Release the old reference to the device and wait until it can't be found.
- int retries = kDisconnectRetries;
- while (true) {
- device_ = NULL;
- if (!FindClaimed()) {
- break;
- }
- if (--retries == 0) {
- LOG(ERROR) << "Device did not disconnect.";
- return false;
- }
- SleepWithRunLoop(TimeDelta::FromMilliseconds(kRetryPeriod));
- }
- VLOG(1) << "It took " << (kDisconnectRetries - retries)
- << " retries for the device to disconnect.";
-
+ DeviceRemoveListener remove_listener(usb_service_, device_);
+ remove_listener.WaitForRemove();
+ device_ = nullptr;
return true;
}
bool UsbTestGadgetImpl::Reconnect() {
- const GURL url("http://" + device_address_ + "/reconnect");
- const int response_code = SimplePOSTRequest(url, "");
+ GURL url("http://" + device_address_ + "/reconnect");
+ int response_code = SimplePOSTRequest(request_context_getter_, url, "");
if (response_code != 200) {
- LOG(ERROR) << "Unexpected HTTP " << response_code << " from /reconnect.";
+ LOG(ERROR) << "Unexpected HTTP " << response_code << " from " << url << ".";
return false;
}
- int retries = kDisconnectRetries;
- while (true) {
- if (FindClaimed()) {
- break;
- }
- if (--retries == 0) {
- LOG(ERROR) << "Device did not reconnect.";
- return false;
- }
- SleepWithRunLoop(TimeDelta::FromMilliseconds(kRetryPeriod));
- }
- VLOG(1) << "It took " << (kDisconnectRetries - retries)
- << " retries for the device to reconnect.";
-
+ DeviceAddListener add_listener(usb_service_, device_address_, -1);
+ device_ = add_listener.WaitForAdd();
+ DCHECK(device_.get());
return true;
}
diff --git a/device/usb/usb_context.cc b/device/usb/usb_context.cc
index cb8214f..7661469 100644
--- a/device/usb/usb_context.cc
+++ b/device/usb/usb_context.cc
@@ -6,7 +6,6 @@
#include "base/atomicops.h"
#include "base/logging.h"
-#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
#include "device/usb/usb_error.h"
#include "third_party/libusb/src/libusb/interrupt.h"
@@ -25,35 +24,30 @@ class UsbContext::UsbEventHandler : public base::PlatformThread::Delegate {
// base::PlatformThread::Delegate
void ThreadMain() override;
+ void Stop();
+
private:
base::subtle::Atomic32 running_;
libusb_context* context_;
base::PlatformThreadHandle thread_handle_;
- base::WaitableEvent start_polling_;
DISALLOW_COPY_AND_ASSIGN(UsbEventHandler);
};
UsbContext::UsbEventHandler::UsbEventHandler(libusb_context* context)
- : context_(context), thread_handle_(0), start_polling_(false, false) {
+ : context_(context), thread_handle_(0) {
base::subtle::Release_Store(&running_, 1);
bool success = base::PlatformThread::Create(0, this, &thread_handle_);
DCHECK(success) << "Failed to create USB IO handling thread.";
- start_polling_.Wait();
}
UsbContext::UsbEventHandler::~UsbEventHandler() {
- base::subtle::Release_Store(&running_, 0);
- libusb_interrupt_handle_event(context_);
- base::PlatformThread::Join(thread_handle_);
+ libusb_exit(context_);
}
void UsbContext::UsbEventHandler::ThreadMain() {
base::PlatformThread::SetName("UsbEventHandler");
VLOG(1) << "UsbEventHandler started.";
- if (base::subtle::Acquire_Load(&running_)) {
- start_polling_.Signal();
- }
while (base::subtle::Acquire_Load(&running_)) {
const int rv = libusb_handle_events(context_);
if (rv != LIBUSB_SUCCESS) {
@@ -61,20 +55,24 @@ void UsbContext::UsbEventHandler::ThreadMain() {
<< ConvertPlatformUsbErrorToString(rv);
}
}
+
VLOG(1) << "UsbEventHandler shutting down.";
+ delete this;
+}
+
+void UsbContext::UsbEventHandler::Stop() {
+ base::subtle::Release_Store(&running_, 0);
+ libusb_interrupt_handle_event(context_);
}
UsbContext::UsbContext(PlatformUsbContext context) : context_(context) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ // Ownership of the PlatformUsbContext is passed to the event handler thread.
event_handler_ = new UsbEventHandler(context_);
}
UsbContext::~UsbContext() {
- // destruction of UsbEventHandler is a blocking operation.
DCHECK(thread_checker_.CalledOnValidThread());
- delete event_handler_;
- event_handler_ = NULL;
- libusb_exit(context_);
+ event_handler_->Stop();
}
} // namespace device
diff --git a/device/usb/usb_device.cc b/device/usb/usb_device.cc
index 4b9ed1e..da926bd 100644
--- a/device/usb/usb_device.cc
+++ b/device/usb/usb_device.cc
@@ -6,8 +6,18 @@
namespace device {
-UsbDevice::UsbDevice(uint16 vendor_id, uint16 product_id, uint32 unique_id)
- : vendor_id_(vendor_id), product_id_(product_id), unique_id_(unique_id) {
+UsbDevice::UsbDevice(uint16 vendor_id,
+ uint16 product_id,
+ uint32 unique_id,
+ const base::string16& manufacturer_string,
+ const base::string16& product_string,
+ const base::string16& serial_number)
+ : vendor_id_(vendor_id),
+ product_id_(product_id),
+ unique_id_(unique_id),
+ manufacturer_string_(manufacturer_string),
+ product_string_(product_string),
+ serial_number_(serial_number) {
}
UsbDevice::~UsbDevice() {
diff --git a/device/usb/usb_device.h b/device/usb/usb_device.h
index e824078..2286467 100644
--- a/device/usb/usb_device.h
+++ b/device/usb/usb_device.h
@@ -16,16 +16,24 @@ class UsbDeviceHandle;
struct UsbConfigDescriptor;
// A UsbDevice object represents a detected USB device, providing basic
-// information about it. For further manipulation of the device, a
-// UsbDeviceHandle must be created from Open() method.
+// information about it. Methods other than simple property accessors must be
+// called from the thread on which this object was created. For further
+// manipulation of the device, a UsbDeviceHandle must be created from Open()
+// method.
class UsbDevice : public base::RefCountedThreadSafe<UsbDevice> {
public:
- typedef base::Callback<void(bool success)> ResultCallback;
+ using OpenCallback = base::Callback<void(scoped_refptr<UsbDeviceHandle>)>;
+ using ResultCallback = base::Callback<void(bool success)>;
// Accessors to basic information.
uint16 vendor_id() const { return vendor_id_; }
uint16 product_id() const { return product_id_; }
uint32 unique_id() const { return unique_id_; }
+ const base::string16& manufacturer_string() const {
+ return manufacturer_string_;
+ }
+ const base::string16& product_string() const { return product_string_; }
+ const base::string16& serial_number() const { return serial_number_; }
// 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
@@ -37,37 +45,23 @@ class UsbDevice : public base::RefCountedThreadSafe<UsbDevice> {
const ResultCallback& callback);
// Creates a UsbDeviceHandle for further manipulation.
- // Blocking method. Must be called on FILE thread.
- virtual scoped_refptr<UsbDeviceHandle> Open() = 0;
+ virtual void Open(const OpenCallback& callback) = 0;
// Explicitly closes a device handle. This method will be automatically called
// by the destructor of a UsbDeviceHandle as well.
- // Closing a closed handle is a safe
- // Blocking method. Must be called on FILE thread.
virtual bool Close(scoped_refptr<UsbDeviceHandle> handle) = 0;
// Gets the UsbConfigDescriptor for the active device configuration or nullptr
// if the device is unconfigured.
- // Blocking method. Must be called on FILE thread.
virtual const UsbConfigDescriptor* GetConfiguration() = 0;
- // Gets the manufacturer string of the device, or false and an empty
- // string. This is a blocking method and must be called on FILE thread.
- // TODO(reillyg): Make this available from the UI thread. crbug.com/427985
- virtual bool GetManufacturer(base::string16* manufacturer) = 0;
-
- // Gets the product string of the device, or returns false and an empty
- // string. This is a blocking method and must be called on FILE thread.
- // TODO(reillyg): Make this available from the UI thread. crbug.com/427985
- virtual bool GetProduct(base::string16* product) = 0;
-
- // Gets the serial number string of the device, or returns false and an empty
- // string. This is a blocking method and must be called on FILE thread.
- // TODO(reillyg): Make this available from the UI thread. crbug.com/427985
- virtual bool GetSerialNumber(base::string16* serial) = 0;
-
protected:
- UsbDevice(uint16 vendor_id, uint16 product_id, uint32 unique_id);
+ UsbDevice(uint16 vendor_id,
+ uint16 product_id,
+ uint32 unique_id,
+ const base::string16& manufacturer_string,
+ const base::string16& product_string,
+ const base::string16& serial_number);
virtual ~UsbDevice();
private:
@@ -76,6 +70,9 @@ class UsbDevice : public base::RefCountedThreadSafe<UsbDevice> {
const uint16 vendor_id_;
const uint16 product_id_;
const uint32 unique_id_;
+ const base::string16 manufacturer_string_;
+ const base::string16 product_string_;
+ const base::string16 serial_number_;
DISALLOW_COPY_AND_ASSIGN(UsbDevice);
};
diff --git a/device/usb/usb_device_filter_unittest.cc b/device/usb/usb_device_filter_unittest.cc
index d66a462..beb12df 100644
--- a/device/usb/usb_device_filter_unittest.cc
+++ b/device/usb/usb_device_filter_unittest.cc
@@ -21,14 +21,16 @@ using testing::Return;
class MockUsbDevice : public UsbDevice {
public:
MockUsbDevice(uint16 vendor_id, uint16 product_id, uint32 unique_id)
- : UsbDevice(vendor_id, product_id, unique_id) {}
-
- MOCK_METHOD0(Open, scoped_refptr<UsbDeviceHandle>());
+ : UsbDevice(vendor_id,
+ product_id,
+ unique_id,
+ base::string16(),
+ base::string16(),
+ base::string16()) {}
+
+ MOCK_METHOD1(Open, void(const OpenCallback&));
MOCK_METHOD1(Close, bool(scoped_refptr<UsbDeviceHandle>));
MOCK_METHOD0(GetConfiguration, const device::UsbConfigDescriptor*());
- MOCK_METHOD1(GetManufacturer, bool(base::string16*));
- MOCK_METHOD1(GetProduct, bool(base::string16*));
- MOCK_METHOD1(GetSerialNumber, bool(base::string16*));
private:
virtual ~MockUsbDevice() {}
@@ -46,8 +48,6 @@ class UsbFilterTest : public testing::Test {
config_.interfaces.push_back(interface);
android_phone_ = new MockUsbDevice(0x18d1, 0x4ee2, 0);
- ON_CALL(*android_phone_.get(), GetConfiguration())
- .WillByDefault(Return(&config_));
}
protected:
@@ -89,12 +89,16 @@ TEST_F(UsbFilterTest, MatchProductIdNegative) {
TEST_F(UsbFilterTest, MatchInterfaceClass) {
UsbDeviceFilter filter;
filter.SetInterfaceClass(0xff);
+ EXPECT_CALL(*android_phone_.get(), GetConfiguration())
+ .WillOnce(Return(&config_));
ASSERT_TRUE(filter.Matches(android_phone_));
}
TEST_F(UsbFilterTest, MatchInterfaceClassNegative) {
UsbDeviceFilter filter;
filter.SetInterfaceClass(0xe0);
+ EXPECT_CALL(*android_phone_.get(), GetConfiguration())
+ .WillOnce(Return(&config_));
ASSERT_FALSE(filter.Matches(android_phone_));
}
@@ -102,6 +106,8 @@ TEST_F(UsbFilterTest, MatchInterfaceSubclass) {
UsbDeviceFilter filter;
filter.SetInterfaceClass(0xff);
filter.SetInterfaceSubclass(0x42);
+ EXPECT_CALL(*android_phone_.get(), GetConfiguration())
+ .WillOnce(Return(&config_));
ASSERT_TRUE(filter.Matches(android_phone_));
}
@@ -109,6 +115,8 @@ TEST_F(UsbFilterTest, MatchInterfaceSubclassNegative) {
UsbDeviceFilter filter;
filter.SetInterfaceClass(0xff);
filter.SetInterfaceSubclass(0x01);
+ EXPECT_CALL(*android_phone_.get(), GetConfiguration())
+ .WillOnce(Return(&config_));
ASSERT_FALSE(filter.Matches(android_phone_));
}
@@ -117,6 +125,8 @@ TEST_F(UsbFilterTest, MatchInterfaceProtocol) {
filter.SetInterfaceClass(0xff);
filter.SetInterfaceSubclass(0x42);
filter.SetInterfaceProtocol(0x01);
+ EXPECT_CALL(*android_phone_.get(), GetConfiguration())
+ .WillOnce(Return(&config_));
ASSERT_TRUE(filter.Matches(android_phone_));
}
@@ -125,6 +135,8 @@ TEST_F(UsbFilterTest, MatchInterfaceProtocolNegative) {
filter.SetInterfaceClass(0xff);
filter.SetInterfaceSubclass(0x42);
filter.SetInterfaceProtocol(0x02);
+ EXPECT_CALL(*android_phone_.get(), GetConfiguration())
+ .WillOnce(Return(&config_));
ASSERT_FALSE(filter.Matches(android_phone_));
}
diff --git a/device/usb/usb_device_handle.h b/device/usb/usb_device_handle.h
index 7098d68..2c59f25 100644
--- a/device/usb/usb_device_handle.h
+++ b/device/usb/usb_device_handle.h
@@ -30,13 +30,13 @@ enum UsbTransferStatus {
USB_TRANSFER_LENGTH_SHORT,
};
-typedef base::Callback<
- void(UsbTransferStatus, scoped_refptr<net::IOBuffer>, size_t)>
- UsbTransferCallback;
-
// UsbDeviceHandle class provides basic I/O related functionalities.
class UsbDeviceHandle : public base::RefCountedThreadSafe<UsbDeviceHandle> {
public:
+ using ResultCallback = base::Callback<void(bool)>;
+ using TransferCallback = base::Callback<
+ void(UsbTransferStatus, scoped_refptr<net::IOBuffer>, size_t)>;
+
enum TransferRequestType { STANDARD, CLASS, VENDOR, RESERVED };
enum TransferRecipient { DEVICE, INTERFACE, ENDPOINT, OTHER };
@@ -49,53 +49,52 @@ class UsbDeviceHandle : public base::RefCountedThreadSafe<UsbDeviceHandle> {
// The platform device handle will be closed when UsbDeviceHandle destructs.
virtual void Close() = 0;
- // Device manipulation operations. These methods are blocking and must be
- // called on FILE thread.
- virtual bool SetConfiguration(int configuration_value) = 0;
- virtual bool ClaimInterface(int interface_number) = 0;
+ // Device manipulation operations.
+ virtual void SetConfiguration(int configuration_value,
+ const ResultCallback& callback) = 0;
+ virtual void ClaimInterface(int interface_number,
+ const ResultCallback& callback) = 0;
virtual bool ReleaseInterface(int interface_number) = 0;
- virtual bool SetInterfaceAlternateSetting(int interface_number,
- int alternate_setting) = 0;
- virtual bool ResetDevice() = 0;
-
- // Gets the string descriptor with the given index from the device, or returns
- // false. This method is blocking and must be called on the FILE thread.
- virtual bool GetStringDescriptor(uint8 string_id, base::string16* string) = 0;
+ virtual void SetInterfaceAlternateSetting(int interface_number,
+ int alternate_setting,
+ const ResultCallback& callback) = 0;
+ virtual void ResetDevice(const ResultCallback& callback) = 0;
- // Async IO. Can be called on any thread.
+ // The transfer functions may be called from any thread. The provided callback
+ // will be run on the caller's thread.
virtual void ControlTransfer(UsbEndpointDirection direction,
TransferRequestType request_type,
TransferRecipient recipient,
uint8 request,
uint16 value,
uint16 index,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
- const UsbTransferCallback& callback) = 0;
+ const TransferCallback& callback) = 0;
virtual void BulkTransfer(UsbEndpointDirection direction,
uint8 endpoint,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
- const UsbTransferCallback& callback) = 0;
+ const TransferCallback& callback) = 0;
virtual void InterruptTransfer(UsbEndpointDirection direction,
uint8 endpoint,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
- const UsbTransferCallback& callback) = 0;
+ const TransferCallback& callback) = 0;
virtual void IsochronousTransfer(UsbEndpointDirection direction,
uint8 endpoint,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int packets,
unsigned int packet_length,
unsigned int timeout,
- const UsbTransferCallback& callback) = 0;
+ const TransferCallback& callback) = 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 fc14e82c..921af4f 100644
--- a/device/usb/usb_device_handle_impl.cc
+++ b/device/usb/usb_device_handle_impl.cc
@@ -157,6 +157,7 @@ bool UsbDeviceHandleImpl::InterfaceClaimer::Claim() const {
class UsbDeviceHandleImpl::Transfer {
public:
static scoped_ptr<Transfer> CreateControlTransfer(
+ scoped_refptr<UsbDeviceHandleImpl> device_handle,
uint8 type,
uint8 request,
uint16 value,
@@ -164,62 +165,77 @@ class UsbDeviceHandleImpl::Transfer {
uint16 length,
scoped_refptr<net::IOBuffer> buffer,
unsigned int timeout,
- const UsbTransferCallback& callback);
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback);
static scoped_ptr<Transfer> CreateBulkTransfer(
+ scoped_refptr<UsbDeviceHandleImpl> device_handle,
uint8 endpoint,
scoped_refptr<net::IOBuffer> buffer,
int length,
unsigned int timeout,
- const UsbTransferCallback& callback);
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback);
static scoped_ptr<Transfer> CreateInterruptTransfer(
+ scoped_refptr<UsbDeviceHandleImpl> device_handle,
uint8 endpoint,
scoped_refptr<net::IOBuffer> buffer,
int length,
unsigned int timeout,
- const UsbTransferCallback& callback);
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback);
static scoped_ptr<Transfer> CreateIsochronousTransfer(
+ scoped_refptr<UsbDeviceHandleImpl> device_handle,
uint8 endpoint,
scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int packets,
unsigned int packet_length,
unsigned int timeout,
- const UsbTransferCallback& callback);
+ scoped_refptr<base::TaskRunner> task_runner,
+ const TransferCallback& callback);
~Transfer();
- bool Submit(base::WeakPtr<UsbDeviceHandleImpl> device_handle);
+ void Submit();
void Cancel();
void ProcessCompletion();
- void Complete(UsbTransferStatus status, size_t bytes_transferred);
+ void TransferComplete(UsbTransferStatus status, size_t bytes_transferred);
const UsbDeviceHandleImpl::InterfaceClaimer* claimed_interface() const {
return claimed_interface_.get();
}
+ scoped_refptr<base::TaskRunner> callback_task_runner() const {
+ return callback_task_runner_;
+ }
+
private:
- Transfer(UsbTransferType transfer_type,
+ Transfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,
+ scoped_refptr<InterfaceClaimer> claimed_interface,
+ UsbTransferType transfer_type,
scoped_refptr<net::IOBuffer> buffer,
size_t length,
- const UsbTransferCallback& callback);
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback);
static void LIBUSB_CALL PlatformCallback(PlatformUsbTransferHandle handle);
UsbTransferType transfer_type_;
- base::WeakPtr<UsbDeviceHandleImpl> device_handle_;
- PlatformUsbTransferHandle platform_transfer_;
+ scoped_refptr<UsbDeviceHandleImpl> device_handle_;
+ PlatformUsbTransferHandle platform_transfer_ = nullptr;
scoped_refptr<net::IOBuffer> buffer_;
scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
size_t length_;
- bool cancelled_;
- UsbTransferCallback callback_;
- scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner_;
+ bool cancelled_ = false;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ scoped_refptr<base::TaskRunner> callback_task_runner_;
+ TransferCallback callback_;
};
// static
scoped_ptr<UsbDeviceHandleImpl::Transfer>
UsbDeviceHandleImpl::Transfer::CreateControlTransfer(
+ scoped_refptr<UsbDeviceHandleImpl> device_handle,
uint8 type,
uint8 request,
uint16 value,
@@ -227,10 +243,11 @@ UsbDeviceHandleImpl::Transfer::CreateControlTransfer(
uint16 length,
scoped_refptr<net::IOBuffer> buffer,
unsigned int timeout,
- const UsbTransferCallback& callback) {
- scoped_ptr<Transfer> transfer(new Transfer(USB_TRANSFER_CONTROL, buffer,
- length + LIBUSB_CONTROL_SETUP_SIZE,
- callback));
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback) {
+ scoped_ptr<Transfer> transfer(new Transfer(
+ device_handle, nullptr, USB_TRANSFER_CONTROL, buffer,
+ length + LIBUSB_CONTROL_SETUP_SIZE, callback_task_runner, callback));
transfer->platform_transfer_ = libusb_alloc_transfer(0);
if (!transfer->platform_transfer_) {
@@ -241,7 +258,7 @@ UsbDeviceHandleImpl::Transfer::CreateControlTransfer(
libusb_fill_control_setup(reinterpret_cast<uint8*>(buffer->data()), type,
request, value, index, length);
libusb_fill_control_transfer(transfer->platform_transfer_,
- nullptr, /* filled in by Submit() */
+ device_handle->handle_,
reinterpret_cast<uint8*>(buffer->data()),
&UsbDeviceHandleImpl::Transfer::PlatformCallback,
transfer.get(), timeout);
@@ -252,13 +269,16 @@ UsbDeviceHandleImpl::Transfer::CreateControlTransfer(
// static
scoped_ptr<UsbDeviceHandleImpl::Transfer>
UsbDeviceHandleImpl::Transfer::CreateBulkTransfer(
+ scoped_refptr<UsbDeviceHandleImpl> device_handle,
uint8 endpoint,
scoped_refptr<net::IOBuffer> buffer,
int length,
unsigned int timeout,
- const UsbTransferCallback& callback) {
- scoped_ptr<Transfer> transfer(
- new Transfer(USB_TRANSFER_BULK, buffer, length, callback));
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback) {
+ scoped_ptr<Transfer> transfer(new Transfer(
+ device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
+ USB_TRANSFER_BULK, buffer, length, callback_task_runner, callback));
transfer->platform_transfer_ = libusb_alloc_transfer(0);
if (!transfer->platform_transfer_) {
@@ -266,12 +286,11 @@ UsbDeviceHandleImpl::Transfer::CreateBulkTransfer(
return nullptr;
}
- libusb_fill_bulk_transfer(transfer->platform_transfer_,
- nullptr, /* filled in by Submit() */
- endpoint, reinterpret_cast<uint8*>(buffer->data()),
- static_cast<int>(length),
- &UsbDeviceHandleImpl::Transfer::PlatformCallback,
- transfer.get(), timeout);
+ libusb_fill_bulk_transfer(
+ transfer->platform_transfer_, device_handle->handle_, endpoint,
+ reinterpret_cast<uint8*>(buffer->data()), static_cast<int>(length),
+ &UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(),
+ timeout);
return transfer.Pass();
}
@@ -279,13 +298,16 @@ UsbDeviceHandleImpl::Transfer::CreateBulkTransfer(
// static
scoped_ptr<UsbDeviceHandleImpl::Transfer>
UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer(
+ scoped_refptr<UsbDeviceHandleImpl> device_handle,
uint8 endpoint,
scoped_refptr<net::IOBuffer> buffer,
int length,
unsigned int timeout,
- const UsbTransferCallback& callback) {
- scoped_ptr<Transfer> transfer(
- new Transfer(USB_TRANSFER_INTERRUPT, buffer, length, callback));
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback) {
+ scoped_ptr<Transfer> transfer(new Transfer(
+ device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
+ USB_TRANSFER_INTERRUPT, buffer, length, callback_task_runner, callback));
transfer->platform_transfer_ = libusb_alloc_transfer(0);
if (!transfer->platform_transfer_) {
@@ -294,9 +316,8 @@ UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer(
}
libusb_fill_interrupt_transfer(
- transfer->platform_transfer_, nullptr, /* filled in by Submit() */
- endpoint, reinterpret_cast<uint8*>(buffer->data()),
- static_cast<int>(length),
+ transfer->platform_transfer_, device_handle->handle_, endpoint,
+ reinterpret_cast<uint8*>(buffer->data()), static_cast<int>(length),
&UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(),
timeout);
@@ -306,18 +327,22 @@ UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer(
// static
scoped_ptr<UsbDeviceHandleImpl::Transfer>
UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer(
+ scoped_refptr<UsbDeviceHandleImpl> device_handle,
uint8 endpoint,
scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int packets,
unsigned int packet_length,
unsigned int timeout,
- const UsbTransferCallback& callback) {
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback) {
DCHECK(packets <= length && (packets * packet_length) <= length)
<< "transfer length is too small";
- scoped_ptr<Transfer> transfer(
- new Transfer(USB_TRANSFER_ISOCHRONOUS, buffer, length, callback));
+ scoped_ptr<Transfer> transfer(new Transfer(
+ device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
+ USB_TRANSFER_ISOCHRONOUS, buffer, length, callback_task_runner,
+ callback));
transfer->platform_transfer_ = libusb_alloc_transfer(packets);
if (!transfer->platform_transfer_) {
@@ -326,27 +351,30 @@ UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer(
}
libusb_fill_iso_transfer(
- transfer->platform_transfer_, nullptr, /* filled in by Submit() */
- endpoint, reinterpret_cast<uint8*>(buffer->data()),
- static_cast<int>(length), packets, &Transfer::PlatformCallback,
- transfer.get(), timeout);
+ transfer->platform_transfer_, device_handle->handle_, endpoint,
+ reinterpret_cast<uint8*>(buffer->data()), static_cast<int>(length),
+ packets, &Transfer::PlatformCallback, transfer.get(), timeout);
libusb_set_iso_packet_lengths(transfer->platform_transfer_, packet_length);
return transfer.Pass();
}
-UsbDeviceHandleImpl::Transfer::Transfer(UsbTransferType transfer_type,
- scoped_refptr<net::IOBuffer> buffer,
- size_t length,
- const UsbTransferCallback& callback)
+UsbDeviceHandleImpl::Transfer::Transfer(
+ scoped_refptr<UsbDeviceHandleImpl> device_handle,
+ scoped_refptr<InterfaceClaimer> claimed_interface,
+ UsbTransferType transfer_type,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback)
: transfer_type_(transfer_type),
+ device_handle_(device_handle),
buffer_(buffer),
+ claimed_interface_(claimed_interface),
length_(length),
- cancelled_(false),
+ callback_task_runner_(callback_task_runner),
callback_(callback) {
- // Remember the thread from which this transfer was created so that |callback|
- // can be dispatched there.
- callback_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ task_runner_ = base::ThreadTaskRunnerHandle::Get();
}
UsbDeviceHandleImpl::Transfer::~Transfer() {
@@ -355,26 +383,12 @@ UsbDeviceHandleImpl::Transfer::~Transfer() {
}
}
-bool UsbDeviceHandleImpl::Transfer::Submit(
- base::WeakPtr<UsbDeviceHandleImpl> device_handle) {
- device_handle_ = device_handle;
- // Remember the thread from which this transfer was submitted so that it can
- // be marked complete there.
- task_runner_ = base::ThreadTaskRunnerHandle::Get();
- // GetClaimedInterfaceForEndpoint may return nullptr. libusb_submit_transfer
- // will fail if it requires an interface we didn't claim.
- claimed_interface_ = device_handle->GetClaimedInterfaceForEndpoint(
- platform_transfer_->endpoint);
- platform_transfer_->dev_handle = device_handle_->handle_;
-
+void UsbDeviceHandleImpl::Transfer::Submit() {
const int rv = libusb_submit_transfer(platform_transfer_);
- if (rv == LIBUSB_SUCCESS) {
- return true;
- } else {
+ if (rv != LIBUSB_SUCCESS) {
USB_LOG(EVENT) << "Failed to submit transfer: "
<< ConvertPlatformUsbErrorToString(rv);
- Complete(USB_TRANSFER_ERROR, 0);
- return false;
+ TransferComplete(USB_TRANSFER_ERROR, 0);
}
}
@@ -453,51 +467,26 @@ void UsbDeviceHandleImpl::Transfer::ProcessCompletion() {
break;
}
- Complete(ConvertTransferStatus(platform_transfer_->status), actual_length);
-}
-
-void UsbDeviceHandleImpl::Transfer::Complete(UsbTransferStatus status,
- size_t bytes_transferred) {
- if (callback_task_runner_->RunsTasksOnCurrentThread()) {
- callback_.Run(status, buffer_, bytes_transferred);
- } else {
- callback_task_runner_->PostTask(
- FROM_HERE, base::Bind(callback_, status, buffer_, bytes_transferred));
- }
+ TransferComplete(ConvertTransferStatus(platform_transfer_->status),
+ actual_length);
}
/* static */
void LIBUSB_CALL UsbDeviceHandleImpl::Transfer::PlatformCallback(
PlatformUsbTransferHandle platform_transfer) {
- scoped_ptr<Transfer> transfer(
- reinterpret_cast<Transfer*>(platform_transfer->user_data));
+ Transfer* transfer =
+ reinterpret_cast<Transfer*>(platform_transfer->user_data);
DCHECK(transfer->platform_transfer_ == platform_transfer);
-
- // Because device_handle_ is a weak pointer it is guaranteed that the callback
- // will be discarded if the handle has been freed.
- Transfer* tmp_transfer = transfer.get(); // base::Passed invalidates transfer
- tmp_transfer->task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbDeviceHandleImpl::CompleteTransfer,
- tmp_transfer->device_handle_,
- base::Passed(&transfer)));
-}
-
-UsbDeviceHandleImpl::UsbDeviceHandleImpl(scoped_refptr<UsbContext> context,
- scoped_refptr<UsbDeviceImpl> device,
- PlatformUsbDeviceHandle handle)
- : device_(device),
- handle_(handle),
- context_(context),
- task_runner_(base::ThreadTaskRunnerHandle::Get()),
- weak_factory_(this) {
- DCHECK(handle) << "Cannot create device with NULL handle.";
+ transfer->ProcessCompletion();
}
-UsbDeviceHandleImpl::~UsbDeviceHandleImpl() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- libusb_close(handle_);
- handle_ = NULL;
+void UsbDeviceHandleImpl::Transfer::TransferComplete(UsbTransferStatus status,
+ size_t bytes_transferred) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbDeviceHandleImpl::TransferComplete, device_handle_,
+ base::Owned(this),
+ base::Bind(callback_, status, buffer_, bytes_transferred)));
}
scoped_refptr<UsbDevice> UsbDeviceHandleImpl::GetDevice() const {
@@ -510,10 +499,12 @@ void UsbDeviceHandleImpl::Close() {
device_->Close(this);
}
-bool UsbDeviceHandleImpl::SetConfiguration(int configuration_value) {
+void UsbDeviceHandleImpl::SetConfiguration(int configuration_value,
+ const ResultCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!device_) {
- return false;
+ callback.Run(false);
+ return;
}
for (Transfer* transfer : transfers_) {
@@ -521,36 +512,31 @@ bool UsbDeviceHandleImpl::SetConfiguration(int configuration_value) {
}
claimed_interfaces_.clear();
- int rv = libusb_set_configuration(handle_, configuration_value);
- if (rv == LIBUSB_SUCCESS) {
- device_->RefreshConfiguration();
- RefreshEndpointMap();
- } else {
- USB_LOG(EVENT) << "Failed to set configuration " << configuration_value
- << ": " << ConvertPlatformUsbErrorToString(rv);
- }
- return rv == LIBUSB_SUCCESS;
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbDeviceHandleImpl::SetConfigurationOnBlockingThread, this,
+ handle_, configuration_value, callback));
}
-bool UsbDeviceHandleImpl::ClaimInterface(const int interface_number) {
+void UsbDeviceHandleImpl::ClaimInterface(int interface_number,
+ const ResultCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!device_)
- return false;
- if (ContainsKey(claimed_interfaces_, interface_number))
- return true;
-
- scoped_refptr<InterfaceClaimer> claimer =
- new InterfaceClaimer(this, interface_number);
-
- if (claimer->Claim()) {
- claimed_interfaces_[interface_number] = claimer;
- RefreshEndpointMap();
- return true;
+ if (!device_) {
+ callback.Run(false);
+ return;
+ }
+ if (ContainsKey(claimed_interfaces_, interface_number)) {
+ callback.Run(true);
+ return;
}
- return false;
+
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbDeviceHandleImpl::ClaimInterfaceOnBlockingThread, this,
+ handle_, interface_number, callback));
}
-bool UsbDeviceHandleImpl::ReleaseInterface(const int interface_number) {
+bool UsbDeviceHandleImpl::ReleaseInterface(int interface_number) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!device_)
return false;
@@ -571,103 +557,282 @@ bool UsbDeviceHandleImpl::ReleaseInterface(const int interface_number) {
return true;
}
-bool UsbDeviceHandleImpl::SetInterfaceAlternateSetting(
- const int interface_number,
- const int alternate_setting) {
+void UsbDeviceHandleImpl::SetInterfaceAlternateSetting(
+ int interface_number,
+ int alternate_setting,
+ const ResultCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!device_)
- return false;
- if (!ContainsKey(claimed_interfaces_, interface_number))
- return false;
- const int rv = libusb_set_interface_alt_setting(
- handle_, interface_number, alternate_setting);
- if (rv == LIBUSB_SUCCESS) {
- claimed_interfaces_[interface_number]->set_alternate_setting(
- alternate_setting);
- RefreshEndpointMap();
+ if (!device_ || !ContainsKey(claimed_interfaces_, interface_number)) {
+ callback.Run(false);
+ return;
+ }
+
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &UsbDeviceHandleImpl::SetInterfaceAlternateSettingOnBlockingThread,
+ this, handle_, interface_number, alternate_setting, callback));
+}
+
+void UsbDeviceHandleImpl::ResetDevice(const ResultCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!device_) {
+ callback.Run(false);
+ return;
+ }
+
+ blocking_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ResetDeviceOnBlockingThread,
+ this, handle_, callback));
+}
+
+void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction,
+ TransferRequestType request_type,
+ TransferRecipient recipient,
+ uint8 request,
+ uint16 value,
+ uint16 index,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int timeout,
+ const TransferCallback& callback) {
+ if (task_runner_->BelongsToCurrentThread()) {
+ ControlTransferInternal(direction, request_type, recipient, request, value,
+ index, buffer, length, timeout, task_runner_,
+ callback);
+ } else {
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ControlTransferInternal,
+ this, direction, request_type, recipient, request,
+ value, index, buffer, length, timeout,
+ base::ThreadTaskRunnerHandle::Get(), callback));
+ }
+}
+
+void UsbDeviceHandleImpl::BulkTransfer(UsbEndpointDirection direction,
+ uint8 endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int timeout,
+ const TransferCallback& callback) {
+ if (task_runner_->BelongsToCurrentThread()) {
+ BulkTransferInternal(direction, endpoint, buffer, length, timeout,
+ task_runner_, callback);
} else {
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UsbDeviceHandleImpl::BulkTransferInternal, this,
+ direction, endpoint, buffer, length, timeout,
+ base::ThreadTaskRunnerHandle::Get(), callback));
+ }
+}
+
+void UsbDeviceHandleImpl::InterruptTransfer(UsbEndpointDirection direction,
+ uint8 endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int timeout,
+ const TransferCallback& callback) {
+ if (task_runner_->BelongsToCurrentThread()) {
+ InterruptTransferInternal(direction, endpoint, buffer, length, timeout,
+ task_runner_, callback);
+ } else {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbDeviceHandleImpl::InterruptTransferInternal, this,
+ direction, endpoint, buffer, length, timeout,
+ base::ThreadTaskRunnerHandle::Get(), callback));
+ }
+}
+
+void UsbDeviceHandleImpl::IsochronousTransfer(
+ UsbEndpointDirection direction,
+ uint8 endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int packets,
+ unsigned int packet_length,
+ unsigned int timeout,
+ const TransferCallback& callback) {
+ if (task_runner_->BelongsToCurrentThread()) {
+ IsochronousTransferInternal(direction, endpoint, buffer, length, packets,
+ packet_length, timeout, task_runner_, callback);
+ } else {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbDeviceHandleImpl::IsochronousTransferInternal, this,
+ direction, endpoint, buffer, length, packets, packet_length,
+ timeout, base::ThreadTaskRunnerHandle::Get(), callback));
+ }
+}
+
+UsbDeviceHandleImpl::UsbDeviceHandleImpl(
+ scoped_refptr<UsbContext> context,
+ scoped_refptr<UsbDeviceImpl> device,
+ PlatformUsbDeviceHandle handle,
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
+ : device_(device),
+ handle_(handle),
+ context_(context),
+ task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ blocking_task_runner_(blocking_task_runner) {
+ DCHECK(handle) << "Cannot create device with NULL handle.";
+}
+
+UsbDeviceHandleImpl::~UsbDeviceHandleImpl() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ libusb_close(handle_);
+ handle_ = NULL;
+}
+
+void UsbDeviceHandleImpl::SetConfigurationOnBlockingThread(
+ PlatformUsbDeviceHandle handle,
+ int configuration_value,
+ const ResultCallback& callback) {
+ int rv = libusb_set_configuration(handle_, configuration_value);
+ if (rv != LIBUSB_SUCCESS) {
+ USB_LOG(EVENT) << "Failed to set configuration " << configuration_value
+ << ": " << ConvertPlatformUsbErrorToString(rv);
+ }
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UsbDeviceHandleImpl::SetConfigurationComplete,
+ this, rv == LIBUSB_SUCCESS, callback));
+}
+
+void UsbDeviceHandleImpl::SetConfigurationComplete(
+ bool success,
+ const ResultCallback& callback) {
+ if (success) {
+ device_->RefreshConfiguration();
+ RefreshEndpointMap();
+ }
+ callback.Run(success);
+}
+
+void UsbDeviceHandleImpl::ClaimInterfaceOnBlockingThread(
+ PlatformUsbDeviceHandle handle,
+ int interface_number,
+ const ResultCallback& callback) {
+ int rv = libusb_claim_interface(handle, interface_number);
+ if (rv != LIBUSB_SUCCESS) {
+ VLOG(1) << "Failed to claim interface: "
+ << ConvertPlatformUsbErrorToString(rv);
+ }
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ClaimInterfaceComplete, this,
+ interface_number, rv == LIBUSB_SUCCESS, callback));
+}
+
+void UsbDeviceHandleImpl::ClaimInterfaceComplete(
+ int interface_number,
+ bool success,
+ const ResultCallback& callback) {
+ if (success) {
+ claimed_interfaces_[interface_number] =
+ new InterfaceClaimer(this, interface_number);
+ RefreshEndpointMap();
+ }
+ callback.Run(success);
+}
+
+void UsbDeviceHandleImpl::SetInterfaceAlternateSettingOnBlockingThread(
+ PlatformUsbDeviceHandle handle,
+ int interface_number,
+ int alternate_setting,
+ const ResultCallback& callback) {
+ int rv = libusb_set_interface_alt_setting(handle, interface_number,
+ alternate_setting);
+ if (rv != LIBUSB_SUCCESS) {
USB_LOG(EVENT) << "Failed to set interface " << interface_number
<< " to alternate setting " << alternate_setting << ": "
<< ConvertPlatformUsbErrorToString(rv);
}
- return rv == LIBUSB_SUCCESS;
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete,
+ this, interface_number, alternate_setting,
+ rv == LIBUSB_SUCCESS, callback));
}
-bool UsbDeviceHandleImpl::ResetDevice() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!device_)
- return false;
+void UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete(
+ int interface_number,
+ int alternate_setting,
+ bool success,
+ const ResultCallback& callback) {
+ if (success) {
+ claimed_interfaces_[interface_number]->set_alternate_setting(
+ alternate_setting);
+ RefreshEndpointMap();
+ }
+ callback.Run(success);
+}
- const int rv = libusb_reset_device(handle_);
+void UsbDeviceHandleImpl::ResetDeviceOnBlockingThread(
+ PlatformUsbDeviceHandle handle,
+ const ResultCallback& callback) {
+ int rv = libusb_reset_device(handle);
if (rv != LIBUSB_SUCCESS) {
USB_LOG(EVENT) << "Failed to reset device: "
<< ConvertPlatformUsbErrorToString(rv);
}
- return rv == LIBUSB_SUCCESS;
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ResetDeviceComplete, this,
+ rv == LIBUSB_SUCCESS, callback));
}
-bool UsbDeviceHandleImpl::GetStringDescriptor(uint8 string_id,
- base::string16* string) {
- if (!GetSupportedLanguages()) {
- return false;
- }
+void UsbDeviceHandleImpl::ResetDeviceComplete(bool success,
+ const ResultCallback& callback) {
+ callback.Run(success);
+}
- std::map<uint8, base::string16>::const_iterator it = strings_.find(string_id);
- if (it != strings_.end()) {
- *string = it->second;
- return true;
- }
-
- for (size_t i = 0; i < languages_.size(); ++i) {
- // Get the string using language ID.
- uint16 language_id = languages_[i];
- // The 1-byte length field limits the descriptor to 256-bytes (128 char16s).
- base::char16 text[128];
- int size =
- libusb_get_string_descriptor(handle_,
- string_id,
- language_id,
- reinterpret_cast<unsigned char*>(&text[0]),
- sizeof(text));
- if (size < 0) {
- USB_LOG(EVENT) << "Failed to get string descriptor " << string_id
- << " (langid " << language_id
- << "): " << ConvertPlatformUsbErrorToString(size);
- continue;
- } else if (size < 2) {
- USB_LOG(EVENT) << "String descriptor " << string_id << " (langid "
- << language_id << ") has no header.";
- continue;
- // The first 2 bytes of the descriptor are the total length and type tag.
- } else if ((text[0] & 0xff) != size) {
- USB_LOG(EVENT) << "String descriptor " << string_id << " (langid "
- << language_id << ") size mismatch: " << (text[0] & 0xff)
- << " != " << size;
- continue;
- } else if ((text[0] >> 8) != LIBUSB_DT_STRING) {
- USB_LOG(EVENT) << "String descriptor " << string_id << " (langid "
- << language_id << ") is not a string descriptor.";
- continue;
- }
+void UsbDeviceHandleImpl::RefreshEndpointMap() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ endpoint_map_.clear();
+ const UsbConfigDescriptor* config = device_->GetConfiguration();
+ if (config) {
+ for (const auto& map_entry : claimed_interfaces_) {
+ int interface_number = map_entry.first;
+ const scoped_refptr<InterfaceClaimer>& claimed_iface = map_entry.second;
- *string = base::string16(text + 1, (size - 2) / 2);
- strings_[string_id] = *string;
- return true;
+ for (const UsbInterfaceDescriptor& iface : config->interfaces) {
+ if (iface.interface_number == interface_number &&
+ iface.alternate_setting == claimed_iface->alternate_setting()) {
+ for (const UsbEndpointDescriptor& endpoint : iface.endpoints) {
+ endpoint_map_[endpoint.address] = interface_number;
+ }
+ break;
+ }
+ }
+ }
}
+}
- return false;
+scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer>
+UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) {
+ if (ContainsKey(endpoint_map_, endpoint))
+ return claimed_interfaces_[endpoint_map_[endpoint]];
+ return NULL;
}
-void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction,
- TransferRequestType request_type,
- TransferRecipient recipient,
- uint8 request,
- uint16 value,
- uint16 index,
- net::IOBuffer* buffer,
- size_t length,
- unsigned int timeout,
- const UsbTransferCallback& callback) {
+void UsbDeviceHandleImpl::ControlTransferInternal(
+ UsbEndpointDirection direction,
+ TransferRequestType request_type,
+ TransferRecipient recipient,
+ uint8 request,
+ uint16 value,
+ uint16 index,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int timeout,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!device_) {
+ callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
+ return;
+ }
+
if (length > UINT16_MAX) {
USB_LOG(USER) << "Transfer too long.";
callback.Run(USB_TRANSFER_ERROR, buffer, 0);
@@ -685,22 +850,32 @@ void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction,
length);
scoped_ptr<Transfer> transfer = Transfer::CreateControlTransfer(
- CreateRequestType(direction, request_type, recipient), request, value,
- index, static_cast<uint16>(length), resized_buffer, timeout, callback);
+ this, CreateRequestType(direction, request_type, recipient), request,
+ value, index, static_cast<uint16>(length), resized_buffer, timeout,
+ callback_task_runner, callback);
if (!transfer) {
callback.Run(USB_TRANSFER_ERROR, buffer, 0);
return;
}
- PostOrSubmitTransfer(transfer.Pass());
+ SubmitTransfer(transfer.Pass());
}
-void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction,
- const uint8 endpoint,
- net::IOBuffer* buffer,
- const size_t length,
- const unsigned int timeout,
- const UsbTransferCallback& callback) {
+void UsbDeviceHandleImpl::BulkTransferInternal(
+ const UsbEndpointDirection direction,
+ const uint8 endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ const size_t length,
+ const unsigned int timeout,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!device_) {
+ callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
+ return;
+ }
+
if (length > INT_MAX) {
USB_LOG(USER) << "Transfer too long.";
callback.Run(USB_TRANSFER_ERROR, buffer, 0);
@@ -708,19 +883,27 @@ void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction,
}
scoped_ptr<Transfer> transfer = Transfer::CreateBulkTransfer(
- ConvertTransferDirection(direction) | endpoint, buffer,
- static_cast<int>(length), timeout, callback);
+ this, ConvertTransferDirection(direction) | endpoint, buffer,
+ static_cast<int>(length), timeout, callback_task_runner, callback);
- PostOrSubmitTransfer(transfer.Pass());
+ SubmitTransfer(transfer.Pass());
}
-void UsbDeviceHandleImpl::InterruptTransfer(
+void UsbDeviceHandleImpl::InterruptTransferInternal(
UsbEndpointDirection direction,
uint8 endpoint,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
- const UsbTransferCallback& callback) {
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!device_) {
+ callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
+ return;
+ }
+
if (length > INT_MAX) {
USB_LOG(USER) << "Transfer too long.";
callback.Run(USB_TRANSFER_ERROR, buffer, 0);
@@ -728,21 +911,29 @@ void UsbDeviceHandleImpl::InterruptTransfer(
}
scoped_ptr<Transfer> transfer = Transfer::CreateInterruptTransfer(
- ConvertTransferDirection(direction) | endpoint, buffer,
- static_cast<int>(length), timeout, callback);
+ this, ConvertTransferDirection(direction) | endpoint, buffer,
+ static_cast<int>(length), timeout, callback_task_runner, callback);
- PostOrSubmitTransfer(transfer.Pass());
+ SubmitTransfer(transfer.Pass());
}
-void UsbDeviceHandleImpl::IsochronousTransfer(
+void UsbDeviceHandleImpl::IsochronousTransferInternal(
const UsbEndpointDirection direction,
- const uint8 endpoint,
- net::IOBuffer* buffer,
- const size_t length,
- const unsigned int packets,
- const unsigned int packet_length,
- const unsigned int timeout,
- const UsbTransferCallback& callback) {
+ uint8 endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int packets,
+ unsigned int packet_length,
+ unsigned int timeout,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!device_) {
+ callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
+ return;
+ }
+
if (length > INT_MAX) {
USB_LOG(USER) << "Transfer too long.";
callback.Run(USB_TRANSFER_ERROR, buffer, 0);
@@ -750,104 +941,35 @@ void UsbDeviceHandleImpl::IsochronousTransfer(
}
scoped_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
- ConvertTransferDirection(direction) | endpoint, buffer,
- static_cast<int>(length), packets, packet_length, timeout, callback);
+ this, ConvertTransferDirection(direction) | endpoint, buffer,
+ static_cast<int>(length), packets, packet_length, timeout,
+ callback_task_runner, callback);
- PostOrSubmitTransfer(transfer.Pass());
+ SubmitTransfer(transfer.Pass());
}
-void UsbDeviceHandleImpl::RefreshEndpointMap() {
+void UsbDeviceHandleImpl::SubmitTransfer(scoped_ptr<Transfer> transfer) {
DCHECK(thread_checker_.CalledOnValidThread());
- endpoint_map_.clear();
- const UsbConfigDescriptor* config = device_->GetConfiguration();
- if (config) {
- for (const auto& map_entry : claimed_interfaces_) {
- int interface_number = map_entry.first;
- const scoped_refptr<InterfaceClaimer>& claimed_iface = map_entry.second;
- for (const UsbInterfaceDescriptor& iface : config->interfaces) {
- if (iface.interface_number == interface_number &&
- iface.alternate_setting == claimed_iface->alternate_setting()) {
- for (const UsbEndpointDescriptor& endpoint : iface.endpoints) {
- endpoint_map_[endpoint.address] = interface_number;
- }
- break;
- }
- }
- }
- }
-}
-
-scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer>
-UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) {
- if (ContainsKey(endpoint_map_, endpoint))
- return claimed_interfaces_[endpoint_map_[endpoint]];
- return NULL;
-}
-
-void UsbDeviceHandleImpl::PostOrSubmitTransfer(scoped_ptr<Transfer> transfer) {
- if (task_runner_->RunsTasksOnCurrentThread()) {
- SubmitTransfer(transfer.Pass());
- } else {
- task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, this,
- base::Passed(&transfer)));
- }
+ // Transfer is owned by libusb until its completion callback is run. This
+ // object holds a weak reference.
+ transfers_.insert(transfer.get());
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&Transfer::Submit, base::Unretained(transfer.release())));
}
-void UsbDeviceHandleImpl::SubmitTransfer(scoped_ptr<Transfer> transfer) {
+void UsbDeviceHandleImpl::TransferComplete(Transfer* transfer,
+ const base::Closure& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(ContainsKey(transfers_, transfer)) << "Missing transfer completed";
+ transfers_.erase(transfer);
- if (device_) {
- if (transfer->Submit(weak_factory_.GetWeakPtr())) {
- // Transfer is now owned by libusb until its completion callback is run.
- // This object holds a weak reference.
- transfers_.insert(transfer.release());
- }
+ if (transfer->callback_task_runner()->RunsTasksOnCurrentThread()) {
+ callback.Run();
} else {
- transfer->Complete(USB_TRANSFER_DISCONNECT, 0);
- }
-}
-
-void UsbDeviceHandleImpl::CompleteTransfer(scoped_ptr<Transfer> transfer) {
- DCHECK(ContainsKey(transfers_, transfer.get()))
- << "Missing transfer completed";
- transfers_.erase(transfer.get());
- transfer->ProcessCompletion();
-}
-
-bool UsbDeviceHandleImpl::GetSupportedLanguages() {
- if (!languages_.empty()) {
- return true;
+ transfer->callback_task_runner()->PostTask(FROM_HERE, callback);
}
-
- // The 1-byte length field limits the descriptor to 256-bytes (128 uint16s).
- uint16 languages[128];
- int size = libusb_get_string_descriptor(
- handle_,
- 0,
- 0,
- reinterpret_cast<unsigned char*>(&languages[0]),
- sizeof(languages));
- if (size < 0) {
- USB_LOG(EVENT) << "Failed to get list of supported languages: "
- << ConvertPlatformUsbErrorToString(size);
- return false;
- } else if (size < 2) {
- USB_LOG(EVENT) << "String descriptor zero has no header.";
- return false;
- // The first 2 bytes of the descriptor are the total length and type tag.
- } else if ((languages[0] & 0xff) != size) {
- USB_LOG(EVENT) << "String descriptor zero size mismatch: "
- << (languages[0] & 0xff) << " != " << size;
- return false;
- } else if ((languages[0] >> 8) != LIBUSB_DT_STRING) {
- USB_LOG(EVENT) << "String descriptor zero is not a string descriptor.";
- return false;
- }
-
- languages_.assign(languages[1], languages[(size - 2) / 2]);
- return true;
}
void UsbDeviceHandleImpl::InternalClose() {
diff --git a/device/usb/usb_device_handle_impl.h b/device/usb/usb_device_handle_impl.h
index 688f8b9..a60f502 100644
--- a/device/usb/usb_device_handle_impl.h
+++ b/device/usb/usb_device_handle_impl.h
@@ -11,15 +11,18 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
#include "base/threading/thread_checker.h"
#include "device/usb/usb_device_handle.h"
-#include "net/base/io_buffer.h"
#include "third_party/libusb/src/libusb/libusb.h"
namespace base {
+class SequencedTaskRunner;
class SingleThreadTaskRunner;
+class TaskRunner;
+}
+
+namespace net {
+class IOBuffer;
}
namespace device {
@@ -37,13 +40,15 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
public:
scoped_refptr<UsbDevice> GetDevice() const override;
void Close() override;
- bool SetConfiguration(int configuration_value) override;
- bool ClaimInterface(int interface_number) override;
+ void SetConfiguration(int configuration_value,
+ const ResultCallback& callback) override;
+ void ClaimInterface(int interface_number,
+ const ResultCallback& callback) override;
bool ReleaseInterface(int interface_number) override;
- bool SetInterfaceAlternateSetting(int interface_number,
- int alternate_setting) override;
- bool ResetDevice() override;
- bool GetStringDescriptor(uint8 string_id, base::string16* string) override;
+ void SetInterfaceAlternateSetting(int interface_number,
+ int alternate_setting,
+ const ResultCallback& callback) override;
+ void ResetDevice(const ResultCallback& callback) override;
void ControlTransfer(UsbEndpointDirection direction,
TransferRequestType request_type,
@@ -51,52 +56,75 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
uint8 request,
uint16 value,
uint16 index,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
- const UsbTransferCallback& callback) override;
+ const TransferCallback& callback) override;
void BulkTransfer(UsbEndpointDirection direction,
uint8 endpoint,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
- const UsbTransferCallback& callback) override;
+ const TransferCallback& callback) override;
void InterruptTransfer(UsbEndpointDirection direction,
uint8 endpoint,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
- const UsbTransferCallback& callback) override;
+ const TransferCallback& callback) override;
void IsochronousTransfer(UsbEndpointDirection direction,
uint8 endpoint,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int packets,
unsigned int packet_length,
unsigned int timeout,
- const UsbTransferCallback& callback) override;
-
- PlatformUsbDeviceHandle handle() const { return handle_; }
+ const TransferCallback& callback) override;
protected:
friend class UsbDeviceImpl;
- // This constructor is called by UsbDevice.
- UsbDeviceHandleImpl(scoped_refptr<UsbContext> context,
- scoped_refptr<UsbDeviceImpl> device,
- PlatformUsbDeviceHandle handle);
+ // This constructor is called by UsbDeviceImpl.
+ UsbDeviceHandleImpl(
+ scoped_refptr<UsbContext> context,
+ scoped_refptr<UsbDeviceImpl> device,
+ PlatformUsbDeviceHandle handle,
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
~UsbDeviceHandleImpl() override;
- private:
- friend class Transfer;
+ PlatformUsbDeviceHandle handle() const { return handle_; }
+ private:
class InterfaceClaimer;
class Transfer;
+ void SetConfigurationOnBlockingThread(PlatformUsbDeviceHandle handle,
+ int configuration_value,
+ const ResultCallback& callback);
+ void SetConfigurationComplete(bool success, const ResultCallback& callback);
+ void ClaimInterfaceOnBlockingThread(PlatformUsbDeviceHandle handle,
+ int interface_number,
+ const ResultCallback& callback);
+ void ClaimInterfaceComplete(int interface_number,
+ bool success,
+ const ResultCallback& callback);
+ void SetInterfaceAlternateSettingOnBlockingThread(
+ PlatformUsbDeviceHandle handle,
+ int interface_number,
+ int alternate_setting,
+ const ResultCallback& callback);
+ void SetInterfaceAlternateSettingComplete(int interface_number,
+ int alternate_setting,
+ bool success,
+ const ResultCallback& callback);
+ void ResetDeviceOnBlockingThread(PlatformUsbDeviceHandle handle,
+ const ResultCallback& callback);
+ void ResetDeviceComplete(bool success, const ResultCallback& callback);
+
// Refresh endpoint_map_ after ClaimInterface, ReleaseInterface and
// SetInterfaceAlternateSetting.
void RefreshEndpointMap();
@@ -106,22 +134,56 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
scoped_refptr<InterfaceClaimer> GetClaimedInterfaceForEndpoint(
unsigned char endpoint);
- // If the device's task runner is on the current thread then the transfer will
- // be submitted directly, otherwise a task to do so it posted. The callback
- // will be called on the current message loop of the thread where this
- // function was called.
- void PostOrSubmitTransfer(scoped_ptr<Transfer> transfer);
+ void ControlTransferInternal(
+ UsbEndpointDirection direction,
+ TransferRequestType request_type,
+ TransferRecipient recipient,
+ uint8 request,
+ uint16 value,
+ uint16 index,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int timeout,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback);
+
+ void BulkTransferInternal(
+ UsbEndpointDirection direction,
+ uint8 endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int timeout,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback);
+
+ void InterruptTransferInternal(
+ UsbEndpointDirection direction,
+ uint8 endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int timeout,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback);
+
+ void IsochronousTransferInternal(
+ UsbEndpointDirection direction,
+ uint8 endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length,
+ unsigned int packets,
+ unsigned int packet_length,
+ unsigned int timeout,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const TransferCallback& callback);
// Submits a transfer and starts tracking it. Retains the buffer and copies
// the completion callback until the transfer finishes, whereupon it invokes
// the callback then releases the buffer.
void SubmitTransfer(scoped_ptr<Transfer> transfer);
- // Invokes the callbacks associated with a given transfer, and removes it from
- // the in-flight transfer set.
- void CompleteTransfer(scoped_ptr<Transfer> transfer);
-
- bool GetSupportedLanguages();
+ // Removes the transfer from the in-flight transfer set and invokes the
+ // completion callback.
+ void TransferComplete(Transfer* transfer, const base::Closure& callback);
// Informs the object to drop internal references.
void InternalClose();
@@ -130,9 +192,6 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
PlatformUsbDeviceHandle handle_;
- std::vector<uint16> languages_;
- std::map<uint8, base::string16> strings_;
-
typedef std::map<int, scoped_refptr<InterfaceClaimer>> ClaimedInterfaceMap;
ClaimedInterfaceMap claimed_interfaces_;
@@ -148,9 +207,9 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
scoped_refptr<UsbContext> context_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
base::ThreadChecker thread_checker_;
- base::WeakPtrFactory<UsbDeviceHandleImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(UsbDeviceHandleImpl);
};
diff --git a/device/usb/usb_device_handle_unittest.cc b/device/usb/usb_device_handle_unittest.cc
index 4cb4dff..4d5586e 100644
--- a/device/usb/usb_device_handle_unittest.cc
+++ b/device/usb/usb_device_handle_unittest.cc
@@ -6,6 +6,7 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_io_thread.h"
#include "device/test/usb_test_gadget.h"
#include "device/usb/usb_device.h"
#include "device/usb/usb_device_handle.h"
@@ -18,35 +19,63 @@ namespace {
class UsbDeviceHandleTest : public ::testing::Test {
public:
void SetUp() override {
- if (!UsbTestGadget::IsTestEnabled()) {
- return;
- }
+ message_loop_.reset(new base::MessageLoopForUI);
+ io_thread_.reset(new base::TestIOThread(base::TestIOThread::kAutoStart));
+ }
- message_loop_.reset(new base::MessageLoopForIO);
+ protected:
+ scoped_ptr<base::TestIOThread> io_thread_;
- gadget_ = UsbTestGadget::Claim();
- ASSERT_TRUE(gadget_.get());
+ private:
+ scoped_ptr<base::MessageLoop> message_loop_;
+};
- ASSERT_TRUE(gadget_->SetType(UsbTestGadget::ECHO));
+class TestOpenCallback {
+ public:
+ TestOpenCallback()
+ : callback_(
+ base::Bind(&TestOpenCallback::SetResult, base::Unretained(this))) {}
- handle_ = gadget_->GetDevice()->Open();
- ASSERT_TRUE(handle_.get());
+ scoped_refptr<UsbDeviceHandle> WaitForResult() {
+ run_loop_.Run();
+ return device_handle_;
}
- void TearDown() override {
- if (handle_.get()) {
- handle_->Close();
- }
- gadget_.reset(NULL);
- message_loop_.reset(NULL);
+ const UsbDevice::OpenCallback& callback() const { return callback_; }
+
+ private:
+ void SetResult(scoped_refptr<UsbDeviceHandle> device_handle) {
+ device_handle_ = device_handle;
+ run_loop_.Quit();
}
- protected:
- scoped_refptr<UsbDeviceHandle> handle_;
+ const UsbDevice::OpenCallback callback_;
+ base::RunLoop run_loop_;
+ scoped_refptr<UsbDeviceHandle> device_handle_;
+};
+
+class TestResultCallback {
+ public:
+ TestResultCallback()
+ : callback_(base::Bind(&TestResultCallback::SetResult,
+ base::Unretained(this))) {}
+
+ bool WaitForResult() {
+ run_loop_.Run();
+ return success_;
+ }
+
+ const UsbDeviceHandle::ResultCallback& callback() const { return callback_; }
private:
- scoped_ptr<UsbTestGadget> gadget_;
- scoped_ptr<base::MessageLoop> message_loop_;
+ void SetResult(bool success) {
+ success_ = success;
+ run_loop_.Quit();
+ }
+
+ const UsbDeviceHandle::ResultCallback callback_;
+ base::RunLoop run_loop_;
+ bool success_;
};
class TestCompletionCallback {
@@ -55,6 +84,15 @@ class TestCompletionCallback {
: callback_(base::Bind(&TestCompletionCallback::SetResult,
base::Unretained(this))) {}
+ void WaitForResult() { run_loop_.Run(); }
+
+ const UsbDeviceHandle::TransferCallback& callback() const {
+ return callback_;
+ }
+ UsbTransferStatus status() const { return status_; }
+ size_t transferred() const { return transferred_; }
+
+ private:
void SetResult(UsbTransferStatus status,
scoped_refptr<net::IOBuffer> buffer,
size_t transferred) {
@@ -63,34 +101,37 @@ class TestCompletionCallback {
run_loop_.Quit();
}
- void WaitForResult() { run_loop_.Run(); }
-
- const UsbTransferCallback& callback() const { return callback_; }
- UsbTransferStatus status() const { return status_; }
- size_t transferred() const { return transferred_; }
-
- private:
- const UsbTransferCallback callback_;
+ const UsbDeviceHandle::TransferCallback callback_;
base::RunLoop run_loop_;
UsbTransferStatus status_;
size_t transferred_;
};
TEST_F(UsbDeviceHandleTest, InterruptTransfer) {
- if (!handle_.get()) {
+ if (!UsbTestGadget::IsTestEnabled()) {
return;
}
- ASSERT_TRUE(handle_->ClaimInterface(0));
+ scoped_ptr<UsbTestGadget> gadget =
+ UsbTestGadget::Claim(io_thread_->task_runner());
+ ASSERT_TRUE(gadget.get());
+ ASSERT_TRUE(gadget->SetType(UsbTestGadget::ECHO));
+
+ TestOpenCallback open_device;
+ gadget->GetDevice()->Open(open_device.callback());
+ scoped_refptr<UsbDeviceHandle> handle = open_device.WaitForResult();
+ ASSERT_TRUE(handle.get());
+
+ TestResultCallback claim_interface;
+ handle->ClaimInterface(0, claim_interface.callback());
+ ASSERT_TRUE(claim_interface.WaitForResult());
scoped_refptr<net::IOBufferWithSize> in_buffer(new net::IOBufferWithSize(64));
TestCompletionCallback in_completion;
- handle_->InterruptTransfer(USB_DIRECTION_INBOUND,
- 0x81,
- in_buffer.get(),
- in_buffer->size(),
- 5000, // 5 second timeout
- in_completion.callback());
+ handle->InterruptTransfer(USB_DIRECTION_INBOUND, 0x81, in_buffer.get(),
+ in_buffer->size(),
+ 5000, // 5 second timeout
+ in_completion.callback());
scoped_refptr<net::IOBufferWithSize> out_buffer(
new net::IOBufferWithSize(in_buffer->size()));
@@ -99,12 +140,10 @@ TEST_F(UsbDeviceHandleTest, InterruptTransfer) {
out_buffer->data()[i] = i;
}
- handle_->InterruptTransfer(USB_DIRECTION_OUTBOUND,
- 0x01,
- out_buffer.get(),
- out_buffer->size(),
- 5000, // 5 second timeout
- out_completion.callback());
+ handle->InterruptTransfer(USB_DIRECTION_OUTBOUND, 0x01, out_buffer.get(),
+ out_buffer->size(),
+ 5000, // 5 second timeout
+ out_completion.callback());
out_completion.WaitForResult();
ASSERT_EQ(USB_TRANSFER_COMPLETED, out_completion.status());
EXPECT_EQ(static_cast<size_t>(out_buffer->size()),
@@ -117,22 +156,36 @@ TEST_F(UsbDeviceHandleTest, InterruptTransfer) {
for (size_t i = 0; i < in_completion.transferred(); ++i) {
EXPECT_EQ(out_buffer->data()[i], in_buffer->data()[i]);
}
+
+ handle->Close();
}
TEST_F(UsbDeviceHandleTest, BulkTransfer) {
- if (!handle_.get()) {
+ if (!UsbTestGadget::IsTestEnabled()) {
return;
}
- ASSERT_TRUE(handle_->ClaimInterface(1));
+ scoped_ptr<UsbTestGadget> gadget =
+ UsbTestGadget::Claim(io_thread_->task_runner());
+ ASSERT_TRUE(gadget.get());
+ ASSERT_TRUE(gadget->SetType(UsbTestGadget::ECHO));
+
+ TestOpenCallback open_device;
+ gadget->GetDevice()->Open(open_device.callback());
+ scoped_refptr<UsbDeviceHandle> handle = open_device.WaitForResult();
+ ASSERT_TRUE(handle.get());
+
+ TestResultCallback claim_interface;
+ handle->ClaimInterface(1, claim_interface.callback());
+ ASSERT_TRUE(claim_interface.WaitForResult());
scoped_refptr<net::IOBufferWithSize> in_buffer(
new net::IOBufferWithSize(512));
TestCompletionCallback in_completion;
- handle_->BulkTransfer(USB_DIRECTION_INBOUND, 0x82, in_buffer.get(),
- in_buffer->size(),
- 5000, // 5 second timeout
- in_completion.callback());
+ handle->BulkTransfer(USB_DIRECTION_INBOUND, 0x82, in_buffer.get(),
+ in_buffer->size(),
+ 5000, // 5 second timeout
+ in_completion.callback());
scoped_refptr<net::IOBufferWithSize> out_buffer(
new net::IOBufferWithSize(in_buffer->size()));
@@ -141,10 +194,10 @@ TEST_F(UsbDeviceHandleTest, BulkTransfer) {
out_buffer->data()[i] = i;
}
- handle_->BulkTransfer(USB_DIRECTION_OUTBOUND, 0x02, out_buffer.get(),
- out_buffer->size(),
- 5000, // 5 second timeout
- out_completion.callback());
+ handle->BulkTransfer(USB_DIRECTION_OUTBOUND, 0x02, out_buffer.get(),
+ out_buffer->size(),
+ 5000, // 5 second timeout
+ out_completion.callback());
out_completion.WaitForResult();
ASSERT_EQ(USB_TRANSFER_COMPLETED, out_completion.status());
EXPECT_EQ(static_cast<size_t>(out_buffer->size()),
@@ -157,6 +210,8 @@ TEST_F(UsbDeviceHandleTest, BulkTransfer) {
for (size_t i = 0; i < in_completion.transferred(); ++i) {
EXPECT_EQ(out_buffer->data()[i], in_buffer->data()[i]);
}
+
+ handle->Close();
}
} // namespace
diff --git a/device/usb/usb_device_impl.cc b/device/usb/usb_device_impl.cc
index 02ceb6f..f04092f 100644
--- a/device/usb/usb_device_impl.cc
+++ b/device/usb/usb_device_impl.cc
@@ -8,10 +8,9 @@
#include "base/bind.h"
#include "base/location.h"
+#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
#include "base/thread_task_runner_handle.h"
#include "components/device_event_log/device_event_log.h"
#include "device/usb/usb_context.h"
@@ -25,25 +24,10 @@
#include "chromeos/dbus/permission_broker_client.h"
#endif // defined(OS_CHROMEOS)
-#if defined(USE_UDEV)
-#include "device/udev_linux/scoped_udev.h"
-#endif // defined(USE_UDEV)
-
namespace device {
namespace {
-#if defined(OS_CHROMEOS)
-
-void PostResultOnTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- const base::Callback<void(bool success)>& callback,
- bool success) {
- task_runner->PostTask(FROM_HERE, base::Bind(callback, success));
-}
-
-#endif // defined(OS_CHROMEOS)
-
UsbEndpointDirection GetDirection(
const libusb_endpoint_descriptor* descriptor) {
switch (descriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) {
@@ -108,69 +92,27 @@ UsbUsageType GetUsageType(const libusb_endpoint_descriptor* descriptor) {
UsbDeviceImpl::UsbDeviceImpl(
scoped_refptr<UsbContext> context,
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
PlatformUsbDevice platform_device,
uint16 vendor_id,
uint16 product_id,
- uint32 unique_id)
- : UsbDevice(vendor_id, product_id, unique_id),
+ uint32 unique_id,
+ const base::string16& manufacturer_string,
+ const base::string16& product_string,
+ const base::string16& serial_number,
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
+ : UsbDevice(vendor_id,
+ product_id,
+ unique_id,
+ manufacturer_string,
+ product_string,
+ serial_number),
platform_device_(platform_device),
context_(context),
- ui_task_runner_(ui_task_runner) {
+ task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ blocking_task_runner_(blocking_task_runner) {
CHECK(platform_device) << "platform_device cannot be NULL";
libusb_ref_device(platform_device);
RefreshConfiguration();
-#if defined(USE_UDEV)
- ScopedUdevPtr udev(udev_new());
- ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev.get()));
-
- udev_enumerate_add_match_subsystem(enumerate.get(), "usb");
- if (udev_enumerate_scan_devices(enumerate.get()) != 0) {
- return;
- }
- std::string bus_number =
- base::IntToString(libusb_get_bus_number(platform_device));
- std::string device_address =
- base::IntToString(libusb_get_device_address(platform_device));
- udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
- for (udev_list_entry* i = devices; i != NULL;
- i = udev_list_entry_get_next(i)) {
- ScopedUdevDevicePtr device(
- udev_device_new_from_syspath(udev.get(), udev_list_entry_get_name(i)));
- if (device) {
- const char* value = udev_device_get_sysattr_value(device.get(), "busnum");
- if (!value || bus_number != value) {
- continue;
- }
- value = udev_device_get_sysattr_value(device.get(), "devnum");
- if (!value || device_address != value) {
- continue;
- }
-
-#if defined(OS_CHROMEOS)
- value = udev_device_get_devnode(device.get());
- if (value) {
- devnode_ = value;
- }
-#endif
- value = udev_device_get_sysattr_value(device.get(), "manufacturer");
- if (value) {
- manufacturer_ = base::UTF8ToUTF16(value);
- }
- value = udev_device_get_sysattr_value(device.get(), "product");
- if (value) {
- product_ = base::UTF8ToUTF16(value);
- }
- value = udev_device_get_sysattr_value(device.get(), "serial");
- if (value) {
- serial_number_ = base::UTF8ToUTF16(value);
- }
- break;
- }
- }
-#else
- strings_cached_ = false;
-#endif
}
UsbDeviceImpl::~UsbDeviceImpl() {
@@ -182,51 +124,28 @@ UsbDeviceImpl::~UsbDeviceImpl() {
void UsbDeviceImpl::CheckUsbAccess(const ResultCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
-
chromeos::PermissionBrokerClient* client =
chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
DCHECK(client) << "Could not get permission broker client.";
-
- ui_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&chromeos::PermissionBrokerClient::CheckPathAccess,
- base::Unretained(client), devnode_,
- base::Bind(&PostResultOnTaskRunner,
- base::ThreadTaskRunnerHandle::Get(), callback)));
+ client->CheckPathAccess(devnode_, callback);
}
void UsbDeviceImpl::RequestUsbAccess(int interface_id,
const ResultCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
-
chromeos::PermissionBrokerClient* client =
chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
DCHECK(client) << "Could not get permission broker client.";
-
- ui_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&chromeos::PermissionBrokerClient::RequestPathAccess,
- base::Unretained(client), devnode_, interface_id,
- base::Bind(&PostResultOnTaskRunner,
- base::ThreadTaskRunnerHandle::Get(), callback)));
+ client->RequestPathAccess(devnode_, interface_id, callback);
}
#endif
-scoped_refptr<UsbDeviceHandle> UsbDeviceImpl::Open() {
+void UsbDeviceImpl::Open(const OpenCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- PlatformUsbDeviceHandle handle;
- const int rv = libusb_open(platform_device_, &handle);
- if (LIBUSB_SUCCESS == rv) {
- scoped_refptr<UsbDeviceHandleImpl> device_handle =
- new UsbDeviceHandleImpl(context_, this, handle);
- handles_.push_back(device_handle);
- return device_handle;
- } else {
- USB_LOG(EVENT) << "Failed to open device: "
- << ConvertPlatformUsbErrorToString(rv);
- return NULL;
- }
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbDeviceImpl::OpenOnBlockingThread, this, callback));
}
bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) {
@@ -248,45 +167,6 @@ const UsbConfigDescriptor* UsbDeviceImpl::GetConfiguration() {
return configuration_.get();
}
-bool UsbDeviceImpl::GetManufacturer(base::string16* manufacturer) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
-#if !defined(USE_UDEV)
- if (!strings_cached_) {
- CacheStrings();
- }
-#endif
-
- *manufacturer = manufacturer_;
- return !manufacturer_.empty();
-}
-
-bool UsbDeviceImpl::GetProduct(base::string16* product) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
-#if !defined(USE_UDEV)
- if (!strings_cached_) {
- CacheStrings();
- }
-#endif
-
- *product = product_;
- return !product_.empty();
-}
-
-bool UsbDeviceImpl::GetSerialNumber(base::string16* serial_number) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
-#if !defined(USE_UDEV)
- if (!strings_cached_) {
- CacheStrings();
- }
-#endif
-
- *serial_number = serial_number_;
- return !serial_number_.empty();
-}
-
void UsbDeviceImpl::OnDisconnect() {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -365,35 +245,26 @@ void UsbDeviceImpl::RefreshConfiguration() {
libusb_free_config_descriptor(platform_config);
}
-#if !defined(USE_UDEV)
-void UsbDeviceImpl::CacheStrings() {
- DCHECK(thread_checker_.CalledOnValidThread());
- // This is a non-blocking call as libusb has the descriptor in memory.
- libusb_device_descriptor desc;
- const int rv = libusb_get_device_descriptor(platform_device_, &desc);
- if (rv == LIBUSB_SUCCESS) {
- scoped_refptr<UsbDeviceHandle> device_handle = Open();
- if (device_handle.get()) {
- if (desc.iManufacturer != 0) {
- device_handle->GetStringDescriptor(desc.iManufacturer, &manufacturer_);
- }
- if (desc.iProduct != 0) {
- device_handle->GetStringDescriptor(desc.iProduct, &product_);
- }
- if (desc.iSerialNumber != 0) {
- device_handle->GetStringDescriptor(desc.iSerialNumber, &serial_number_);
- }
- device_handle->Close();
- } else {
- USB_LOG(EVENT) << "Failed to open device to cache string descriptors.";
- }
+void UsbDeviceImpl::OpenOnBlockingThread(const OpenCallback& callback) {
+ PlatformUsbDeviceHandle handle;
+ const int rv = libusb_open(platform_device_, &handle);
+ if (LIBUSB_SUCCESS == rv) {
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UsbDeviceImpl::Opened, this, handle, callback));
} else {
- USB_LOG(EVENT)
- << "Failed to read device descriptor to cache string descriptors: "
- << ConvertPlatformUsbErrorToString(rv);
+ USB_LOG(EVENT) << "Failed to open device: "
+ << ConvertPlatformUsbErrorToString(rv);
+ task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
}
- strings_cached_ = true;
}
-#endif // !defined(USE_UDEV)
+
+void UsbDeviceImpl::Opened(PlatformUsbDeviceHandle platform_handle,
+ const OpenCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ scoped_refptr<UsbDeviceHandleImpl> device_handle = new UsbDeviceHandleImpl(
+ context_, this, platform_handle, blocking_task_runner_);
+ handles_.push_back(device_handle);
+ callback.Run(device_handle);
+}
} // namespace device
diff --git a/device/usb/usb_device_impl.h b/device/usb/usb_device_impl.h
index 897b4910..a865ea2 100644
--- a/device/usb/usb_device_impl.h
+++ b/device/usb/usb_device_impl.h
@@ -15,9 +15,10 @@
struct libusb_device;
struct libusb_config_descriptor;
+struct libusb_device_handle;
namespace base {
-class SingleThreadTaskRunner;
+class SequencedTaskRunner;
}
namespace device {
@@ -25,8 +26,9 @@ namespace device {
class UsbDeviceHandleImpl;
class UsbContext;
-typedef libusb_device* PlatformUsbDevice;
-typedef libusb_config_descriptor* PlatformUsbConfigDescriptor;
+typedef struct libusb_device* PlatformUsbDevice;
+typedef struct libusb_config_descriptor* PlatformUsbConfigDescriptor;
+typedef struct libusb_device_handle* PlatformUsbDeviceHandle;
class UsbDeviceImpl : public UsbDevice {
public:
@@ -37,12 +39,9 @@ class UsbDeviceImpl : public UsbDevice {
void RequestUsbAccess(int interface_id,
const ResultCallback& callback) override;
#endif // OS_CHROMEOS
- scoped_refptr<UsbDeviceHandle> Open() override;
+ void Open(const OpenCallback& callback) override;
bool Close(scoped_refptr<UsbDeviceHandle> handle) override;
const UsbConfigDescriptor* GetConfiguration() override;
- bool GetManufacturer(base::string16* manufacturer) override;
- bool GetProduct(base::string16* product) override;
- bool GetSerialNumber(base::string16* serial_number) override;
protected:
friend class UsbServiceImpl;
@@ -50,37 +49,35 @@ class UsbDeviceImpl : public UsbDevice {
// Called by UsbServiceImpl only;
UsbDeviceImpl(scoped_refptr<UsbContext> context,
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
PlatformUsbDevice platform_device,
uint16 vendor_id,
uint16 product_id,
- uint32 unique_id);
+ uint32 unique_id,
+ const base::string16& manufacturer_string,
+ const base::string16& product_string,
+ const base::string16& serial_number,
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
~UsbDeviceImpl() override;
// Called only by UsbServiceImpl.
+ PlatformUsbDevice platform_device() const { return platform_device_; }
+ void set_visited(bool visited) { visited_ = visited; }
+ bool was_visited() const { return visited_; }
void OnDisconnect();
// Called by UsbDeviceHandleImpl.
void RefreshConfiguration();
private:
+ void OpenOnBlockingThread(const OpenCallback& callback);
+ void Opened(PlatformUsbDeviceHandle platform_handle,
+ const OpenCallback& callback);
+
base::ThreadChecker thread_checker_;
PlatformUsbDevice platform_device_;
+ bool visited_ = false;
- // On Linux these properties are read from sysfs when the device is enumerated
- // to avoid hitting the permission broker on Chrome OS for a real string
- // descriptor request.
- base::string16 manufacturer_;
- base::string16 product_;
- base::string16 serial_number_;
-#if !defined(USE_UDEV)
- // On other platforms the device must be opened in order to cache them. This
- // should be delayed until the strings are needed to avoid poor interactions
- // with other applications.
- void CacheStrings();
- bool strings_cached_;
-#endif
#if defined(OS_CHROMEOS)
// On Chrome OS save the devnode string for requesting path access from
// permission broker.
@@ -98,8 +95,8 @@ class UsbDeviceImpl : public UsbDevice {
typedef std::vector<scoped_refptr<UsbDeviceHandleImpl> > HandlesVector;
HandlesVector handles_;
- // Reference to the UI thread for permission-broker calls.
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
DISALLOW_COPY_AND_ASSIGN(UsbDeviceImpl);
};
diff --git a/device/usb/usb_service.cc b/device/usb/usb_service.cc
index 10338fc..18732b5 100644
--- a/device/usb/usb_service.cc
+++ b/device/usb/usb_service.cc
@@ -17,28 +17,6 @@ UsbService* g_service;
} // namespace
-// This class manages the lifetime of the global UsbService instance so that
-// it is destroyed when the current message loop is destroyed. A lazy instance
-// cannot be used because this object does not live on the main thread.
-class UsbService::Destroyer : private base::MessageLoop::DestructionObserver {
- public:
- explicit Destroyer(UsbService* usb_service) : usb_service_(usb_service) {
- base::MessageLoop::current()->AddDestructionObserver(this);
- }
- ~Destroyer() override {}
-
- private:
- // base::MessageLoop::DestructionObserver implementation.
- void WillDestroyCurrentMessageLoop() override {
- base::MessageLoop::current()->RemoveDestructionObserver(this);
- delete usb_service_;
- delete this;
- g_service = nullptr;
- }
-
- UsbService* usb_service_;
-};
-
void UsbService::Observer::OnDeviceAdded(scoped_refptr<UsbDevice> device) {
}
@@ -51,25 +29,23 @@ void UsbService::Observer::OnDeviceRemovedCleanup(
// static
UsbService* UsbService::GetInstance(
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) {
if (!g_service) {
- g_service = UsbServiceImpl::Create(ui_task_runner);
- // This object will clean itself up when the message loop is destroyed.
- new Destroyer(g_service);
+ // UsbService constructor saves the pointer this returns and UsbServiceImpl
+ // will destroy itself when the current message loop exits.
+ UsbServiceImpl::Create(blocking_task_runner);
}
return g_service;
}
-// static
-void UsbService::SetInstanceForTest(UsbService* instance) {
- g_service = instance;
- new Destroyer(instance);
-}
-
UsbService::UsbService() {
+ DCHECK(!g_service);
+ g_service = this;
}
UsbService::~UsbService() {
+ DCHECK(g_service);
+ g_service = nullptr;
}
void UsbService::AddObserver(Observer* observer) {
@@ -85,18 +61,12 @@ void UsbService::RemoveObserver(Observer* observer) {
void UsbService::NotifyDeviceAdded(scoped_refptr<UsbDevice> device) {
DCHECK(CalledOnValidThread());
- USB_LOG(USER) << "USB device added: vendorId = " << device->vendor_id()
- << ", productId = " << device->product_id()
- << ", uniqueId = " << device->unique_id();
-
FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceAdded(device));
}
void UsbService::NotifyDeviceRemoved(scoped_refptr<UsbDevice> device) {
DCHECK(CalledOnValidThread());
- USB_LOG(USER) << "USB device removed: uniqueId = " << device->unique_id();
-
FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceRemoved(device));
FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceRemovedCleanup(device));
}
diff --git a/device/usb/usb_service.h b/device/usb/usb_service.h
index a2dfa9e..5dfe942 100644
--- a/device/usb/usb_service.h
+++ b/device/usb/usb_service.h
@@ -7,13 +7,14 @@
#include <vector>
+#include "base/bind_helpers.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/threading/non_thread_safe.h"
namespace base {
-class SingleThreadTaskRunner;
+class SequencedTaskRunner;
}
namespace device {
@@ -24,11 +25,11 @@ class UsbDevice;
// used to manage and dispatch USB events. It is also responsible for device
// discovery on the system, which allows it to re-use device handles to prevent
// competition for the same USB device.
-//
-// All functions on this object must be called from a thread with a
-// MessageLoopForIO (for example, BrowserThread::FILE).
class UsbService : public base::NonThreadSafe {
public:
+ using GetDevicesCallback =
+ base::Callback<void(const std::vector<scoped_refptr<UsbDevice>>&)>;
+
class Observer {
public:
// These events are delivered from the thread on which the UsbService object
@@ -40,19 +41,15 @@ class UsbService : public base::NonThreadSafe {
virtual void OnDeviceRemovedCleanup(scoped_refptr<UsbDevice> device);
};
- // The UI task runner reference is used to talk to the PermissionBrokerClient
- // on ChromeOS (UI thread). Returns NULL when initialization fails.
+ // The file task runner reference is used for blocking I/O operations.
+ // Returns NULL when initialization fails.
static UsbService* GetInstance(
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
-
- static void SetInstanceForTest(UsbService* instance);
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
virtual scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) = 0;
- // Get all of the devices attached to the system, inserting them into
- // |devices|. Clears |devices| before use. The result will be sorted by id
- // in increasing order.
- virtual void GetDevices(std::vector<scoped_refptr<UsbDevice> >* devices) = 0;
+ // Enumerates available devices.
+ virtual void GetDevices(const GetDevicesCallback& callback) = 0;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
@@ -67,7 +64,7 @@ class UsbService : public base::NonThreadSafe {
ObserverList<Observer, true> observer_list_;
private:
- class Destroyer;
+ friend void base::DeletePointer<UsbService>(UsbService* service);
DISALLOW_COPY_AND_ASSIGN(UsbService);
};
diff --git a/device/usb/usb_service_impl.cc b/device/usb/usb_service_impl.cc
index 6bdac2b..ce5b51a 100644
--- a/device/usb/usb_service_impl.cc
+++ b/device/usb/usb_service_impl.cc
@@ -4,6 +4,7 @@
#include "device/usb/usb_service_impl.h"
+#include <algorithm>
#include <set>
#include "base/bind.h"
@@ -11,25 +12,160 @@
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/thread_task_runner_handle.h"
#include "components/device_event_log/device_event_log.h"
#include "device/usb/usb_error.h"
+#include "third_party/libusb/src/libusb/libusb.h"
#if defined(OS_WIN)
#include <setupapi.h>
#include <usbiodef.h>
-#include "base/scoped_observer.h"
#include "base/strings/string_util.h"
-#include "device/core/device_monitor_win.h"
#endif // OS_WIN
-namespace device {
+#if defined(USE_UDEV)
+#include "device/udev_linux/scoped_udev.h"
+#endif // USE_UDEV
-#if defined(OS_WIN)
+namespace device {
namespace {
+#if defined(USE_UDEV)
+
+void ReadDeviceStrings(PlatformUsbDevice platform_device,
+ libusb_device_descriptor* descriptor,
+ base::string16* manufacturer_string,
+ base::string16* product_string,
+ base::string16* serial_number,
+ std::string* device_node) {
+ ScopedUdevPtr udev(udev_new());
+ ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev.get()));
+
+ udev_enumerate_add_match_subsystem(enumerate.get(), "usb");
+ if (udev_enumerate_scan_devices(enumerate.get()) != 0) {
+ return;
+ }
+ std::string bus_number =
+ base::IntToString(libusb_get_bus_number(platform_device));
+ std::string device_address =
+ base::IntToString(libusb_get_device_address(platform_device));
+ udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
+ for (udev_list_entry* i = devices; i != NULL;
+ i = udev_list_entry_get_next(i)) {
+ ScopedUdevDevicePtr device(
+ udev_device_new_from_syspath(udev.get(), udev_list_entry_get_name(i)));
+ if (device) {
+ const char* value = udev_device_get_sysattr_value(device.get(), "busnum");
+ if (!value || bus_number != value) {
+ continue;
+ }
+ value = udev_device_get_sysattr_value(device.get(), "devnum");
+ if (!value || device_address != value) {
+ continue;
+ }
+
+ value = udev_device_get_devnode(device.get());
+ if (value) {
+ *device_node = value;
+ }
+ value = udev_device_get_sysattr_value(device.get(), "manufacturer");
+ if (value) {
+ *manufacturer_string = base::UTF8ToUTF16(value);
+ }
+ value = udev_device_get_sysattr_value(device.get(), "product");
+ if (value) {
+ *product_string = base::UTF8ToUTF16(value);
+ }
+ value = udev_device_get_sysattr_value(device.get(), "serial");
+ if (value) {
+ *serial_number = base::UTF8ToUTF16(value);
+ }
+ break;
+ }
+ }
+}
+
+#else
+
+uint16 ReadDeviceLanguage(PlatformUsbDeviceHandle handle) {
+ uint16 language_id = 0x0409;
+ uint8 buffer[256];
+ int size =
+ libusb_get_string_descriptor(handle, 0, 0, &buffer[0], sizeof(buffer));
+ if (size < 0) {
+ USB_LOG(EVENT) << "Failed to get supported string languages: "
+ << ConvertPlatformUsbErrorToString(size);
+ } else if (size >= 4) {
+ // Just pick the first supported language.
+ language_id = buffer[2] | (buffer[3] << 8);
+ } else {
+ USB_LOG(EVENT) << "List of available string languages invalid.";
+ }
+
+ return language_id;
+}
+
+void ReadDeviceString(PlatformUsbDeviceHandle handle,
+ uint8 string_id,
+ uint16 language_id,
+ base::string16* string) {
+ if (string_id == 0) {
+ return;
+ }
+
+ uint8 buffer[256];
+ int size = libusb_get_string_descriptor(handle, string_id, language_id,
+ &buffer[0], sizeof(buffer));
+ if (size < 0) {
+ USB_LOG(EVENT) << "Failed to read string " << (int)string_id
+ << " from the device: "
+ << ConvertPlatformUsbErrorToString(size);
+ } else if (size > 2) {
+ *string = base::string16(reinterpret_cast<base::char16*>(&buffer[2]),
+ size / 2 - 1);
+ } else {
+ USB_LOG(EVENT) << "String descriptor " << string_id << " is invalid.";
+ }
+}
+
+void ReadDeviceStrings(PlatformUsbDevice platform_device,
+ libusb_device_descriptor* descriptor,
+ base::string16* manufacturer_string,
+ base::string16* product_string,
+ base::string16* serial_number,
+ std::string* device_node) {
+ if (descriptor->iManufacturer == 0 && descriptor->iProduct == 0 &&
+ descriptor->iSerialNumber == 0) {
+ // Don't bother distrubing the device if it doesn't have any string
+ // descriptors we care about.
+ return;
+ }
+
+ PlatformUsbDeviceHandle handle;
+ int rv = libusb_open(platform_device, &handle);
+ if (rv != LIBUSB_SUCCESS) {
+ USB_LOG(EVENT) << "Failed to open device to read string descriptors: "
+ << ConvertPlatformUsbErrorToString(rv);
+ return;
+ }
+
+ uint16 language_id = ReadDeviceLanguage(handle);
+ ReadDeviceString(handle, descriptor->iManufacturer, language_id,
+ manufacturer_string);
+ ReadDeviceString(handle, descriptor->iProduct, language_id, product_string);
+ ReadDeviceString(handle, descriptor->iSerialNumber, language_id,
+ serial_number);
+ libusb_close(handle);
+}
+
+#endif // USE_UDEV
+
+#if defined(OS_WIN)
+
// Wrapper around a HDEVINFO that automatically destroys it.
class ScopedDeviceInfoList {
public:
@@ -81,62 +217,57 @@ class ScopedDeviceInfo {
SP_DEVINFO_DATA dev_info_data_;
};
-} // namespace
-
-// This class lives on the application main thread so that it can listen for
-// device change notification window messages. It registers for notifications
-// that may indicate new devices that the UsbService will enumerate.
-class UsbServiceImpl::UIThreadHelper final
- : private DeviceMonitorWin::Observer {
- public:
- UIThreadHelper(base::WeakPtr<UsbServiceImpl> usb_service)
- : task_runner_(base::ThreadTaskRunnerHandle::Get()),
- usb_service_(usb_service),
- device_observer_(this) {}
-
- ~UIThreadHelper() {}
+bool IsWinUsbInterface(const std::string& device_path) {
+ ScopedDeviceInfoList dev_info_list(SetupDiCreateDeviceInfoList(NULL, NULL));
+ if (!dev_info_list.valid()) {
+ USB_PLOG(ERROR) << "Failed to create a device information set";
+ return false;
+ }
- void Start() {
- DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces();
- if (device_monitor) {
- device_observer_.Add(device_monitor);
- }
+ // This will add the device to |dev_info_list| so we can query driver info.
+ if (!SetupDiOpenDeviceInterfaceA(dev_info_list.get(), device_path.c_str(), 0,
+ NULL)) {
+ USB_PLOG(ERROR) << "Failed to get device interface data for "
+ << device_path;
+ return false;
}
- private:
- void OnDeviceAdded(const GUID& class_guid,
- const std::string& device_path) override {
- // Only the root node of a composite USB device has the class GUID
- // GUID_DEVINTERFACE_USB_DEVICE but we want to wait until WinUSB is loaded.
- // This first pass filter will catch anything that's sitting on the USB bus
- // (including devices on 3rd party USB controllers) to avoid the more
- // expensive driver check that needs to be done on the FILE thread.
- if (device_path.find("usb") != std::string::npos) {
- task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevicesIfWinUsbDevice,
- usb_service_, device_path));
- }
+ ScopedDeviceInfo dev_info;
+ if (!SetupDiEnumDeviceInfo(dev_info_list.get(), 0, dev_info.get())) {
+ USB_PLOG(ERROR) << "Failed to get device info for " << device_path;
+ return false;
}
+ dev_info.set_valid(dev_info_list.get());
- void OnDeviceRemoved(const GUID& class_guid,
- const std::string& device_path) override {
- // The root USB device node is removed last
- if (class_guid == GUID_DEVINTERFACE_USB_DEVICE) {
- task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevices, usb_service_));
- }
+ DWORD reg_data_type;
+ BYTE buffer[256];
+ if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list.get(), dev_info.get(),
+ SPDRP_SERVICE, &reg_data_type,
+ &buffer[0], sizeof buffer, NULL)) {
+ USB_PLOG(ERROR) << "Failed to get device service property";
+ return false;
+ }
+ if (reg_data_type != REG_SZ) {
+ USB_LOG(ERROR) << "Unexpected data type for driver service: "
+ << reg_data_type;
+ return false;
}
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- base::WeakPtr<UsbServiceImpl> usb_service_;
- ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_;
-};
+ USB_LOG(DEBUG) << "Driver for " << device_path << " is " << buffer << ".";
+ if (base::strncasecmp("WinUSB", (const char*)&buffer[0], sizeof "WinUSB") ==
+ 0) {
+ return true;
+ }
+ return false;
+}
#endif // OS_WIN
+} // namespace
+
// static
UsbService* UsbServiceImpl::Create(
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) {
PlatformUsbContext context = NULL;
const int rv = libusb_init(&context);
if (rv != LIBUSB_SUCCESS) {
@@ -148,42 +279,21 @@ UsbService* UsbServiceImpl::Create(
return nullptr;
}
- return new UsbServiceImpl(context, ui_task_runner);
-}
-
-scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) {
- DCHECK(CalledOnValidThread());
- RefreshDevices();
- DeviceMap::iterator it = devices_.find(unique_id);
- if (it != devices_.end()) {
- return it->second;
- }
- return NULL;
-}
-
-void UsbServiceImpl::GetDevices(
- std::vector<scoped_refptr<UsbDevice> >* devices) {
- DCHECK(CalledOnValidThread());
- STLClearObject(devices);
-
- if (!hotplug_enabled_) {
- RefreshDevices();
- }
-
- for (const auto& map_entry : devices_) {
- devices->push_back(map_entry.second);
- }
+ return new UsbServiceImpl(context, blocking_task_runner);
}
UsbServiceImpl::UsbServiceImpl(
PlatformUsbContext context,
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
: context_(new UsbContext(context)),
- ui_task_runner_(ui_task_runner),
- next_unique_id_(0),
- hotplug_enabled_(false),
+ task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ blocking_task_runner_(blocking_task_runner),
+#if defined(OS_WIN)
+ device_observer_(this),
+#endif
weak_factory_(this) {
- task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ base::MessageLoop::current()->AddDestructionObserver(this);
+
int rv = libusb_hotplug_register_callback(
context_->context(),
static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
@@ -193,149 +303,269 @@ UsbServiceImpl::UsbServiceImpl(
&UsbServiceImpl::HotplugCallback, this, &hotplug_handle_);
if (rv == LIBUSB_SUCCESS) {
hotplug_enabled_ = true;
+
+ // libusb will call the hotplug callback for each device currently
+ // enumerated. Once this is complete enumeration_ready_ can be set to true
+ // but we must first wait for any tasks posted to blocking_task_runner_ to
+ // complete.
+ blocking_task_runner_->PostTaskAndReply(
+ FROM_HERE, base::Bind(&base::DoNothing),
+ base::Bind(&UsbServiceImpl::RefreshDevicesComplete,
+ weak_factory_.GetWeakPtr(), nullptr, 0));
} else {
+ RefreshDevices("");
#if defined(OS_WIN)
- ui_thread_helper_ = new UIThreadHelper(weak_factory_.GetWeakPtr());
- ui_task_runner_->PostTask(FROM_HERE,
- base::Bind(&UIThreadHelper::Start,
- base::Unretained(ui_thread_helper_)));
+ DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces();
+ if (device_monitor) {
+ device_observer_.Add(device_monitor);
+ }
#endif // OS_WIN
}
}
UsbServiceImpl::~UsbServiceImpl() {
+ base::MessageLoop::current()->RemoveDestructionObserver(this);
+
if (hotplug_enabled_) {
libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_);
}
-#if defined(OS_WIN)
- if (ui_thread_helper_) {
- ui_task_runner_->DeleteSoon(FROM_HERE, ui_thread_helper_);
- }
-#endif // OS_WIN
for (const auto& map_entry : devices_) {
map_entry.second->OnDisconnect();
}
}
-void UsbServiceImpl::RefreshDevices() {
+scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) {
DCHECK(CalledOnValidThread());
-
- libusb_device** platform_devices = NULL;
- const ssize_t device_count =
- libusb_get_device_list(context_->context(), &platform_devices);
- if (device_count < 0) {
- USB_LOG(ERROR) << "Failed to get device list: "
- << ConvertPlatformUsbErrorToString(device_count);
+ DeviceMap::iterator it = devices_.find(unique_id);
+ if (it != devices_.end()) {
+ return it->second;
}
+ return NULL;
+}
- std::set<UsbDevice*> connected_devices;
- std::vector<PlatformUsbDevice> disconnected_devices;
+void UsbServiceImpl::GetDevices(const GetDevicesCallback& callback) {
+ DCHECK(CalledOnValidThread());
- // Populates new devices.
- for (ssize_t i = 0; i < device_count; ++i) {
- if (!ContainsKey(platform_devices_, platform_devices[i])) {
- scoped_refptr<UsbDeviceImpl> new_device = AddDevice(platform_devices[i]);
- if (new_device) {
- connected_devices.insert(new_device.get());
- }
- } else {
- connected_devices.insert(platform_devices_[platform_devices[i]].get());
+ if (!enumeration_ready_) {
+ // On startup wait for the first enumeration,
+ pending_enumerations_.push_back(callback);
+ } else if (hotplug_enabled_) {
+ // The device list is updated live when hotplug events are supported.
+ std::vector<scoped_refptr<UsbDevice>> devices;
+ for (const auto& map_entry : devices_) {
+ devices.push_back(map_entry.second);
+ }
+ callback.Run(devices);
+ } else {
+ // Only post one re-enumeration task at a time.
+ if (pending_enumerations_.empty()) {
+ RefreshDevices("");
}
+ pending_enumerations_.push_back(callback);
}
+}
- // Find disconnected devices.
- for (const auto& map_entry : platform_devices_) {
- PlatformUsbDevice platform_device = map_entry.first;
- scoped_refptr<UsbDeviceImpl> device = map_entry.second;
- if (!ContainsKey(connected_devices, device.get())) {
- disconnected_devices.push_back(platform_device);
- devices_.erase(device->unique_id());
-
- NotifyDeviceRemoved(device);
- device->OnDisconnect();
- }
+#if defined(OS_WIN)
+
+void UsbServiceImpl::OnDeviceAdded(const GUID& class_guid,
+ const std::string& device_path) {
+ // Only the root node of a composite USB device has the class GUID
+ // GUID_DEVINTERFACE_USB_DEVICE but we want to wait until WinUSB is loaded.
+ // This first pass filter will catch anything that's sitting on the USB bus
+ // (including devices on 3rd party USB controllers) to avoid the more
+ // expensive driver check that needs to be done on the FILE thread.
+ if (device_path.find("usb") != std::string::npos) {
+ RefreshDevices(device_path);
}
+}
- // Remove disconnected devices from platform_devices_.
- for (const PlatformUsbDevice& platform_device : disconnected_devices) {
- // UsbDevice will be destroyed after this. The corresponding
- // PlatformUsbDevice will be unref'ed during this process.
- platform_devices_.erase(platform_device);
+void UsbServiceImpl::OnDeviceRemoved(const GUID& class_guid,
+ const std::string& device_path) {
+ // The root USB device node is removed last
+ if (class_guid == GUID_DEVINTERFACE_USB_DEVICE) {
+ RefreshDevices("");
}
+}
- libusb_free_device_list(platform_devices, true);
+#endif // OS_WIN
+
+void UsbServiceImpl::WillDestroyCurrentMessageLoop() {
+ DCHECK(CalledOnValidThread());
+ delete this;
}
-#if defined(OS_WIN)
-void UsbServiceImpl::RefreshDevicesIfWinUsbDevice(
- const std::string& device_path) {
- ScopedDeviceInfoList dev_info_list(SetupDiCreateDeviceInfoList(NULL, NULL));
- if (!dev_info_list.valid()) {
- USB_PLOG(ERROR) << "Failed to create a device information set";
- return;
- }
+void UsbServiceImpl::RefreshDevices(const std::string& new_device_path) {
+ DCHECK(CalledOnValidThread());
- // This will add the device to |dev_info_list| so we can query driver info.
- if (!SetupDiOpenDeviceInterfaceA(dev_info_list.get(), device_path.c_str(), 0,
- NULL)) {
- USB_PLOG(ERROR) << "Failed to get device interface data for "
- << device_path;
- return;
+ std::set<PlatformUsbDevice> current_devices;
+ for (const auto& map_entry : platform_devices_) {
+ current_devices.insert(map_entry.first);
}
+ blocking_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevicesOnBlockingThread,
+ weak_factory_.GetWeakPtr(), new_device_path,
+ task_runner_, context_, current_devices));
+}
- ScopedDeviceInfo dev_info;
- if (!SetupDiEnumDeviceInfo(dev_info_list.get(), 0, dev_info.get())) {
- USB_PLOG(ERROR) << "Failed to get device info for " << device_path;
- return;
+// static
+void UsbServiceImpl::RefreshDevicesOnBlockingThread(
+ base::WeakPtr<UsbServiceImpl> usb_service,
+ const std::string& new_device_path,
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ scoped_refptr<UsbContext> usb_context,
+ const std::set<PlatformUsbDevice>& previous_devices) {
+ if (!new_device_path.empty()) {
+#if defined(OS_WIN)
+ if (!IsWinUsbInterface(new_device_path)) {
+ // Wait to call libusb_get_device_list until libusb will be able to find
+ // a WinUSB interface for the device.
+ return;
+ }
+#endif // defined(OS_WIN)
}
- dev_info.set_valid(dev_info_list.get());
- DWORD reg_data_type;
- BYTE buffer[256];
- if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list.get(), dev_info.get(),
- SPDRP_SERVICE, &reg_data_type,
- &buffer[0], sizeof buffer, NULL)) {
- USB_PLOG(ERROR) << "Failed to get device service property";
- return;
- }
- if (reg_data_type != REG_SZ) {
- USB_LOG(ERROR) << "Unexpected data type for driver service: "
- << reg_data_type;
+ libusb_device** platform_devices = NULL;
+ const ssize_t device_count =
+ libusb_get_device_list(usb_context->context(), &platform_devices);
+ if (device_count < 0) {
+ USB_LOG(ERROR) << "Failed to get device list: "
+ << ConvertPlatformUsbErrorToString(device_count);
+ task_runner->PostTask(FROM_HERE,
+ base::Bind(&UsbServiceImpl::RefreshDevicesComplete,
+ usb_service, nullptr, 0));
return;
}
- USB_LOG(DEBUG) << "Driver for " << device_path << " is " << buffer << ".";
- if (base::strncasecmp("WinUSB", (const char*)&buffer[0], sizeof "WinUSB") ==
- 0) {
- RefreshDevices();
+ // Find new devices.
+ for (ssize_t i = 0; i < device_count; ++i) {
+ PlatformUsbDevice platform_device = platform_devices[i];
+ if (previous_devices.find(platform_device) == previous_devices.end()) {
+ libusb_ref_device(platform_device);
+ AddDeviceOnBlockingThread(usb_service, task_runner, platform_device);
+ }
}
+
+ // |platform_devices| will be freed in this callback.
+ task_runner->PostTask(
+ FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevicesComplete,
+ usb_service, platform_devices, device_count));
}
-#endif // OS_WIN
-scoped_refptr<UsbDeviceImpl> UsbServiceImpl::AddDevice(
+// static
+void UsbServiceImpl::AddDeviceOnBlockingThread(
+ base::WeakPtr<UsbServiceImpl> usb_service,
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
PlatformUsbDevice platform_device) {
libusb_device_descriptor descriptor;
int rv = libusb_get_device_descriptor(platform_device, &descriptor);
if (rv == LIBUSB_SUCCESS) {
- uint32 unique_id;
- do {
- unique_id = ++next_unique_id_;
- } while (devices_.find(unique_id) != devices_.end());
-
- scoped_refptr<UsbDeviceImpl> new_device(new UsbDeviceImpl(
- context_, ui_task_runner_, platform_device, descriptor.idVendor,
- descriptor.idProduct, unique_id));
- platform_devices_[platform_device] = new_device;
- devices_[unique_id] = new_device;
- NotifyDeviceAdded(new_device);
- return new_device;
+ base::string16 manufacturer_string;
+ base::string16 product_string;
+ base::string16 serial_number;
+ std::string device_node;
+ ReadDeviceStrings(platform_device, &descriptor, &manufacturer_string,
+ &product_string, &serial_number, &device_node);
+
+ task_runner->PostTask(
+ FROM_HERE, base::Bind(&UsbServiceImpl::AddDevice, usb_service,
+ platform_device, descriptor.idVendor,
+ descriptor.idProduct, manufacturer_string,
+ product_string, serial_number, device_node));
} else {
USB_LOG(EVENT) << "Failed to get device descriptor: "
<< ConvertPlatformUsbErrorToString(rv);
- return nullptr;
+ libusb_unref_device(platform_device);
}
}
+void UsbServiceImpl::RefreshDevicesComplete(libusb_device** platform_devices,
+ ssize_t device_count) {
+ if (platform_devices) {
+ // Mark devices seen in this enumeration.
+ for (ssize_t i = 0; i < device_count; ++i) {
+ const PlatformDeviceMap::iterator it =
+ platform_devices_.find(platform_devices[i]);
+ if (it != platform_devices_.end()) {
+ it->second->set_visited(true);
+ }
+ }
+
+ // Remove devices not seen in this enumeration.
+ for (PlatformDeviceMap::iterator it = platform_devices_.begin();
+ it != platform_devices_.end();
+ /* incremented internally */) {
+ PlatformDeviceMap::iterator current = it++;
+ const scoped_refptr<UsbDeviceImpl>& device = current->second;
+ if (device->was_visited()) {
+ device->set_visited(false);
+ } else {
+ RemoveDevice(device);
+ }
+ }
+
+ libusb_free_device_list(platform_devices, true);
+ }
+
+ enumeration_ready_ = true;
+
+ if (!pending_enumerations_.empty()) {
+ std::vector<scoped_refptr<UsbDevice>> devices;
+ for (const auto& map_entry : devices_) {
+ devices.push_back(map_entry.second);
+ }
+
+ std::vector<GetDevicesCallback> pending_enumerations;
+ pending_enumerations.swap(pending_enumerations_);
+ for (const GetDevicesCallback& callback : pending_enumerations) {
+ callback.Run(devices);
+ }
+ }
+}
+
+void UsbServiceImpl::AddDevice(PlatformUsbDevice platform_device,
+ uint16 vendor_id,
+ uint16 product_id,
+ base::string16 manufacturer_string,
+ base::string16 product_string,
+ base::string16 serial_number,
+ std::string device_node) {
+ uint32 unique_id;
+ do {
+ unique_id = ++next_unique_id_;
+ } while (devices_.find(unique_id) != devices_.end());
+
+ scoped_refptr<UsbDeviceImpl> device(
+ new UsbDeviceImpl(context_, platform_device, vendor_id, product_id,
+ unique_id, manufacturer_string, product_string,
+ serial_number, blocking_task_runner_));
+
+ platform_devices_[platform_device] = device;
+ devices_[unique_id] = device;
+
+ USB_LOG(USER) << "USB device added: vendor=" << device->vendor_id() << " \""
+ << device->manufacturer_string()
+ << "\", product=" << device->product_id() << " \""
+ << device->product_string() << "\", serial=\""
+ << device->serial_number()
+ << "\", uniqueId=" << device->unique_id();
+
+ if (enumeration_ready_) {
+ NotifyDeviceAdded(device);
+ }
+
+ libusb_unref_device(platform_device);
+}
+
+void UsbServiceImpl::RemoveDevice(scoped_refptr<UsbDeviceImpl> device) {
+ platform_devices_.erase(device->platform_device());
+ devices_.erase(device->unique_id());
+
+ USB_LOG(USER) << "USB device removed: uniqueId=" << device->unique_id();
+
+ NotifyDeviceRemoved(device);
+ device->OnDisconnect();
+}
+
// static
int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context,
PlatformUsbDevice device,
@@ -348,22 +578,22 @@ int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context,
UsbServiceImpl* self = reinterpret_cast<UsbServiceImpl*>(user_data);
switch (event) {
case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
- libusb_ref_device(device); // Released in OnDeviceAdded.
+ libusb_ref_device(device); // Released in OnPlatformDeviceAdded.
if (self->task_runner_->BelongsToCurrentThread()) {
- self->OnDeviceAdded(device);
+ self->OnPlatformDeviceAdded(device);
} else {
self->task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbServiceImpl::OnDeviceAdded,
+ FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceAdded,
base::Unretained(self), device));
}
break;
case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
- libusb_ref_device(device); // Released in OnDeviceRemoved.
+ libusb_ref_device(device); // Released in OnPlatformDeviceRemoved.
if (self->task_runner_->BelongsToCurrentThread()) {
- self->OnDeviceRemoved(device);
+ self->OnPlatformDeviceRemoved(device);
} else {
self->task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbServiceImpl::OnDeviceRemoved,
+ FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceRemoved,
base::Unretained(self), device));
}
break;
@@ -374,30 +604,28 @@ int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context,
return 0;
}
-void UsbServiceImpl::OnDeviceAdded(PlatformUsbDevice platform_device) {
+void UsbServiceImpl::OnPlatformDeviceAdded(PlatformUsbDevice platform_device) {
DCHECK(CalledOnValidThread());
DCHECK(!ContainsKey(platform_devices_, platform_device));
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbServiceImpl::AddDeviceOnBlockingThread,
+ weak_factory_.GetWeakPtr(), task_runner_, platform_device));
- AddDevice(platform_device);
- libusb_unref_device(platform_device);
+ // libusb_unref_device(platform_device) is called by the task above.
}
-void UsbServiceImpl::OnDeviceRemoved(PlatformUsbDevice platform_device) {
+void UsbServiceImpl::OnPlatformDeviceRemoved(
+ PlatformUsbDevice platform_device) {
DCHECK(CalledOnValidThread());
-
PlatformDeviceMap::iterator it = platform_devices_.find(platform_device);
if (it != platform_devices_.end()) {
scoped_refptr<UsbDeviceImpl> device = it->second;
- DeviceMap::iterator dev_it = devices_.find(device->unique_id());
- if (dev_it != devices_.end()) {
- devices_.erase(dev_it);
- } else {
- NOTREACHED();
- }
- platform_devices_.erase(it);
-
- NotifyDeviceRemoved(device);
- device->OnDisconnect();
+ // Serialize with calls to AddDeviceOnBlockingThread.
+ blocking_task_runner_->PostTaskAndReply(
+ FROM_HERE, base::Bind(&base::DoNothing),
+ base::Bind(&UsbServiceImpl::RemoveDevice, weak_factory_.GetWeakPtr(),
+ device));
} else {
NOTREACHED();
}
diff --git a/device/usb/usb_service_impl.h b/device/usb/usb_service_impl.h
index 44fff41..e4c4443 100644
--- a/device/usb/usb_service_impl.h
+++ b/device/usb/usb_service_impl.h
@@ -5,42 +5,92 @@
#include "device/usb/usb_service.h"
#include <map>
+#include <set>
#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
+#include "base/message_loop/message_loop.h"
#include "device/usb/usb_context.h"
#include "device/usb/usb_device_impl.h"
#include "third_party/libusb/src/libusb/libusb.h"
+#if defined(OS_WIN)
+#include "base/scoped_observer.h"
+#include "device/core/device_monitor_win.h"
+#endif // OS_WIN
+
+struct libusb_device;
+struct libusb_context;
+
+namespace base {
+class SequencedTaskRunner;
+class SingleThreadTaskRunner;
+}
+
namespace device {
typedef struct libusb_device* PlatformUsbDevice;
typedef struct libusb_context* PlatformUsbContext;
-class UsbServiceImpl : public UsbService {
+class UsbServiceImpl : public UsbService,
+#if defined(OS_WIN)
+ public DeviceMonitorWin::Observer,
+#endif // OS_WIN
+ public base::MessageLoop::DestructionObserver {
public:
static UsbService* Create(
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
private:
explicit UsbServiceImpl(
PlatformUsbContext context,
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
~UsbServiceImpl() override;
// device::UsbService implementation
scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override;
- void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override;
-
- // Enumerate USB devices from OS and update devices_ map.
- void RefreshDevices();
+ void GetDevices(const GetDevicesCallback& callback) override;
#if defined(OS_WIN)
- void RefreshDevicesIfWinUsbDevice(const std::string& device_path);
+ // device::DeviceMonitorWin::Observer implementation
+ void OnDeviceAdded(const GUID& class_guid,
+ const std::string& device_path) override;
+ void OnDeviceRemoved(const GUID& class_guid,
+ const std::string& device_path) override;
#endif // OS_WIN
+ // base::MessageLoop::DestructionObserver implementation
+ void WillDestroyCurrentMessageLoop() override;
+
+ // Enumerate USB devices from OS and update devices_ map. |new_device_path| is
+ // an optional hint used on Windows to prevent enumerations before drivers for
+ // a new device have been completely loaded.
+ void RefreshDevices(const std::string& new_device_path);
+
+ static void RefreshDevicesOnBlockingThread(
+ base::WeakPtr<UsbServiceImpl> usb_service,
+ const std::string& new_device_path,
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ scoped_refptr<UsbContext> usb_context,
+ const std::set<PlatformUsbDevice>& previous_devices);
+
+ static void AddDeviceOnBlockingThread(
+ base::WeakPtr<UsbServiceImpl> usb_service,
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ PlatformUsbDevice platform_device);
+
+ void RefreshDevicesComplete(libusb_device** platform_devices,
+ ssize_t device_count);
+
// Adds a new UsbDevice to the devices_ map based on the given libusb device.
- scoped_refptr<UsbDeviceImpl> AddDevice(PlatformUsbDevice platform_device);
+ void AddDevice(PlatformUsbDevice platform_device,
+ uint16 vendor_id,
+ uint16 product_id,
+ base::string16 manufacturer_string,
+ base::string16 product_string,
+ base::string16 serial_number,
+ std::string device_node);
+
+ void RemoveDevice(scoped_refptr<UsbDeviceImpl> device);
// Handle hotplug events from libusb.
static int LIBUSB_CALL HotplugCallback(libusb_context* context,
@@ -48,27 +98,26 @@ class UsbServiceImpl : public UsbService {
libusb_hotplug_event event,
void* user_data);
// These functions release a reference to the provided platform device.
- void OnDeviceAdded(PlatformUsbDevice platform_device);
- void OnDeviceRemoved(PlatformUsbDevice platform_device);
+ void OnPlatformDeviceAdded(PlatformUsbDevice platform_device);
+ void OnPlatformDeviceRemoved(PlatformUsbDevice platform_device);
scoped_refptr<UsbContext> context_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
-
-#if defined(OS_WIN)
- class UIThreadHelper;
- UIThreadHelper* ui_thread_helper_;
-#endif // OS_WIN
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
// TODO(reillyg): Figure out a better solution for device IDs.
- uint32 next_unique_id_;
+ uint32 next_unique_id_ = 0;
// When available the device list will be updated when new devices are
// connected instead of only when a full enumeration is requested.
// TODO(reillyg): Support this on all platforms. crbug.com/411715
- bool hotplug_enabled_;
+ bool hotplug_enabled_ = false;
libusb_hotplug_callback_handle hotplug_handle_;
+ // Enumeration callbacks are queued until an enumeration completes.
+ bool enumeration_ready_ = false;
+ std::vector<GetDevicesCallback> pending_enumerations_;
+
// The map from unique IDs to UsbDevices.
typedef std::map<uint32, scoped_refptr<UsbDeviceImpl>> DeviceMap;
DeviceMap devices_;
@@ -78,6 +127,10 @@ class UsbServiceImpl : public UsbService {
PlatformDeviceMap;
PlatformDeviceMap platform_devices_;
+#if defined(OS_WIN)
+ ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_;
+#endif // OS_WIN
+
base::WeakPtrFactory<UsbServiceImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(UsbServiceImpl);
diff --git a/device/usb/usb_service_unittest.cc b/device/usb/usb_service_unittest.cc
index edd0712..f0e5ae2 100644
--- a/device/usb/usb_service_unittest.cc
+++ b/device/usb/usb_service_unittest.cc
@@ -4,6 +4,7 @@
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_io_thread.h"
#include "device/test/usb_test_gadget.h"
#include "device/usb/usb_device.h"
#include "device/usb/usb_device_handle.h"
@@ -15,34 +16,34 @@ namespace {
class UsbServiceTest : public ::testing::Test {
public:
- void SetUp() override { message_loop_.reset(new base::MessageLoopForIO); }
+ void SetUp() override {
+ message_loop_.reset(new base::MessageLoopForUI);
+ io_thread_.reset(new base::TestIOThread(base::TestIOThread::kAutoStart));
+ }
- private:
+ protected:
scoped_ptr<base::MessageLoop> message_loop_;
+ scoped_ptr<base::TestIOThread> io_thread_;
};
TEST_F(UsbServiceTest, ClaimGadget) {
if (!UsbTestGadget::IsTestEnabled()) return;
- scoped_ptr<UsbTestGadget> gadget = UsbTestGadget::Claim();
+ scoped_ptr<UsbTestGadget> gadget =
+ UsbTestGadget::Claim(io_thread_->task_runner());
ASSERT_TRUE(gadget.get());
scoped_refptr<UsbDevice> device = gadget->GetDevice();
- base::string16 utf16;
- ASSERT_TRUE(device->GetManufacturer(&utf16));
- ASSERT_EQ("Google Inc.", base::UTF16ToUTF8(utf16));
-
- ASSERT_TRUE(device->GetProduct(&utf16));
- ASSERT_EQ("Test Gadget (default state)", base::UTF16ToUTF8(utf16));
-
- ASSERT_TRUE(device->GetSerialNumber(&utf16));
- ASSERT_EQ(gadget->GetSerialNumber(), base::UTF16ToUTF8(utf16));
+ ASSERT_EQ("Google Inc.", base::UTF16ToUTF8(device->manufacturer_string()));
+ ASSERT_EQ("Test Gadget (default state)",
+ base::UTF16ToUTF8(device->product_string()));
}
TEST_F(UsbServiceTest, DisconnectAndReconnect) {
if (!UsbTestGadget::IsTestEnabled()) return;
- scoped_ptr<UsbTestGadget> gadget = UsbTestGadget::Claim();
+ scoped_ptr<UsbTestGadget> gadget =
+ UsbTestGadget::Claim(io_thread_->task_runner());
ASSERT_TRUE(gadget.get());
ASSERT_TRUE(gadget->Disconnect());
ASSERT_TRUE(gadget->Reconnect());
diff --git a/extensions/browser/api/device_permissions_manager.cc b/extensions/browser/api/device_permissions_manager.cc
index 17e3eab..d64c027 100644
--- a/extensions/browser/api/device_permissions_manager.cc
+++ b/extensions/browser/api/device_permissions_manager.cc
@@ -233,16 +233,13 @@ std::set<scoped_refptr<DevicePermissionEntry>> GetDevicePermissionEntries(
} // namespace
DevicePermissionEntry::DevicePermissionEntry(
- scoped_refptr<device::UsbDevice> device,
- const base::string16& serial_number,
- const base::string16& manufacturer_string,
- const base::string16& product_string)
+ scoped_refptr<device::UsbDevice> device)
: device_(device),
vendor_id_(device->vendor_id()),
product_id_(device->product_id()),
- serial_number_(serial_number),
- manufacturer_string_(manufacturer_string),
- product_string_(product_string) {
+ serial_number_(device->serial_number()),
+ manufacturer_string_(device->manufacturer_string()),
+ product_string_(device->product_string()) {
}
DevicePermissionEntry::DevicePermissionEntry(
@@ -341,14 +338,13 @@ DevicePermissions::~DevicePermissions() {
}
scoped_refptr<DevicePermissionEntry> DevicePermissions::FindEntry(
- scoped_refptr<device::UsbDevice> device,
- const base::string16& serial_number) const {
+ scoped_refptr<device::UsbDevice> device) const {
const auto& ephemeral_device_entry = ephemeral_devices_.find(device);
if (ephemeral_device_entry != ephemeral_devices_.end()) {
return ephemeral_device_entry->second;
}
- if (serial_number.empty()) {
+ if (device->serial_number().empty()) {
return nullptr;
}
@@ -362,7 +358,7 @@ scoped_refptr<DevicePermissionEntry> DevicePermissions::FindEntry(
if (entry->product_id() != device->product_id()) {
continue;
}
- if (entry->serial_number() != serial_number) {
+ if (entry->serial_number() != device->serial_number()) {
continue;
}
return entry;
@@ -376,50 +372,22 @@ DevicePermissions::DevicePermissions(BrowserContext* context,
entries_ = GetDevicePermissionEntries(prefs, extension_id);
}
-DevicePermissions::DevicePermissions(const DevicePermissions* original)
- : entries_(original->entries_),
- ephemeral_devices_(original->ephemeral_devices_) {
-}
-
-class DevicePermissionsManager::FileThreadHelper : public UsbService::Observer {
- public:
- FileThreadHelper(
- base::WeakPtr<DevicePermissionsManager> device_permissions_manager)
- : device_permissions_manager_(device_permissions_manager),
- observer_(this) {}
- virtual ~FileThreadHelper() {}
-
- void Start() {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- UsbService* service = device::DeviceClient::Get()->GetUsbService();
- if (service) {
- observer_.Add(service);
- }
- }
-
- private:
- void OnDeviceRemovedCleanup(scoped_refptr<UsbDevice> device) override {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DevicePermissionsManager::OnDeviceRemoved,
- device_permissions_manager_, device));
- }
-
- base::WeakPtr<DevicePermissionsManager> device_permissions_manager_;
- ScopedObserver<UsbService, UsbService::Observer> observer_;
-};
-
// static
DevicePermissionsManager* DevicePermissionsManager::Get(
BrowserContext* context) {
return DevicePermissionsManagerFactory::GetForBrowserContext(context);
}
-scoped_ptr<DevicePermissions> DevicePermissionsManager::GetForExtension(
+DevicePermissions* DevicePermissionsManager::GetForExtension(
const std::string& extension_id) {
DCHECK(CalledOnValidThread());
- return make_scoped_ptr(new DevicePermissions(GetOrInsert(extension_id)));
+ DevicePermissions* device_permissions = GetInternal(extension_id);
+ if (!device_permissions) {
+ device_permissions = new DevicePermissions(context_, extension_id);
+ extension_id_to_device_permissions_[extension_id] = device_permissions;
+ }
+
+ return device_permissions;
}
std::vector<base::string16>
@@ -427,7 +395,7 @@ DevicePermissionsManager::GetPermissionMessageStrings(
const std::string& extension_id) const {
DCHECK(CalledOnValidThread());
std::vector<base::string16> messages;
- const DevicePermissions* device_permissions = Get(extension_id);
+ const DevicePermissions* device_permissions = GetInternal(extension_id);
if (device_permissions) {
for (const scoped_refptr<DevicePermissionEntry>& entry :
device_permissions->entries()) {
@@ -439,15 +407,12 @@ DevicePermissionsManager::GetPermissionMessageStrings(
void DevicePermissionsManager::AllowUsbDevice(
const std::string& extension_id,
- scoped_refptr<device::UsbDevice> device,
- const base::string16& product_string,
- const base::string16& manufacturer_string,
- const base::string16& serial_number) {
+ scoped_refptr<device::UsbDevice> device) {
DCHECK(CalledOnValidThread());
- DevicePermissions* device_permissions = GetOrInsert(extension_id);
+ DevicePermissions* device_permissions = GetForExtension(extension_id);
- scoped_refptr<DevicePermissionEntry> device_entry(new DevicePermissionEntry(
- device, serial_number, manufacturer_string, product_string));
+ scoped_refptr<DevicePermissionEntry> device_entry(
+ new DevicePermissionEntry(device));
if (device_entry->IsPersistent()) {
for (const auto& entry : device_permissions->entries()) {
@@ -474,13 +439,9 @@ void DevicePermissionsManager::AllowUsbDevice(
// Only start observing when an ephemeral device has been added so that
// UsbService is not automatically initialized on profile creation (which it
// would be if this call were in the constructor).
- if (!helper_) {
- helper_ = new FileThreadHelper(weak_factory_.GetWeakPtr());
- // base::Unretained is safe because any task to delete helper_ will be
- // executed after this call.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&FileThreadHelper::Start, base::Unretained(helper_)));
+ UsbService* usb_service = device::DeviceClient::Get()->GetUsbService();
+ if (!usb_service_observer_.IsObserving(usb_service)) {
+ usb_service_observer_.Add(usb_service);
}
}
}
@@ -499,7 +460,7 @@ void DevicePermissionsManager::RemoveEntry(
const std::string& extension_id,
scoped_refptr<DevicePermissionEntry> entry) {
DCHECK(CalledOnValidThread());
- DevicePermissions* device_permissions = Get(extension_id);
+ DevicePermissions* device_permissions = GetInternal(extension_id);
DCHECK(device_permissions);
DCHECK(ContainsKey(device_permissions->entries_, entry));
device_permissions->entries_.erase(entry);
@@ -514,7 +475,7 @@ void DevicePermissionsManager::Clear(const std::string& extension_id) {
DCHECK(CalledOnValidThread());
ClearDevicePermissionEntries(ExtensionPrefs::Get(context_), extension_id);
- DevicePermissions* device_permissions = Get(extension_id);
+ DevicePermissions* device_permissions = GetInternal(extension_id);
if (device_permissions) {
extension_id_to_device_permissions_.erase(extension_id);
delete device_permissions;
@@ -525,8 +486,7 @@ DevicePermissionsManager::DevicePermissionsManager(
content::BrowserContext* context)
: context_(context),
process_manager_observer_(this),
- helper_(nullptr),
- weak_factory_(this) {
+ usb_service_observer_(this) {
process_manager_observer_.Add(ProcessManager::Get(context));
}
@@ -535,13 +495,9 @@ DevicePermissionsManager::~DevicePermissionsManager() {
DevicePermissions* device_permissions = map_entry.second;
delete device_permissions;
}
- if (helper_) {
- BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, helper_);
- helper_ = nullptr;
- }
}
-DevicePermissions* DevicePermissionsManager::Get(
+DevicePermissions* DevicePermissionsManager::GetInternal(
const std::string& extension_id) const {
std::map<std::string, DevicePermissions*>::const_iterator it =
extension_id_to_device_permissions_.find(extension_id);
@@ -552,22 +508,11 @@ DevicePermissions* DevicePermissionsManager::Get(
return NULL;
}
-DevicePermissions* DevicePermissionsManager::GetOrInsert(
- const std::string& extension_id) {
- DevicePermissions* device_permissions = Get(extension_id);
- if (!device_permissions) {
- device_permissions = new DevicePermissions(context_, extension_id);
- extension_id_to_device_permissions_[extension_id] = device_permissions;
- }
-
- return device_permissions;
-}
-
void DevicePermissionsManager::OnBackgroundHostClose(
const std::string& extension_id) {
DCHECK(CalledOnValidThread());
- DevicePermissions* device_permissions = Get(extension_id);
+ DevicePermissions* device_permissions = GetInternal(extension_id);
if (device_permissions) {
// When all of the app's windows are closed and the background page is
// suspended all ephemeral device permissions are cleared.
@@ -578,7 +523,7 @@ void DevicePermissionsManager::OnBackgroundHostClose(
}
}
-void DevicePermissionsManager::OnDeviceRemoved(
+void DevicePermissionsManager::OnDeviceRemovedCleanup(
scoped_refptr<UsbDevice> device) {
DCHECK(CalledOnValidThread());
for (const auto& map_entry : extension_id_to_device_permissions_) {
diff --git a/extensions/browser/api/device_permissions_manager.h b/extensions/browser/api/device_permissions_manager.h
index 159cd7b..7d3a500 100644
--- a/extensions/browser/api/device_permissions_manager.h
+++ b/extensions/browser/api/device_permissions_manager.h
@@ -40,13 +40,7 @@ namespace extensions {
class DevicePermissionEntry
: public base::RefCountedThreadSafe<DevicePermissionEntry> {
public:
- // TODO(reillyg): This function should be able to take only the
- // device::UsbDevice and read the strings from there. This is not yet possible
- // as the device can not be accessed from the UI thread. crbug.com/427985
- DevicePermissionEntry(scoped_refptr<device::UsbDevice> device,
- const base::string16& serial_number,
- const base::string16& manufacturer_string,
- const base::string16& product_string);
+ DevicePermissionEntry(scoped_refptr<device::UsbDevice> device);
DevicePermissionEntry(uint16_t vendor_id,
uint16_t product_id,
const base::string16& serial_number,
@@ -98,7 +92,7 @@ class DevicePermissionEntry
base::Time last_used_;
};
-// Stores a copy of device permissions associated with a particular extension.
+// Stores device permissions associated with a particular extension.
class DevicePermissions {
public:
virtual ~DevicePermissions();
@@ -108,8 +102,7 @@ class DevicePermissions {
// to call device->GetSerialNumber() which may not be possible on the
// current thread.
scoped_refptr<DevicePermissionEntry> FindEntry(
- scoped_refptr<device::UsbDevice> device,
- const base::string16& serial_number) const;
+ scoped_refptr<device::UsbDevice> device) const;
const std::set<scoped_refptr<DevicePermissionEntry>>& entries() const {
return entries_;
@@ -121,9 +114,6 @@ class DevicePermissions {
// Reads permissions out of ExtensionPrefs.
DevicePermissions(content::BrowserContext* context,
const std::string& extension_id);
- // Does a shallow copy, duplicating the device lists so that the resulting
- // object can be used from a different thread.
- DevicePermissions(const DevicePermissions* original);
std::set<scoped_refptr<DevicePermissionEntry>> entries_;
std::map<scoped_refptr<device::UsbDevice>,
@@ -135,28 +125,21 @@ class DevicePermissions {
// Manages saved device permissions for all extensions.
class DevicePermissionsManager : public KeyedService,
public base::NonThreadSafe,
- public ProcessManagerObserver {
+ public ProcessManagerObserver,
+ public device::UsbService::Observer {
public:
static DevicePermissionsManager* Get(content::BrowserContext* context);
- // Returns a copy of the DevicePermissions object for a given extension that
- // can be used by any thread.
- scoped_ptr<DevicePermissions> GetForExtension(
- const std::string& extension_id);
+ // The DevicePermissions object for a given extension.
+ DevicePermissions* GetForExtension(const std::string& extension_id);
// Equivalent to calling GetForExtension and extracting the permission string
// for each entry.
std::vector<base::string16> GetPermissionMessageStrings(
const std::string& extension_id) const;
- // TODO(reillyg): AllowUsbDevice should only take the extension ID and
- // device, with the strings read from the device. This isn't possible now as
- // the device can not be accessed from the UI thread yet. crbug.com/427985
void AllowUsbDevice(const std::string& extension_id,
- scoped_refptr<device::UsbDevice> device,
- const base::string16& serial_number,
- const base::string16& manufacturer_string,
- const base::string16& product_string);
+ scoped_refptr<device::UsbDevice> device);
// Updates the "last used" timestamp on the given device entry and writes it
// out to ExtensionPrefs.
@@ -171,7 +154,6 @@ class DevicePermissionsManager : public KeyedService,
void Clear(const std::string& extension_id);
private:
- class FileThreadHelper;
friend class DevicePermissionsManagerFactory;
FRIEND_TEST_ALL_PREFIXES(DevicePermissionsManagerTest, SuspendExtension);
@@ -179,20 +161,20 @@ class DevicePermissionsManager : public KeyedService,
DevicePermissionsManager(content::BrowserContext* context);
~DevicePermissionsManager() override;
- DevicePermissions* Get(const std::string& extension_id) const;
- DevicePermissions* GetOrInsert(const std::string& extension_id);
- void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device);
+ DevicePermissions* GetInternal(const std::string& extension_id) const;
// ProcessManagerObserver implementation
void OnBackgroundHostClose(const std::string& extension_id) override;
+ // UsbService::Observer implementation
+ void OnDeviceRemovedCleanup(scoped_refptr<device::UsbDevice> device) override;
+
content::BrowserContext* context_;
std::map<std::string, DevicePermissions*> extension_id_to_device_permissions_;
ScopedObserver<ProcessManager, ProcessManagerObserver>
process_manager_observer_;
- FileThreadHelper* helper_;
-
- base::WeakPtrFactory<DevicePermissionsManager> weak_factory_;
+ ScopedObserver<device::UsbService, device::UsbService::Observer>
+ usb_service_observer_;
DISALLOW_COPY_AND_ASSIGN(DevicePermissionsManager);
};
diff --git a/extensions/browser/api/device_permissions_prompt.cc b/extensions/browser/api/device_permissions_prompt.cc
index f45ae56..fe6d535 100644
--- a/extensions/browser/api/device_permissions_prompt.cc
+++ b/extensions/browser/api/device_permissions_prompt.cc
@@ -28,10 +28,8 @@ namespace extensions {
DevicePermissionsPrompt::Prompt::DeviceInfo::DeviceInfo(
scoped_refptr<UsbDevice> device)
: device(device) {
- base::string16 manufacturer_string;
- if (device->GetManufacturer(&manufacturer_string)) {
- original_manufacturer_string = manufacturer_string;
- } else {
+ base::string16 manufacturer_string = device->manufacturer_string();
+ if (manufacturer_string.empty()) {
const char* vendor_name =
device::UsbIds::GetVendorName(device->vendor_id());
if (vendor_name) {
@@ -44,10 +42,8 @@ DevicePermissionsPrompt::Prompt::DeviceInfo::DeviceInfo(
}
}
- base::string16 product_string;
- if (device->GetProduct(&product_string)) {
- original_product_string = product_string;
- } else {
+ base::string16 product_string = device->product_string();
+ if (product_string.empty()) {
const char* product_name = device::UsbIds::GetProductName(
device->vendor_id(), device->product_id());
if (product_name) {
@@ -60,10 +56,6 @@ DevicePermissionsPrompt::Prompt::DeviceInfo::DeviceInfo(
}
}
- if (!device->GetSerialNumber(&serial_number)) {
- serial_number.clear();
- }
-
name = l10n_util::GetStringFUTF16(IDS_DEVICE_PERMISSIONS_DEVICE_NAME,
product_string, manufacturer_string);
}
@@ -71,21 +63,19 @@ DevicePermissionsPrompt::Prompt::DeviceInfo::DeviceInfo(
DevicePermissionsPrompt::Prompt::DeviceInfo::~DeviceInfo() {
}
-DevicePermissionsPrompt::Prompt::Prompt()
- : extension_(nullptr),
- browser_context_(nullptr),
- multiple_(false),
- observer_(nullptr),
- usb_service_observer_(this) {
+DevicePermissionsPrompt::Prompt::Prompt() : usb_service_observer_(this) {
}
void DevicePermissionsPrompt::Prompt::SetObserver(Observer* observer) {
observer_ = observer;
if (observer_) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&DevicePermissionsPrompt::Prompt::DoDeviceQuery, this));
+ UsbService* service = device::DeviceClient::Get()->GetUsbService();
+ if (service && !usb_service_observer_.IsObserving(service)) {
+ service->GetDevices(base::Bind(
+ &DevicePermissionsPrompt::Prompt::OnDevicesEnumerated, this));
+ usb_service_observer_.Add(service);
+ }
}
}
@@ -115,9 +105,7 @@ void DevicePermissionsPrompt::Prompt::GrantDevicePermission(
DevicePermissionsManager::Get(browser_context_);
if (permissions_manager) {
const DeviceInfo& device = devices_[index];
- permissions_manager->AllowUsbDevice(
- extension_->id(), device.device, device.original_product_string,
- device.original_manufacturer_string, device.serial_number);
+ permissions_manager->AllowUsbDevice(extension_->id(), device.device);
}
}
@@ -129,82 +117,17 @@ void DevicePermissionsPrompt::Prompt::set_filters(
DevicePermissionsPrompt::Prompt::~Prompt() {
}
-void DevicePermissionsPrompt::Prompt::DoDeviceQuery() {
- UsbService* service = device::DeviceClient::Get()->GetUsbService();
- if (!service) {
+void DevicePermissionsPrompt::Prompt::OnDeviceAdded(
+ scoped_refptr<UsbDevice> device) {
+ if (!(filters_.empty() || UsbDeviceFilter::MatchesAny(device, filters_))) {
return;
}
- std::vector<scoped_refptr<UsbDevice>> devices;
- service->GetDevices(&devices);
-
- if (!usb_service_observer_.IsObserving(service)) {
- usb_service_observer_.Add(service);
- }
-
- std::vector<DeviceInfo>* device_info = new std::vector<DeviceInfo>();
- base::Closure barrier = base::BarrierClosure(
- devices.size(),
- base::Bind(&DevicePermissionsPrompt::Prompt::DeviceQueryComplete, this,
- base::Owned(device_info)));
-
- for (const auto& device : devices) {
- if (filters_.empty() || UsbDeviceFilter::MatchesAny(device, filters_)) {
- device->CheckUsbAccess(
- base::Bind(&DevicePermissionsPrompt::Prompt::AppendCheckedUsbDevice,
- this, device_info, device, barrier));
- } else {
- barrier.Run();
- }
- }
-}
-
-void DevicePermissionsPrompt::Prompt::AppendCheckedUsbDevice(
- std::vector<DeviceInfo>* device_info,
- scoped_refptr<UsbDevice> device,
- const base::Closure& callback,
- bool allowed) {
- if (allowed) {
- device_info->push_back(DeviceInfo(device));
- }
- callback.Run();
-}
-
-void DevicePermissionsPrompt::Prompt::AddCheckedUsbDevice(
- scoped_refptr<UsbDevice> device,
- bool allowed) {
- if (allowed) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DevicePermissionsPrompt::Prompt::AddDevice, this,
- DeviceInfo(device)));
- }
-}
-
-void DevicePermissionsPrompt::Prompt::DeviceQueryComplete(
- std::vector<DeviceInfo>* device_info) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DevicePermissionsPrompt::Prompt::SetDevices, this,
- *device_info));
-}
-
-void DevicePermissionsPrompt::Prompt::SetDevices(
- const std::vector<DeviceInfo>& devices) {
- devices_ = devices;
- if (observer_) {
- observer_->OnDevicesChanged();
- }
-}
-
-void DevicePermissionsPrompt::Prompt::AddDevice(const DeviceInfo& device) {
- devices_.push_back(device);
- if (observer_) {
- observer_->OnDevicesChanged();
- }
+ device->CheckUsbAccess(base::Bind(
+ &DevicePermissionsPrompt::Prompt::AddCheckedUsbDevice, this, device));
}
-void DevicePermissionsPrompt::Prompt::RemoveDevice(
+void DevicePermissionsPrompt::Prompt::OnDeviceRemoved(
scoped_refptr<UsbDevice> device) {
bool removed_entry = false;
for (std::vector<DeviceInfo>::iterator it = devices_.begin();
@@ -220,21 +143,25 @@ void DevicePermissionsPrompt::Prompt::RemoveDevice(
}
}
-void DevicePermissionsPrompt::Prompt::OnDeviceAdded(
- scoped_refptr<UsbDevice> device) {
- if (!(filters_.empty() || UsbDeviceFilter::MatchesAny(device, filters_))) {
- return;
+void DevicePermissionsPrompt::Prompt::OnDevicesEnumerated(
+ const std::vector<scoped_refptr<UsbDevice>>& devices) {
+ for (const auto& device : devices) {
+ if (filters_.empty() || UsbDeviceFilter::MatchesAny(device, filters_)) {
+ device->CheckUsbAccess(base::Bind(
+ &DevicePermissionsPrompt::Prompt::AddCheckedUsbDevice, this, device));
+ }
}
-
- device->CheckUsbAccess(base::Bind(
- &DevicePermissionsPrompt::Prompt::AddCheckedUsbDevice, this, device));
}
-void DevicePermissionsPrompt::Prompt::OnDeviceRemoved(
- scoped_refptr<UsbDevice> device) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DevicePermissionsPrompt::Prompt::RemoveDevice, this, device));
+void DevicePermissionsPrompt::Prompt::AddCheckedUsbDevice(
+ scoped_refptr<UsbDevice> device,
+ bool allowed) {
+ if (allowed) {
+ devices_.push_back(DeviceInfo(device));
+ if (observer_) {
+ observer_->OnDevicesChanged();
+ }
+ }
}
DevicePermissionsPrompt::DevicePermissionsPrompt(
diff --git a/extensions/browser/api/device_permissions_prompt.h b/extensions/browser/api/device_permissions_prompt.h
index e7d11ca..26775bf 100644
--- a/extensions/browser/api/device_permissions_prompt.h
+++ b/extensions/browser/api/device_permissions_prompt.h
@@ -13,6 +13,7 @@
#include "base/scoped_observer.h"
#include "base/strings/string16.h"
#include "content/public/browser/browser_thread.h"
+#include "device/usb/usb_device.h"
#include "device/usb/usb_service.h"
namespace content {
@@ -21,7 +22,6 @@ class WebContents;
}
namespace device {
-class UsbDevice;
class UsbDeviceFilter;
}
@@ -34,9 +34,7 @@ class Extension;
class DevicePermissionsPrompt {
public:
// Context information available to the UI implementation.
- class Prompt : public base::RefCountedThreadSafe<
- Prompt,
- content::BrowserThread::DeleteOnFileThread>,
+ class Prompt : public base::RefCounted<Prompt>,
public device::UsbService::Observer {
public:
// Displayed properties of a device.
@@ -46,9 +44,6 @@ class DevicePermissionsPrompt {
scoped_refptr<device::UsbDevice> device;
base::string16 name;
- base::string16 original_manufacturer_string;
- base::string16 original_product_string;
- base::string16 serial_number;
};
// Since the set of devices can change while the UI is visible an
@@ -73,7 +68,7 @@ class DevicePermissionsPrompt {
}
base::string16 GetDeviceSerialNumber(size_t index) const {
DCHECK_LT(index, devices_.size());
- return devices_[index].serial_number;
+ return devices_[index].device->serial_number();
}
// Notifies the DevicePermissionsManager for the current extension that
@@ -98,35 +93,25 @@ class DevicePermissionsPrompt {
void set_filters(const std::vector<device::UsbDeviceFilter>& filters);
private:
- friend struct content::BrowserThread::DeleteOnThread<
- content::BrowserThread::FILE>;
- friend class base::DeleteHelper<Prompt>;
+ friend class base::RefCounted<Prompt>;
virtual ~Prompt();
- // Querying for devices must be done asynchronously on the FILE thread.
- void DoDeviceQuery();
- void AppendCheckedUsbDevice(std::vector<DeviceInfo>* device_info,
- scoped_refptr<device::UsbDevice> device,
- const base::Closure& callback,
- bool allowed);
- void AddCheckedUsbDevice(scoped_refptr<device::UsbDevice> device,
- bool allowed);
- void DeviceQueryComplete(std::vector<DeviceInfo>* device_info);
- void SetDevices(const std::vector<DeviceInfo>& devices);
- void AddDevice(const DeviceInfo& device);
- void RemoveDevice(scoped_refptr<device::UsbDevice> device);
-
// device::UsbService::Observer implementation:
void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override;
void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override;
- const extensions::Extension* extension_;
- content::BrowserContext* browser_context_;
- bool multiple_;
+ void OnDevicesEnumerated(
+ const std::vector<scoped_refptr<device::UsbDevice>>& devices);
+ void AddCheckedUsbDevice(scoped_refptr<device::UsbDevice> device,
+ bool allowed);
+
+ const extensions::Extension* extension_ = nullptr;
+ content::BrowserContext* browser_context_ = nullptr;
+ bool multiple_ = false;
std::vector<device::UsbDeviceFilter> filters_;
std::vector<DeviceInfo> devices_;
- Observer* observer_;
+ Observer* observer_ = nullptr;
ScopedObserver<device::UsbService, device::UsbService::Observer>
usb_service_observer_;
};
diff --git a/extensions/browser/api/usb/usb_api.cc b/extensions/browser/api/usb/usb_api.cc
index f1fcd23..d023813 100644
--- a/extensions/browser/api/usb/usb_api.cc
+++ b/extensions/browser/api/usb/usb_api.cc
@@ -7,8 +7,8 @@
#include <string>
#include <vector>
+#include "base/barrier_closure.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "device/core/device_client.h"
#include "device/usb/usb_device_handle.h"
#include "device/usb/usb_service.h"
@@ -70,9 +70,6 @@ using usb::SynchronizationType;
using usb::TransferType;
using usb::UsageType;
-typedef std::vector<scoped_refptr<UsbDevice> > DeviceVector;
-typedef scoped_ptr<DeviceVector> ScopedDeviceVector;
-
namespace {
const char kDataKey[] = "data";
@@ -100,6 +97,7 @@ const char kErrorConvertDirection[] = "Invalid transfer direction.";
const char kErrorConvertRecipient[] = "Invalid transfer recipient.";
const char kErrorConvertRequestType[] = "Invalid request type.";
const char kErrorMalformedParameters[] = "Error parsing parameters.";
+const char kErrorNoConnection[] = "No such connection.";
const char kErrorNoDevice[] = "No such device.";
const char kErrorPermissionDenied[] = "Permission to access device was denied";
const char kErrorInvalidTransferLength[] =
@@ -242,56 +240,6 @@ const char* ConvertTransferStatusToApi(const UsbTransferStatus status) {
}
}
-void RequestUsbDevicesAccessHelper(
- ScopedDeviceVector devices,
- std::vector<scoped_refptr<UsbDevice> >::iterator i,
- int interface_id,
- const base::Callback<void(ScopedDeviceVector result)>& callback,
- bool success) {
- if (success) {
- ++i;
- } else {
- i = devices->erase(i);
- }
- if (i == devices->end()) {
- callback.Run(devices.Pass());
- return;
- }
- (*i)->RequestUsbAccess(interface_id,
- base::Bind(RequestUsbDevicesAccessHelper,
- base::Passed(devices.Pass()),
- i,
- interface_id,
- callback));
-}
-
-void RequestUsbDevicesAccess(
- ScopedDeviceVector devices,
- int interface_id,
- const base::Callback<void(ScopedDeviceVector result)>& callback) {
- if (devices->empty()) {
- callback.Run(devices.Pass());
- return;
- }
- std::vector<scoped_refptr<UsbDevice> >::iterator i = devices->begin();
- (*i)->RequestUsbAccess(interface_id,
- base::Bind(RequestUsbDevicesAccessHelper,
- base::Passed(devices.Pass()),
- i,
- interface_id,
- callback));
-}
-
-base::DictionaryValue* CreateTransferInfo(UsbTransferStatus status,
- scoped_refptr<net::IOBuffer> data,
- size_t length) {
- base::DictionaryValue* result = new base::DictionaryValue();
- result->SetInteger(kResultCodeKey, status);
- result->Set(kDataKey,
- base::BinaryValue::CreateWithCopiedBuffer(data->data(), length));
- return result;
-}
-
base::Value* PopulateConnectionHandle(int handle,
int vendor_id,
int product_id) {
@@ -434,31 +382,25 @@ void ConvertDeviceFilter(const usb::DeviceFilter& input,
namespace extensions {
-UsbAsyncApiFunction::UsbAsyncApiFunction() : manager_(NULL) {
-}
-
-UsbAsyncApiFunction::~UsbAsyncApiFunction() {
+UsbPermissionCheckingFunction::UsbPermissionCheckingFunction()
+ : device_permissions_manager_(nullptr) {
}
-bool UsbAsyncApiFunction::PrePrepare() {
- manager_ = ApiResourceManager<UsbDeviceResource>::Get(browser_context());
- set_work_thread_id(BrowserThread::FILE);
- return manager_ != NULL;
+UsbPermissionCheckingFunction::~UsbPermissionCheckingFunction() {
}
-bool UsbAsyncApiFunction::Respond() {
- return error_.empty();
-}
-
-bool UsbAsyncApiFunction::HasDevicePermission(scoped_refptr<UsbDevice> device) {
- DCHECK(device_permissions_);
+bool UsbPermissionCheckingFunction::HasDevicePermission(
+ scoped_refptr<UsbDevice> device) {
+ if (!device_permissions_manager_) {
+ device_permissions_manager_ =
+ DevicePermissionsManager::Get(browser_context());
+ }
- // Check the DevicePermissionsManager first so that if an entry is found
- // it can be stored for later. This requires the serial number.
- base::string16 serial_number;
- device->GetSerialNumber(&serial_number);
+ DevicePermissions* device_permissions =
+ device_permissions_manager_->GetForExtension(extension_id());
+ DCHECK(device_permissions);
- permission_entry_ = device_permissions_->FindEntry(device, serial_number);
+ permission_entry_ = device_permissions->FindEntry(device);
if (permission_entry_.get()) {
return true;
}
@@ -475,83 +417,65 @@ bool UsbAsyncApiFunction::HasDevicePermission(scoped_refptr<UsbDevice> device) {
return false;
}
-scoped_refptr<UsbDeviceHandle>
-UsbAsyncApiFunction::GetDeviceHandleOrCompleteWithError(
- const ConnectionHandle& input_device_handle) {
- UsbDeviceResource* resource =
- manager_->Get(extension_->id(), input_device_handle.handle);
- if (!resource) {
- CompleteWithError(kErrorNoDevice);
- return NULL;
- }
-
- if (!resource->device().get() || !resource->device()->GetDevice().get()) {
- CompleteWithError(kErrorDisconnect);
- manager_->Remove(extension_->id(), input_device_handle.handle);
- return NULL;
- }
-
- if (resource->device()->GetDevice()->vendor_id() !=
- input_device_handle.vendor_id ||
- resource->device()->GetDevice()->product_id() !=
- input_device_handle.product_id) {
- CompleteWithError(kErrorNoDevice);
- return NULL;
+void UsbPermissionCheckingFunction::RecordDeviceLastUsed() {
+ if (permission_entry_.get()) {
+ device_permissions_manager_->UpdateLastUsed(extension_id(),
+ permission_entry_);
}
-
- return resource->device();
}
-void UsbAsyncApiFunction::RemoveUsbDeviceResource(int api_resource_id) {
- manager_->Remove(extension_->id(), api_resource_id);
+UsbConnectionFunction::UsbConnectionFunction() {
}
-void UsbAsyncApiFunction::CompleteWithError(const std::string& error) {
- SetError(error);
- AsyncWorkCompleted();
+UsbConnectionFunction::~UsbConnectionFunction() {
}
-UsbAsyncApiTransferFunction::UsbAsyncApiTransferFunction() {
-}
+scoped_refptr<device::UsbDeviceHandle> UsbConnectionFunction::GetDeviceHandle(
+ const extensions::core_api::usb::ConnectionHandle& handle) {
+ ApiResourceManager<UsbDeviceResource>* manager =
+ ApiResourceManager<UsbDeviceResource>::Get(browser_context());
+ if (!manager) {
+ return nullptr;
+ }
-UsbAsyncApiTransferFunction::~UsbAsyncApiTransferFunction() {
-}
+ UsbDeviceResource* resource = manager->Get(extension_id(), handle.handle);
+ if (!resource) {
+ return nullptr;
+ }
-void UsbAsyncApiTransferFunction::OnCompleted(UsbTransferStatus status,
- scoped_refptr<net::IOBuffer> data,
- size_t length) {
- if (status != device::USB_TRANSFER_COMPLETED)
- SetError(ConvertTransferStatusToApi(status));
+ return resource->device();
+}
- SetResult(CreateTransferInfo(status, data, length));
- AsyncWorkCompleted();
+void UsbConnectionFunction::ReleaseDeviceHandle(
+ const extensions::core_api::usb::ConnectionHandle& handle) {
+ ApiResourceManager<UsbDeviceResource>* manager =
+ ApiResourceManager<UsbDeviceResource>::Get(browser_context());
+ manager->Remove(extension_id(), handle.handle);
}
-bool UsbAsyncApiTransferFunction::ConvertDirectionSafely(
- const Direction& input,
- UsbEndpointDirection* output) {
- const bool converted = ConvertDirectionFromApi(input, output);
- if (!converted)
- SetError(kErrorConvertDirection);
- return converted;
+UsbTransferFunction::UsbTransferFunction() {
}
-bool UsbAsyncApiTransferFunction::ConvertRequestTypeSafely(
- const RequestType& input,
- UsbDeviceHandle::TransferRequestType* output) {
- const bool converted = ConvertRequestTypeFromApi(input, output);
- if (!converted)
- SetError(kErrorConvertRequestType);
- return converted;
+UsbTransferFunction::~UsbTransferFunction() {
}
-bool UsbAsyncApiTransferFunction::ConvertRecipientSafely(
- const Recipient& input,
- UsbDeviceHandle::TransferRecipient* output) {
- const bool converted = ConvertRecipientFromApi(input, output);
- if (!converted)
- SetError(kErrorConvertRecipient);
- return converted;
+void UsbTransferFunction::OnCompleted(UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> data,
+ size_t length) {
+ scoped_ptr<base::DictionaryValue> transfer_info(new base::DictionaryValue());
+ transfer_info->SetInteger(kResultCodeKey, status);
+ transfer_info->Set(kDataKey, base::BinaryValue::CreateWithCopiedBuffer(
+ data->data(), length));
+
+ if (status == device::USB_TRANSFER_COMPLETED) {
+ Respond(OneArgument(transfer_info.release()));
+ } else {
+ scoped_ptr<base::ListValue> error_args(new base::ListValue());
+ error_args->Append(transfer_info.release());
+ // Returning arguments with an error is wrong but we're stuck with it.
+ Respond(ErrorWithArguments(error_args.Pass(),
+ ConvertTransferStatusToApi(status)));
+ }
}
UsbFindDevicesFunction::UsbFindDevicesFunction() {
@@ -560,71 +484,77 @@ UsbFindDevicesFunction::UsbFindDevicesFunction() {
UsbFindDevicesFunction::~UsbFindDevicesFunction() {
}
-bool UsbFindDevicesFunction::Prepare() {
- parameters_ = FindDevices::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction UsbFindDevicesFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::FindDevices::Params> parameters =
+ FindDevices::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbFindDevicesFunction::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;
- int interface_id = parameters_->options.interface_id.get()
- ? *parameters_->options.interface_id.get()
- : UsbDevicePermissionData::ANY_INTERFACE;
- UsbDevicePermission::CheckParam param(vendor_id, product_id, interface_id);
+ vendor_id_ = parameters->options.vendor_id;
+ product_id_ = parameters->options.product_id;
+ interface_id_ = parameters->options.interface_id.get()
+ ? *parameters->options.interface_id.get()
+ : UsbDevicePermissionData::ANY_INTERFACE;
+ UsbDevicePermission::CheckParam param(vendor_id_, product_id_, interface_id_);
if (!extension()->permissions_data()->CheckAPIPermissionWithParam(
APIPermission::kUsbDevice, &param)) {
- LOG(WARNING) << "Insufficient permissions to access device.";
- CompleteWithError(kErrorPermissionDenied);
- return;
+ return RespondNow(Error(kErrorPermissionDenied));
}
UsbService* service = device::DeviceClient::Get()->GetUsbService();
if (!service) {
- CompleteWithError(kErrorInitService);
- return;
+ return RespondNow(Error(kErrorInitService));
}
- ScopedDeviceVector devices(new DeviceVector());
- service->GetDevices(devices.get());
+ service->GetDevices(
+ base::Bind(&UsbFindDevicesFunction::OnGetDevicesComplete, this));
+ return RespondLater();
+}
- for (DeviceVector::iterator it = devices->begin(); it != devices->end();) {
- if ((*it)->vendor_id() != vendor_id || (*it)->product_id() != product_id) {
- it = devices->erase(it);
+void UsbFindDevicesFunction::OnGetDevicesComplete(
+ const std::vector<scoped_refptr<UsbDevice>>& devices) {
+ result_.reset(new base::ListValue());
+ barrier_ = base::BarrierClosure(
+ devices.size(), base::Bind(&UsbFindDevicesFunction::OpenComplete, this));
+
+ for (const scoped_refptr<UsbDevice>& device : devices) {
+ if (device->vendor_id() != vendor_id_ ||
+ device->product_id() != product_id_) {
+ barrier_.Run();
} else {
- ++it;
+ device->RequestUsbAccess(
+ interface_id_,
+ base::Bind(&UsbFindDevicesFunction::OnRequestAccessComplete, this,
+ device));
}
}
-
- RequestUsbDevicesAccess(
- devices.Pass(),
- interface_id,
- base::Bind(&UsbFindDevicesFunction::OpenDevices, this));
}
-void UsbFindDevicesFunction::OpenDevices(ScopedDeviceVector devices) {
- base::ListValue* result = new base::ListValue();
-
- for (size_t i = 0; i < devices->size(); ++i) {
- scoped_refptr<UsbDeviceHandle> device_handle = devices->at(i)->Open();
- if (device_handle.get())
- device_handles_.push_back(device_handle);
+void UsbFindDevicesFunction::OnRequestAccessComplete(
+ scoped_refptr<UsbDevice> device,
+ bool success) {
+ if (success) {
+ device->Open(base::Bind(&UsbFindDevicesFunction::OnDeviceOpened, this));
+ } else {
+ barrier_.Run();
}
+}
- for (size_t i = 0; i < device_handles_.size(); ++i) {
- UsbDeviceHandle* const device_handle = device_handles_[i].get();
- UsbDeviceResource* const resource =
- new UsbDeviceResource(extension_->id(), device_handle);
-
- result->Append(PopulateConnectionHandle(manager_->Add(resource),
- parameters_->options.vendor_id,
- parameters_->options.product_id));
+void UsbFindDevicesFunction::OnDeviceOpened(
+ scoped_refptr<UsbDeviceHandle> device_handle) {
+ if (device_handle.get()) {
+ ApiResourceManager<UsbDeviceResource>* manager =
+ ApiResourceManager<UsbDeviceResource>::Get(browser_context());
+ UsbDeviceResource* resource =
+ new UsbDeviceResource(extension_id(), device_handle);
+ scoped_refptr<UsbDevice> device = device_handle->GetDevice();
+ result_->Append(PopulateConnectionHandle(
+ manager->Add(resource), device->vendor_id(), device->product_id()));
}
+ barrier_.Run();
+}
- SetResult(result);
- AsyncWorkCompleted();
+void UsbFindDevicesFunction::OpenComplete() {
+ Respond(OneArgument(result_.release()));
}
UsbGetDevicesFunction::UsbGetDevicesFunction() {
@@ -633,51 +563,47 @@ UsbGetDevicesFunction::UsbGetDevicesFunction() {
UsbGetDevicesFunction::~UsbGetDevicesFunction() {
}
-bool UsbGetDevicesFunction::Prepare() {
- parameters_ = GetDevices::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- device_permissions_ = DevicePermissionsManager::Get(browser_context())
- ->GetForExtension(extension()->id());
- return true;
-}
+ExtensionFunction::ResponseAction UsbGetDevicesFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::GetDevices::Params> parameters =
+ GetDevices::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbGetDevicesFunction::AsyncWorkStart() {
- 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) {
- ConvertDeviceFilter(*parameters_->options.filters->at(i).get(),
- &filters[i]);
+ if (parameters->options.filters) {
+ filters_.resize(parameters->options.filters->size());
+ for (size_t i = 0; i < parameters->options.filters->size(); ++i) {
+ ConvertDeviceFilter(*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);
+ 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();
if (!service) {
- CompleteWithError(kErrorInitService);
- return;
+ return RespondNow(Error(kErrorInitService));
}
- DeviceVector devices;
- service->GetDevices(&devices);
+ service->GetDevices(
+ base::Bind(&UsbGetDevicesFunction::OnGetDevicesComplete, this));
+ return RespondLater();
+}
+void UsbGetDevicesFunction::OnGetDevicesComplete(
+ const std::vector<scoped_refptr<UsbDevice>>& devices) {
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)) &&
+ for (const scoped_refptr<UsbDevice>& device : devices) {
+ if ((filters_.empty() || UsbDeviceFilter::MatchesAny(device, filters_)) &&
HasDevicePermission(device)) {
- result->Append(PopulateDevice(it->get()));
+ result->Append(PopulateDevice(device.get()));
}
}
- SetResult(result.release());
- AsyncWorkCompleted();
+ Respond(OneArgument(result.release()));
}
UsbGetUserSelectedDevicesFunction::UsbGetUserSelectedDevicesFunction() {
@@ -686,7 +612,7 @@ UsbGetUserSelectedDevicesFunction::UsbGetUserSelectedDevicesFunction() {
UsbGetUserSelectedDevicesFunction::~UsbGetUserSelectedDevicesFunction() {
}
-AsyncApiFunction::ResponseAction UsbGetUserSelectedDevicesFunction::Run() {
+ExtensionFunction::ResponseAction UsbGetUserSelectedDevicesFunction::Run() {
scoped_ptr<extensions::core_api::usb::GetUserSelectedDevices::Params>
parameters = GetUserSelectedDevices::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters.get());
@@ -728,8 +654,7 @@ void UsbGetUserSelectedDevicesFunction::OnUsbDevicesChosen(
result->Append(PopulateDevice(device.get()));
}
- SetResult(result.release());
- SendResponse(true);
+ Respond(OneArgument(result.release()));
Release();
}
@@ -739,15 +664,11 @@ UsbRequestAccessFunction::UsbRequestAccessFunction() {
UsbRequestAccessFunction::~UsbRequestAccessFunction() {
}
-bool UsbRequestAccessFunction::Prepare() {
- parameters_ = RequestAccess::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
-
-void UsbRequestAccessFunction::AsyncWorkStart() {
- SetResult(new base::FundamentalValue(true));
- AsyncWorkCompleted();
+ExtensionFunction::ResponseAction UsbRequestAccessFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::RequestAccess::Params> parameters =
+ RequestAccess::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
+ return RespondNow(OneArgument(new base::FundamentalValue(true)));
}
UsbOpenDeviceFunction::UsbOpenDeviceFunction() {
@@ -756,67 +677,60 @@ UsbOpenDeviceFunction::UsbOpenDeviceFunction() {
UsbOpenDeviceFunction::~UsbOpenDeviceFunction() {
}
-bool UsbOpenDeviceFunction::Prepare() {
- parameters_ = OpenDevice::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- device_permissions_manager_ =
- DevicePermissionsManager::Get(browser_context());
- device_permissions_ =
- device_permissions_manager_->GetForExtension(extension()->id());
- return true;
-}
+ExtensionFunction::ResponseAction UsbOpenDeviceFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::OpenDevice::Params> parameters =
+ OpenDevice::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbOpenDeviceFunction::AsyncWorkStart() {
UsbService* service = device::DeviceClient::Get()->GetUsbService();
if (!service) {
- CompleteWithError(kErrorInitService);
- return;
+ return RespondNow(Error(kErrorInitService));
}
- device_ = service->GetDeviceById(parameters_->device.device);
- if (!device_.get()) {
- CompleteWithError(kErrorNoDevice);
- return;
+ scoped_refptr<UsbDevice> device =
+ service->GetDeviceById(parameters->device.device);
+ if (!device.get()) {
+ return RespondNow(Error(kErrorNoDevice));
}
- if (!HasDevicePermission(device_)) {
+ if (!HasDevicePermission(device)) {
// This function must act as if there is no such device. Otherwise it can be
// used to fingerprint unauthorized devices.
- CompleteWithError(kErrorNoDevice);
- return;
+ return RespondNow(Error(kErrorNoDevice));
}
- device_->RequestUsbAccess(
+ device->RequestUsbAccess(
-1, /* any interface, unused by the permission broker */
- base::Bind(&UsbOpenDeviceFunction::OnRequestAccessComplete, this));
+ base::Bind(&UsbOpenDeviceFunction::OnRequestAccessComplete, this,
+ device));
+ return RespondLater();
}
-void UsbOpenDeviceFunction::OnRequestAccessComplete(bool success) {
- if (!success) {
- SetError(kErrorPermissionDenied);
- AsyncWorkCompleted();
- return;
+void UsbOpenDeviceFunction::OnRequestAccessComplete(
+ scoped_refptr<UsbDevice> device,
+ bool success) {
+ if (success) {
+ device->Open(base::Bind(&UsbOpenDeviceFunction::OnDeviceOpened, this));
+ } else {
+ Respond(Error(kErrorPermissionDenied));
}
+}
- scoped_refptr<UsbDeviceHandle> handle = device_->Open();
- if (!handle.get()) {
- SetError(kErrorOpen);
- AsyncWorkCompleted();
+void UsbOpenDeviceFunction::OnDeviceOpened(
+ scoped_refptr<UsbDeviceHandle> device_handle) {
+ if (!device_handle.get()) {
+ Respond(Error(kErrorOpen));
return;
}
- SetResult(PopulateConnectionHandle(
- manager_->Add(new UsbDeviceResource(extension_->id(), handle)),
- device_->vendor_id(), device_->product_id()));
- AsyncWorkCompleted();
-}
+ RecordDeviceLastUsed();
-bool UsbOpenDeviceFunction::Respond() {
- if (permission_entry_.get()) {
- device_permissions_manager_->UpdateLastUsed(extension_->id(),
- permission_entry_);
- }
- return UsbAsyncApiFunction::Respond();
+ ApiResourceManager<UsbDeviceResource>* manager =
+ ApiResourceManager<UsbDeviceResource>::Get(browser_context());
+ scoped_refptr<UsbDevice> device = device_handle->GetDevice();
+ Respond(OneArgument(PopulateConnectionHandle(
+ manager->Add(new UsbDeviceResource(extension_id(), device_handle)),
+ device->vendor_id(), device->product_id())));
}
UsbSetConfigurationFunction::UsbSetConfigurationFunction() {
@@ -825,23 +739,29 @@ UsbSetConfigurationFunction::UsbSetConfigurationFunction() {
UsbSetConfigurationFunction::~UsbSetConfigurationFunction() {
}
-bool UsbSetConfigurationFunction::Prepare() {
- parameters_ = SetConfiguration::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction UsbSetConfigurationFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::SetConfiguration::Params> parameters =
+ SetConfiguration::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbSetConfigurationFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
+ GetDeviceHandle(parameters->handle);
if (!device_handle.get()) {
- return;
+ return RespondNow(Error(kErrorNoConnection));
}
- if (!device_handle->SetConfiguration(parameters_->configuration_value)) {
- SetError(kErrorCannotSetConfiguration);
+ device_handle->SetConfiguration(
+ parameters->configuration_value,
+ base::Bind(&UsbSetConfigurationFunction::OnComplete, this));
+ return RespondLater();
+}
+
+void UsbSetConfigurationFunction::OnComplete(bool success) {
+ if (success) {
+ Respond(NoArguments());
+ } else {
+ Respond(Error(kErrorCannotSetConfiguration));
}
- AsyncWorkCompleted();
}
UsbGetConfigurationFunction::UsbGetConfigurationFunction() {
@@ -850,17 +770,15 @@ UsbGetConfigurationFunction::UsbGetConfigurationFunction() {
UsbGetConfigurationFunction::~UsbGetConfigurationFunction() {
}
-bool UsbGetConfigurationFunction::Prepare() {
- parameters_ = GetConfiguration::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction UsbGetConfigurationFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::GetConfiguration::Params> parameters =
+ GetConfiguration::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbGetConfigurationFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
+ GetDeviceHandle(parameters->handle);
if (!device_handle.get()) {
- return;
+ return RespondNow(Error(kErrorNoConnection));
}
const UsbConfigDescriptor* config_descriptor =
@@ -868,12 +786,10 @@ void UsbGetConfigurationFunction::AsyncWorkStart() {
if (config_descriptor) {
ConfigDescriptor config;
ConvertConfigDescriptor(*config_descriptor, &config);
- SetResult(config.ToValue().release());
+ return RespondNow(OneArgument(config.ToValue().release()));
} else {
- SetError(kErrorNotConfigured);
+ return RespondNow(Error(kErrorNotConfigured));
}
-
- AsyncWorkCompleted();
}
UsbListInterfacesFunction::UsbListInterfacesFunction() {
@@ -882,17 +798,15 @@ UsbListInterfacesFunction::UsbListInterfacesFunction() {
UsbListInterfacesFunction::~UsbListInterfacesFunction() {
}
-bool UsbListInterfacesFunction::Prepare() {
- parameters_ = ListInterfaces::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction UsbListInterfacesFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::ListInterfaces::Params> parameters =
+ ListInterfaces::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbListInterfacesFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
+ GetDeviceHandle(parameters->handle);
if (!device_handle.get()) {
- return;
+ return RespondNow(Error(kErrorNoConnection));
}
const UsbConfigDescriptor* config_descriptor =
@@ -906,12 +820,10 @@ void UsbListInterfacesFunction::AsyncWorkStart() {
result->Append(config.interfaces[i]->ToValue().release());
}
- SetResult(result.release());
+ return RespondNow(OneArgument(result.release()));
} else {
- SetError(kErrorNotConfigured);
+ return RespondNow(Error(kErrorNotConfigured));
}
-
- AsyncWorkCompleted();
}
UsbCloseDeviceFunction::UsbCloseDeviceFunction() {
@@ -920,21 +832,20 @@ UsbCloseDeviceFunction::UsbCloseDeviceFunction() {
UsbCloseDeviceFunction::~UsbCloseDeviceFunction() {
}
-bool UsbCloseDeviceFunction::Prepare() {
- parameters_ = CloseDevice::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction UsbCloseDeviceFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::CloseDevice::Params> parameters =
+ CloseDevice::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbCloseDeviceFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
- if (!device_handle.get())
- return;
+ GetDeviceHandle(parameters->handle);
+ if (!device_handle.get()) {
+ return RespondNow(Error(kErrorNoConnection));
+ }
// The device handle is closed when the resource is destroyed.
- RemoveUsbDeviceResource(parameters_->handle.handle);
- AsyncWorkCompleted();
+ ReleaseDeviceHandle(parameters->handle);
+ return RespondNow(NoArguments());
}
UsbClaimInterfaceFunction::UsbClaimInterfaceFunction() {
@@ -943,23 +854,29 @@ UsbClaimInterfaceFunction::UsbClaimInterfaceFunction() {
UsbClaimInterfaceFunction::~UsbClaimInterfaceFunction() {
}
-bool UsbClaimInterfaceFunction::Prepare() {
- parameters_ = ClaimInterface::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction UsbClaimInterfaceFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::ClaimInterface::Params> parameters =
+ ClaimInterface::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbClaimInterfaceFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
- if (!device_handle.get())
- return;
+ GetDeviceHandle(parameters->handle);
+ if (!device_handle.get()) {
+ return RespondNow(Error(kErrorNoConnection));
+ }
- bool success = device_handle->ClaimInterface(parameters_->interface_number);
+ device_handle->ClaimInterface(
+ parameters->interface_number,
+ base::Bind(&UsbClaimInterfaceFunction::OnComplete, this));
+ return RespondLater();
+}
- if (!success)
- SetError(kErrorCannotClaimInterface);
- AsyncWorkCompleted();
+void UsbClaimInterfaceFunction::OnComplete(bool success) {
+ if (success) {
+ Respond(NoArguments());
+ } else {
+ Respond(Error(kErrorCannotClaimInterface));
+ }
}
UsbReleaseInterfaceFunction::UsbReleaseInterfaceFunction() {
@@ -968,22 +885,22 @@ UsbReleaseInterfaceFunction::UsbReleaseInterfaceFunction() {
UsbReleaseInterfaceFunction::~UsbReleaseInterfaceFunction() {
}
-bool UsbReleaseInterfaceFunction::Prepare() {
- parameters_ = ReleaseInterface::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction UsbReleaseInterfaceFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::ReleaseInterface::Params> parameters =
+ ReleaseInterface::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbReleaseInterfaceFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
- if (!device_handle.get())
- return;
+ GetDeviceHandle(parameters->handle);
+ if (!device_handle.get()) {
+ return RespondNow(Error(kErrorNoConnection));
+ }
- bool success = device_handle->ReleaseInterface(parameters_->interface_number);
- if (!success)
- SetError(kErrorCannotReleaseInterface);
- AsyncWorkCompleted();
+ if (device_handle->ReleaseInterface(parameters->interface_number)) {
+ return RespondNow(NoArguments());
+ } else {
+ return RespondNow(Error(kErrorCannotReleaseInterface));
+ }
}
UsbSetInterfaceAlternateSettingFunction::
@@ -994,24 +911,30 @@ UsbSetInterfaceAlternateSettingFunction::
~UsbSetInterfaceAlternateSettingFunction() {
}
-bool UsbSetInterfaceAlternateSettingFunction::Prepare() {
- parameters_ = SetInterfaceAlternateSetting::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction
+UsbSetInterfaceAlternateSettingFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::SetInterfaceAlternateSetting::Params>
+ parameters = SetInterfaceAlternateSetting::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbSetInterfaceAlternateSettingFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
- if (!device_handle.get())
- return;
+ GetDeviceHandle(parameters->handle);
+ if (!device_handle.get()) {
+ return RespondNow(Error(kErrorNoConnection));
+ }
- bool success = device_handle->SetInterfaceAlternateSetting(
- parameters_->interface_number, parameters_->alternate_setting);
- if (!success)
- SetError(kErrorCannotSetInterfaceAlternateSetting);
+ device_handle->SetInterfaceAlternateSetting(
+ parameters->interface_number, parameters->alternate_setting,
+ base::Bind(&UsbSetInterfaceAlternateSettingFunction::OnComplete, this));
+ return RespondLater();
+}
- AsyncWorkCompleted();
+void UsbSetInterfaceAlternateSettingFunction::OnComplete(bool success) {
+ if (success) {
+ Respond(NoArguments());
+ } else {
+ Respond(Error(kErrorCannotSetInterfaceAlternateSetting));
+ }
}
UsbControlTransferFunction::UsbControlTransferFunction() {
@@ -1020,54 +943,55 @@ UsbControlTransferFunction::UsbControlTransferFunction() {
UsbControlTransferFunction::~UsbControlTransferFunction() {
}
-bool UsbControlTransferFunction::Prepare() {
- parameters_ = ControlTransfer::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction UsbControlTransferFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::ControlTransfer::Params> parameters =
+ ControlTransfer::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbControlTransferFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
- if (!device_handle.get())
- return;
-
- const ControlTransferInfo& transfer = parameters_->transfer_info;
+ GetDeviceHandle(parameters->handle);
+ if (!device_handle.get()) {
+ return RespondNow(Error(kErrorNoConnection));
+ }
+ const ControlTransferInfo& transfer = parameters->transfer_info;
UsbEndpointDirection direction;
UsbDeviceHandle::TransferRequestType request_type;
UsbDeviceHandle::TransferRecipient recipient;
size_t size = 0;
- if (!ConvertDirectionSafely(transfer.direction, &direction) ||
- !ConvertRequestTypeSafely(transfer.request_type, &request_type) ||
- !ConvertRecipientSafely(transfer.recipient, &recipient)) {
- AsyncWorkCompleted();
- return;
+ if (!ConvertDirectionFromApi(transfer.direction, &direction)) {
+ return RespondNow(Error(kErrorConvertDirection));
+ }
+
+ if (!ConvertRequestTypeFromApi(transfer.request_type, &request_type)) {
+ return RespondNow(Error(kErrorConvertRequestType));
+ }
+
+ if (!ConvertRecipientFromApi(transfer.recipient, &recipient)) {
+ return RespondNow(Error(kErrorConvertRecipient));
}
if (!GetTransferSize(transfer, &size)) {
- CompleteWithError(kErrorInvalidTransferLength);
- return;
+ return RespondNow(Error(kErrorInvalidTransferLength));
}
scoped_refptr<net::IOBuffer> buffer =
CreateBufferForTransfer(transfer, direction, size);
if (!buffer.get()) {
- CompleteWithError(kErrorMalformedParameters);
- return;
+ return RespondNow(Error(kErrorMalformedParameters));
}
int timeout = transfer.timeout ? *transfer.timeout : 0;
if (timeout < 0) {
- CompleteWithError(kErrorInvalidTimeout);
- return;
+ return RespondNow(Error(kErrorInvalidTimeout));
}
device_handle->ControlTransfer(
direction, request_type, recipient, transfer.request, transfer.value,
transfer.index, buffer.get(), size, timeout,
base::Bind(&UsbControlTransferFunction::OnCompleted, this));
+ return RespondLater();
}
UsbBulkTransferFunction::UsbBulkTransferFunction() {
@@ -1076,49 +1000,44 @@ UsbBulkTransferFunction::UsbBulkTransferFunction() {
UsbBulkTransferFunction::~UsbBulkTransferFunction() {
}
-bool UsbBulkTransferFunction::Prepare() {
- parameters_ = BulkTransfer::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction UsbBulkTransferFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::BulkTransfer::Params> parameters =
+ BulkTransfer::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbBulkTransferFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
- if (!device_handle.get())
- return;
-
- const GenericTransferInfo& transfer = parameters_->transfer_info;
+ GetDeviceHandle(parameters->handle);
+ if (!device_handle.get()) {
+ return RespondNow(Error(kErrorNoConnection));
+ }
+ const GenericTransferInfo& transfer = parameters->transfer_info;
UsbEndpointDirection direction;
size_t size = 0;
- if (!ConvertDirectionSafely(transfer.direction, &direction)) {
- AsyncWorkCompleted();
- return;
+ if (!ConvertDirectionFromApi(transfer.direction, &direction)) {
+ return RespondNow(Error(kErrorConvertDirection));
}
if (!GetTransferSize(transfer, &size)) {
- CompleteWithError(kErrorInvalidTransferLength);
- return;
+ return RespondNow(Error(kErrorInvalidTransferLength));
}
scoped_refptr<net::IOBuffer> buffer =
CreateBufferForTransfer(transfer, direction, size);
if (!buffer.get()) {
- CompleteWithError(kErrorMalformedParameters);
- return;
+ return RespondNow(Error(kErrorMalformedParameters));
}
int timeout = transfer.timeout ? *transfer.timeout : 0;
if (timeout < 0) {
- CompleteWithError(kErrorInvalidTimeout);
- return;
+ return RespondNow(Error(kErrorInvalidTimeout));
}
device_handle->BulkTransfer(
direction, transfer.endpoint, buffer.get(), size, timeout,
base::Bind(&UsbBulkTransferFunction::OnCompleted, this));
+ return RespondLater();
}
UsbInterruptTransferFunction::UsbInterruptTransferFunction() {
@@ -1127,49 +1046,44 @@ UsbInterruptTransferFunction::UsbInterruptTransferFunction() {
UsbInterruptTransferFunction::~UsbInterruptTransferFunction() {
}
-bool UsbInterruptTransferFunction::Prepare() {
- parameters_ = InterruptTransfer::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction UsbInterruptTransferFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::InterruptTransfer::Params> parameters =
+ InterruptTransfer::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbInterruptTransferFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
- if (!device_handle.get())
- return;
-
- const GenericTransferInfo& transfer = parameters_->transfer_info;
+ GetDeviceHandle(parameters->handle);
+ if (!device_handle.get()) {
+ return RespondNow(Error(kErrorNoConnection));
+ }
+ const GenericTransferInfo& transfer = parameters->transfer_info;
UsbEndpointDirection direction;
size_t size = 0;
- if (!ConvertDirectionSafely(transfer.direction, &direction)) {
- AsyncWorkCompleted();
- return;
+ if (!ConvertDirectionFromApi(transfer.direction, &direction)) {
+ return RespondNow(Error(kErrorConvertDirection));
}
if (!GetTransferSize(transfer, &size)) {
- CompleteWithError(kErrorInvalidTransferLength);
- return;
+ return RespondNow(Error(kErrorInvalidTransferLength));
}
scoped_refptr<net::IOBuffer> buffer =
CreateBufferForTransfer(transfer, direction, size);
if (!buffer.get()) {
- CompleteWithError(kErrorMalformedParameters);
- return;
+ return RespondNow(Error(kErrorMalformedParameters));
}
int timeout = transfer.timeout ? *transfer.timeout : 0;
if (timeout < 0) {
- CompleteWithError(kErrorInvalidTimeout);
- return;
+ return RespondNow(Error(kErrorInvalidTimeout));
}
device_handle->InterruptTransfer(
direction, transfer.endpoint, buffer.get(), size, timeout,
base::Bind(&UsbInterruptTransferFunction::OnCompleted, this));
+ return RespondLater();
}
UsbIsochronousTransferFunction::UsbIsochronousTransferFunction() {
@@ -1178,66 +1092,62 @@ UsbIsochronousTransferFunction::UsbIsochronousTransferFunction() {
UsbIsochronousTransferFunction::~UsbIsochronousTransferFunction() {
}
-bool UsbIsochronousTransferFunction::Prepare() {
- parameters_ = IsochronousTransfer::Params::Create(*args_);
- EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
+ExtensionFunction::ResponseAction UsbIsochronousTransferFunction::Run() {
+ scoped_ptr<extensions::core_api::usb::IsochronousTransfer::Params>
+ parameters = IsochronousTransfer::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(parameters.get());
-void UsbIsochronousTransferFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
- if (!device_handle.get())
- return;
+ GetDeviceHandle(parameters->handle);
+ if (!device_handle.get()) {
+ return RespondNow(Error(kErrorNoConnection));
+ }
- const IsochronousTransferInfo& transfer = parameters_->transfer_info;
+ const IsochronousTransferInfo& transfer = parameters->transfer_info;
const GenericTransferInfo& generic_transfer = transfer.transfer_info;
-
size_t size = 0;
UsbEndpointDirection direction;
- if (!ConvertDirectionSafely(generic_transfer.direction, &direction)) {
- AsyncWorkCompleted();
- return;
+ if (!ConvertDirectionFromApi(generic_transfer.direction, &direction)) {
+ return RespondNow(Error(kErrorConvertDirection));
}
+
if (!GetTransferSize(generic_transfer, &size)) {
- CompleteWithError(kErrorInvalidTransferLength);
- return;
+ return RespondNow(Error(kErrorInvalidTransferLength));
}
+
if (transfer.packets < 0 || transfer.packets >= kMaxPackets) {
- CompleteWithError(kErrorInvalidNumberOfPackets);
- return;
+ return RespondNow(Error(kErrorInvalidNumberOfPackets));
}
+
unsigned int packets = transfer.packets;
if (transfer.packet_length < 0 ||
transfer.packet_length >= kMaxPacketLength) {
- CompleteWithError(kErrorInvalidPacketLength);
- return;
+ return RespondNow(Error(kErrorInvalidPacketLength));
}
+
unsigned int packet_length = transfer.packet_length;
const uint64 total_length = packets * packet_length;
if (packets > size || total_length > size) {
- CompleteWithError(kErrorTransferLength);
- return;
+ return RespondNow(Error(kErrorTransferLength));
}
scoped_refptr<net::IOBuffer> buffer =
CreateBufferForTransfer(generic_transfer, direction, size);
if (!buffer.get()) {
- CompleteWithError(kErrorMalformedParameters);
- return;
+ return RespondNow(Error(kErrorMalformedParameters));
}
int timeout = generic_transfer.timeout ? *generic_transfer.timeout : 0;
if (timeout < 0) {
- CompleteWithError(kErrorInvalidTimeout);
- return;
+ return RespondNow(Error(kErrorInvalidTimeout));
}
device_handle->IsochronousTransfer(
direction, generic_transfer.endpoint, buffer.get(), size, packets,
packet_length, timeout,
base::Bind(&UsbIsochronousTransferFunction::OnCompleted, this));
+ return RespondLater();
}
UsbResetDeviceFunction::UsbResetDeviceFunction() {
@@ -1246,29 +1156,37 @@ UsbResetDeviceFunction::UsbResetDeviceFunction() {
UsbResetDeviceFunction::~UsbResetDeviceFunction() {
}
-bool UsbResetDeviceFunction::Prepare() {
+ExtensionFunction::ResponseAction UsbResetDeviceFunction::Run() {
parameters_ = ResetDevice::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters_.get());
- return true;
-}
-void UsbResetDeviceFunction::AsyncWorkStart() {
scoped_refptr<UsbDeviceHandle> device_handle =
- GetDeviceHandleOrCompleteWithError(parameters_->handle);
- if (!device_handle.get())
- return;
-
- bool success = device_handle->ResetDevice();
- if (!success) {
- device_handle->Close();
- RemoveUsbDeviceResource(parameters_->handle.handle);
- SetResult(new base::FundamentalValue(false));
- CompleteWithError(kErrorResetDevice);
- return;
+ GetDeviceHandle(parameters_->handle);
+ if (!device_handle.get()) {
+ return RespondNow(Error(kErrorNoConnection));
}
- SetResult(new base::FundamentalValue(true));
- AsyncWorkCompleted();
+ device_handle->ResetDevice(
+ base::Bind(&UsbResetDeviceFunction::OnComplete, this));
+ return RespondLater();
+}
+
+void UsbResetDeviceFunction::OnComplete(bool success) {
+ if (success) {
+ Respond(OneArgument(new base::FundamentalValue(true)));
+ } else {
+ scoped_refptr<UsbDeviceHandle> device_handle =
+ GetDeviceHandle(parameters_->handle);
+ if (device_handle.get()) {
+ device_handle->Close();
+ }
+ ReleaseDeviceHandle(parameters_->handle);
+
+ scoped_ptr<base::ListValue> error_args(new base::ListValue());
+ error_args->AppendBoolean(false);
+ // Returning arguments with an error is wrong but we're stuck with it.
+ Respond(ErrorWithArguments(error_args.Pass(), kErrorResetDevice));
+ }
}
} // namespace extensions
diff --git a/extensions/browser/api/usb/usb_api.h b/extensions/browser/api/usb/usb_api.h
index 8903348..c7ab6c3 100644
--- a/extensions/browser/api/usb/usb_api.h
+++ b/extensions/browser/api/usb/usb_api.h
@@ -14,8 +14,8 @@
#include "device/usb/usb_device_filter.h"
#include "device/usb/usb_device_handle.h"
#include "extensions/browser/api/api_resource_manager.h"
-#include "extensions/browser/api/async_api_function.h"
#include "extensions/browser/api/device_permissions_prompt.h"
+#include "extensions/browser/extension_function.h"
#include "extensions/common/api/usb.h"
#include "net/base/io_buffer.h"
@@ -26,83 +26,86 @@ class DevicePermissions;
class DevicePermissionsManager;
class UsbDeviceResource;
-class UsbAsyncApiFunction : public AsyncApiFunction {
- public:
- UsbAsyncApiFunction();
-
+class UsbPermissionCheckingFunction : public UIThreadExtensionFunction {
protected:
- ~UsbAsyncApiFunction() override;
-
- // AsyncApiFunction:
- bool PrePrepare() override;
- bool Respond() override;
+ UsbPermissionCheckingFunction();
+ ~UsbPermissionCheckingFunction() override;
bool HasDevicePermission(scoped_refptr<device::UsbDevice> device);
- scoped_refptr<device::UsbDeviceHandle> GetDeviceHandleOrCompleteWithError(
- const extensions::core_api::usb::ConnectionHandle& input_device_handle);
- void RemoveUsbDeviceResource(int api_resource_id);
- void CompleteWithError(const std::string& error);
+ void RecordDeviceLastUsed();
- ApiResourceManager<UsbDeviceResource>* manager_;
- scoped_ptr<DevicePermissions> device_permissions_;
+ private:
+ DevicePermissionsManager* device_permissions_manager_;
scoped_refptr<DevicePermissionEntry> permission_entry_;
};
-class UsbAsyncApiTransferFunction : public UsbAsyncApiFunction {
+class UsbConnectionFunction : public UIThreadExtensionFunction {
protected:
- UsbAsyncApiTransferFunction();
- ~UsbAsyncApiTransferFunction() override;
-
- bool ConvertDirectionSafely(const extensions::core_api::usb::Direction& input,
- device::UsbEndpointDirection* output);
- bool ConvertRequestTypeSafely(
- const extensions::core_api::usb::RequestType& input,
- device::UsbDeviceHandle::TransferRequestType* output);
- bool ConvertRecipientSafely(
- const extensions::core_api::usb::Recipient& input,
- device::UsbDeviceHandle::TransferRecipient* output);
+ UsbConnectionFunction();
+ ~UsbConnectionFunction() override;
+
+ scoped_refptr<device::UsbDeviceHandle> GetDeviceHandle(
+ const extensions::core_api::usb::ConnectionHandle& handle);
+ void ReleaseDeviceHandle(
+ const extensions::core_api::usb::ConnectionHandle& handle);
+};
+
+class UsbTransferFunction : public UsbConnectionFunction {
+ protected:
+ UsbTransferFunction();
+ ~UsbTransferFunction() override;
void OnCompleted(device::UsbTransferStatus status,
scoped_refptr<net::IOBuffer> data,
size_t length);
};
-class UsbFindDevicesFunction : public UsbAsyncApiFunction {
+class UsbFindDevicesFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.findDevices", USB_FINDDEVICES)
UsbFindDevicesFunction();
- protected:
+ private:
~UsbFindDevicesFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ void OnGetDevicesComplete(
+ const std::vector<scoped_refptr<device::UsbDevice>>& devices);
+ void OnRequestAccessComplete(scoped_refptr<device::UsbDevice> device,
+ bool success);
+ void OnDeviceOpened(scoped_refptr<device::UsbDeviceHandle> device_handle);
+ void OpenComplete();
- private:
- void OpenDevices(
- scoped_ptr<std::vector<scoped_refptr<device::UsbDevice> > > devices);
+ uint16_t vendor_id_;
+ uint16_t product_id_;
+ int interface_id_;
+ scoped_ptr<base::ListValue> result_;
+ base::Closure barrier_;
- std::vector<scoped_refptr<device::UsbDeviceHandle> > device_handles_;
- scoped_ptr<extensions::core_api::usb::FindDevices::Params> parameters_;
+ DISALLOW_COPY_AND_ASSIGN(UsbFindDevicesFunction);
};
-class UsbGetDevicesFunction : public UsbAsyncApiFunction {
+class UsbGetDevicesFunction : public UsbPermissionCheckingFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.getDevices", USB_GETDEVICES)
UsbGetDevicesFunction();
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
-
- protected:
+ private:
~UsbGetDevicesFunction() override;
- private:
- scoped_ptr<extensions::core_api::usb::GetDevices::Params> parameters_;
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ void OnGetDevicesComplete(
+ const std::vector<scoped_refptr<device::UsbDevice>>& devices);
+
+ std::vector<device::UsbDeviceFilter> filters_;
+
+ DISALLOW_COPY_AND_ASSIGN(UsbGetDevicesFunction);
};
class UsbGetUserSelectedDevicesFunction
@@ -114,130 +117,117 @@ class UsbGetUserSelectedDevicesFunction
UsbGetUserSelectedDevicesFunction();
- protected:
+ private:
~UsbGetUserSelectedDevicesFunction() override;
// ExtensionFunction:
ResponseAction Run() override;
- private:
void OnUsbDevicesChosen(
const std::vector<scoped_refptr<device::UsbDevice>>& devices) override;
scoped_ptr<DevicePermissionsPrompt> prompt_;
- std::vector<uint32> device_ids_;
- std::vector<scoped_refptr<device::UsbDevice>> devices_;
- std::vector<base::string16> serial_numbers_;
+
+ DISALLOW_COPY_AND_ASSIGN(UsbGetUserSelectedDevicesFunction);
};
-class UsbRequestAccessFunction : public UsbAsyncApiFunction {
+class UsbRequestAccessFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.requestAccess", USB_REQUESTACCESS)
UsbRequestAccessFunction();
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
-
- protected:
+ private:
~UsbRequestAccessFunction() override;
- private:
- scoped_ptr<extensions::core_api::usb::RequestAccess::Params> parameters_;
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ DISALLOW_COPY_AND_ASSIGN(UsbRequestAccessFunction);
};
-class UsbOpenDeviceFunction : public UsbAsyncApiFunction {
+class UsbOpenDeviceFunction : public UsbPermissionCheckingFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.openDevice", USB_OPENDEVICE)
UsbOpenDeviceFunction();
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
- bool Respond() override;
-
- protected:
+ private:
~UsbOpenDeviceFunction() override;
- private:
- void OnRequestAccessComplete(bool success);
+ // ExtensionFunction:
+ ResponseAction Run() override;
- DevicePermissionsManager* device_permissions_manager_;
- scoped_refptr<device::UsbDevice> device_;
- scoped_ptr<extensions::core_api::usb::OpenDevice::Params> parameters_;
+ void OnRequestAccessComplete(scoped_refptr<device::UsbDevice> device,
+ bool success);
+ void OnDeviceOpened(scoped_refptr<device::UsbDeviceHandle> device_handle);
+
+ DISALLOW_COPY_AND_ASSIGN(UsbOpenDeviceFunction);
};
-class UsbSetConfigurationFunction : public UsbAsyncApiFunction {
+class UsbSetConfigurationFunction : public UsbConnectionFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.setConfiguration", USB_SETCONFIGURATION)
UsbSetConfigurationFunction();
- protected:
+ private:
~UsbSetConfigurationFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
- private:
- scoped_ptr<extensions::core_api::usb::SetConfiguration::Params> parameters_;
+ void OnComplete(bool success);
+
+ DISALLOW_COPY_AND_ASSIGN(UsbSetConfigurationFunction);
};
-class UsbGetConfigurationFunction : public UsbAsyncApiFunction {
+class UsbGetConfigurationFunction : public UsbConnectionFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.getConfiguration", USB_GETCONFIGURATION)
UsbGetConfigurationFunction();
- protected:
+ private:
~UsbGetConfigurationFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
- private:
- scoped_ptr<extensions::core_api::usb::GetConfiguration::Params> parameters_;
+ DISALLOW_COPY_AND_ASSIGN(UsbGetConfigurationFunction);
};
-class UsbListInterfacesFunction : public UsbAsyncApiFunction {
+class UsbListInterfacesFunction : public UsbConnectionFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.listInterfaces", USB_LISTINTERFACES)
UsbListInterfacesFunction();
- protected:
+ private:
~UsbListInterfacesFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
- private:
- scoped_ptr<extensions::core_api::usb::ListInterfaces::Params> parameters_;
+ DISALLOW_COPY_AND_ASSIGN(UsbListInterfacesFunction);
};
-class UsbCloseDeviceFunction : public UsbAsyncApiFunction {
+class UsbCloseDeviceFunction : public UsbConnectionFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.closeDevice", USB_CLOSEDEVICE)
UsbCloseDeviceFunction();
- protected:
+ private:
~UsbCloseDeviceFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
- private:
- scoped_ptr<extensions::core_api::usb::CloseDevice::Params> parameters_;
+ DISALLOW_COPY_AND_ASSIGN(UsbCloseDeviceFunction);
};
-class UsbClaimInterfaceFunction : public UsbAsyncApiFunction {
+class UsbClaimInterfaceFunction : public UsbConnectionFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.claimInterface", USB_CLAIMINTERFACE)
@@ -246,32 +236,30 @@ class UsbClaimInterfaceFunction : public UsbAsyncApiFunction {
protected:
~UsbClaimInterfaceFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ void OnComplete(bool success);
- private:
- scoped_ptr<extensions::core_api::usb::ClaimInterface::Params> parameters_;
+ DISALLOW_COPY_AND_ASSIGN(UsbClaimInterfaceFunction);
};
-class UsbReleaseInterfaceFunction : public UsbAsyncApiFunction {
+class UsbReleaseInterfaceFunction : public UsbConnectionFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.releaseInterface", USB_RELEASEINTERFACE)
UsbReleaseInterfaceFunction();
- protected:
+ private:
~UsbReleaseInterfaceFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
- private:
- scoped_ptr<extensions::core_api::usb::ReleaseInterface::Params> parameters_;
+ DISALLOW_COPY_AND_ASSIGN(UsbReleaseInterfaceFunction);
};
-class UsbSetInterfaceAlternateSettingFunction : public UsbAsyncApiFunction {
+class UsbSetInterfaceAlternateSettingFunction : public UsbConnectionFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.setInterfaceAlternateSetting",
USB_SETINTERFACEALTERNATESETTING)
@@ -281,98 +269,91 @@ class UsbSetInterfaceAlternateSettingFunction : public UsbAsyncApiFunction {
private:
~UsbSetInterfaceAlternateSettingFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ void OnComplete(bool success);
- scoped_ptr<extensions::core_api::usb::SetInterfaceAlternateSetting::Params>
- parameters_;
+ DISALLOW_COPY_AND_ASSIGN(UsbSetInterfaceAlternateSettingFunction);
};
-class UsbControlTransferFunction : public UsbAsyncApiTransferFunction {
+class UsbControlTransferFunction : public UsbTransferFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.controlTransfer", USB_CONTROLTRANSFER)
UsbControlTransferFunction();
- protected:
+ private:
~UsbControlTransferFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
- private:
- scoped_ptr<extensions::core_api::usb::ControlTransfer::Params> parameters_;
+ DISALLOW_COPY_AND_ASSIGN(UsbControlTransferFunction);
};
-class UsbBulkTransferFunction : public UsbAsyncApiTransferFunction {
+class UsbBulkTransferFunction : public UsbTransferFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.bulkTransfer", USB_BULKTRANSFER)
UsbBulkTransferFunction();
- protected:
+ private:
~UsbBulkTransferFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
- private:
- scoped_ptr<extensions::core_api::usb::BulkTransfer::Params> parameters_;
+ DISALLOW_COPY_AND_ASSIGN(UsbBulkTransferFunction);
};
-class UsbInterruptTransferFunction : public UsbAsyncApiTransferFunction {
+class UsbInterruptTransferFunction : public UsbTransferFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.interruptTransfer", USB_INTERRUPTTRANSFER)
UsbInterruptTransferFunction();
- protected:
+ private:
~UsbInterruptTransferFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
- private:
- scoped_ptr<extensions::core_api::usb::InterruptTransfer::Params> parameters_;
+ DISALLOW_COPY_AND_ASSIGN(UsbInterruptTransferFunction);
};
-class UsbIsochronousTransferFunction : public UsbAsyncApiTransferFunction {
+class UsbIsochronousTransferFunction : public UsbTransferFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.isochronousTransfer", USB_ISOCHRONOUSTRANSFER)
UsbIsochronousTransferFunction();
- protected:
+ private:
~UsbIsochronousTransferFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
- private:
- scoped_ptr<extensions::core_api::usb::IsochronousTransfer::Params>
- parameters_;
+ DISALLOW_COPY_AND_ASSIGN(UsbIsochronousTransferFunction);
};
-class UsbResetDeviceFunction : public UsbAsyncApiFunction {
+class UsbResetDeviceFunction : public UsbConnectionFunction {
public:
DECLARE_EXTENSION_FUNCTION("usb.resetDevice", USB_RESETDEVICE)
UsbResetDeviceFunction();
- protected:
+ private:
~UsbResetDeviceFunction() override;
- // AsyncApiFunction:
- bool Prepare() override;
- void AsyncWorkStart() override;
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ void OnComplete(bool success);
- private:
scoped_ptr<extensions::core_api::usb::ResetDevice::Params> parameters_;
+
+ DISALLOW_COPY_AND_ASSIGN(UsbResetDeviceFunction);
};
} // namespace extensions
diff --git a/extensions/browser/api/usb/usb_apitest.cc b/extensions/browser/api/usb/usb_apitest.cc
index ad36408..d2be33c 100644
--- a/extensions/browser/api/usb/usb_apitest.cc
+++ b/extensions/browser/api/usb/usb_apitest.cc
@@ -25,12 +25,17 @@ using device::UsbDeviceHandle;
using device::UsbEndpointDirection;
using device::UsbInterfaceDescriptor;
using device::UsbService;
-using device::UsbTransferCallback;
namespace extensions {
namespace {
+ACTION_TEMPLATE(InvokeCallback,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(p1)) {
+ ::std::tr1::get<k>(args).Run(p1);
+}
+
ACTION_TEMPLATE(InvokeUsbTransferCallback,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(p1)) {
@@ -84,44 +89,48 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
uint8 request,
uint16 value,
uint16 index,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
- const UsbTransferCallback& callback));
+ const TransferCallback& callback));
MOCK_METHOD6(BulkTransfer,
void(UsbEndpointDirection direction,
uint8 endpoint,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
- const UsbTransferCallback& callback));
+ const TransferCallback& callback));
MOCK_METHOD6(InterruptTransfer,
void(UsbEndpointDirection direction,
uint8 endpoint,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
- const UsbTransferCallback& callback));
+ const TransferCallback& callback));
MOCK_METHOD8(IsochronousTransfer,
void(UsbEndpointDirection direction,
uint8 endpoint,
- net::IOBuffer* buffer,
+ scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int packets,
unsigned int packet_length,
unsigned int timeout,
- const UsbTransferCallback& callback));
+ const TransferCallback& callback));
- MOCK_METHOD0(ResetDevice, bool());
+ MOCK_METHOD1(ResetDevice, void(const ResultCallback& callback));
MOCK_METHOD2(GetStringDescriptor, bool(uint8_t, base::string16*));
- MOCK_METHOD1(SetConfiguration, bool(int));
- MOCK_METHOD1(ClaimInterface, bool(int interface_number));
+ 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_METHOD2(SetInterfaceAlternateSetting,
- bool(int interface_number, int alternate_setting));
+ MOCK_METHOD3(SetInterfaceAlternateSetting,
+ void(int interface_number,
+ int alternate_setting,
+ const ResultCallback& callback));
virtual scoped_refptr<UsbDevice> GetDevice() const override {
return device_;
@@ -138,14 +147,16 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
class MockUsbDevice : public UsbDevice {
public:
MockUsbDevice(uint16 vendor_id, uint16 product_id, uint32 unique_id)
- : UsbDevice(vendor_id, product_id, unique_id) {}
-
- MOCK_METHOD0(Open, scoped_refptr<UsbDeviceHandle>());
+ : UsbDevice(vendor_id,
+ product_id,
+ unique_id,
+ base::string16(),
+ base::string16(),
+ base::string16()) {}
+
+ MOCK_METHOD1(Open, void(const OpenCallback&));
MOCK_METHOD1(Close, bool(scoped_refptr<UsbDeviceHandle>));
MOCK_METHOD0(GetConfiguration, const device::UsbConfigDescriptor*());
- MOCK_METHOD1(GetManufacturer, bool(base::string16*));
- MOCK_METHOD1(GetProduct, bool(base::string16*));
- MOCK_METHOD1(GetSerialNumber, bool(base::string16*));
private:
virtual ~MockUsbDevice() {}
@@ -171,9 +182,10 @@ class MockUsbService : public UsbService {
return device_;
}
- void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override {
- STLClearObject(devices);
- devices->push_back(device_);
+ void GetDevices(const GetDevicesCallback& callback) override {
+ std::vector<scoped_refptr<UsbDevice>> devices;
+ devices.push_back(device_);
+ callback.Run(devices);
}
scoped_refptr<UsbDevice> device_;
@@ -185,46 +197,17 @@ class UsbApiTest : public ShellApiTest {
ShellApiTest::SetUpOnMainThread();
mock_device_ = new MockUsbDevice(0, 0, 0);
- EXPECT_CALL(*mock_device_.get(), GetManufacturer(_))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(*mock_device_.get(), GetProduct(_))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(*mock_device_.get(), GetSerialNumber(_))
- .WillRepeatedly(Return(false));
-
mock_device_handle_ = new MockUsbDeviceHandle();
mock_device_handle_->set_device(mock_device_.get());
- EXPECT_CALL(*mock_device_.get(), Open())
- .WillRepeatedly(Return(mock_device_handle_));
-
- base::RunLoop run_loop;
- BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
- base::Bind(&UsbApiTest::SetUpService, this),
- run_loop.QuitClosure());
- run_loop.Run();
- }
-
- void SetUpService() {
- mock_service_ = new MockUsbService(mock_device_);
- UsbService::SetInstanceForTest(mock_service_);
- }
-
- void AddTestDevices() {
- scoped_refptr<MockUsbDevice> device(new MockUsbDevice(0x18D1, 0x58F0, 1));
- EXPECT_CALL(*device.get(), GetSerialNumber(_))
- .WillRepeatedly(Return(false));
- mock_service_->NotifyDeviceAdded(device);
-
- device = new MockUsbDevice(0x18D1, 0x58F1, 2);
- EXPECT_CALL(*device.get(), GetSerialNumber(_))
- .WillRepeatedly(Return(false));
- mock_service_->NotifyDeviceAdded(device);
+ EXPECT_CALL(*mock_device_.get(), Open(_))
+ .WillRepeatedly(InvokeCallback<0>(mock_device_handle_));
+ mock_service_.reset(new MockUsbService(mock_device_));
}
protected:
scoped_refptr<MockUsbDeviceHandle> mock_device_handle_;
scoped_refptr<MockUsbDevice> mock_device_;
- MockUsbService* mock_service_;
+ scoped_ptr<MockUsbService> mock_service_;
};
} // namespace
@@ -236,9 +219,9 @@ IN_PROC_BROWSER_TEST_F(UsbApiTest, DeviceHandling) {
IN_PROC_BROWSER_TEST_F(UsbApiTest, ResetDevice) {
EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(2);
- EXPECT_CALL(*mock_device_handle_.get(), ResetDevice())
- .WillOnce(Return(true))
- .WillOnce(Return(false));
+ EXPECT_CALL(*mock_device_handle_.get(), ResetDevice(_))
+ .WillOnce(InvokeCallback<0>(true))
+ .WillOnce(InvokeCallback<0>(false));
EXPECT_CALL(*mock_device_handle_.get(),
InterruptTransfer(device::USB_DIRECTION_OUTBOUND, 2, _, 1, _, _))
.WillOnce(InvokeUsbTransferCallback<5>(device::USB_TRANSFER_COMPLETED));
@@ -247,8 +230,8 @@ IN_PROC_BROWSER_TEST_F(UsbApiTest, ResetDevice) {
IN_PROC_BROWSER_TEST_F(UsbApiTest, SetConfiguration) {
UsbConfigDescriptor config_descriptor;
- EXPECT_CALL(*mock_device_handle_.get(), SetConfiguration(1))
- .WillOnce(Return(true));
+ EXPECT_CALL(*mock_device_handle_.get(), SetConfiguration(1, _))
+ .WillOnce(InvokeCallback<1>(true));
EXPECT_CALL(*mock_device_handle_.get(), Close()).Times(1);
EXPECT_CALL(*mock_device_.get(), GetConfiguration())
.WillOnce(Return(nullptr))
@@ -325,12 +308,11 @@ IN_PROC_BROWSER_TEST_F(UsbApiTest, OnDeviceAdded) {
ASSERT_TRUE(LoadApp("api_test/usb/add_event"));
ASSERT_TRUE(load_listener.WaitUntilSatisfied());
- base::RunLoop run_loop;
- BrowserThread::PostTaskAndReply(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&UsbApiTest::AddTestDevices, base::Unretained(this)),
- run_loop.QuitClosure());
- run_loop.Run();
+ scoped_refptr<MockUsbDevice> device(new MockUsbDevice(0x18D1, 0x58F0, 1));
+ mock_service_->NotifyDeviceAdded(device);
+
+ device = new MockUsbDevice(0x18D1, 0x58F1, 2);
+ mock_service_->NotifyDeviceAdded(device);
ASSERT_TRUE(result_listener.WaitUntilSatisfied());
}
@@ -343,14 +325,7 @@ IN_PROC_BROWSER_TEST_F(UsbApiTest, OnDeviceRemoved) {
ASSERT_TRUE(LoadApp("api_test/usb/remove_event"));
ASSERT_TRUE(load_listener.WaitUntilSatisfied());
- base::RunLoop run_loop;
- BrowserThread::PostTaskAndReply(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&MockUsbService::NotifyDeviceRemoved,
- base::Unretained(mock_service_), mock_device_),
- run_loop.QuitClosure());
- run_loop.Run();
-
+ mock_service_->NotifyDeviceRemoved(mock_device_);
ASSERT_TRUE(result_listener.WaitUntilSatisfied());
}
@@ -365,14 +340,7 @@ IN_PROC_BROWSER_TEST_F(UsbApiTest, GetUserSelectedDevices) {
ASSERT_TRUE(LoadApp("api_test/usb/get_user_selected_devices"));
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
- base::RunLoop run_loop;
- BrowserThread::PostTaskAndReply(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&MockUsbService::NotifyDeviceRemoved,
- base::Unretained(mock_service_), mock_device_),
- run_loop.QuitClosure());
- run_loop.Run();
-
+ mock_service_->NotifyDeviceRemoved(mock_device_);
ASSERT_TRUE(result_listener.WaitUntilSatisfied());
}
diff --git a/extensions/browser/api/usb/usb_device_resource.h b/extensions/browser/api/usb/usb_device_resource.h
index a0de7f3..d44675f 100644
--- a/extensions/browser/api/usb/usb_device_resource.h
+++ b/extensions/browser/api/usb/usb_device_resource.h
@@ -25,7 +25,7 @@ namespace extensions {
class UsbDeviceResource : public ApiResource {
public:
static const content::BrowserThread::ID kThreadId =
- content::BrowserThread::FILE;
+ content::BrowserThread::UI;
UsbDeviceResource(const std::string& owner_extension_id,
scoped_refptr<device::UsbDeviceHandle> device);
diff --git a/extensions/browser/api/usb/usb_event_router.cc b/extensions/browser/api/usb/usb_event_router.cc
index 93fff3f..41ae777 100644
--- a/extensions/browser/api/usb/usb_event_router.cc
+++ b/extensions/browser/api/usb/usb_event_router.cc
@@ -6,7 +6,6 @@
#include "device/core/device_client.h"
#include "device/usb/usb_device.h"
-#include "device/usb/usb_service.h"
#include "extensions/browser/api/device_permissions_manager.h"
#include "extensions/common/api/usb.h"
#include "extensions/common/permissions/permissions_data.h"
@@ -25,7 +24,6 @@ namespace {
// Returns true iff the given extension has permission to receive events
// regarding this device.
bool WillDispatchDeviceEvent(scoped_refptr<UsbDevice> device,
- const base::string16& serial_number,
content::BrowserContext* browser_context,
const Extension* extension,
base::ListValue* event_args) {
@@ -39,10 +37,10 @@ bool WillDispatchDeviceEvent(scoped_refptr<UsbDevice> device,
}
// Check permissions granted through chrome.usb.getUserSelectedDevices.
- scoped_ptr<DevicePermissions> device_permissions =
+ DevicePermissions* device_permissions =
DevicePermissionsManager::Get(browser_context)
->GetForExtension(extension->id());
- if (device_permissions->FindEntry(device, serial_number).get()) {
+ if (device_permissions->FindEntry(device).get()) {
return true;
}
@@ -54,50 +52,6 @@ base::LazyInstance<BrowserContextKeyedAPIFactory<UsbEventRouter>>::Leaky
} // namespace
-class UsbEventRouter::FileThreadHelper : public UsbService::Observer {
- public:
- FileThreadHelper(base::WeakPtr<UsbEventRouter> usb_event_router)
- : usb_event_router_(usb_event_router), observer_(this) {}
- virtual ~FileThreadHelper() {}
-
- void Start() {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- UsbService* service = device::DeviceClient::Get()->GetUsbService();
- if (service) {
- observer_.Add(service);
- }
- }
-
- private:
- // UsbService::Observer implementation.
- void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-
- base::string16 serial_number;
- device->GetSerialNumber(&serial_number);
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&UsbEventRouter::DispatchEvent, usb_event_router_,
- usb::OnDeviceAdded::kEventName, device, serial_number));
- }
-
- void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-
- base::string16 serial_number;
- device->GetSerialNumber(&serial_number);
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&UsbEventRouter::DispatchEvent, usb_event_router_,
- usb::OnDeviceRemoved::kEventName, device, serial_number));
- }
-
- base::WeakPtr<UsbEventRouter> usb_event_router_;
- ScopedObserver<device::UsbService, device::UsbService::Observer> observer_;
-};
-
// static
BrowserContextKeyedAPIFactory<UsbEventRouter>*
UsbEventRouter::GetFactoryInstance() {
@@ -105,7 +59,7 @@ UsbEventRouter::GetFactoryInstance() {
}
UsbEventRouter::UsbEventRouter(content::BrowserContext* browser_context)
- : browser_context_(browser_context), weak_factory_(this) {
+ : browser_context_(browser_context), observer_(this) {
EventRouter* event_router = EventRouter::Get(browser_context_);
if (event_router) {
event_router->RegisterObserver(this, usb::OnDeviceAdded::kEventName);
@@ -121,21 +75,26 @@ void UsbEventRouter::Shutdown() {
if (event_router) {
event_router->UnregisterObserver(this);
}
- helper_.reset(nullptr);
}
void UsbEventRouter::OnListenerAdded(const EventListenerInfo& details) {
- if (!helper_) {
- helper_.reset(new FileThreadHelper(weak_factory_.GetWeakPtr()));
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&FileThreadHelper::Start, base::Unretained(helper_.get())));
+ UsbService* service = device::DeviceClient::Get()->GetUsbService();
+ if (!observer_.IsObserving(service)) {
+ observer_.Add(service);
}
}
+void UsbEventRouter::OnDeviceAdded(scoped_refptr<device::UsbDevice> device) {
+ DispatchEvent(usb::OnDeviceAdded::kEventName, device);
+}
+
+void UsbEventRouter::OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) {
+ DispatchEvent(usb::OnDeviceRemoved::kEventName, device);
+}
+
void UsbEventRouter::DispatchEvent(const std::string& event_name,
- scoped_refptr<UsbDevice> device,
- const base::string16& serial_number) {
+ scoped_refptr<UsbDevice> device) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
EventRouter* event_router = EventRouter::Get(browser_context_);
if (event_router) {
usb::Device device_obj;
@@ -154,7 +113,7 @@ void UsbEventRouter::DispatchEvent(const std::string& event_name,
}
event->will_dispatch_callback =
- base::Bind(&WillDispatchDeviceEvent, device, serial_number);
+ base::Bind(&WillDispatchDeviceEvent, device);
event_router->BroadcastEvent(event.Pass());
}
}
diff --git a/extensions/browser/api/usb/usb_event_router.h b/extensions/browser/api/usb/usb_event_router.h
index 5ff750e..6f081a2 100644
--- a/extensions/browser/api/usb/usb_event_router.h
+++ b/extensions/browser/api/usb/usb_event_router.h
@@ -6,6 +6,7 @@
#define EXTENSIONS_BROWSER_API_USB_USB_EVENT_ROUTER_H_
#include "content/public/browser/browser_thread.h"
+#include "device/usb/usb_service.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/event_router.h"
@@ -18,7 +19,8 @@ namespace extensions {
// A BrowserContext-scoped object which is registered as an observer of the
// EventRouter and UsbService in order to generate device add/remove events.
class UsbEventRouter : public BrowserContextKeyedAPI,
- public EventRouter::Observer {
+ public EventRouter::Observer,
+ public device::UsbService::Observer {
public:
// BrowserContextKeyedAPI implementation.
static BrowserContextKeyedAPIFactory<UsbEventRouter>* GetFactoryInstance();
@@ -26,8 +28,6 @@ class UsbEventRouter : public BrowserContextKeyedAPI,
private:
friend class BrowserContextKeyedAPIFactory<UsbEventRouter>;
- class FileThreadHelper;
-
explicit UsbEventRouter(content::BrowserContext* context);
~UsbEventRouter() override;
@@ -41,16 +41,17 @@ class UsbEventRouter : public BrowserContextKeyedAPI,
// EventRouter::Observer implementation.
void OnListenerAdded(const EventListenerInfo& details) override;
+ // UsbService::Observer implementation.
+ void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override;
+ void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override;
+
// Broadcasts a device add or remove event for the given device.
void DispatchEvent(const std::string& event_name,
- scoped_refptr<device::UsbDevice> device,
- const base::string16& serial_number);
+ scoped_refptr<device::UsbDevice> device);
content::BrowserContext* const browser_context_;
- scoped_ptr<FileThreadHelper, content::BrowserThread::DeleteOnFileThread>
- helper_;
- base::WeakPtrFactory<UsbEventRouter> weak_factory_;
+ ScopedObserver<device::UsbService, device::UsbService::Observer> observer_;
DISALLOW_COPY_AND_ASSIGN(UsbEventRouter);
};
diff --git a/extensions/shell/browser/shell_device_client.cc b/extensions/shell/browser/shell_device_client.cc
index 90e974b..5dd1c6b 100644
--- a/extensions/shell/browser/shell_device_client.cc
+++ b/extensions/shell/browser/shell_device_client.cc
@@ -9,6 +9,8 @@
#include "device/hid/hid_service.h"
#include "device/usb/usb_service.h"
+using content::BrowserThread;
+
namespace extensions {
ShellDeviceClient::ShellDeviceClient() {}
@@ -16,15 +18,15 @@ ShellDeviceClient::ShellDeviceClient() {}
ShellDeviceClient::~ShellDeviceClient() {}
device::UsbService* ShellDeviceClient::GetUsbService() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
return device::UsbService::GetInstance(
- content::BrowserThread::GetMessageLoopProxyForThread(
- content::BrowserThread::UI));
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
}
device::HidService* ShellDeviceClient::GetHidService() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
return device::HidService::GetInstance(
- content::BrowserThread::GetMessageLoopProxyForThread(
- content::BrowserThread::FILE));
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
}
}
diff --git a/extensions/test/data/api_test/usb/reset_device/test.js b/extensions/test/data/api_test/usb/reset_device/test.js
index 2a39ada..e709fff 100644
--- a/extensions/test/data/api_test/usb/reset_device/test.js
+++ b/extensions/test/data/api_test/usb/reset_device/test.js
@@ -19,10 +19,10 @@ function resetDevice() {
usb.resetDevice(devices[0], function(result) {
chrome.test.assertLastError(
'Error resetting the device. The device has been closed.');
- chrome.test.assertEq(result, false);
+ chrome.test.assertEq(false, result);
usb.interruptTransfer(devices[0], transfer, function(result) {
- chrome.test.assertEq(result, undefined);
- chrome.test.assertLastError('No such device.');
+ chrome.test.assertEq(undefined, result);
+ chrome.test.assertLastError('No such connection.');
chrome.test.succeed();
});
});