hid_service_win.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/device/hid/hid_service_win.h"
  5. #define INITGUID
  6. #include <dbt.h>
  7. #include <devpkey.h>
  8. #include <setupapi.h>
  9. #include <stddef.h>
  10. #include <wdmguid.h>
  11. #include <winioctl.h>
  12. #include <algorithm>
  13. #include <limits>
  14. #include <memory>
  15. #include <set>
  16. #include <utility>
  17. #include "base/bind.h"
  18. #include "base/callback_helpers.h"
  19. #include "base/files/file.h"
  20. #include "base/location.h"
  21. #include "base/memory/free_deleter.h"
  22. #include "base/strings/string_split.h"
  23. #include "base/strings/string_util.h"
  24. #include "base/strings/sys_string_conversions.h"
  25. #include "base/strings/utf_string_conversions.h"
  26. #include "base/task/sequenced_task_runner.h"
  27. #include "base/task/thread_pool.h"
  28. #include "base/threading/sequenced_task_runner_handle.h"
  29. #include "base/win/scoped_devinfo.h"
  30. #include "base/win/win_util.h"
  31. #include "components/device_event_log/device_event_log.h"
  32. #include "services/device/hid/hid_connection_win.h"
  33. #include "services/device/hid/hid_device_info.h"
  34. #include "services/device/hid/hid_preparsed_data.h"
  35. namespace device {
  36. namespace {
  37. // Flags for the BitField member of HIDP_BUTTON_CAPS and HIDP_VALUE_CAPS. This
  38. // bitfield is defined in the Device Class Definition for HID v1.11 section
  39. // 6.2.2.5.
  40. // https://www.usb.org/document-library/device-class-definition-hid-111
  41. constexpr uint16_t kBitFieldFlagConstant = 1 << 0;
  42. constexpr uint16_t kBitFieldFlagVariable = 1 << 1;
  43. constexpr uint16_t kBitFieldFlagRelative = 1 << 2;
  44. constexpr uint16_t kBitFieldFlagWrap = 1 << 3;
  45. constexpr uint16_t kBitFieldFlagNonLinear = 1 << 4;
  46. constexpr uint16_t kBitFieldFlagNoPreferredState = 1 << 5;
  47. constexpr uint16_t kBitFieldFlagHasNullPosition = 1 << 6;
  48. constexpr uint16_t kBitFieldFlagVolatile = 1 << 7;
  49. constexpr uint16_t kBitFieldFlagBufferedBytes = 1 << 8;
  50. // Unpacks |bit_field| into the corresponding members of |item|.
  51. void UnpackBitField(uint16_t bit_field, mojom::HidReportItem* item) {
  52. item->is_constant = bit_field & kBitFieldFlagConstant;
  53. item->is_variable = bit_field & kBitFieldFlagVariable;
  54. item->is_relative = bit_field & kBitFieldFlagRelative;
  55. item->wrap = bit_field & kBitFieldFlagWrap;
  56. item->is_non_linear = bit_field & kBitFieldFlagNonLinear;
  57. item->no_preferred_state = bit_field & kBitFieldFlagNoPreferredState;
  58. item->has_null_position = bit_field & kBitFieldFlagHasNullPosition;
  59. item->is_volatile = bit_field & kBitFieldFlagVolatile;
  60. item->is_buffered_bytes = bit_field & kBitFieldFlagBufferedBytes;
  61. }
  62. // Looks up the value of a string device property specified by |property_key|
  63. // for the device described by |device_info_data|. On success, returns the
  64. // property value as a wstring. Returns absl::nullopt if the property is not
  65. // present or has a different type.
  66. absl::optional<std::wstring> GetDeviceStringProperty(
  67. HDEVINFO device_info_set,
  68. SP_DEVINFO_DATA& device_info_data,
  69. const DEVPROPKEY& property_key) {
  70. DEVPROPTYPE property_type;
  71. DWORD required_size;
  72. if (SetupDiGetDeviceProperty(device_info_set, &device_info_data,
  73. &property_key, &property_type,
  74. /*PropertyBuffer=*/nullptr,
  75. /*PropertyBufferSize=*/0, &required_size,
  76. /*Flags=*/0)) {
  77. HID_LOG(DEBUG) << "SetupDiGetDeviceProperty unexpectedly succeeded.";
  78. return absl::nullopt;
  79. }
  80. DWORD last_error = GetLastError();
  81. if (last_error == ERROR_NOT_FOUND)
  82. return absl::nullopt;
  83. if (last_error != ERROR_INSUFFICIENT_BUFFER) {
  84. HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed";
  85. return absl::nullopt;
  86. }
  87. if (property_type != DEVPROP_TYPE_STRING)
  88. return absl::nullopt;
  89. std::wstring property_buffer;
  90. if (!SetupDiGetDeviceProperty(
  91. device_info_set, &device_info_data, &property_key, &property_type,
  92. reinterpret_cast<PBYTE>(
  93. base::WriteInto(&property_buffer, required_size)),
  94. required_size, /*RequiredSize=*/nullptr, /*Flags=*/0)) {
  95. HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed";
  96. return absl::nullopt;
  97. }
  98. return property_buffer;
  99. }
  100. // Looks up the value of a GUID-type device property specified by |property| for
  101. // the device described by |device_info_data|. On success, returns the property
  102. // value as a string. Returns absl::nullopt if the property is not present or
  103. // has a different type.
  104. absl::optional<std::string> GetDeviceGuidProperty(
  105. HDEVINFO device_info_set,
  106. SP_DEVINFO_DATA& device_info_data,
  107. const DEVPROPKEY& property_key) {
  108. DEVPROPTYPE property_type;
  109. GUID property_buffer;
  110. if (!SetupDiGetDeviceProperty(
  111. device_info_set, &device_info_data, &property_key, &property_type,
  112. reinterpret_cast<PBYTE>(&property_buffer), sizeof(property_buffer),
  113. /*RequiredSize=*/nullptr, /*Flags=*/0)) {
  114. HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed";
  115. return absl::nullopt;
  116. }
  117. if (property_type != DEVPROP_TYPE_GUID)
  118. return absl::nullopt;
  119. return base::SysWideToUTF8(base::win::WStringFromGUID(property_buffer));
  120. }
  121. // Looks up information about the device described by |device_interface_data|
  122. // in |device_info_set|. On success, returns true and sets |device_info_data|
  123. // and |device_path|. Returns false if an error occurred.
  124. bool GetDeviceInfoAndPathFromInterface(
  125. HDEVINFO device_info_set,
  126. SP_DEVICE_INTERFACE_DATA& device_interface_data,
  127. SP_DEVINFO_DATA* device_info_data,
  128. std::wstring* device_path) {
  129. // Get the required buffer size. When called with
  130. // DeviceInterfaceDetailData == nullptr and DeviceInterfaceDetailSize == 0,
  131. // SetupDiGetDeviceInterfaceDetail returns the required buffer size at
  132. // RequiredSize and fails with GetLastError() == ERROR_INSUFFICIENT_BUFFER.
  133. DWORD required_size;
  134. if (SetupDiGetDeviceInterfaceDetail(device_info_set, &device_interface_data,
  135. /*DeviceInterfaceDetailData=*/nullptr,
  136. /*DeviceInterfaceDetailSize=*/0,
  137. &required_size,
  138. /*DeviceInfoData=*/nullptr)) {
  139. HID_LOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail unexpectedly succeeded.";
  140. return false;
  141. }
  142. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  143. HID_PLOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail failed";
  144. return false;
  145. }
  146. std::unique_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA, base::FreeDeleter>
  147. device_interface_detail_data(
  148. static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(malloc(required_size)));
  149. device_interface_detail_data->cbSize = sizeof(*device_interface_detail_data);
  150. // Call the function again with the correct buffer size to get the detailed
  151. // data for this device.
  152. if (!SetupDiGetDeviceInterfaceDetail(device_info_set, &device_interface_data,
  153. device_interface_detail_data.get(),
  154. required_size, /*RequiredSize=*/nullptr,
  155. device_info_data)) {
  156. HID_PLOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail failed";
  157. return false;
  158. }
  159. // Windows uses case-insensitive paths and may return paths that differ only
  160. // by case. Canonicalize the device path by converting to lowercase.
  161. std::wstring path = device_interface_detail_data->DevicePath;
  162. DCHECK(base::IsStringASCII(path));
  163. *device_path = base::ToLowerASCII(path);
  164. return true;
  165. }
  166. // Returns a device info set containing only the device described by
  167. // |device_path|, or an invalid ScopedDevInfo if there was an error while
  168. // creating the device set. The device info is returned in |device_info_data|.
  169. base::win::ScopedDevInfo GetDeviceInfoSetFromDevicePath(
  170. const std::wstring& device_path,
  171. SP_DEVINFO_DATA* device_info_data) {
  172. base::win::ScopedDevInfo device_info_set(SetupDiGetClassDevs(
  173. &GUID_DEVINTERFACE_HID, /*Enumerator=*/nullptr,
  174. /*hwndParent=*/0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
  175. if (!device_info_set.is_valid()) {
  176. HID_PLOG(DEBUG) << "SetupDiGetClassDevs failed";
  177. return base::win::ScopedDevInfo();
  178. }
  179. SP_DEVICE_INTERFACE_DATA device_interface_data;
  180. device_interface_data.cbSize = sizeof(device_interface_data);
  181. if (!SetupDiOpenDeviceInterface(device_info_set.get(), device_path.c_str(),
  182. /*OpenFlags=*/0, &device_interface_data)) {
  183. HID_PLOG(DEBUG) << "SetupDiOpenDeviceInterface failed";
  184. return base::win::ScopedDevInfo();
  185. }
  186. std::wstring intf_device_path;
  187. GetDeviceInfoAndPathFromInterface(device_info_set.get(),
  188. device_interface_data, device_info_data,
  189. &intf_device_path);
  190. DCHECK_EQ(intf_device_path, device_path);
  191. return device_info_set;
  192. }
  193. // Returns the instance ID of the parent of the device described by
  194. // |device_interface_data| in |device_info_set|. Returns nullopt if the parent
  195. // instance ID could not be retrieved.
  196. absl::optional<std::wstring> GetParentInstanceId(
  197. HDEVINFO device_info_set,
  198. SP_DEVICE_INTERFACE_DATA& device_interface_data) {
  199. // Get device info for |device_interface_data|.
  200. SP_DEVINFO_DATA device_info_data = {.cbSize = sizeof(device_info_data)};
  201. std::wstring device_path;
  202. if (!GetDeviceInfoAndPathFromInterface(device_info_set, device_interface_data,
  203. &device_info_data, &device_path)) {
  204. return absl::nullopt;
  205. }
  206. // Get the parent instance ID.
  207. auto instance_id = GetDeviceStringProperty(device_info_set, device_info_data,
  208. DEVPKEY_Device_Parent);
  209. if (!instance_id)
  210. return absl::nullopt;
  211. // Canonicalize the instance ID.
  212. DCHECK(base::IsStringASCII(*instance_id));
  213. instance_id = base::ToLowerASCII(*instance_id);
  214. // Remove trailing NUL bytes.
  215. return std::wstring(base::TrimString(
  216. *instance_id, base::WStringPiece(L"\0", 1), base::TRIM_TRAILING));
  217. }
  218. mojom::HidReportItemPtr CreateHidReportItem(
  219. const HidServiceWin::PreparsedData::ReportItem& item) {
  220. auto hid_report_item = mojom::HidReportItem::New();
  221. UnpackBitField(item.bit_field, hid_report_item.get());
  222. if (item.usage_minimum == item.usage_maximum) {
  223. hid_report_item->is_range = false;
  224. hid_report_item->usages.push_back(
  225. mojom::HidUsageAndPage::New(item.usage_minimum, item.usage_page));
  226. hid_report_item->usage_minimum = mojom::HidUsageAndPage::New(0, 0);
  227. hid_report_item->usage_maximum = mojom::HidUsageAndPage::New(0, 0);
  228. } else {
  229. hid_report_item->is_range = true;
  230. hid_report_item->usage_minimum =
  231. mojom::HidUsageAndPage::New(item.usage_minimum, item.usage_page);
  232. hid_report_item->usage_maximum =
  233. mojom::HidUsageAndPage::New(item.usage_maximum, item.usage_page);
  234. }
  235. hid_report_item->designator_minimum = item.designator_minimum;
  236. hid_report_item->designator_maximum = item.designator_maximum;
  237. hid_report_item->string_minimum = item.string_minimum;
  238. hid_report_item->string_maximum = item.string_maximum;
  239. hid_report_item->logical_minimum = item.logical_minimum;
  240. hid_report_item->logical_maximum = item.logical_maximum;
  241. hid_report_item->physical_minimum = item.physical_minimum;
  242. hid_report_item->physical_maximum = item.physical_maximum;
  243. hid_report_item->unit_exponent = item.unit_exponent;
  244. hid_report_item->unit = item.unit;
  245. hid_report_item->report_size = item.report_size;
  246. hid_report_item->report_count = item.report_count;
  247. return hid_report_item;
  248. }
  249. // Returns a mojom::HidReportItemPtr representing a constant (zero) field within
  250. // a report. |bit_size| is the bit width of the constant field.
  251. mojom::HidReportItemPtr CreateConstHidReportItem(uint16_t bit_size) {
  252. auto hid_report_item = mojom::HidReportItem::New();
  253. hid_report_item->is_constant = true;
  254. hid_report_item->report_count = 1;
  255. hid_report_item->report_size = bit_size;
  256. hid_report_item->usage_minimum = mojom::HidUsageAndPage::New(0, 0);
  257. hid_report_item->usage_maximum = mojom::HidUsageAndPage::New(0, 0);
  258. return hid_report_item;
  259. }
  260. // Returns a vector of mojom::HidReportDescriptionPtr constructed from the
  261. // information about the top-level collection described by |preparsed_data|.
  262. // The returned vector contains information about all reports of type
  263. // |report_type|.
  264. std::vector<mojom::HidReportDescriptionPtr> CreateReportDescriptions(
  265. const HidServiceWin::PreparsedData& preparsed_data,
  266. HIDP_REPORT_TYPE report_type) {
  267. auto report_items = preparsed_data.GetReportItems(report_type);
  268. // Sort items by |report_id| and |bit_index|.
  269. base::ranges::sort(report_items, [](const auto& a, const auto& b) {
  270. if (a.report_id < b.report_id)
  271. return true;
  272. if (a.report_id == b.report_id)
  273. return a.bit_index < b.bit_index;
  274. return false;
  275. });
  276. std::vector<mojom::HidReportDescriptionPtr> reports;
  277. mojom::HidReportDescription* current_report = nullptr;
  278. mojom::HidReportItem* current_item = nullptr;
  279. size_t current_bit_index = 0;
  280. size_t next_bit_index = 0;
  281. for (const auto& item : report_items) {
  282. if (!current_report || current_report->report_id != item.report_id) {
  283. reports.push_back(mojom::HidReportDescription::New());
  284. current_report = reports.back().get();
  285. current_report->report_id = item.report_id;
  286. current_item = nullptr;
  287. current_bit_index = 0;
  288. next_bit_index = 0;
  289. }
  290. // If |item| occupies the same bit index as |current_item| then they must be
  291. // merged into a single HidReportItem. This can occur when a report item is
  292. // defined with a list of usages instead of a usage range.
  293. if (current_item && current_bit_index == item.bit_index) {
  294. // Usage ranges cannot be merged into a single item. Ensure that both
  295. // |item| and |current_item| are single-usage items. If either has a usage
  296. // range, omit |item| from the report.
  297. if (!current_item->is_range && item.usage_minimum == item.usage_maximum) {
  298. current_item->usages.push_back(
  299. mojom::HidUsageAndPage::New(item.usage_minimum, item.usage_page));
  300. }
  301. continue;
  302. }
  303. // If there is a gap between the last bit of |current_item| and the first
  304. // bit of |item|, insert a constant item for padding.
  305. if (next_bit_index < item.bit_index) {
  306. size_t pad_bits = item.bit_index - next_bit_index;
  307. current_report->items.push_back(CreateConstHidReportItem(pad_bits));
  308. }
  309. current_report->items.push_back(CreateHidReportItem(item));
  310. current_item = current_report->items.back().get();
  311. current_bit_index = item.bit_index;
  312. next_bit_index = item.bit_index + item.report_size * item.report_count;
  313. }
  314. // Compute the size of each report and, if needed, add a final constant item
  315. // to pad the report to the expected report byte length.
  316. const size_t report_byte_length =
  317. preparsed_data.GetReportByteLength(report_type);
  318. for (auto& report : reports) {
  319. size_t bit_length = 0;
  320. for (auto& item : report->items)
  321. bit_length += item->report_size * item->report_count;
  322. DCHECK_LE(bit_length, report_byte_length * CHAR_BIT);
  323. size_t pad_bits = report_byte_length * CHAR_BIT - bit_length;
  324. if (pad_bits > 0)
  325. report->items.push_back(CreateConstHidReportItem(pad_bits));
  326. }
  327. return reports;
  328. }
  329. // Buffer size for calls to HidD_Get*String methods. 1023 characters plus NUL
  330. // terminator is more than enough for a USB string descriptor which is limited
  331. // to 126 characters.
  332. constexpr size_t kBufferSize = 1024;
  333. std::string GetHidProductString(HANDLE device_handle) {
  334. // HidD_Get*String methods may return successfully even when they do not write
  335. // to the output buffer. Ensure the buffer is zeroed before calling. See
  336. // https://crbug.com/1205511.
  337. std::wstring buffer;
  338. if (!HidD_GetProductString(
  339. device_handle, base::WriteInto(&buffer, kBufferSize), kBufferSize)) {
  340. return std::string();
  341. }
  342. // HidD_GetProductString is guaranteed to write a NUL-terminated string into
  343. // |buffer|. The characters following the string were value-initialized by
  344. // base::WriteInto and are also NUL. Trim the trailing NUL characters.
  345. buffer = std::wstring(base::TrimString(buffer, base::WStringPiece(L"\0", 1),
  346. base::TRIM_TRAILING));
  347. return base::SysWideToUTF8(buffer);
  348. }
  349. std::string GetHidSerialNumberString(HANDLE device_handle) {
  350. // HidD_Get*String methods may return successfully even when they do not write
  351. // to the output buffer. Ensure the buffer is zeroed before calling. See
  352. // https://crbug.com/1205511.
  353. std::wstring buffer;
  354. if (!HidD_GetSerialNumberString(
  355. device_handle, base::WriteInto(&buffer, kBufferSize), kBufferSize)) {
  356. return std::string();
  357. }
  358. // HidD_GetSerialNumberString is guaranteed to write a NUL-terminated string
  359. // into |buffer|. The characters following the string were value-initialized
  360. // by base::WriteInto and are also NUL. Trim the trailing NUL characters.
  361. buffer = std::wstring(base::TrimString(buffer, base::WStringPiece(L"\0", 1),
  362. base::TRIM_TRAILING));
  363. return base::SysWideToUTF8(buffer);
  364. }
  365. } // namespace
  366. mojom::HidCollectionInfoPtr
  367. HidServiceWin::PreparsedData::CreateHidCollectionInfo() const {
  368. const HIDP_CAPS& caps = GetCaps();
  369. auto collection_info = mojom::HidCollectionInfo::New();
  370. collection_info->usage =
  371. mojom::HidUsageAndPage::New(caps.Usage, caps.UsagePage);
  372. collection_info->input_reports = CreateReportDescriptions(*this, HidP_Input);
  373. collection_info->output_reports =
  374. CreateReportDescriptions(*this, HidP_Output);
  375. collection_info->feature_reports =
  376. CreateReportDescriptions(*this, HidP_Feature);
  377. // Collect and de-duplicate report IDs.
  378. std::set<uint8_t> report_ids;
  379. for (const auto& report : collection_info->input_reports) {
  380. if (report->report_id)
  381. report_ids.insert(report->report_id);
  382. }
  383. for (const auto& report : collection_info->output_reports) {
  384. if (report->report_id)
  385. report_ids.insert(report->report_id);
  386. }
  387. for (const auto& report : collection_info->feature_reports) {
  388. if (report->report_id)
  389. report_ids.insert(report->report_id);
  390. }
  391. collection_info->report_ids.insert(collection_info->report_ids.end(),
  392. report_ids.begin(), report_ids.end());
  393. return collection_info;
  394. }
  395. uint16_t HidServiceWin::PreparsedData::GetReportByteLength(
  396. HIDP_REPORT_TYPE report_type) const {
  397. uint16_t report_length = 0;
  398. switch (report_type) {
  399. case HidP_Input:
  400. report_length = GetCaps().InputReportByteLength;
  401. break;
  402. case HidP_Output:
  403. report_length = GetCaps().OutputReportByteLength;
  404. break;
  405. case HidP_Feature:
  406. report_length = GetCaps().FeatureReportByteLength;
  407. break;
  408. default:
  409. NOTREACHED();
  410. break;
  411. }
  412. // Whether or not the device includes report IDs in its reports the size
  413. // of the report ID is included in the value provided by Windows. This
  414. // appears contrary to the MSDN documentation.
  415. if (report_length)
  416. return report_length - 1;
  417. return 0;
  418. }
  419. HidServiceWin::HidServiceWin()
  420. : task_runner_(base::SequencedTaskRunnerHandle::Get()),
  421. blocking_task_runner_(
  422. base::ThreadPool::CreateSequencedTaskRunner(kBlockingTaskTraits)) {
  423. DeviceMonitorWin* device_monitor =
  424. DeviceMonitorWin::GetForDeviceInterface(GUID_DEVINTERFACE_HID);
  425. if (device_monitor)
  426. device_observation_.Observe(device_monitor);
  427. blocking_task_runner_->PostTask(
  428. FROM_HERE, base::BindOnce(&HidServiceWin::EnumerateBlocking,
  429. weak_factory_.GetWeakPtr(), task_runner_));
  430. }
  431. HidServiceWin::~HidServiceWin() = default;
  432. void HidServiceWin::Connect(const std::string& device_guid,
  433. bool allow_protected_reports,
  434. bool allow_fido_reports,
  435. ConnectCallback callback) {
  436. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  437. const auto& map_entry = devices().find(device_guid);
  438. if (map_entry == devices().end()) {
  439. task_runner_->PostTask(FROM_HERE,
  440. base::BindOnce(std::move(callback), nullptr));
  441. return;
  442. }
  443. scoped_refptr<HidDeviceInfo> device_info = map_entry->second;
  444. const auto& platform_device_id_map = device_info->platform_device_id_map();
  445. std::vector<std::unique_ptr<HidConnectionWin::HidDeviceEntry>> file_handles;
  446. for (const auto& entry : platform_device_id_map) {
  447. base::win::ScopedHandle file_handle(OpenDevice(entry.platform_device_id));
  448. if (!file_handle.IsValid()) {
  449. HID_PLOG(DEBUG) << "Failed to open device with deviceId='"
  450. << entry.platform_device_id << "'";
  451. continue;
  452. }
  453. file_handles.push_back(std::make_unique<HidConnectionWin::HidDeviceEntry>(
  454. entry.report_ids, std::move(file_handle)));
  455. }
  456. if (file_handles.empty()) {
  457. // Report failure if none of the file handles could be opened.
  458. task_runner_->PostTask(FROM_HERE,
  459. base::BindOnce(std::move(callback), nullptr));
  460. return;
  461. }
  462. task_runner_->PostTask(
  463. FROM_HERE,
  464. base::BindOnce(std::move(callback),
  465. HidConnectionWin::Create(
  466. device_info, std::move(file_handles),
  467. allow_protected_reports, allow_fido_reports)));
  468. }
  469. base::WeakPtr<HidService> HidServiceWin::GetWeakPtr() {
  470. return weak_factory_.GetWeakPtr();
  471. }
  472. // static
  473. void HidServiceWin::EnumerateBlocking(
  474. base::WeakPtr<HidServiceWin> service,
  475. scoped_refptr<base::SequencedTaskRunner> task_runner) {
  476. base::win::ScopedDevInfo device_info_set(SetupDiGetClassDevs(
  477. &GUID_DEVINTERFACE_HID, /*Enumerator=*/nullptr,
  478. /*hwndParent=*/nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
  479. if (device_info_set.is_valid()) {
  480. SP_DEVICE_INTERFACE_DATA device_interface_data = {
  481. .cbSize = sizeof(device_interface_data)};
  482. for (int device_index = 0; SetupDiEnumDeviceInterfaces(
  483. device_info_set.get(), /*DeviceInfoData=*/nullptr,
  484. &GUID_DEVINTERFACE_HID, device_index, &device_interface_data);
  485. ++device_index) {
  486. SP_DEVINFO_DATA device_info_data = {.cbSize = sizeof(device_info_data)};
  487. std::wstring device_path;
  488. if (!GetDeviceInfoAndPathFromInterface(device_info_set.get(),
  489. device_interface_data,
  490. &device_info_data, &device_path)) {
  491. continue;
  492. }
  493. // Get the container ID for the physical device.
  494. auto physical_device_id = GetDeviceGuidProperty(
  495. device_info_set.get(), device_info_data, DEVPKEY_Device_ContainerId);
  496. if (!physical_device_id)
  497. continue;
  498. auto interface_id =
  499. GetParentInstanceId(device_info_set.get(), device_interface_data);
  500. if (!interface_id)
  501. continue;
  502. AddDeviceBlocking(service, task_runner, device_path, *physical_device_id,
  503. *interface_id);
  504. }
  505. }
  506. task_runner->PostTask(
  507. FROM_HERE,
  508. base::BindOnce(&HidServiceWin::FirstEnumerationComplete, service));
  509. }
  510. // static
  511. void HidServiceWin::AddDeviceBlocking(
  512. base::WeakPtr<HidServiceWin> service,
  513. scoped_refptr<base::SequencedTaskRunner> task_runner,
  514. const std::wstring& device_path,
  515. const std::string& physical_device_id,
  516. const std::wstring& interface_id) {
  517. base::win::ScopedHandle device_handle(OpenDevice(device_path));
  518. if (!device_handle.IsValid())
  519. return;
  520. auto preparsed_data = HidPreparsedData::Create(device_handle.Get());
  521. if (!preparsed_data)
  522. return;
  523. HIDD_ATTRIBUTES attrib = {.Size = sizeof(attrib)};
  524. if (!HidD_GetAttributes(device_handle.Get(), &attrib)) {
  525. HID_LOG(DEBUG) << "Failed to get device attributes.";
  526. return;
  527. }
  528. uint16_t vendor_id = attrib.VendorID;
  529. uint16_t product_id = attrib.ProductID;
  530. auto product_string = GetHidProductString(device_handle.Get());
  531. auto serial_number = GetHidSerialNumberString(device_handle.Get());
  532. // Create a HidCollectionInfo for |device_path| and update the relevant
  533. // HidDeviceInfo properties.
  534. auto collection = preparsed_data->CreateHidCollectionInfo();
  535. uint16_t max_input_report_size =
  536. preparsed_data->GetReportByteLength(HidP_Input);
  537. uint16_t max_output_report_size =
  538. preparsed_data->GetReportByteLength(HidP_Output);
  539. uint16_t max_feature_report_size =
  540. preparsed_data->GetReportByteLength(HidP_Feature);
  541. // This populates the HidDeviceInfo instance without a raw report descriptor.
  542. // The descriptor is unavailable on Windows.
  543. auto device_info = base::MakeRefCounted<HidDeviceInfo>(
  544. device_path, physical_device_id, base::SysWideToUTF8(interface_id),
  545. vendor_id, product_id, product_string, serial_number,
  546. // TODO(crbug.com/443335): Detect Bluetooth.
  547. mojom::HidBusType::kHIDBusTypeUSB, std::move(collection),
  548. max_input_report_size, max_output_report_size, max_feature_report_size);
  549. task_runner->PostTask(FROM_HERE,
  550. base::BindOnce(&HidServiceWin::AddDevice, service,
  551. std::move(device_info)));
  552. }
  553. void HidServiceWin::OnDeviceAdded(const GUID& class_guid,
  554. const std::wstring& device_path) {
  555. SP_DEVINFO_DATA device_info_data = {.cbSize = sizeof(device_info_data)};
  556. auto device_info_set =
  557. GetDeviceInfoSetFromDevicePath(device_path, &device_info_data);
  558. if (!device_info_set.is_valid())
  559. return;
  560. // Assume there is at most one matching device.
  561. SP_DEVICE_INTERFACE_DATA device_interface_data;
  562. device_interface_data.cbSize = sizeof(device_interface_data);
  563. if (!SetupDiEnumDeviceInterfaces(device_info_set.get(), &device_info_data,
  564. &GUID_DEVINTERFACE_HID,
  565. /*MemberIndex=*/0, &device_interface_data)) {
  566. HID_PLOG(DEBUG) << "SetupDiEnumDeviceInterfaces failed";
  567. return;
  568. }
  569. // Get the container ID for the physical device.
  570. auto physical_device_id = GetDeviceGuidProperty(
  571. device_info_set.get(), device_info_data, DEVPKEY_Device_ContainerId);
  572. if (!physical_device_id)
  573. return;
  574. // The parent device represents the HID interface.
  575. auto interface_id =
  576. GetParentInstanceId(device_info_set.get(), device_interface_data);
  577. if (!interface_id)
  578. return;
  579. blocking_task_runner_->PostTask(
  580. FROM_HERE,
  581. base::BindOnce(&HidServiceWin::AddDeviceBlocking,
  582. weak_factory_.GetWeakPtr(), task_runner_, device_path,
  583. *physical_device_id, *interface_id));
  584. }
  585. void HidServiceWin::OnDeviceRemoved(const GUID& class_guid,
  586. const std::wstring& device_path) {
  587. // Execute a no-op closure on the file task runner to synchronize with any
  588. // devices that are still being enumerated.
  589. blocking_task_runner_->PostTaskAndReply(
  590. FROM_HERE, base::DoNothing(),
  591. base::BindOnce(&HidServiceWin::RemoveDevice, weak_factory_.GetWeakPtr(),
  592. device_path));
  593. }
  594. // static
  595. base::win::ScopedHandle HidServiceWin::OpenDevice(
  596. const std::wstring& device_path) {
  597. base::win::ScopedHandle file(
  598. CreateFile(device_path.c_str(), GENERIC_WRITE | GENERIC_READ,
  599. FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
  600. FILE_FLAG_OVERLAPPED, nullptr));
  601. if (!file.IsValid() && GetLastError() == ERROR_ACCESS_DENIED) {
  602. file.Set(CreateFile(device_path.c_str(), GENERIC_READ, FILE_SHARE_READ,
  603. nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr));
  604. }
  605. return file;
  606. }
  607. } // namespace device