summaryrefslogtreecommitdiffstats
path: root/device
diff options
context:
space:
mode:
authorreillyg <reillyg@chromium.org>2014-10-16 12:19:14 -0700
committerCommit bot <commit-bot@chromium.org>2014-10-16 19:21:49 +0000
commit7f4f508547ac3058d7c47337313972ec1ac2fb1b (patch)
treedaf6ad84ae3eb0451ba21a203fe7d3ea8bb033ab /device
parentb92d87bee7689009c26be560634070a33508bcaf (diff)
downloadchromium_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.cc45
-rw-r--r--device/hid/hid_service.h16
-rw-r--r--device/hid/hid_service_linux.cc129
-rw-r--r--device/hid/hid_service_linux.h17
-rw-r--r--device/hid/hid_service_mac.cc20
-rw-r--r--device/hid/hid_service_mac.h4
-rw-r--r--device/hid/hid_service_win.cc27
-rw-r--r--device/hid/hid_service_win.h6
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);
};