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.
5 #include "device/usb/usb_service_impl.h"
10 #include "base/barrier_closure.h"
11 #include "base/bind.h"
12 #include "base/location.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "components/device_event_log/device_event_log.h"
20 #include "device/usb/usb_device_handle.h"
21 #include "device/usb/usb_error.h"
22 #include "device/usb/webusb_descriptors.h"
23 #include "third_party/libusb/src/libusb/libusb.h"
29 #include "base/strings/string_util.h"
33 #include "device/udev_linux/scoped_udev.h"
36 using net::IOBufferWithSize
;
42 // Standard USB requests and descriptor types:
43 const uint16_t kUsbVersion2_1
= 0x0210;
44 const uint8_t kGetDescriptorRequest
= 0x06;
45 const uint8_t kStringDescriptorType
= 0x03;
46 const uint8_t kBosDescriptorType
= 0x0F;
49 const uint8_t kGetAllowedOriginsRequest
= 0x01;
50 const uint8_t kGetLandingPageRequest
= 0x02;
52 const int kControlTransferTimeout
= 60000; // 1 minute
56 // Wrapper around a HDEVINFO that automatically destroys it.
57 class ScopedDeviceInfoList
{
59 explicit ScopedDeviceInfoList(HDEVINFO handle
) : handle_(handle
) {}
61 ~ScopedDeviceInfoList() {
63 SetupDiDestroyDeviceInfoList(handle_
);
67 bool valid() { return handle_
!= INVALID_HANDLE_VALUE
; }
69 HDEVINFO
get() { return handle_
; }
74 DISALLOW_COPY_AND_ASSIGN(ScopedDeviceInfoList
);
77 // Wrapper around an SP_DEVINFO_DATA that initializes it properly and
78 // automatically deletes it.
79 class ScopedDeviceInfo
{
82 memset(&dev_info_data_
, 0, sizeof(dev_info_data_
));
83 dev_info_data_
.cbSize
= sizeof(dev_info_data_
);
87 if (dev_info_set_
!= INVALID_HANDLE_VALUE
) {
88 SetupDiDeleteDeviceInfo(dev_info_set_
, &dev_info_data_
);
92 // Once the SP_DEVINFO_DATA has been populated it must be freed using the
93 // HDEVINFO it was created from.
94 void set_valid(HDEVINFO dev_info_set
) {
95 DCHECK(dev_info_set_
== INVALID_HANDLE_VALUE
);
96 DCHECK(dev_info_set
!= INVALID_HANDLE_VALUE
);
97 dev_info_set_
= dev_info_set
;
100 PSP_DEVINFO_DATA
get() { return &dev_info_data_
; }
103 HDEVINFO dev_info_set_
= INVALID_HANDLE_VALUE
;
104 SP_DEVINFO_DATA dev_info_data_
;
107 bool IsWinUsbInterface(const std::string
& device_path
) {
108 ScopedDeviceInfoList
dev_info_list(SetupDiCreateDeviceInfoList(NULL
, NULL
));
109 if (!dev_info_list
.valid()) {
110 USB_PLOG(ERROR
) << "Failed to create a device information set";
114 // This will add the device to |dev_info_list| so we can query driver info.
115 if (!SetupDiOpenDeviceInterfaceA(dev_info_list
.get(), device_path
.c_str(), 0,
117 USB_PLOG(ERROR
) << "Failed to get device interface data for "
122 ScopedDeviceInfo dev_info
;
123 if (!SetupDiEnumDeviceInfo(dev_info_list
.get(), 0, dev_info
.get())) {
124 USB_PLOG(ERROR
) << "Failed to get device info for " << device_path
;
127 dev_info
.set_valid(dev_info_list
.get());
131 if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list
.get(), dev_info
.get(),
132 SPDRP_SERVICE
, ®_data_type
,
133 &buffer
[0], sizeof buffer
, NULL
)) {
134 USB_PLOG(ERROR
) << "Failed to get device service property";
137 if (reg_data_type
!= REG_SZ
) {
138 USB_LOG(ERROR
) << "Unexpected data type for driver service: "
143 USB_LOG(DEBUG
) << "Driver for " << device_path
<< " is " << buffer
<< ".";
144 if (base::StartsWith(reinterpret_cast<const char*>(buffer
), "WinUSB",
145 base::CompareCase::INSENSITIVE_ASCII
))
152 void GetDeviceListOnBlockingThread(
153 const std::string
& new_device_path
,
154 scoped_refptr
<UsbContext
> usb_context
,
155 scoped_refptr
<base::SequencedTaskRunner
> task_runner
,
156 base::Callback
<void(libusb_device
**, size_t)> callback
) {
158 if (!new_device_path
.empty()) {
159 if (!IsWinUsbInterface(new_device_path
)) {
160 // Wait to call libusb_get_device_list until libusb will be able to find
161 // a WinUSB interface for the device.
162 task_runner
->PostTask(FROM_HERE
, base::Bind(callback
, nullptr, 0));
166 #endif // defined(OS_WIN)
168 libusb_device
** platform_devices
= NULL
;
169 const ssize_t device_count
=
170 libusb_get_device_list(usb_context
->context(), &platform_devices
);
171 if (device_count
< 0) {
172 USB_LOG(ERROR
) << "Failed to get device list: "
173 << ConvertPlatformUsbErrorToString(device_count
);
174 task_runner
->PostTask(FROM_HERE
, base::Bind(callback
, nullptr, 0));
178 task_runner
->PostTask(FROM_HERE
,
179 base::Bind(callback
, platform_devices
, device_count
));
182 void OnReadStringDescriptor(
183 const base::Callback
<void(const base::string16
&)>& callback
,
184 UsbTransferStatus status
,
185 scoped_refptr
<net::IOBuffer
> buffer
,
187 base::string16 string
;
188 if (status
== USB_TRANSFER_COMPLETED
&&
189 ParseUsbStringDescriptor(
190 std::vector
<uint8
>(buffer
->data(), buffer
->data() + length
),
192 callback
.Run(string
);
194 callback
.Run(base::string16());
198 void ReadStringDescriptor(
199 scoped_refptr
<UsbDeviceHandle
> device_handle
,
202 const base::Callback
<void(const base::string16
&)>& callback
) {
203 scoped_refptr
<IOBufferWithSize
> buffer
= new IOBufferWithSize(256);
204 device_handle
->ControlTransfer(
205 USB_DIRECTION_INBOUND
, UsbDeviceHandle::STANDARD
, UsbDeviceHandle::DEVICE
,
206 kGetDescriptorRequest
, kStringDescriptorType
<< 8 | index
, language_id
,
207 buffer
, buffer
->size(), kControlTransferTimeout
,
208 base::Bind(&OnReadStringDescriptor
, callback
));
211 void OnReadWebUsbLandingPage(scoped_refptr
<UsbDevice
> device
,
212 const base::Closure
& callback
,
213 UsbTransferStatus status
,
214 scoped_refptr
<net::IOBuffer
> buffer
,
216 if (status
!= USB_TRANSFER_COMPLETED
) {
217 USB_LOG(EVENT
) << "Failed to read WebUSB landing page.";
223 if (ParseWebUsbUrlDescriptor(
224 std::vector
<uint8_t>(buffer
->data(), buffer
->data() + length
),
226 UsbDeviceImpl
* device_impl
= static_cast<UsbDeviceImpl
*>(device
.get());
227 device_impl
->set_webusb_landing_page(landing_page
);
232 void ReadWebUsbLandingPage(scoped_refptr
<UsbDeviceHandle
> device_handle
,
233 const base::Closure
& callback
,
235 scoped_refptr
<IOBufferWithSize
> buffer
= new IOBufferWithSize(256);
236 device_handle
->ControlTransfer(
237 USB_DIRECTION_INBOUND
, UsbDeviceHandle::VENDOR
, UsbDeviceHandle::DEVICE
,
238 vendor_code
, 0, kGetLandingPageRequest
, buffer
, buffer
->size(),
239 kControlTransferTimeout
,
240 base::Bind(&OnReadWebUsbLandingPage
, device_handle
->GetDevice(),
244 void OnReadWebUsbAllowedOrigins(scoped_refptr
<UsbDevice
> device
,
245 const base::Closure
& callback
,
246 UsbTransferStatus status
,
247 scoped_refptr
<net::IOBuffer
> buffer
,
249 if (status
!= USB_TRANSFER_COMPLETED
) {
250 USB_LOG(EVENT
) << "Failed to read WebUSB allowed origins.";
255 scoped_ptr
<WebUsbDescriptorSet
> descriptors(new WebUsbDescriptorSet());
256 if (descriptors
->Parse(
257 std::vector
<uint8
>(buffer
->data(), buffer
->data() + length
))) {
258 UsbDeviceImpl
* device_impl
= static_cast<UsbDeviceImpl
*>(device
.get());
259 device_impl
->set_webusb_allowed_origins(descriptors
.Pass());
264 void OnReadWebUsbAllowedOriginsHeader(
265 scoped_refptr
<UsbDeviceHandle
> device_handle
,
266 const base::Closure
& callback
,
268 UsbTransferStatus status
,
269 scoped_refptr
<net::IOBuffer
> buffer
,
271 if (status
!= USB_TRANSFER_COMPLETED
|| length
!= 4) {
272 USB_LOG(EVENT
) << "Failed to read WebUSB allowed origins header.";
277 uint16 new_length
= buffer
->data()[2] | (buffer
->data()[3] << 8);
278 scoped_refptr
<IOBufferWithSize
> new_buffer
= new IOBufferWithSize(new_length
);
279 device_handle
->ControlTransfer(
280 USB_DIRECTION_INBOUND
, UsbDeviceHandle::VENDOR
, UsbDeviceHandle::DEVICE
,
281 vendor_code
, 0, kGetAllowedOriginsRequest
, new_buffer
, new_buffer
->size(),
282 kControlTransferTimeout
,
283 base::Bind(&OnReadWebUsbAllowedOrigins
, device_handle
->GetDevice(),
287 void ReadWebUsbAllowedOrigins(scoped_refptr
<UsbDeviceHandle
> device_handle
,
288 const base::Closure
& callback
,
290 scoped_refptr
<IOBufferWithSize
> buffer
= new IOBufferWithSize(4);
291 device_handle
->ControlTransfer(
292 USB_DIRECTION_INBOUND
, UsbDeviceHandle::VENDOR
, UsbDeviceHandle::DEVICE
,
293 vendor_code
, 0, kGetAllowedOriginsRequest
, buffer
, buffer
->size(),
294 kControlTransferTimeout
,
295 base::Bind(&OnReadWebUsbAllowedOriginsHeader
, device_handle
, callback
,
299 void OnReadBosDescriptor(scoped_refptr
<UsbDeviceHandle
> device_handle
,
300 const base::Closure
& callback
,
301 UsbTransferStatus status
,
302 scoped_refptr
<net::IOBuffer
> buffer
,
304 if (status
!= USB_TRANSFER_COMPLETED
) {
305 USB_LOG(EVENT
) << "Failed to read BOS descriptor.";
310 WebUsbPlatformCapabilityDescriptor descriptor
;
311 if (!descriptor
.ParseFromBosDescriptor(
312 std::vector
<uint8
>(buffer
->data(), buffer
->data() + length
))) {
317 base::Closure barrier
= base::BarrierClosure(2, callback
);
318 ReadWebUsbLandingPage(device_handle
, barrier
, descriptor
.vendor_code
);
319 ReadWebUsbAllowedOrigins(device_handle
, barrier
, descriptor
.vendor_code
);
322 void OnReadBosDescriptorHeader(scoped_refptr
<UsbDeviceHandle
> device_handle
,
323 const base::Closure
& callback
,
324 UsbTransferStatus status
,
325 scoped_refptr
<net::IOBuffer
> buffer
,
327 if (status
!= USB_TRANSFER_COMPLETED
|| length
!= 5) {
328 USB_LOG(EVENT
) << "Failed to read BOS descriptor header.";
333 uint16 new_length
= buffer
->data()[2] | (buffer
->data()[3] << 8);
334 scoped_refptr
<IOBufferWithSize
> new_buffer
= new IOBufferWithSize(new_length
);
335 device_handle
->ControlTransfer(
336 USB_DIRECTION_INBOUND
, UsbDeviceHandle::STANDARD
, UsbDeviceHandle::DEVICE
,
337 kGetDescriptorRequest
, kBosDescriptorType
<< 8, 0, new_buffer
,
338 new_buffer
->size(), kControlTransferTimeout
,
339 base::Bind(&OnReadBosDescriptor
, device_handle
, callback
));
342 void ReadBosDescriptor(scoped_refptr
<UsbDeviceHandle
> device_handle
,
343 const base::Closure
& callback
) {
344 scoped_refptr
<IOBufferWithSize
> buffer
= new IOBufferWithSize(5);
345 device_handle
->ControlTransfer(
346 USB_DIRECTION_INBOUND
, UsbDeviceHandle::STANDARD
, UsbDeviceHandle::DEVICE
,
347 kGetDescriptorRequest
, kBosDescriptorType
<< 8, 0, buffer
, buffer
->size(),
348 kControlTransferTimeout
,
349 base::Bind(&OnReadBosDescriptorHeader
, device_handle
, callback
));
352 void CloseHandleAndRunContinuation(scoped_refptr
<UsbDeviceHandle
> device_handle
,
353 const base::Closure
& continuation
) {
354 device_handle
->Close();
358 void SaveStringAndRunContinuation(
359 const base::Callback
<void(const base::string16
&)>& save_callback
,
360 const base::Closure
& continuation
,
361 const base::string16
& value
) {
362 if (!value
.empty()) {
363 save_callback
.Run(value
);
368 // This function runs |barrier| once for every string it tries to read.
369 void OnReadLanguageIds(scoped_refptr
<UsbDeviceHandle
> device_handle
,
373 const base::Closure
& barrier
,
374 const base::string16
& languages
) {
375 // Default to English unless the device provides a language and then just pick
377 uint16 language_id
= 0x0409;
378 if (!languages
.empty()) {
379 language_id
= languages
[0];
382 scoped_refptr
<UsbDeviceImpl
> device
=
383 static_cast<UsbDeviceImpl
*>(device_handle
->GetDevice().get());
385 if (manufacturer
!= 0) {
386 ReadStringDescriptor(
387 device_handle
, manufacturer
, language_id
,
388 base::Bind(&SaveStringAndRunContinuation
,
389 base::Bind(&UsbDeviceImpl::set_manufacturer_string
, device
),
394 ReadStringDescriptor(
395 device_handle
, product
, language_id
,
396 base::Bind(&SaveStringAndRunContinuation
,
397 base::Bind(&UsbDeviceImpl::set_product_string
, device
),
401 if (serial_number
!= 0) {
402 ReadStringDescriptor(
403 device_handle
, serial_number
, language_id
,
404 base::Bind(&SaveStringAndRunContinuation
,
405 base::Bind(&UsbDeviceImpl::set_serial_number
, device
),
410 void OnDeviceOpenedReadDescriptors(
414 bool read_bos_descriptors
,
415 const base::Closure
& success_closure
,
416 const base::Closure
& failure_closure
,
417 scoped_refptr
<UsbDeviceHandle
> device_handle
) {
420 if (manufacturer
!= 0)
424 if (serial_number
!= 0)
426 if (read_bos_descriptors
)
430 base::Closure barrier
=
431 base::BarrierClosure(count
, base::Bind(&CloseHandleAndRunContinuation
,
432 device_handle
, success_closure
));
434 if (manufacturer
!= 0 || product
!= 0 || serial_number
!= 0) {
435 ReadStringDescriptor(
437 base::Bind(&OnReadLanguageIds
, device_handle
, manufacturer
, product
,
438 serial_number
, barrier
));
441 if (read_bos_descriptors
) {
442 ReadBosDescriptor(device_handle
, barrier
);
445 failure_closure
.Run();
449 #if defined(USE_UDEV)
451 void EnumerateUdevDevice(scoped_refptr
<UsbDeviceImpl
> device
,
452 bool read_bos_descriptors
,
453 scoped_refptr
<base::SequencedTaskRunner
> task_runner
,
454 const base::Closure
& success_closure
,
455 const base::Closure
& failure_closure
) {
456 ScopedUdevPtr
udev(udev_new());
457 ScopedUdevEnumeratePtr
udev_enumerate(udev_enumerate_new(udev
.get()));
459 udev_enumerate_add_match_subsystem(udev_enumerate
.get(), "usb");
460 if (udev_enumerate_scan_devices(udev_enumerate
.get()) != 0) {
461 task_runner
->PostTask(FROM_HERE
, failure_closure
);
465 std::string bus_number
=
466 base::UintToString(libusb_get_bus_number(device
->platform_device()));
467 std::string device_address
=
468 base::UintToString(libusb_get_device_address(device
->platform_device()));
469 udev_list_entry
* devices
=
470 udev_enumerate_get_list_entry(udev_enumerate
.get());
471 for (udev_list_entry
* i
= devices
; i
!= NULL
;
472 i
= udev_list_entry_get_next(i
)) {
473 ScopedUdevDevicePtr
udev_device(
474 udev_device_new_from_syspath(udev
.get(), udev_list_entry_get_name(i
)));
477 udev_device_get_sysattr_value(udev_device
.get(), "busnum");
478 if (!value
|| bus_number
!= value
) {
481 value
= udev_device_get_sysattr_value(udev_device
.get(), "devnum");
482 if (!value
|| device_address
!= value
) {
486 value
= udev_device_get_sysattr_value(udev_device
.get(), "manufacturer");
488 device
->set_manufacturer_string(base::UTF8ToUTF16(value
));
490 value
= udev_device_get_sysattr_value(udev_device
.get(), "product");
492 device
->set_product_string(base::UTF8ToUTF16(value
));
494 value
= udev_device_get_sysattr_value(udev_device
.get(), "serial");
496 device
->set_serial_number(base::UTF8ToUTF16(value
));
499 value
= udev_device_get_devnode(udev_device
.get());
501 device
->set_device_path(value
);
503 if (read_bos_descriptors
) {
504 task_runner
->PostTask(
506 base::Bind(&UsbDevice::Open
, device
,
507 base::Bind(&OnDeviceOpenedReadDescriptors
, 0, 0, 0,
508 true, success_closure
, failure_closure
)));
510 task_runner
->PostTask(FROM_HERE
, success_closure
);
519 task_runner
->PostTask(FROM_HERE
, failure_closure
);
526 UsbServiceImpl::UsbServiceImpl(
527 scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner
)
528 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
529 blocking_task_runner_(blocking_task_runner
),
531 device_observer_(this),
533 weak_factory_(this) {
535 PlatformUsbContext platform_context
= nullptr;
536 int rv
= libusb_init(&platform_context
);
537 if (rv
!= LIBUSB_SUCCESS
|| !platform_context
) {
538 USB_LOG(DEBUG
) << "Failed to initialize libusb: "
539 << ConvertPlatformUsbErrorToString(rv
);
542 context_
= new UsbContext(platform_context
);
544 rv
= libusb_hotplug_register_callback(
546 static_cast<libusb_hotplug_event
>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
|
547 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT
),
548 static_cast<libusb_hotplug_flag
>(0), LIBUSB_HOTPLUG_MATCH_ANY
,
549 LIBUSB_HOTPLUG_MATCH_ANY
, LIBUSB_HOTPLUG_MATCH_ANY
,
550 &UsbServiceImpl::HotplugCallback
, this, &hotplug_handle_
);
551 if (rv
== LIBUSB_SUCCESS
) {
552 hotplug_enabled_
= true;
557 DeviceMonitorWin
* device_monitor
= DeviceMonitorWin::GetForAllInterfaces();
558 if (device_monitor
) {
559 device_observer_
.Add(device_monitor
);
564 UsbServiceImpl::~UsbServiceImpl() {
565 if (hotplug_enabled_
) {
566 libusb_hotplug_deregister_callback(context_
->context(), hotplug_handle_
);
568 for (const auto& map_entry
: devices_
) {
569 map_entry
.second
->OnDisconnect();
573 scoped_refptr
<UsbDevice
> UsbServiceImpl::GetDevice(const std::string
& guid
) {
574 DCHECK(CalledOnValidThread());
575 DeviceMap::iterator it
= devices_
.find(guid
);
576 if (it
!= devices_
.end()) {
582 void UsbServiceImpl::GetDevices(const GetDevicesCallback
& callback
) {
583 DCHECK(CalledOnValidThread());
586 task_runner_
->PostTask(
588 base::Bind(callback
, std::vector
<scoped_refptr
<UsbDevice
>>()));
592 if (hotplug_enabled_
&& !enumeration_in_progress_
) {
593 // The device list is updated live when hotplug events are supported.
594 std::vector
<scoped_refptr
<UsbDevice
>> devices
;
595 for (const auto& map_entry
: devices_
) {
596 devices
.push_back(map_entry
.second
);
598 task_runner_
->PostTask(FROM_HERE
, base::Bind(callback
, devices
));
600 pending_enumeration_callbacks_
.push_back(callback
);
607 void UsbServiceImpl::OnDeviceAdded(const GUID
& class_guid
,
608 const std::string
& device_path
) {
609 // Only the root node of a composite USB device has the class GUID
610 // GUID_DEVINTERFACE_USB_DEVICE but we want to wait until WinUSB is loaded.
611 // This first pass filter will catch anything that's sitting on the USB bus
612 // (including devices on 3rd party USB controllers) to avoid the more
613 // expensive driver check that needs to be done on the FILE thread.
614 if (device_path
.find("usb") != std::string::npos
) {
615 pending_path_enumerations_
.push(device_path
);
620 void UsbServiceImpl::OnDeviceRemoved(const GUID
& class_guid
,
621 const std::string
& device_path
) {
622 // The root USB device node is removed last.
623 if (class_guid
== GUID_DEVINTERFACE_USB_DEVICE
) {
630 void UsbServiceImpl::RefreshDevices() {
631 DCHECK(CalledOnValidThread());
634 if (enumeration_in_progress_
) {
638 enumeration_in_progress_
= true;
639 DCHECK(devices_being_enumerated_
.empty());
641 std::string device_path
;
642 if (!pending_path_enumerations_
.empty()) {
643 device_path
= pending_path_enumerations_
.front();
644 pending_path_enumerations_
.pop();
647 blocking_task_runner_
->PostTask(
649 base::Bind(&GetDeviceListOnBlockingThread
, device_path
, context_
,
650 task_runner_
, base::Bind(&UsbServiceImpl::OnDeviceList
,
651 weak_factory_
.GetWeakPtr())));
654 void UsbServiceImpl::OnDeviceList(libusb_device
** platform_devices
,
655 size_t device_count
) {
656 DCHECK(CalledOnValidThread());
657 if (!platform_devices
) {
658 RefreshDevicesComplete();
662 base::Closure refresh_complete
=
663 base::BarrierClosure(static_cast<int>(device_count
),
664 base::Bind(&UsbServiceImpl::RefreshDevicesComplete
,
665 weak_factory_
.GetWeakPtr()));
666 std::list
<PlatformUsbDevice
> new_devices
;
668 // Look for new and existing devices.
669 for (size_t i
= 0; i
< device_count
; ++i
) {
670 PlatformUsbDevice platform_device
= platform_devices
[i
];
671 auto it
= platform_devices_
.find(platform_device
);
673 if (it
== platform_devices_
.end()) {
674 libusb_ref_device(platform_device
);
675 new_devices
.push_back(platform_device
);
677 it
->second
->set_visited(true);
678 refresh_complete
.Run();
682 // Remove devices not seen in this enumeration.
683 for (PlatformDeviceMap::iterator it
= platform_devices_
.begin();
684 it
!= platform_devices_
.end();
685 /* incremented internally */) {
686 PlatformDeviceMap::iterator current
= it
++;
687 const scoped_refptr
<UsbDeviceImpl
>& device
= current
->second
;
688 if (device
->was_visited()) {
689 device
->set_visited(false);
691 RemoveDevice(device
);
695 for (PlatformUsbDevice platform_device
: new_devices
) {
696 EnumerateDevice(platform_device
, refresh_complete
);
699 libusb_free_device_list(platform_devices
, true);
702 void UsbServiceImpl::RefreshDevicesComplete() {
703 DCHECK(CalledOnValidThread());
704 DCHECK(enumeration_in_progress_
);
706 enumeration_ready_
= true;
707 enumeration_in_progress_
= false;
708 devices_being_enumerated_
.clear();
710 if (!pending_enumeration_callbacks_
.empty()) {
711 std::vector
<scoped_refptr
<UsbDevice
>> devices
;
712 for (const auto& map_entry
: devices_
) {
713 devices
.push_back(map_entry
.second
);
716 std::vector
<GetDevicesCallback
> callbacks
;
717 callbacks
.swap(pending_enumeration_callbacks_
);
718 for (const GetDevicesCallback
& callback
: callbacks
) {
719 callback
.Run(devices
);
723 if (!pending_path_enumerations_
.empty()) {
728 void UsbServiceImpl::EnumerateDevice(PlatformUsbDevice platform_device
,
729 const base::Closure
& refresh_complete
) {
731 devices_being_enumerated_
.insert(platform_device
);
733 libusb_device_descriptor descriptor
;
734 int rv
= libusb_get_device_descriptor(platform_device
, &descriptor
);
735 if (rv
== LIBUSB_SUCCESS
) {
736 scoped_refptr
<UsbDeviceImpl
> device(
737 new UsbDeviceImpl(context_
, platform_device
, descriptor
.idVendor
,
738 descriptor
.idProduct
, blocking_task_runner_
));
740 base::Closure add_device
=
741 base::Bind(&UsbServiceImpl::AddDevice
, weak_factory_
.GetWeakPtr(),
742 refresh_complete
, device
);
743 bool read_bos_descriptors
= descriptor
.bcdUSB
>= kUsbVersion2_1
;
745 #if defined(USE_UDEV)
746 blocking_task_runner_
->PostTask(
748 base::Bind(&EnumerateUdevDevice
, device
, read_bos_descriptors
,
749 task_runner_
, add_device
, refresh_complete
));
751 if (descriptor
.iManufacturer
== 0 && descriptor
.iProduct
== 0 &&
752 descriptor
.iSerialNumber
== 0 && !read_bos_descriptors
) {
753 // Don't bother disturbing the device if it has no descriptors to offer.
756 device
->Open(base::Bind(&OnDeviceOpenedReadDescriptors
,
757 descriptor
.iManufacturer
, descriptor
.iProduct
,
758 descriptor
.iSerialNumber
, read_bos_descriptors
,
759 add_device
, refresh_complete
));
763 USB_LOG(EVENT
) << "Failed to get device descriptor: "
764 << ConvertPlatformUsbErrorToString(rv
);
765 refresh_complete
.Run();
769 void UsbServiceImpl::AddDevice(const base::Closure
& refresh_complete
,
770 scoped_refptr
<UsbDeviceImpl
> device
) {
771 auto it
= devices_being_enumerated_
.find(device
->platform_device());
772 if (it
== devices_being_enumerated_
.end()) {
773 // Device was removed while being enumerated.
774 refresh_complete
.Run();
778 platform_devices_
[device
->platform_device()] = device
;
779 DCHECK(!ContainsKey(devices_
, device
->guid()));
780 devices_
[device
->guid()] = device
;
782 USB_LOG(USER
) << "USB device added: vendor=" << device
->vendor_id() << " \""
783 << device
->manufacturer_string()
784 << "\", product=" << device
->product_id() << " \""
785 << device
->product_string() << "\", serial=\""
786 << device
->serial_number() << "\", guid=" << device
->guid();
788 if (enumeration_ready_
) {
789 NotifyDeviceAdded(device
);
792 refresh_complete
.Run();
795 void UsbServiceImpl::RemoveDevice(scoped_refptr
<UsbDeviceImpl
> device
) {
796 platform_devices_
.erase(device
->platform_device());
797 devices_
.erase(device
->guid());
799 USB_LOG(USER
) << "USB device removed: guid=" << device
->guid();
801 NotifyDeviceRemoved(device
);
802 device
->OnDisconnect();
806 int LIBUSB_CALL
UsbServiceImpl::HotplugCallback(libusb_context
* context
,
807 PlatformUsbDevice device
,
808 libusb_hotplug_event event
,
810 // It is safe to access the UsbServiceImpl* here because libusb takes a lock
811 // around registering, deregistering and calling hotplug callback functions
812 // and so guarantees that this function will not be called by the event
813 // processing thread after it has been deregistered.
814 UsbServiceImpl
* self
= reinterpret_cast<UsbServiceImpl
*>(user_data
);
816 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
:
817 libusb_ref_device(device
); // Released in OnPlatformDeviceAdded.
818 if (self
->task_runner_
->BelongsToCurrentThread()) {
819 self
->OnPlatformDeviceAdded(device
);
821 self
->task_runner_
->PostTask(
822 FROM_HERE
, base::Bind(&UsbServiceImpl::OnPlatformDeviceAdded
,
823 base::Unretained(self
), device
));
826 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT
:
827 libusb_ref_device(device
); // Released in OnPlatformDeviceRemoved.
828 if (self
->task_runner_
->BelongsToCurrentThread()) {
829 self
->OnPlatformDeviceRemoved(device
);
831 self
->task_runner_
->PostTask(
832 FROM_HERE
, base::Bind(&UsbServiceImpl::OnPlatformDeviceRemoved
,
833 base::Unretained(self
), device
));
843 void UsbServiceImpl::OnPlatformDeviceAdded(PlatformUsbDevice platform_device
) {
844 DCHECK(CalledOnValidThread());
845 DCHECK(!ContainsKey(platform_devices_
, platform_device
));
846 EnumerateDevice(platform_device
, base::Bind(&base::DoNothing
));
847 libusb_unref_device(platform_device
);
850 void UsbServiceImpl::OnPlatformDeviceRemoved(
851 PlatformUsbDevice platform_device
) {
852 DCHECK(CalledOnValidThread());
853 PlatformDeviceMap::iterator it
= platform_devices_
.find(platform_device
);
854 if (it
!= platform_devices_
.end()) {
855 RemoveDevice(it
->second
);
857 devices_being_enumerated_
.erase(platform_device
);
859 libusb_unref_device(platform_device
);
862 } // namespace device