diff options
author | reillyg <reillyg@chromium.org> | 2014-10-16 12:19:14 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-10-16 19:21:49 +0000 |
commit | 7f4f508547ac3058d7c47337313972ec1ac2fb1b (patch) | |
tree | daf6ad84ae3eb0451ba21a203fe7d3ea8bb033ab /device | |
parent | b92d87bee7689009c26be560634070a33508bcaf (diff) | |
download | chromium_src-7f4f508547ac3058d7c47337313972ec1ac2fb1b.zip chromium_src-7f4f508547ac3058d7c47337313972ec1ac2fb1b.tar.gz chromium_src-7f4f508547ac3058d7c47337313972ec1ac2fb1b.tar.bz2 |
Open HID connections asynchronously.
By making HidService::Connect return its result asynchronously platform
specific details such as whether device nodes must be opened on a
different thread (due to blocking) or requesting access from the Chrome
OS permission broker can be abstracted away.
BUG=422540
Review URL: https://codereview.chromium.org/660573007
Cr-Commit-Position: refs/heads/master@{#299950}
Diffstat (limited to 'device')
-rw-r--r-- | device/hid/hid_connection_unittest.cc | 45 | ||||
-rw-r--r-- | device/hid/hid_service.h | 16 | ||||
-rw-r--r-- | device/hid/hid_service_linux.cc | 129 | ||||
-rw-r--r-- | device/hid/hid_service_linux.h | 17 | ||||
-rw-r--r-- | device/hid/hid_service_mac.cc | 20 | ||||
-rw-r--r-- | device/hid/hid_service_mac.h | 4 | ||||
-rw-r--r-- | device/hid/hid_service_win.cc | 27 | ||||
-rw-r--r-- | device/hid/hid_service_win.h | 6 |
8 files changed, 165 insertions, 99 deletions
diff --git a/device/hid/hid_connection_unittest.cc b/device/hid/hid_connection_unittest.cc index 903cf5a..5654fc0 100644 --- a/device/hid/hid_connection_unittest.cc +++ b/device/hid/hid_connection_unittest.cc @@ -21,14 +21,39 @@ namespace { using net::IOBufferWithSize; -class TestCompletionCallback { +class TestConnectCallback { public: - TestCompletionCallback() - : read_callback_(base::Bind(&TestCompletionCallback::SetReadResult, - base::Unretained(this))), - write_callback_(base::Bind(&TestCompletionCallback::SetWriteResult, + TestConnectCallback() + : callback_(base::Bind(&TestConnectCallback::SetConnection, + base::Unretained(this))) {} + ~TestConnectCallback() {} + + void SetConnection(scoped_refptr<HidConnection> connection) { + connection_ = connection; + run_loop_.Quit(); + } + + scoped_refptr<HidConnection> WaitForConnection() { + run_loop_.Run(); + return connection_; + } + + const HidService::ConnectCallback& callback() { return callback_; } + + private: + HidService::ConnectCallback callback_; + base::RunLoop run_loop_; + scoped_refptr<HidConnection> connection_; +}; + +class TestIoCallback { + public: + TestIoCallback() + : read_callback_( + base::Bind(&TestIoCallback::SetReadResult, base::Unretained(this))), + write_callback_(base::Bind(&TestIoCallback::SetWriteResult, base::Unretained(this))) {} - ~TestCompletionCallback() {} + ~TestIoCallback() {} void SetReadResult(bool success, scoped_refptr<net::IOBuffer> buffer, @@ -128,7 +153,9 @@ class HidConnectionTest : public testing::Test { TEST_F(HidConnectionTest, ReadWrite) { if (!UsbTestGadget::IsTestEnabled()) return; - scoped_refptr<HidConnection> conn = service_->Connect(device_id_); + TestConnectCallback connect_callback; + service_->Connect(device_id_, connect_callback.callback()); + scoped_refptr<HidConnection> conn = connect_callback.WaitForConnection(); ASSERT_TRUE(conn.get()); for (int i = 0; i < 8; ++i) { @@ -138,11 +165,11 @@ TEST_F(HidConnectionTest, ReadWrite) { buffer->data()[j] = i + j - 1; } - TestCompletionCallback write_callback; + TestIoCallback write_callback; conn->Write(buffer, buffer->size(), write_callback.write_callback()); ASSERT_TRUE(write_callback.WaitForResult()); - TestCompletionCallback read_callback; + TestIoCallback read_callback; conn->Read(read_callback.read_callback()); ASSERT_TRUE(read_callback.WaitForResult()); ASSERT_EQ(9UL, read_callback.size()); diff --git a/device/hid/hid_service.h b/device/hid/hid_service.h index a571434..a3f7132 100644 --- a/device/hid/hid_service.h +++ b/device/hid/hid_service.h @@ -20,6 +20,9 @@ class HidConnection; class HidService { public: + typedef base::Callback<void(scoped_refptr<HidConnection> connection)> + ConnectCallback; + static HidService* GetInstance( scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); @@ -31,15 +34,10 @@ class HidService { // Returns |true| if successful or |false| if |device_id| is invalid. bool GetDeviceInfo(const HidDeviceId& device_id, HidDeviceInfo* info) const; -#if defined(OS_CHROMEOS) - // Requests access to the given device from the Chrome OS permission broker. - virtual void RequestAccess( - const HidDeviceId& device_id, - const base::Callback<void(bool success)>& callback) = 0; -#endif - - virtual scoped_refptr<HidConnection> Connect( - const HidDeviceId& device_id) = 0; + // Opens a connection to a device. The callback will be run with null on + // failure. + virtual void Connect(const HidDeviceId& device_id, + const ConnectCallback& callback) = 0; protected: friend class HidConnectionTest; diff --git a/device/hid/hid_service_linux.cc b/device/hid/hid_service_linux.cc index 0cbf5cd..e5fcb52 100644 --- a/device/hid/hid_service_linux.cc +++ b/device/hid/hid_service_linux.cc @@ -38,6 +38,40 @@ const char kHIDName[] = "HID_NAME"; const char kHIDUnique[] = "HID_UNIQ"; const char kSysfsReportDescriptorKey[] = "report_descriptor"; +#if defined(OS_CHROMEOS) +void OnRequestAccessComplete( + scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner, + const base::Callback<void(bool success)>& callback, + bool success) { + reply_task_runner->PostTask(FROM_HERE, base::Bind(callback, success)); +} + +void RequestAccess( + const std::string& device_node, + scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner, + const base::Callback<void(bool success)>& callback) { + bool success = false; + + if (base::SysInfo::IsRunningOnChromeOS()) { + chromeos::PermissionBrokerClient* client = + chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient(); + DCHECK(client) << "Could not get permission broker client."; + if (client) { + client->RequestPathAccess( + device_node, + -1, + base::Bind(OnRequestAccessComplete, reply_task_runner, callback)); + return; + } + } else { + // Not really running on Chrome OS, declare success. + success = true; + } + + reply_task_runner->PostTask(FROM_HERE, base::Bind(callback, success)); +} +#endif + } // namespace HidServiceLinux::HidServiceLinux( @@ -52,61 +86,42 @@ HidServiceLinux::HidServiceLinux( base::Bind(&HidServiceLinux::OnDeviceAdded, weak_factory_.GetWeakPtr())); } -#if defined(OS_CHROMEOS) -void HidServiceLinux::RequestAccess( - const HidDeviceId& device_id, - const base::Callback<void(bool success)>& callback) { - bool success = false; +void HidServiceLinux::Connect(const HidDeviceId& device_id, + const ConnectCallback& callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + ScopedUdevDevicePtr device = DeviceMonitorLinux::GetInstance()->GetDeviceFromPath( device_id); - - if (device) { - const char* dev_node = udev_device_get_devnode(device.get()); - - if (base::SysInfo::IsRunningOnChromeOS()) { - chromeos::PermissionBrokerClient* client = - chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient(); - DCHECK(client) << "Could not get permission broker client."; - if (client) { - ui_task_runner_->PostTask( - FROM_HERE, - base::Bind(&chromeos::PermissionBrokerClient::RequestPathAccess, - base::Unretained(client), - std::string(dev_node), - -1, - base::Bind(&HidServiceLinux::OnRequestAccessComplete, - weak_factory_.GetWeakPtr(), - callback))); - return; - } - } else { - // Not really running on Chrome OS, declare success. - success = true; - } + if (!device) { + task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); + return; } - task_runner_->PostTask(FROM_HERE, base::Bind(callback, success)); -} -#endif - -scoped_refptr<HidConnection> HidServiceLinux::Connect( - const HidDeviceId& device_id) { - HidDeviceInfo device_info; - if (!GetDeviceInfo(device_id, &device_info)) - return NULL; - ScopedUdevDevicePtr device = - DeviceMonitorLinux::GetInstance()->GetDeviceFromPath( - device_info.device_id); - - if (device) { - const char* dev_node = udev_device_get_devnode(device.get()); - if (dev_node) { - return new HidConnectionLinux(device_info, dev_node); - } + const char* device_node = udev_device_get_devnode(device.get()); + if (!device_node) { + task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); + return; } - return NULL; + base::Callback<void(bool success)> finish_connect = + base::Bind(&HidServiceLinux::FinishConnect, + weak_factory_.GetWeakPtr(), + device_id, + std::string(device_node), + callback); + +#if defined(OS_CHROMEOS) + ui_task_runner_->PostTask(FROM_HERE, + base::Bind(RequestAccess, + std::string(device_node), + task_runner_, + finish_connect)); +#else + // Use the task runner to preserve the asynchronous behavior of this call on + // non-Chrome OS platforms. + task_runner_->PostTask(FROM_HERE, base::Bind(finish_connect, true)); +#endif } HidServiceLinux::~HidServiceLinux() { @@ -195,10 +210,22 @@ void HidServiceLinux::OnDeviceRemoved(udev_device* device) { } } -void HidServiceLinux::OnRequestAccessComplete( - const base::Callback<void(bool success)>& callback, +void HidServiceLinux::FinishConnect( + const HidDeviceId& device_id, + const std::string device_node, + const base::Callback<void(scoped_refptr<HidConnection>)>& callback, bool success) { - task_runner_->PostTask(FROM_HERE, base::Bind(callback, success)); + DCHECK(thread_checker_.CalledOnValidThread()); + if (!success) { + callback.Run(nullptr); + } + + const auto& map_entry = devices().find(device_id); + if (map_entry == devices().end()) { + callback.Run(nullptr); + } + + callback.Run(new HidConnectionLinux(map_entry->second, device_node)); } } // namespace device diff --git a/device/hid/hid_service_linux.h b/device/hid/hid_service_linux.h index 765278f..bc406ad 100644 --- a/device/hid/hid_service_linux.h +++ b/device/hid/hid_service_linux.h @@ -23,14 +23,8 @@ class HidServiceLinux : public HidService, public: HidServiceLinux(scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); -#if defined(OS_CHROMEOS) - virtual void RequestAccess( - const HidDeviceId& device_id, - const base::Callback<void(bool success)>& callback) override; -#endif - - virtual scoped_refptr<HidConnection> Connect(const HidDeviceId& device_id) - override; + virtual void Connect(const HidDeviceId& device_id, + const ConnectCallback& callback) override; // Implements DeviceMonitorLinux::Observer: virtual void OnDeviceAdded(udev_device* device) override; @@ -39,9 +33,10 @@ class HidServiceLinux : public HidService, private: virtual ~HidServiceLinux(); - void OnRequestAccessComplete( - const base::Callback<void(bool success)>& callback, - bool success); + void FinishConnect(const HidDeviceId& device_id, + const std::string device_node, + const ConnectCallback& callback, + bool success); scoped_refptr<base::SingleThreadTaskRunner> task_runner_; scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; diff --git a/device/hid/hid_service_mac.cc b/device/hid/hid_service_mac.cc index c32ebb4..4723668 100644 --- a/device/hid/hid_service_mac.cc +++ b/device/hid/hid_service_mac.cc @@ -259,13 +259,14 @@ void HidServiceMac::RemoveDevices() { } } -scoped_refptr<HidConnection> HidServiceMac::Connect( - const HidDeviceId& device_id) { +void HidServiceMac::Connect(const HidDeviceId& device_id, + const ConnectCallback& callback) { DCHECK(thread_checker_.CalledOnValidThread()); const auto& map_entry = devices().find(device_id); if (map_entry == devices().end()) { - return NULL; + task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); + return; } const HidDeviceInfo& device_info = map_entry->second; @@ -275,7 +276,8 @@ scoped_refptr<HidConnection> HidServiceMac::Connect( IORegistryEntryFromPath(kIOMasterPortDefault, service_path)); if (!service.get()) { VLOG(1) << "IOService not found for path: " << device_id; - return NULL; + task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); + return; } base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device( @@ -284,11 +286,15 @@ scoped_refptr<HidConnection> HidServiceMac::Connect( if (result != kIOReturnSuccess) { VLOG(1) << "Failed to open device: " << base::StringPrintf("0x%04x", result); - return NULL; + task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); + return; } - return make_scoped_refptr(new HidConnectionMac( - hid_device.release(), device_info, file_task_runner_)); + task_runner_->PostTask( + FROM_HERE, + base::Bind(callback, + make_scoped_refptr(new HidConnectionMac( + hid_device.release(), device_info, file_task_runner_)))); } } // namespace device diff --git a/device/hid/hid_service_mac.h b/device/hid/hid_service_mac.h index c354524..44f63d4 100644 --- a/device/hid/hid_service_mac.h +++ b/device/hid/hid_service_mac.h @@ -27,8 +27,8 @@ class HidServiceMac : public HidService { public: HidServiceMac(scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); - virtual scoped_refptr<HidConnection> Connect(const HidDeviceId& device_id) - override; + virtual void Connect(const HidDeviceId& device_id, + const ConnectCallback& connect) override; private: virtual ~HidServiceMac(); diff --git a/device/hid/hid_service_win.cc b/device/hid/hid_service_win.cc index 09ad89d..3e0bb15 100644 --- a/device/hid/hid_service_win.cc +++ b/device/hid/hid_service_win.cc @@ -6,9 +6,13 @@ #include <cstdlib> +#include "base/bind.h" #include "base/files/file.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/sys_string_conversions.h" +#include "base/thread_task_runner_handle.h" #include "base/threading/thread_restrictions.h" #include "device/hid/hid_connection_win.h" #include "device/hid/hid_device_info.h" @@ -37,6 +41,8 @@ const char kHIDClass[] = "HIDClass"; HidServiceWin::HidServiceWin() { base::ThreadRestrictions::AssertIOAllowed(); + task_runner_ = base::ThreadTaskRunnerHandle::Get(); + DCHECK(task_runner_.get()); Enumerate(); } @@ -304,17 +310,22 @@ void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) { HidService::GetDevices(devices); } -scoped_refptr<HidConnection> HidServiceWin::Connect( - const HidDeviceId& device_id) { - HidDeviceInfo device_info; - if (!GetDeviceInfo(device_id, &device_info)) - return NULL; +void HidServiceWin::Connect(const HidDeviceId& device_id, + const ConnectCallback& callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + const auto& map_entry = devices().find(device_id); + if (map_entry == devices().end()) { + task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); + return; + } + const HidDeviceInfo& device_info = map_entry->second; + scoped_refptr<HidConnectionWin> connection(new HidConnectionWin(device_info)); if (!connection->available()) { - PLOG(ERROR) << "Failed to open device."; - return NULL; + PLOG(ERROR) << "Failed to open device"; + connection = nullptr; } - return connection; + task_runner_->PostTask(FROM_HERE, base::Bind(callback, connection)); } } // namespace device diff --git a/device/hid/hid_service_win.h b/device/hid/hid_service_win.h index 4c9dec6..e9ac9e98 100644 --- a/device/hid/hid_service_win.h +++ b/device/hid/hid_service_win.h @@ -32,8 +32,8 @@ class HidServiceWin : public HidService { virtual void GetDevices(std::vector<HidDeviceInfo>* devices) override; - virtual scoped_refptr<HidConnection> Connect(const HidDeviceId& device_id) - override; + virtual void Connect(const HidDeviceId& device_id, + const ConnectCallback& callback) override; private: virtual ~HidServiceWin(); @@ -50,6 +50,8 @@ class HidServiceWin : public HidService { void PlatformAddDevice(const std::string& device_path); void PlatformRemoveDevice(const std::string& device_path); + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + DISALLOW_COPY_AND_ASSIGN(HidServiceWin); }; |