summaryrefslogtreecommitdiffstats
path: root/device/hid
diff options
context:
space:
mode:
authorreillyg <reillyg@chromium.org>2015-02-18 16:53:00 -0800
committerCommit bot <commit-bot@chromium.org>2015-02-19 00:53:50 +0000
commit8c5a2c5f3c9efbc0c5810e8269d788210175a6af (patch)
tree3e88dcba018766a322446bf32c68be8cebf51d4f /device/hid
parent34855a14235a5a533d8d98d1ba53175f54703b98 (diff)
downloadchromium_src-8c5a2c5f3c9efbc0c5810e8269d788210175a6af.zip
chromium_src-8c5a2c5f3c9efbc0c5810e8269d788210175a6af.tar.gz
chromium_src-8c5a2c5f3c9efbc0c5810e8269d788210175a6af.tar.bz2
Enumerate HID devices asynchronously on Windows.
Avoid possibly long blocking times in the Windows SetupDi function calls made to enumerate devices by offloading to the FILE thread. Now that we can be sure that a stray request to the device won't block the UI additional calls to get the device's product and serial number strings can be made. BUG=457899 Review URL: https://codereview.chromium.org/936603003 Cr-Commit-Position: refs/heads/master@{#316939}
Diffstat (limited to 'device/hid')
-rw-r--r--device/hid/hid_service.cc2
-rw-r--r--device/hid/hid_service_win.cc72
-rw-r--r--device/hid/hid_service_win.h15
3 files changed, 74 insertions, 15 deletions
diff --git a/device/hid/hid_service.cc b/device/hid/hid_service.cc
index c0b176e..8f502df 100644
--- a/device/hid/hid_service.cc
+++ b/device/hid/hid_service.cc
@@ -41,7 +41,7 @@ HidService* HidService::GetInstance(
#elif defined(OS_MACOSX)
g_service = new HidServiceMac(file_task_runner);
#elif defined(OS_WIN)
- g_service = new HidServiceWin();
+ g_service = new HidServiceWin(file_task_runner);
#endif
if (g_service != nullptr) {
base::AtExitManager::RegisterTask(base::Bind(
diff --git a/device/hid/hid_service_win.cc b/device/hid/hid_service_win.cc
index 234d37b..3ab8286 100644
--- a/device/hid/hid_service_win.cc
+++ b/device/hid/hid_service_win.cc
@@ -28,7 +28,18 @@
namespace device {
-HidServiceWin::HidServiceWin() : device_observer_(this) {
+namespace {
+
+void Noop() {
+ // This function does nothing.
+}
+}
+
+HidServiceWin::HidServiceWin(
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
+ : device_observer_(this),
+ file_task_runner_(file_task_runner),
+ weak_factory_(this) {
task_runner_ = base::ThreadTaskRunnerHandle::Get();
DCHECK(task_runner_.get());
DeviceMonitorWin* device_monitor =
@@ -36,7 +47,9 @@ HidServiceWin::HidServiceWin() : device_observer_(this) {
if (device_monitor) {
device_observer_.Add(device_monitor);
}
- DoInitialEnumeration();
+ file_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&HidServiceWin::EnumerateOnFileThread,
+ weak_factory_.GetWeakPtr(), task_runner_));
}
void HidServiceWin::Connect(const HidDeviceId& device_id,
@@ -64,7 +77,10 @@ void HidServiceWin::Connect(const HidDeviceId& device_id,
HidServiceWin::~HidServiceWin() {
}
-void HidServiceWin::DoInitialEnumeration() {
+// static
+void HidServiceWin::EnumerateOnFileThread(
+ base::WeakPtr<HidServiceWin> service,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
HDEVINFO device_info_set =
SetupDiGetClassDevs(&GUID_DEVINTERFACE_HID, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
@@ -103,11 +119,13 @@ void HidServiceWin::DoInitialEnumeration() {
std::string device_path(
base::SysWideToUTF8(device_interface_detail_data->DevicePath));
DCHECK(base::IsStringASCII(device_path));
- OnDeviceAdded(base::StringToLowerASCII(device_path));
+ AddDeviceOnFileThread(service, task_runner,
+ base::StringToLowerASCII(device_path));
}
}
- FirstEnumerationComplete();
+ task_runner->PostTask(
+ FROM_HERE, base::Bind(&HidServiceWin::FirstEnumerationComplete, service));
}
// static
@@ -155,7 +173,11 @@ void HidServiceWin::CollectInfoFromValueCaps(
}
}
-void HidServiceWin::OnDeviceAdded(const std::string& device_path) {
+// static
+void HidServiceWin::AddDeviceOnFileThread(
+ base::WeakPtr<HidServiceWin> service,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const std::string& device_path) {
base::win::ScopedHandle device_handle(OpenDevice(device_path));
if (!device_handle.IsValid()) {
return;
@@ -220,25 +242,53 @@ void HidServiceWin::OnDeviceAdded(const std::string& device_path) {
capabilities.NumberFeatureValueCaps,
&collection_info);
+ // 1023 characters plus NULL terminator is more than enough for a USB string
+ // descriptor which is limited to 126 characters.
+ wchar_t buffer[1024];
+ std::string product_name;
+ if (HidD_GetProductString(device_handle.Get(), &buffer[0], sizeof(buffer))) {
+ // NULL termination guaranteed by the API.
+ product_name = base::SysWideToUTF8(buffer);
+ }
+ std::string serial_number;
+ if (HidD_GetSerialNumberString(device_handle.Get(), &buffer[0],
+ sizeof(buffer))) {
+ // NULL termination guaranteed by the API.
+ serial_number = base::SysWideToUTF8(buffer);
+ }
+
// This populates the HidDeviceInfo instance without a raw report descriptor.
// The descriptor is unavailable on Windows because HID devices are exposed to
// user-space as individual top-level collections.
scoped_refptr<HidDeviceInfo> device_info(new HidDeviceInfo(
- device_path, attrib.VendorID, attrib.ProductID,
- "", // TODO(reillyg): Get product name from Windows.
- "", // TODO(reillyg): Get serial number from Windows.
+ device_path, attrib.VendorID, attrib.ProductID, product_name,
+ serial_number,
kHIDBusTypeUSB, // TODO(reillyg): Detect Bluetooth. crbug.com/443335
collection_info, max_input_report_size, max_output_report_size,
max_feature_report_size));
HidD_FreePreparsedData(preparsed_data);
- AddDevice(device_info);
+ task_runner->PostTask(
+ FROM_HERE, base::Bind(&HidServiceWin::AddDevice, service, device_info));
+}
+
+void HidServiceWin::OnDeviceAdded(const std::string& device_path) {
+ file_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&HidServiceWin::AddDeviceOnFileThread,
+ weak_factory_.GetWeakPtr(), task_runner_, device_path));
}
void HidServiceWin::OnDeviceRemoved(const std::string& device_path) {
- RemoveDevice(device_path);
+ // Execute a no-op closure on the file task runner to synchronize with any
+ // devices that are still being enumerated.
+ file_task_runner_->PostTaskAndReply(
+ FROM_HERE, base::Bind(&Noop),
+ base::Bind(&HidServiceWin::RemoveDevice, weak_factory_.GetWeakPtr(),
+ device_path));
}
+// static
base::win::ScopedHandle HidServiceWin::OpenDevice(
const std::string& device_path) {
base::win::ScopedHandle file(
diff --git a/device/hid/hid_service_win.h b/device/hid/hid_service_win.h
index 902d431..1704ac7 100644
--- a/device/hid/hid_service_win.h
+++ b/device/hid/hid_service_win.h
@@ -14,6 +14,7 @@ extern "C" {
}
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
#include "base/win/scoped_handle.h"
#include "device/core/device_monitor_win.h"
@@ -30,7 +31,7 @@ namespace device {
class HidServiceWin : public HidService, public DeviceMonitorWin::Observer {
public:
- HidServiceWin();
+ HidServiceWin(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner);
virtual void Connect(const HidDeviceId& device_id,
const ConnectCallback& callback) override;
@@ -38,7 +39,9 @@ class HidServiceWin : public HidService, public DeviceMonitorWin::Observer {
private:
virtual ~HidServiceWin();
- void DoInitialEnumeration();
+ static void EnumerateOnFileThread(
+ base::WeakPtr<HidServiceWin> service,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
static void CollectInfoFromButtonCaps(PHIDP_PREPARSED_DATA preparsed_data,
HIDP_REPORT_TYPE report_type,
USHORT button_caps_length,
@@ -47,16 +50,22 @@ class HidServiceWin : public HidService, public DeviceMonitorWin::Observer {
HIDP_REPORT_TYPE report_type,
USHORT value_caps_length,
HidCollectionInfo* collection_info);
+ static void AddDeviceOnFileThread(
+ base::WeakPtr<HidServiceWin> service,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const std::string& device_path);
// DeviceMonitorWin::Observer implementation:
void OnDeviceAdded(const std::string& device_path) override;
void OnDeviceRemoved(const std::string& device_path) override;
// Tries to open the device read-write and falls back to read-only.
- base::win::ScopedHandle OpenDevice(const std::string& device_path);
+ static base::win::ScopedHandle OpenDevice(const std::string& device_path);
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_;
+ base::WeakPtrFactory<HidServiceWin> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(HidServiceWin);
};