1 // Copyright 2017 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 
5 #include "services/device/usb/usb_service_win.h"
6 
7 #include <objbase.h>
8 #include <setupapi.h>
9 #include <stdint.h>
10 #include <usbiodef.h>
11 #include "base/strings/string_piece_forward.h"
12 
13 #define INITGUID
14 #include <devpkey.h>
15 
16 #include "base/bind.h"
17 #include "base/location.h"
18 #include "base/memory/free_deleter.h"
19 #include "base/memory/ptr_util.h"
20 #include "base/scoped_generic.h"
21 #include "base/single_thread_task_runner.h"
22 #include "base/stl_util.h"
23 #include "base/strings/string_number_conversions.h"
24 #include "base/strings/string_split.h"
25 #include "base/strings/string_util.h"
26 #include "base/strings/sys_string_conversions.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/threading/scoped_blocking_call.h"
29 #include "base/threading/scoped_thread_priority.h"
30 #include "base/threading/thread_task_runner_handle.h"
31 #include "base/win/registry.h"
32 #include "base/win/scoped_devinfo.h"
33 #include "base/win/scoped_handle.h"
34 #include "components/device_event_log/device_event_log.h"
35 #include "services/device/usb/usb_descriptors.h"
36 #include "services/device/usb/usb_device_handle.h"
37 #include "services/device/usb/webusb_descriptors.h"
38 #include "third_party/re2/src/re2/re2.h"
39 
40 namespace device {
41 
42 namespace {
43 
IsCompositeDevice(const std::wstring & service_name)44 bool IsCompositeDevice(const std::wstring& service_name) {
45   // Windows built-in composite device driver
46   return base::EqualsCaseInsensitiveASCII(service_name, L"usbccgp") ||
47          // Samsung Mobile USB Composite device driver
48          base::EqualsCaseInsensitiveASCII(service_name, L"dg_ssudbus");
49 }
50 
GetDeviceUint32Property(HDEVINFO dev_info,SP_DEVINFO_DATA * dev_info_data,const DEVPROPKEY & property)51 base::Optional<uint32_t> GetDeviceUint32Property(HDEVINFO dev_info,
52                                                  SP_DEVINFO_DATA* dev_info_data,
53                                                  const DEVPROPKEY& property) {
54   // SetupDiGetDeviceProperty() makes an RPC which may block.
55   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
56                                                 base::BlockingType::MAY_BLOCK);
57 
58   DEVPROPTYPE property_type;
59   uint32_t buffer;
60   if (!SetupDiGetDeviceProperty(
61           dev_info, dev_info_data, &property, &property_type,
62           reinterpret_cast<PBYTE>(&buffer), sizeof(buffer), nullptr, 0) ||
63       property_type != DEVPROP_TYPE_UINT32) {
64     return base::nullopt;
65   }
66 
67   return buffer;
68 }
69 
GetDeviceStringProperty(HDEVINFO dev_info,SP_DEVINFO_DATA * dev_info_data,const DEVPROPKEY & property)70 base::Optional<std::wstring> GetDeviceStringProperty(
71     HDEVINFO dev_info,
72     SP_DEVINFO_DATA* dev_info_data,
73     const DEVPROPKEY& property) {
74   // SetupDiGetDeviceProperty() makes an RPC which may block.
75   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
76                                                 base::BlockingType::MAY_BLOCK);
77 
78   DEVPROPTYPE property_type;
79   DWORD required_size;
80   if (SetupDiGetDeviceProperty(dev_info, dev_info_data, &property,
81                                &property_type, nullptr, 0, &required_size, 0) ||
82       GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
83       property_type != DEVPROP_TYPE_STRING) {
84     return base::nullopt;
85   }
86 
87   std::wstring buffer;
88   if (!SetupDiGetDeviceProperty(
89           dev_info, dev_info_data, &property, &property_type,
90           reinterpret_cast<PBYTE>(base::WriteInto(&buffer, required_size)),
91           required_size, nullptr, 0)) {
92     return base::nullopt;
93   }
94 
95   return buffer;
96 }
97 
GetDeviceStringListProperty(HDEVINFO dev_info,SP_DEVINFO_DATA * dev_info_data,const DEVPROPKEY & property)98 base::Optional<std::vector<std::wstring>> GetDeviceStringListProperty(
99     HDEVINFO dev_info,
100     SP_DEVINFO_DATA* dev_info_data,
101     const DEVPROPKEY& property) {
102   // SetupDiGetDeviceProperty() makes an RPC which may block.
103   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
104                                                 base::BlockingType::MAY_BLOCK);
105 
106   DEVPROPTYPE property_type;
107   DWORD required_size;
108   if (SetupDiGetDeviceProperty(dev_info, dev_info_data, &property,
109                                &property_type, nullptr, 0, &required_size, 0) ||
110       GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
111       property_type != DEVPROP_TYPE_STRING_LIST) {
112     return base::nullopt;
113   }
114 
115   std::wstring buffer;
116   if (!SetupDiGetDeviceProperty(
117           dev_info, dev_info_data, &property, &property_type,
118           reinterpret_cast<PBYTE>(base::WriteInto(&buffer, required_size)),
119           required_size, nullptr, 0)) {
120     return base::nullopt;
121   }
122 
123   // Windows string list properties use a NUL character as the delimiter.
124   return base::SplitString(buffer, base::WStringPiece(L"\0", 1),
125                            base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
126 }
127 
GetServiceName(HDEVINFO dev_info,SP_DEVINFO_DATA * dev_info_data)128 std::wstring GetServiceName(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data) {
129   base::Optional<std::wstring> property =
130       GetDeviceStringProperty(dev_info, dev_info_data, DEVPKEY_Device_Service);
131   if (!property.has_value())
132     return std::wstring();
133 
134   // Windows pads this string with a variable number of NUL bytes for no
135   // discernible reason.
136   return std::wstring(base::TrimString(*property, base::WStringPiece(L"\0", 1),
137                                        base::TRIM_TRAILING));
138 }
139 
GetDeviceInterfaceDetails(HDEVINFO dev_info,SP_DEVICE_INTERFACE_DATA * device_interface_data,std::wstring * device_path,uint32_t * bus_number,uint32_t * port_number,std::wstring * instance_id,std::wstring * parent_instance_id,std::vector<std::wstring> * child_instance_ids,std::vector<std::wstring> * hardware_ids,std::wstring * service_name)140 bool GetDeviceInterfaceDetails(HDEVINFO dev_info,
141                                SP_DEVICE_INTERFACE_DATA* device_interface_data,
142                                std::wstring* device_path,
143                                uint32_t* bus_number,
144                                uint32_t* port_number,
145                                std::wstring* instance_id,
146                                std::wstring* parent_instance_id,
147                                std::vector<std::wstring>* child_instance_ids,
148                                std::vector<std::wstring>* hardware_ids,
149                                std::wstring* service_name) {
150   SP_DEVINFO_DATA dev_info_data = {};
151   dev_info_data.cbSize = sizeof(dev_info_data);
152 
153   DWORD required_size = 0;
154   std::unique_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA, base::FreeDeleter>
155       device_interface_detail_data;
156 
157   // Probing for the required size of the SP_DEVICE_INTERFACE_DETAIL_DATA
158   // struct is only required if we are looking for the device path.
159   // Otherwise all the necessary data can be queried from the SP_DEVINFO_DATA.
160   if (device_path) {
161     if (!SetupDiGetDeviceInterfaceDetail(dev_info, device_interface_data,
162                                          /*DeviceInterfaceDetailData=*/nullptr,
163                                          /*DeviceInterfaceDetailDataSize=*/0,
164                                          &required_size,
165                                          /*DeviceInfoData=*/nullptr) &&
166         GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
167       return false;
168     }
169 
170     device_interface_detail_data.reset(
171         static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(malloc(required_size)));
172     device_interface_detail_data->cbSize =
173         sizeof(*device_interface_detail_data);
174   }
175 
176   if (!SetupDiGetDeviceInterfaceDetail(
177           dev_info, device_interface_data, device_interface_detail_data.get(),
178           required_size, /*RequiredSize=*/nullptr, &dev_info_data) &&
179       (device_path || GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
180     USB_PLOG(ERROR) << "SetupDiGetDeviceInterfaceDetail";
181     return false;
182   }
183 
184   if (device_path)
185     *device_path = std::wstring(device_interface_detail_data->DevicePath);
186 
187   if (bus_number) {
188     auto result = GetDeviceUint32Property(dev_info, &dev_info_data,
189                                           DEVPKEY_Device_BusNumber);
190     if (!result.has_value()) {
191       USB_PLOG(ERROR) << "Failed to get device bus number";
192       return false;
193     }
194     *bus_number = result.value();
195   }
196 
197   if (port_number) {
198     auto result = GetDeviceUint32Property(dev_info, &dev_info_data,
199                                           DEVPKEY_Device_Address);
200     if (!result.has_value()) {
201       USB_PLOG(ERROR) << "Failed to get device address";
202       return false;
203     }
204     *port_number = result.value();
205   }
206 
207   if (instance_id) {
208     auto result = GetDeviceStringProperty(dev_info, &dev_info_data,
209                                           DEVPKEY_Device_InstanceId);
210     if (!result.has_value()) {
211       USB_PLOG(ERROR) << "Failed to get the instance ID";
212       return false;
213     }
214     *instance_id = std::move(result.value());
215   }
216 
217   if (parent_instance_id) {
218     auto result = GetDeviceStringProperty(dev_info, &dev_info_data,
219                                           DEVPKEY_Device_Parent);
220     if (!result.has_value()) {
221       USB_PLOG(ERROR) << "Failed to get the device parent";
222       return false;
223     }
224     *parent_instance_id = std::move(result.value());
225   }
226 
227   if (child_instance_ids) {
228     auto result = GetDeviceStringListProperty(dev_info, &dev_info_data,
229                                               DEVPKEY_Device_Children);
230     if (!result.has_value()) {
231       if (GetLastError() == ERROR_NOT_FOUND) {
232         result.emplace();
233       } else {
234         USB_PLOG(ERROR) << "Failed to get device children";
235         return false;
236       }
237     }
238     *child_instance_ids = std::move(result.value());
239   }
240 
241   if (hardware_ids) {
242     auto result = GetDeviceStringListProperty(dev_info, &dev_info_data,
243                                               DEVPKEY_Device_HardwareIds);
244     if (!result.has_value()) {
245       if (GetLastError() == ERROR_NOT_FOUND) {
246         result.emplace();
247       } else {
248         USB_PLOG(ERROR) << "Failed to get hardware IDs";
249         return false;
250       }
251     }
252     *hardware_ids = std::move(result.value());
253   }
254 
255   if (service_name) {
256     *service_name = GetServiceName(dev_info, &dev_info_data);
257     if (service_name->empty()) {
258       USB_PLOG(ERROR) << "Failed to get device driver name";
259       return false;
260     }
261   }
262 
263   return true;
264 }
265 
GetDevicePath(const std::wstring & instance_id,const GUID & device_interface_guid)266 std::wstring GetDevicePath(const std::wstring& instance_id,
267                            const GUID& device_interface_guid) {
268   base::win::ScopedDevInfo dev_info(
269       SetupDiGetClassDevs(&device_interface_guid, instance_id.c_str(), 0,
270                           DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
271   if (!dev_info.is_valid()) {
272     USB_PLOG(ERROR) << "SetupDiGetClassDevs";
273     return std::wstring();
274   }
275 
276   SP_DEVICE_INTERFACE_DATA device_interface_data = {};
277   device_interface_data.cbSize = sizeof(device_interface_data);
278   if (!SetupDiEnumDeviceInterfaces(dev_info.get(), nullptr,
279                                    &device_interface_guid, 0,
280                                    &device_interface_data)) {
281     USB_PLOG(ERROR) << "SetupDiEnumDeviceInterfaces";
282     return std::wstring();
283   }
284 
285   std::wstring device_path;
286   if (!GetDeviceInterfaceDetails(
287           dev_info.get(), &device_interface_data, &device_path,
288           /*bus_number=*/nullptr, /*port_number=*/nullptr,
289           /*instance_id=*/nullptr, /*parent_instance_id=*/nullptr,
290           /*child_instance_ids=*/nullptr, /*hardware_ids=*/nullptr,
291           /*service_name=*/nullptr)) {
292     return std::wstring();
293   }
294 
295   return device_path;
296 }
297 
GetInterfaceNumber(const std::wstring & instance_id,const std::vector<std::wstring> & hardware_ids)298 int GetInterfaceNumber(const std::wstring& instance_id,
299                        const std::vector<std::wstring>& hardware_ids) {
300   // According to MSDN the instance IDs for the device nodes created by the
301   // composite driver is in the form "USB\VID_vvvv&PID_dddd&MI_zz" where "zz"
302   // is the interface number.
303   //
304   // https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices
305   RE2 pattern("MI_([0-9a-fA-F]{2})");
306 
307   std::string instance_id_ascii = base::WideToASCII(instance_id);
308   std::string match;
309   if (!RE2::PartialMatch(instance_id_ascii, pattern, &match)) {
310     // Alternative composite drivers, such as the one used for Samsung devices,
311     // don't use the standard format for the instance ID, but one of the
312     // hardware IDs will still match the expected pattern.
313     bool found = false;
314     for (const std::wstring& hardware_id : hardware_ids) {
315       std::string hardware_id_ascii = base::WideToASCII(hardware_id);
316       if (RE2::PartialMatch(hardware_id_ascii, pattern, &match)) {
317         found = true;
318         break;
319       }
320     }
321     if (!found)
322       return -1;
323   }
324 
325   int interface_number;
326   if (!base::HexStringToInt(match, &interface_number))
327     return -1;
328   return interface_number;
329 }
330 
GetFunctionInfo(const std::wstring & instance_id)331 UsbDeviceWin::FunctionInfo GetFunctionInfo(const std::wstring& instance_id) {
332   UsbDeviceWin::FunctionInfo info;
333   info.interface_number = -1;
334 
335   base::win::ScopedDevInfo dev_info(
336       SetupDiCreateDeviceInfoList(nullptr, nullptr));
337   if (!dev_info.is_valid()) {
338     USB_PLOG(ERROR) << "SetupDiCreateDeviceInfoList";
339     return info;
340   }
341 
342   SP_DEVINFO_DATA dev_info_data = {};
343   dev_info_data.cbSize = sizeof(dev_info_data);
344   if (!SetupDiOpenDeviceInfo(dev_info.get(), instance_id.c_str(), nullptr, 0,
345                              &dev_info_data)) {
346     USB_PLOG(ERROR) << "SetupDiOpenDeviceInfo";
347     return info;
348   }
349 
350   info.driver = GetServiceName(dev_info.get(), &dev_info_data);
351   if (info.driver.empty()) {
352     USB_PLOG(ERROR) << "Could not get child device's service name";
353     return info;
354   }
355 
356   base::Optional<std::vector<std::wstring>> hardware_ids =
357       GetDeviceStringListProperty(dev_info.get(), &dev_info_data,
358                                   DEVPKEY_Device_HardwareIds);
359   if (!hardware_ids) {
360     USB_PLOG(ERROR) << "Could not get the child device's hardware IDs";
361     return info;
362   }
363 
364   info.interface_number = GetInterfaceNumber(instance_id, *hardware_ids);
365 
366   if (!base::EqualsCaseInsensitiveASCII(info.driver, L"winusb"))
367     return info;
368 
369   // Boost priority while potentially loading Advapi32.dll on a background
370   // thread for the registry functions used below.
371   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
372 
373   // There is no standard device interface GUID for USB functions and so we
374   // must discover the set of GUIDs that have been set in the registry by
375   // the INF file or Microsoft OS Compatibility descriptors before
376   // SetupDiGetDeviceInterfaceDetail() can be used to get the device path.
377   HKEY key = SetupDiOpenDevRegKey(dev_info.get(), &dev_info_data,
378                                   DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
379   if (key == INVALID_HANDLE_VALUE) {
380     USB_PLOG(ERROR) << "Could not open device registry key";
381     return info;
382   }
383   base::win::RegKey scoped_key(key);
384 
385   std::vector<std::wstring> device_interface_guids;
386   LONG result =
387       scoped_key.ReadValues(L"DeviceInterfaceGUIDs", &device_interface_guids);
388   if (result != ERROR_SUCCESS) {
389     USB_LOG(ERROR) << "Could not read device interface GUIDs: "
390                    << logging::SystemErrorCodeToString(result);
391     return info;
392   }
393 
394   for (const auto& guid_string : device_interface_guids) {
395     // Boost priority while potentially loading Ole32.dll on a background
396     // thread for CLSIDFromString().
397     SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
398 
399     GUID guid;
400     if (FAILED(CLSIDFromString(guid_string.c_str(), &guid))) {
401       USB_LOG(ERROR) << "Failed to parse device interface GUID: "
402                      << guid_string;
403       continue;
404     }
405 
406     info.path = GetDevicePath(instance_id, guid);
407     if (!info.path.empty())
408       return info;
409   }
410 
411   return info;
412 }
413 
414 }  // namespace
415 
416 class UsbServiceWin::BlockingTaskRunnerHelper {
417  public:
BlockingTaskRunnerHelper(base::WeakPtr<UsbServiceWin> service)418   explicit BlockingTaskRunnerHelper(base::WeakPtr<UsbServiceWin> service)
419       : service_task_runner_(base::ThreadTaskRunnerHandle::Get()),
420         service_(service) {}
~BlockingTaskRunnerHelper()421   ~BlockingTaskRunnerHelper() {}
422 
EnumerateDevices()423   void EnumerateDevices() {
424     // Boost priority while potentially loading SetupAPI.dll for the following
425     // functions on a background thread.
426     SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
427 
428     base::win::ScopedDevInfo dev_info(
429         SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, nullptr, 0,
430                             DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
431     if (!dev_info.is_valid()) {
432       USB_PLOG(ERROR) << "Failed to set up device enumeration";
433       service_task_runner_->PostTask(
434           FROM_HERE, base::BindOnce(&UsbServiceWin::HelperStarted, service_));
435       return;
436     }
437 
438     SP_DEVICE_INTERFACE_DATA device_interface_data = {};
439     device_interface_data.cbSize = sizeof(device_interface_data);
440     for (DWORD i = 0; SetupDiEnumDeviceInterfaces(dev_info.get(), nullptr,
441                                                   &GUID_DEVINTERFACE_USB_DEVICE,
442                                                   i, &device_interface_data);
443          ++i) {
444       EnumerateDevice(dev_info.get(), &device_interface_data, base::nullopt);
445     }
446 
447     if (GetLastError() != ERROR_NO_MORE_ITEMS)
448       USB_PLOG(ERROR) << "Failed to enumerate devices";
449 
450     service_task_runner_->PostTask(
451         FROM_HERE, base::BindOnce(&UsbServiceWin::HelperStarted, service_));
452   }
453 
OnDeviceAdded(const GUID & guid,const std::wstring & device_path)454   void OnDeviceAdded(const GUID& guid, const std::wstring& device_path) {
455     // Boost priority while potentially loading SetupAPI.dll and Ole32.dll on a
456     // background thread for the following functions.
457     SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
458 
459     base::win::ScopedDevInfo dev_info(SetupDiGetClassDevs(
460         &guid, nullptr, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
461     if (!dev_info.is_valid()) {
462       USB_PLOG(ERROR) << "Failed to set up device enumeration";
463       return;
464     }
465 
466     SP_DEVICE_INTERFACE_DATA device_interface_data = {};
467     device_interface_data.cbSize = sizeof(device_interface_data);
468     if (!SetupDiOpenDeviceInterface(dev_info.get(), device_path.c_str(), 0,
469                                     &device_interface_data)) {
470       USB_PLOG(ERROR) << "Failed to add device interface: " << device_path;
471       return;
472     }
473 
474     if (IsEqualGUID(guid, GUID_DEVINTERFACE_USB_DEVICE)) {
475       EnumerateDevice(dev_info.get(), &device_interface_data, device_path);
476     } else {
477       EnumeratePotentialFunction(dev_info.get(), &device_interface_data,
478                                  device_path);
479     }
480   }
481 
482  private:
EnumerateDevice(HDEVINFO dev_info,SP_DEVICE_INTERFACE_DATA * device_interface_data,const base::Optional<std::wstring> & opt_device_path)483   void EnumerateDevice(HDEVINFO dev_info,
484                        SP_DEVICE_INTERFACE_DATA* device_interface_data,
485                        const base::Optional<std::wstring>& opt_device_path) {
486     std::wstring device_path;
487     std::wstring* device_path_ptr = &device_path;
488     if (opt_device_path) {
489       device_path = *opt_device_path;
490       device_path_ptr = nullptr;
491     }
492 
493     uint32_t bus_number;
494     uint32_t port_number;
495     std::wstring parent_instance_id;
496     std::vector<std::wstring> child_instance_ids;
497     std::wstring service_name;
498     if (!GetDeviceInterfaceDetails(dev_info, device_interface_data,
499                                    device_path_ptr, &bus_number, &port_number,
500                                    /*instance_id=*/nullptr, &parent_instance_id,
501                                    &child_instance_ids,
502                                    /*hardware_ids=*/nullptr, &service_name)) {
503       return;
504     }
505 
506     auto driver_type = UsbDeviceWin::DriverType::kUnsupported;
507     std::vector<std::pair<int, UsbDeviceWin::FunctionInfo>> functions;
508     if (IsCompositeDevice(service_name)) {
509       driver_type = UsbDeviceWin::DriverType::kComposite;
510       // For composite devices Windows a composite device driver (usually the
511       // built-in usbccgp.sys) creates child device nodes for each device
512       // function. The device paths for these children must be opened in order
513       // to communicate with the WinUSB driver.
514       for (const std::wstring& instance_id : child_instance_ids) {
515         UsbDeviceWin::FunctionInfo info = GetFunctionInfo(instance_id);
516         if (info.interface_number != -1) {
517           functions.emplace_back(info.interface_number, info);
518         }
519       }
520     } else if (base::EqualsCaseInsensitiveASCII(service_name, L"winusb")) {
521       driver_type = UsbDeviceWin::DriverType::kWinUSB;
522       // A non-composite device has a single device node for all interfaces. It
523       // may still include multiple functions but they will be ignored.
524       UsbDeviceWin::FunctionInfo info;
525       info.driver = service_name;
526       info.path = device_path;
527       functions.emplace_back(/*interface_number=*/0, info);
528     }
529 
530     std::wstring& hub_path = hub_paths_[parent_instance_id];
531     if (hub_path.empty()) {
532       hub_path = GetDevicePath(parent_instance_id, GUID_DEVINTERFACE_USB_HUB);
533       if (hub_path.empty())
534         return;
535     }
536 
537     service_task_runner_->PostTask(
538         FROM_HERE, base::BindOnce(&UsbServiceWin::CreateDeviceObject, service_,
539                                   std::move(device_path), std::move(hub_path),
540                                   std::move(functions), bus_number, port_number,
541                                   driver_type, service_name));
542   }
543 
EnumeratePotentialFunction(HDEVINFO dev_info,SP_DEVICE_INTERFACE_DATA * device_interface_data,const std::wstring & device_path)544   void EnumeratePotentialFunction(
545       HDEVINFO dev_info,
546       SP_DEVICE_INTERFACE_DATA* device_interface_data,
547       const std::wstring& device_path) {
548     std::wstring instance_id;
549     std::wstring parent_instance_id;
550     std::vector<std::wstring> hardware_ids;
551     std::wstring service_name;
552     if (!GetDeviceInterfaceDetails(
553             dev_info, device_interface_data,
554             /*device_path=*/nullptr, /*bus_number=*/nullptr,
555             /*port_number=*/nullptr, &instance_id, &parent_instance_id,
556             /*child_instance_ids=*/nullptr, &hardware_ids, &service_name)) {
557       return;
558     }
559 
560     int interface_number = GetInterfaceNumber(instance_id, hardware_ids);
561     if (interface_number == -1)
562       return;
563 
564     std::wstring parent_path =
565         GetDevicePath(parent_instance_id, GUID_DEVINTERFACE_USB_DEVICE);
566     if (parent_path.empty())
567       return;
568 
569     UsbDeviceWin::FunctionInfo info;
570     info.driver = service_name;
571     info.path = device_path;
572 
573     service_task_runner_->PostTask(
574         FROM_HERE,
575         base::BindOnce(&UsbServiceWin::UpdateFunction, service_,
576                        std::move(parent_path), interface_number, info));
577   }
578 
579   std::unordered_map<std::wstring, std::wstring> hub_paths_;
580 
581   // Calls back to |service_| must be posted to |service_task_runner_|, which
582   // runs tasks on the thread where that object lives.
583   scoped_refptr<base::SingleThreadTaskRunner> service_task_runner_;
584   base::WeakPtr<UsbServiceWin> service_;
585 };
586 
UsbServiceWin()587 UsbServiceWin::UsbServiceWin()
588     : UsbService(),
589       blocking_task_runner_(CreateBlockingTaskRunner()),
590       helper_(nullptr, base::OnTaskRunnerDeleter(blocking_task_runner_)),
591       device_observer_(this) {
592   DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces();
593   if (device_monitor)
594     device_observer_.Add(device_monitor);
595 
596   helper_.reset(new BlockingTaskRunnerHelper(weak_factory_.GetWeakPtr()));
597   blocking_task_runner_->PostTask(
598       FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::EnumerateDevices,
599                                 base::Unretained(helper_.get())));
600 }
601 
~UsbServiceWin()602 UsbServiceWin::~UsbServiceWin() {
603   NotifyWillDestroyUsbService();
604 }
605 
GetDevices(GetDevicesCallback callback)606 void UsbServiceWin::GetDevices(GetDevicesCallback callback) {
607   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
608   if (enumeration_ready())
609     UsbService::GetDevices(std::move(callback));
610   else
611     enumeration_callbacks_.push_back(std::move(callback));
612 }
613 
OnDeviceAdded(const GUID & class_guid,const std::wstring & device_path)614 void UsbServiceWin::OnDeviceAdded(const GUID& class_guid,
615                                   const std::wstring& device_path) {
616   blocking_task_runner_->PostTask(
617       FROM_HERE,
618       base::BindOnce(&BlockingTaskRunnerHelper::OnDeviceAdded,
619                      base::Unretained(helper_.get()), class_guid, device_path));
620 }
621 
OnDeviceRemoved(const GUID & class_guid,const std::wstring & device_path)622 void UsbServiceWin::OnDeviceRemoved(const GUID& class_guid,
623                                     const std::wstring& device_path) {
624   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
625   auto by_path_it = devices_by_path_.find(device_path);
626   if (by_path_it == devices_by_path_.end())
627     return;
628 
629   scoped_refptr<UsbDeviceWin> device = by_path_it->second;
630   devices_by_path_.erase(by_path_it);
631   device->OnDisconnect();
632 
633   auto by_guid_it = devices().find(device->guid());
634   if (by_guid_it != devices().end() && enumeration_ready()) {
635     USB_LOG(USER) << "USB device removed: path=" << device->device_path()
636                   << " guid=" << device->guid();
637 
638     devices().erase(by_guid_it);
639     NotifyDeviceRemoved(device);
640   }
641 }
642 
HelperStarted()643 void UsbServiceWin::HelperStarted() {
644   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
645   helper_started_ = true;
646   if (enumeration_ready()) {
647     std::vector<scoped_refptr<UsbDevice>> result;
648     result.reserve(devices().size());
649     for (const auto& map_entry : devices())
650       result.push_back(map_entry.second);
651     for (auto& callback : enumeration_callbacks_)
652       std::move(callback).Run(result);
653     enumeration_callbacks_.clear();
654   }
655 }
656 
CreateDeviceObject(const std::wstring & device_path,const std::wstring & hub_path,const base::flat_map<int,UsbDeviceWin::FunctionInfo> & functions,uint32_t bus_number,uint32_t port_number,UsbDeviceWin::DriverType driver_type,const std::wstring & driver_name)657 void UsbServiceWin::CreateDeviceObject(
658     const std::wstring& device_path,
659     const std::wstring& hub_path,
660     const base::flat_map<int, UsbDeviceWin::FunctionInfo>& functions,
661     uint32_t bus_number,
662     uint32_t port_number,
663     UsbDeviceWin::DriverType driver_type,
664     const std::wstring& driver_name) {
665   // Devices that appear during initial enumeration are gathered into the first
666   // result returned by GetDevices() and prevent device add/remove notifications
667   // from being sent.
668   if (!enumeration_ready())
669     ++first_enumeration_countdown_;
670 
671   auto device = base::MakeRefCounted<UsbDeviceWin>(
672       device_path, hub_path, functions, bus_number, port_number, driver_type);
673   devices_by_path_[device->device_path()] = device;
674   device->ReadDescriptors(base::BindOnce(&UsbServiceWin::DeviceReady,
675                                          weak_factory_.GetWeakPtr(), device,
676                                          driver_name));
677 }
678 
UpdateFunction(const std::wstring & device_path,int interface_number,const UsbDeviceWin::FunctionInfo & function_info)679 void UsbServiceWin::UpdateFunction(
680     const std::wstring& device_path,
681     int interface_number,
682     const UsbDeviceWin::FunctionInfo& function_info) {
683   auto it = devices_by_path_.find(device_path);
684   if (it == devices_by_path_.end())
685     return;
686   const scoped_refptr<UsbDeviceWin>& device = it->second;
687 
688   USB_LOG(EVENT) << "USB device function updated: guid=" << device->guid()
689                  << ", interface_number=" << interface_number << ", path=\""
690                  << function_info.path << "\", driver=\""
691                  << function_info.driver << "\"";
692   device->UpdateFunction(interface_number, function_info);
693 }
694 
DeviceReady(scoped_refptr<UsbDeviceWin> device,const std::wstring & driver_name,bool success)695 void UsbServiceWin::DeviceReady(scoped_refptr<UsbDeviceWin> device,
696                                 const std::wstring& driver_name,
697                                 bool success) {
698   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
699 
700   bool enumeration_became_ready = false;
701   if (!enumeration_ready()) {
702     DCHECK_GT(first_enumeration_countdown_, 0u);
703     first_enumeration_countdown_--;
704     if (enumeration_ready())
705       enumeration_became_ready = true;
706   }
707 
708   // If |device| was disconnected while descriptors were being read then it
709   // will have been removed from |devices_by_path_|.
710   auto it = devices_by_path_.find(device->device_path());
711   if (it == devices_by_path_.end()) {
712     success = false;
713   } else if (success) {
714     DCHECK(!base::Contains(devices(), device->guid()));
715     devices()[device->guid()] = device;
716 
717     USB_LOG(USER) << "USB device added: path=" << device->device_path()
718                   << " vendor=" << device->vendor_id() << " \""
719                   << device->manufacturer_string()
720                   << "\", product=" << device->product_id() << " \""
721                   << device->product_string() << "\", serial=\""
722                   << device->serial_number() << "\", driver=\"" << driver_name
723                   << "\", guid=" << device->guid();
724   } else {
725     devices_by_path_.erase(it);
726   }
727 
728   if (enumeration_became_ready) {
729     std::vector<scoped_refptr<UsbDevice>> result;
730     result.reserve(devices().size());
731     for (const auto& map_entry : devices())
732       result.push_back(map_entry.second);
733     for (auto& callback : enumeration_callbacks_)
734       std::move(callback).Run(result);
735     enumeration_callbacks_.clear();
736   } else if (success && enumeration_ready()) {
737     NotifyDeviceAdded(device);
738   }
739 }
740 
741 }  // namespace device
742