summaryrefslogtreecommitdiffstats
path: root/device/hid/hid_service_win.cc
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/hid_service_win.cc
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/hid_service_win.cc')
-rw-r--r--device/hid/hid_service_win.cc72
1 files changed, 61 insertions, 11 deletions
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(