diff options
author | reillyg <reillyg@chromium.org> | 2015-02-18 16:53:00 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-19 00:53:50 +0000 |
commit | 8c5a2c5f3c9efbc0c5810e8269d788210175a6af (patch) | |
tree | 3e88dcba018766a322446bf32c68be8cebf51d4f /device/hid | |
parent | 34855a14235a5a533d8d98d1ba53175f54703b98 (diff) | |
download | chromium_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.cc | 2 | ||||
-rw-r--r-- | device/hid/hid_service_win.cc | 72 | ||||
-rw-r--r-- | device/hid/hid_service_win.h | 15 |
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); }; |