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"
11 #include "base/barrier_closure.h"
12 #include "base/bind.h"
13 #include "base/location.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "components/device_event_log/device_event_log.h"
21 #include "device/usb/usb_device_handle.h"
22 #include "device/usb/usb_error.h"
23 #include "device/usb/webusb_descriptors.h"
24 #include "third_party/libusb/src/libusb/libusb.h"
30 #include "base/strings/string_util.h"
34 #include "device/udev_linux/scoped_udev.h"
37 using net::IOBufferWithSize
;
43 // Standard USB requests and descriptor types:
44 const uint16_t kUsbVersion2_1
= 0x0210;
45 const uint8_t kGetDescriptorRequest
= 0x06;
46 const uint8_t kStringDescriptorType
= 0x03;
47 const uint8_t kBosDescriptorType
= 0x0F;
50 const uint8_t kGetAllowedOriginsRequest
= 0x01;
51 const uint8_t kGetLandingPageRequest
= 0x02;
52 const uint8_t kUrlDescriptorType
= 0x03;
54 const int kControlTransferTimeout
= 60000; // 1 minute
58 // Wrapper around a HDEVINFO that automatically destroys it.
59 class ScopedDeviceInfoList
{
61 explicit ScopedDeviceInfoList(HDEVINFO handle
) : handle_(handle
) {}
63 ~ScopedDeviceInfoList() {
65 SetupDiDestroyDeviceInfoList(handle_
);
69 bool valid() { return handle_
!= INVALID_HANDLE_VALUE
; }
71 HDEVINFO
get() { return handle_
; }
76 DISALLOW_COPY_AND_ASSIGN(ScopedDeviceInfoList
);
79 // Wrapper around an SP_DEVINFO_DATA that initializes it properly and
80 // automatically deletes it.
81 class ScopedDeviceInfo
{
84 memset(&dev_info_data_
, 0, sizeof(dev_info_data_
));
85 dev_info_data_
.cbSize
= sizeof(dev_info_data_
);
89 if (dev_info_set_
!= INVALID_HANDLE_VALUE
) {
90 SetupDiDeleteDeviceInfo(dev_info_set_
, &dev_info_data_
);
94 // Once the SP_DEVINFO_DATA has been populated it must be freed using the
95 // HDEVINFO it was created from.
96 void set_valid(HDEVINFO dev_info_set
) {
97 DCHECK(dev_info_set_
== INVALID_HANDLE_VALUE
);
98 DCHECK(dev_info_set
!= INVALID_HANDLE_VALUE
);
99 dev_info_set_
= dev_info_set
;
102 PSP_DEVINFO_DATA
get() { return &dev_info_data_
; }
105 HDEVINFO dev_info_set_
= INVALID_HANDLE_VALUE
;
106 SP_DEVINFO_DATA dev_info_data_
;
109 bool IsWinUsbInterface(const std::string
& device_path
) {
110 ScopedDeviceInfoList
dev_info_list(SetupDiCreateDeviceInfoList(NULL
, NULL
));
111 if (!dev_info_list
.valid()) {
112 USB_PLOG(ERROR
) << "Failed to create a device information set";
116 // This will add the device to |dev_info_list| so we can query driver info.
117 if (!SetupDiOpenDeviceInterfaceA(dev_info_list
.get(), device_path
.c_str(), 0,
119 USB_PLOG(ERROR
) << "Failed to get device interface data for "
124 ScopedDeviceInfo dev_info
;
125 if (!SetupDiEnumDeviceInfo(dev_info_list
.get(), 0, dev_info
.get())) {
126 USB_PLOG(ERROR
) << "Failed to get device info for " << device_path
;
129 dev_info
.set_valid(dev_info_list
.get());
133 if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list
.get(), dev_info
.get(),
134 SPDRP_SERVICE
, ®_data_type
,
135 &buffer
[0], sizeof buffer
, NULL
)) {
136 USB_PLOG(ERROR
) << "Failed to get device service property";
139 if (reg_data_type
!= REG_SZ
) {
140 USB_LOG(ERROR
) << "Unexpected data type for driver service: "
145 USB_LOG(DEBUG
) << "Driver for " << device_path
<< " is " << buffer
<< ".";
146 if (base::StartsWith(reinterpret_cast<const char*>(buffer
), "WinUSB",
147 base::CompareCase::INSENSITIVE_ASCII
))
154 void GetDeviceListOnBlockingThread(
155 const std::string
& new_device_path
,
156 scoped_refptr
<UsbContext
> usb_context
,
157 scoped_refptr
<base::SequencedTaskRunner
> task_runner
,
158 base::Callback
<void(libusb_device
**, size_t)> callback
) {
160 if (!new_device_path
.empty()) {
161 if (!IsWinUsbInterface(new_device_path
)) {
162 // Wait to call libusb_get_device_list until libusb will be able to find
163 // a WinUSB interface for the device.
164 task_runner
->PostTask(FROM_HERE
, base::Bind(callback
, nullptr, 0));
168 #endif // defined(OS_WIN)
170 libusb_device
** platform_devices
= NULL
;
171 const ssize_t device_count
=
172 libusb_get_device_list(usb_context
->context(), &platform_devices
);
173 if (device_count
< 0) {
174 USB_LOG(ERROR
) << "Failed to get device list: "
175 << ConvertPlatformUsbErrorToString(device_count
);
176 task_runner
->PostTask(FROM_HERE
, base::Bind(callback
, nullptr, 0));
180 task_runner
->PostTask(FROM_HERE
,
181 base::Bind(callback
, platform_devices
, device_count
));
184 void OnReadStringDescriptor(
185 const base::Callback
<void(const base::string16
&)>& callback
,
186 UsbTransferStatus status
,
187 scoped_refptr
<net::IOBuffer
> buffer
,
189 if (status
!= USB_TRANSFER_COMPLETED
|| length
< 2) {
190 callback
.Run(base::string16());
192 // Take the lesser of the length of data returned by the device and the
193 // length reported in the descriptor.
194 size_t internal_length
= reinterpret_cast<uint8
*>(buffer
->data())[0];
195 length
= std::min(length
, internal_length
);
196 // Cut off the first 2 bytes of the descriptor which are the length and
197 // descriptor type (always STRING).
198 callback
.Run(base::string16(
199 reinterpret_cast<base::char16
*>(buffer
->data() + 2), length
/ 2 - 1));
203 void ReadStringDescriptor(
204 scoped_refptr
<UsbDeviceHandle
> device_handle
,
207 const base::Callback
<void(const base::string16
&)>& callback
) {
208 scoped_refptr
<IOBufferWithSize
> buffer
= new IOBufferWithSize(256);
209 device_handle
->ControlTransfer(
210 USB_DIRECTION_INBOUND
, UsbDeviceHandle::STANDARD
, UsbDeviceHandle::DEVICE
,
211 kGetDescriptorRequest
, kStringDescriptorType
<< 8 | index
, language_id
,
212 buffer
, buffer
->size(), kControlTransferTimeout
,
213 base::Bind(&OnReadStringDescriptor
, callback
));
216 void OnReadWebUsbLandingPage(scoped_refptr
<UsbDevice
> device
,
217 const base::Closure
& callback
,
218 UsbTransferStatus status
,
219 scoped_refptr
<net::IOBuffer
> buffer
,
221 if (status
!= USB_TRANSFER_COMPLETED
|| length
< 2) {
226 uint8_t string_length
= buffer
->data()[0];
227 if (string_length
< 2 || string_length
> length
||
228 buffer
->data()[1] != kUrlDescriptorType
) {
233 GURL
url(std::string(&buffer
->data()[2], string_length
- 2));
234 if (url
.is_valid()) {
235 UsbDeviceImpl
* device_impl
= static_cast<UsbDeviceImpl
*>(device
.get());
236 device_impl
->set_webusb_landing_page(url
);
241 void ReadWebUsbLandingPage(scoped_refptr
<UsbDeviceHandle
> device_handle
,
242 const base::Closure
& callback
,
244 scoped_refptr
<IOBufferWithSize
> buffer
= new IOBufferWithSize(256);
245 device_handle
->ControlTransfer(
246 USB_DIRECTION_INBOUND
, UsbDeviceHandle::VENDOR
, UsbDeviceHandle::DEVICE
,
247 vendor_code
, 0, kGetLandingPageRequest
, buffer
, buffer
->size(),
248 kControlTransferTimeout
,
249 base::Bind(&OnReadWebUsbLandingPage
, device_handle
->GetDevice(),
253 void OnReadWebUsbAllowedOrigins(scoped_refptr
<UsbDevice
> device
,
254 const base::Closure
& callback
,
255 UsbTransferStatus status
,
256 scoped_refptr
<net::IOBuffer
> buffer
,
258 if (status
!= USB_TRANSFER_COMPLETED
) {
259 USB_LOG(EVENT
) << "Failed to read WebUSB allowed origins.";
264 scoped_ptr
<WebUsbDescriptorSet
> descriptors(new WebUsbDescriptorSet());
265 if (descriptors
->Parse(
266 std::vector
<uint8
>(buffer
->data(), buffer
->data() + length
))) {
267 UsbDeviceImpl
* device_impl
= static_cast<UsbDeviceImpl
*>(device
.get());
268 device_impl
->set_webusb_allowed_origins(descriptors
.Pass());
273 void OnReadWebUsbAllowedOriginsHeader(
274 scoped_refptr
<UsbDeviceHandle
> device_handle
,
275 const base::Closure
& callback
,
277 UsbTransferStatus status
,
278 scoped_refptr
<net::IOBuffer
> buffer
,
280 if (status
!= USB_TRANSFER_COMPLETED
|| length
!= 4) {
281 USB_LOG(EVENT
) << "Failed to read WebUSB allowed origins header.";
286 uint16 new_length
= buffer
->data()[2] | (buffer
->data()[3] << 8);
287 scoped_refptr
<IOBufferWithSize
> new_buffer
= new IOBufferWithSize(new_length
);
288 device_handle
->ControlTransfer(
289 USB_DIRECTION_INBOUND
, UsbDeviceHandle::VENDOR
, UsbDeviceHandle::DEVICE
,
290 vendor_code
, 0, kGetAllowedOriginsRequest
, new_buffer
, new_buffer
->size(),
291 kControlTransferTimeout
,
292 base::Bind(&OnReadWebUsbAllowedOrigins
, device_handle
->GetDevice(),
296 void ReadWebUsbAllowedOrigins(scoped_refptr
<UsbDeviceHandle
> device_handle
,
297 const base::Closure
& callback
,
299 scoped_refptr
<IOBufferWithSize
> buffer
= new IOBufferWithSize(4);
300 device_handle
->ControlTransfer(
301 USB_DIRECTION_INBOUND
, UsbDeviceHandle::VENDOR
, UsbDeviceHandle::DEVICE
,
302 vendor_code
, 0, kGetAllowedOriginsRequest
, buffer
, buffer
->size(),
303 kControlTransferTimeout
,
304 base::Bind(&OnReadWebUsbAllowedOriginsHeader
, device_handle
, callback
,
308 void OnReadBosDescriptor(scoped_refptr
<UsbDeviceHandle
> device_handle
,
309 const base::Closure
& callback
,
310 UsbTransferStatus status
,
311 scoped_refptr
<net::IOBuffer
> buffer
,
313 if (status
!= USB_TRANSFER_COMPLETED
) {
314 USB_LOG(EVENT
) << "Failed to read BOS descriptor.";
319 WebUsbPlatformCapabilityDescriptor descriptor
;
320 if (!descriptor
.ParseFromBosDescriptor(
321 std::vector
<uint8
>(buffer
->data(), buffer
->data() + length
))) {
326 base::Closure barrier
= base::BarrierClosure(2, callback
);
327 ReadWebUsbLandingPage(device_handle
, barrier
, descriptor
.vendor_code
);
328 ReadWebUsbAllowedOrigins(device_handle
, barrier
, descriptor
.vendor_code
);
331 void OnReadBosDescriptorHeader(scoped_refptr
<UsbDeviceHandle
> device_handle
,
332 const base::Closure
& callback
,
333 UsbTransferStatus status
,
334 scoped_refptr
<net::IOBuffer
> buffer
,
336 if (status
!= USB_TRANSFER_COMPLETED
|| length
!= 5) {
337 USB_LOG(EVENT
) << "Failed to read BOS descriptor header.";
342 uint16 new_length
= buffer
->data()[2] | (buffer
->data()[3] << 8);
343 scoped_refptr
<IOBufferWithSize
> new_buffer
= new IOBufferWithSize(new_length
);
344 device_handle
->ControlTransfer(
345 USB_DIRECTION_INBOUND
, UsbDeviceHandle::STANDARD
, UsbDeviceHandle::DEVICE
,
346 kGetDescriptorRequest
, kBosDescriptorType
<< 8, 0, new_buffer
,
347 new_buffer
->size(), kControlTransferTimeout
,
348 base::Bind(&OnReadBosDescriptor
, device_handle
, callback
));
351 void ReadBosDescriptor(scoped_refptr
<UsbDeviceHandle
> device_handle
,
352 const base::Closure
& callback
) {
353 scoped_refptr
<IOBufferWithSize
> buffer
= new IOBufferWithSize(5);
354 device_handle
->ControlTransfer(
355 USB_DIRECTION_INBOUND
, UsbDeviceHandle::STANDARD
, UsbDeviceHandle::DEVICE
,
356 kGetDescriptorRequest
, kBosDescriptorType
<< 8, 0, buffer
, buffer
->size(),
357 kControlTransferTimeout
,
358 base::Bind(&OnReadBosDescriptorHeader
, device_handle
, callback
));
361 void CloseHandleAndRunContinuation(scoped_refptr
<UsbDeviceHandle
> device_handle
,
362 const base::Closure
& continuation
) {
363 device_handle
->Close();
367 void SaveStringAndRunContinuation(
368 const base::Callback
<void(const base::string16
&)>& save_callback
,
369 const base::Closure
& continuation
,
370 const base::string16
& value
) {
371 if (!value
.empty()) {
372 save_callback
.Run(value
);
377 // This function runs |barrier| once for every string it tries to read.
378 void OnReadLanguageIds(scoped_refptr
<UsbDeviceHandle
> device_handle
,
382 const base::Closure
& barrier
,
383 const base::string16
& languages
) {
384 // Default to English unless the device provides a language and then just pick
386 uint16 language_id
= 0x0409;
387 if (!languages
.empty()) {
388 language_id
= languages
[0];
391 scoped_refptr
<UsbDeviceImpl
> device
=
392 static_cast<UsbDeviceImpl
*>(device_handle
->GetDevice().get());
394 if (manufacturer
!= 0) {
395 ReadStringDescriptor(
396 device_handle
, manufacturer
, language_id
,
397 base::Bind(&SaveStringAndRunContinuation
,
398 base::Bind(&UsbDeviceImpl::set_manufacturer_string
, device
),
403 ReadStringDescriptor(
404 device_handle
, product
, language_id
,
405 base::Bind(&SaveStringAndRunContinuation
,
406 base::Bind(&UsbDeviceImpl::set_product_string
, device
),
410 if (serial_number
!= 0) {
411 ReadStringDescriptor(
412 device_handle
, serial_number
, language_id
,
413 base::Bind(&SaveStringAndRunContinuation
,
414 base::Bind(&UsbDeviceImpl::set_serial_number
, device
),
419 void OnDeviceOpenedReadDescriptors(
423 bool read_bos_descriptors
,
424 const base::Closure
& success_closure
,
425 const base::Closure
& failure_closure
,
426 scoped_refptr
<UsbDeviceHandle
> device_handle
) {
429 if (manufacturer
!= 0)
433 if (serial_number
!= 0)
435 if (read_bos_descriptors
)
439 base::Closure barrier
=
440 base::BarrierClosure(count
, base::Bind(&CloseHandleAndRunContinuation
,
441 device_handle
, success_closure
));
443 if (manufacturer
!= 0 || product
!= 0 || serial_number
!= 0) {
444 ReadStringDescriptor(
446 base::Bind(&OnReadLanguageIds
, device_handle
, manufacturer
, product
,
447 serial_number
, barrier
));
450 if (read_bos_descriptors
) {
451 ReadBosDescriptor(device_handle
, barrier
);
454 failure_closure
.Run();
458 #if defined(USE_UDEV)
460 void EnumerateUdevDevice(scoped_refptr
<UsbDeviceImpl
> device
,
461 bool read_bos_descriptors
,
462 scoped_refptr
<base::SequencedTaskRunner
> task_runner
,
463 const base::Closure
& success_closure
,
464 const base::Closure
& failure_closure
) {
465 ScopedUdevPtr
udev(udev_new());
466 ScopedUdevEnumeratePtr
udev_enumerate(udev_enumerate_new(udev
.get()));
468 udev_enumerate_add_match_subsystem(udev_enumerate
.get(), "usb");
469 if (udev_enumerate_scan_devices(udev_enumerate
.get()) != 0) {
470 task_runner
->PostTask(FROM_HERE
, failure_closure
);
474 std::string bus_number
=
475 base::IntToString(libusb_get_bus_number(device
->platform_device()));
476 std::string device_address
=
477 base::IntToString(libusb_get_device_address(device
->platform_device()));
478 udev_list_entry
* devices
=
479 udev_enumerate_get_list_entry(udev_enumerate
.get());
480 for (udev_list_entry
* i
= devices
; i
!= NULL
;
481 i
= udev_list_entry_get_next(i
)) {
482 ScopedUdevDevicePtr
udev_device(
483 udev_device_new_from_syspath(udev
.get(), udev_list_entry_get_name(i
)));
486 udev_device_get_sysattr_value(udev_device
.get(), "busnum");
487 if (!value
|| bus_number
!= value
) {
490 value
= udev_device_get_sysattr_value(udev_device
.get(), "devnum");
491 if (!value
|| device_address
!= value
) {
495 value
= udev_device_get_sysattr_value(udev_device
.get(), "manufacturer");
497 device
->set_manufacturer_string(base::UTF8ToUTF16(value
));
499 value
= udev_device_get_sysattr_value(udev_device
.get(), "product");
501 device
->set_product_string(base::UTF8ToUTF16(value
));
503 value
= udev_device_get_sysattr_value(udev_device
.get(), "serial");
505 device
->set_serial_number(base::UTF8ToUTF16(value
));
508 value
= udev_device_get_devnode(udev_device
.get());
510 device
->set_device_path(value
);
512 if (read_bos_descriptors
) {
513 task_runner
->PostTask(
515 base::Bind(&UsbDevice::Open
, device
,
516 base::Bind(&OnDeviceOpenedReadDescriptors
, 0, 0, 0,
517 true, success_closure
, failure_closure
)));
519 task_runner
->PostTask(FROM_HERE
, success_closure
);
528 task_runner
->PostTask(FROM_HERE
, failure_closure
);
536 UsbService
* UsbServiceImpl::Create(
537 scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner
) {
538 PlatformUsbContext context
= NULL
;
539 const int rv
= libusb_init(&context
);
540 if (rv
!= LIBUSB_SUCCESS
) {
541 USB_LOG(ERROR
) << "Failed to initialize libusb: "
542 << ConvertPlatformUsbErrorToString(rv
);
549 return new UsbServiceImpl(context
, blocking_task_runner
);
552 UsbServiceImpl::UsbServiceImpl(
553 PlatformUsbContext context
,
554 scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner
)
555 : context_(new UsbContext(context
)),
556 task_runner_(base::ThreadTaskRunnerHandle::Get()),
557 blocking_task_runner_(blocking_task_runner
),
559 device_observer_(this),
561 weak_factory_(this) {
562 base::MessageLoop::current()->AddDestructionObserver(this);
564 int rv
= libusb_hotplug_register_callback(
566 static_cast<libusb_hotplug_event
>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
|
567 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT
),
568 static_cast<libusb_hotplug_flag
>(0), LIBUSB_HOTPLUG_MATCH_ANY
,
569 LIBUSB_HOTPLUG_MATCH_ANY
, LIBUSB_HOTPLUG_MATCH_ANY
,
570 &UsbServiceImpl::HotplugCallback
, this, &hotplug_handle_
);
571 if (rv
== LIBUSB_SUCCESS
) {
572 hotplug_enabled_
= true;
577 DeviceMonitorWin
* device_monitor
= DeviceMonitorWin::GetForAllInterfaces();
578 if (device_monitor
) {
579 device_observer_
.Add(device_monitor
);
584 UsbServiceImpl::~UsbServiceImpl() {
585 base::MessageLoop::current()->RemoveDestructionObserver(this);
587 if (hotplug_enabled_
) {
588 libusb_hotplug_deregister_callback(context_
->context(), hotplug_handle_
);
590 for (const auto& map_entry
: devices_
) {
591 map_entry
.second
->OnDisconnect();
595 scoped_refptr
<UsbDevice
> UsbServiceImpl::GetDevice(const std::string
& guid
) {
596 DCHECK(CalledOnValidThread());
597 DeviceMap::iterator it
= devices_
.find(guid
);
598 if (it
!= devices_
.end()) {
604 void UsbServiceImpl::GetDevices(const GetDevicesCallback
& callback
) {
605 DCHECK(CalledOnValidThread());
607 if (hotplug_enabled_
&& !enumeration_in_progress_
) {
608 // The device list is updated live when hotplug events are supported.
609 std::vector
<scoped_refptr
<UsbDevice
>> devices
;
610 for (const auto& map_entry
: devices_
) {
611 devices
.push_back(map_entry
.second
);
613 callback
.Run(devices
);
615 pending_enumeration_callbacks_
.push_back(callback
);
622 void UsbServiceImpl::OnDeviceAdded(const GUID
& class_guid
,
623 const std::string
& device_path
) {
624 // Only the root node of a composite USB device has the class GUID
625 // GUID_DEVINTERFACE_USB_DEVICE but we want to wait until WinUSB is loaded.
626 // This first pass filter will catch anything that's sitting on the USB bus
627 // (including devices on 3rd party USB controllers) to avoid the more
628 // expensive driver check that needs to be done on the FILE thread.
629 if (device_path
.find("usb") != std::string::npos
) {
630 pending_path_enumerations_
.push(device_path
);
635 void UsbServiceImpl::OnDeviceRemoved(const GUID
& class_guid
,
636 const std::string
& device_path
) {
637 // The root USB device node is removed last.
638 if (class_guid
== GUID_DEVINTERFACE_USB_DEVICE
) {
645 void UsbServiceImpl::WillDestroyCurrentMessageLoop() {
646 DCHECK(CalledOnValidThread());
650 void UsbServiceImpl::RefreshDevices() {
651 DCHECK(CalledOnValidThread());
653 if (enumeration_in_progress_
) {
657 enumeration_in_progress_
= true;
658 DCHECK(devices_being_enumerated_
.empty());
660 std::string device_path
;
661 if (!pending_path_enumerations_
.empty()) {
662 device_path
= pending_path_enumerations_
.front();
663 pending_path_enumerations_
.pop();
666 blocking_task_runner_
->PostTask(
668 base::Bind(&GetDeviceListOnBlockingThread
, device_path
, context_
,
669 task_runner_
, base::Bind(&UsbServiceImpl::OnDeviceList
,
670 weak_factory_
.GetWeakPtr())));
673 void UsbServiceImpl::OnDeviceList(libusb_device
** platform_devices
,
674 size_t device_count
) {
675 DCHECK(CalledOnValidThread());
676 if (!platform_devices
) {
677 RefreshDevicesComplete();
681 base::Closure refresh_complete
=
682 base::BarrierClosure(static_cast<int>(device_count
),
683 base::Bind(&UsbServiceImpl::RefreshDevicesComplete
,
684 weak_factory_
.GetWeakPtr()));
685 std::list
<PlatformUsbDevice
> new_devices
;
687 // Look for new and existing devices.
688 for (size_t i
= 0; i
< device_count
; ++i
) {
689 PlatformUsbDevice platform_device
= platform_devices
[i
];
690 auto it
= platform_devices_
.find(platform_device
);
692 if (it
== platform_devices_
.end()) {
693 libusb_ref_device(platform_device
);
694 new_devices
.push_back(platform_device
);
696 it
->second
->set_visited(true);
697 refresh_complete
.Run();
701 // Remove devices not seen in this enumeration.
702 for (PlatformDeviceMap::iterator it
= platform_devices_
.begin();
703 it
!= platform_devices_
.end();
704 /* incremented internally */) {
705 PlatformDeviceMap::iterator current
= it
++;
706 const scoped_refptr
<UsbDeviceImpl
>& device
= current
->second
;
707 if (device
->was_visited()) {
708 device
->set_visited(false);
710 RemoveDevice(device
);
714 for (PlatformUsbDevice platform_device
: new_devices
) {
715 EnumerateDevice(platform_device
, refresh_complete
);
718 libusb_free_device_list(platform_devices
, true);
721 void UsbServiceImpl::RefreshDevicesComplete() {
722 DCHECK(CalledOnValidThread());
723 DCHECK(enumeration_in_progress_
);
725 enumeration_ready_
= true;
726 enumeration_in_progress_
= false;
727 devices_being_enumerated_
.clear();
729 if (!pending_enumeration_callbacks_
.empty()) {
730 std::vector
<scoped_refptr
<UsbDevice
>> devices
;
731 for (const auto& map_entry
: devices_
) {
732 devices
.push_back(map_entry
.second
);
735 std::vector
<GetDevicesCallback
> callbacks
;
736 callbacks
.swap(pending_enumeration_callbacks_
);
737 for (const GetDevicesCallback
& callback
: callbacks
) {
738 callback
.Run(devices
);
742 if (!pending_path_enumerations_
.empty()) {
747 void UsbServiceImpl::EnumerateDevice(PlatformUsbDevice platform_device
,
748 const base::Closure
& refresh_complete
) {
749 devices_being_enumerated_
.insert(platform_device
);
751 libusb_device_descriptor descriptor
;
752 int rv
= libusb_get_device_descriptor(platform_device
, &descriptor
);
753 if (rv
== LIBUSB_SUCCESS
) {
754 scoped_refptr
<UsbDeviceImpl
> device(
755 new UsbDeviceImpl(context_
, platform_device
, descriptor
.idVendor
,
756 descriptor
.idProduct
, blocking_task_runner_
));
758 base::Closure add_device
=
759 base::Bind(&UsbServiceImpl::AddDevice
, weak_factory_
.GetWeakPtr(),
760 refresh_complete
, device
);
761 bool read_bos_descriptors
= descriptor
.bcdUSB
>= kUsbVersion2_1
;
763 #if defined(USE_UDEV)
764 blocking_task_runner_
->PostTask(
766 base::Bind(&EnumerateUdevDevice
, device
, read_bos_descriptors
,
767 task_runner_
, add_device
, refresh_complete
));
769 if (descriptor
.iManufacturer
== 0 && descriptor
.iProduct
== 0 &&
770 descriptor
.iSerialNumber
== 0 && !read_bos_descriptors
) {
771 // Don't bother disturbing the device if it has no descriptors to offer.
774 device
->Open(base::Bind(&OnDeviceOpenedReadDescriptors
,
775 descriptor
.iManufacturer
, descriptor
.iProduct
,
776 descriptor
.iSerialNumber
, read_bos_descriptors
,
777 add_device
, refresh_complete
));
781 USB_LOG(EVENT
) << "Failed to get device descriptor: "
782 << ConvertPlatformUsbErrorToString(rv
);
783 refresh_complete
.Run();
787 void UsbServiceImpl::AddDevice(const base::Closure
& refresh_complete
,
788 scoped_refptr
<UsbDeviceImpl
> device
) {
789 auto it
= devices_being_enumerated_
.find(device
->platform_device());
790 if (it
== devices_being_enumerated_
.end()) {
791 // Device was removed while being enumerated.
792 refresh_complete
.Run();
796 platform_devices_
[device
->platform_device()] = device
;
797 DCHECK(!ContainsKey(devices_
, device
->guid()));
798 devices_
[device
->guid()] = device
;
800 USB_LOG(USER
) << "USB device added: vendor=" << device
->vendor_id() << " \""
801 << device
->manufacturer_string()
802 << "\", product=" << device
->product_id() << " \""
803 << device
->product_string() << "\", serial=\""
804 << device
->serial_number() << "\", guid=" << device
->guid();
806 if (enumeration_ready_
) {
807 NotifyDeviceAdded(device
);
810 refresh_complete
.Run();
813 void UsbServiceImpl::RemoveDevice(scoped_refptr
<UsbDeviceImpl
> device
) {
814 platform_devices_
.erase(device
->platform_device());
815 devices_
.erase(device
->guid());
817 USB_LOG(USER
) << "USB device removed: guid=" << device
->guid();
819 NotifyDeviceRemoved(device
);
820 device
->OnDisconnect();
824 int LIBUSB_CALL
UsbServiceImpl::HotplugCallback(libusb_context
* context
,
825 PlatformUsbDevice device
,
826 libusb_hotplug_event event
,
828 // It is safe to access the UsbServiceImpl* here because libusb takes a lock
829 // around registering, deregistering and calling hotplug callback functions
830 // and so guarantees that this function will not be called by the event
831 // processing thread after it has been deregistered.
832 UsbServiceImpl
* self
= reinterpret_cast<UsbServiceImpl
*>(user_data
);
834 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
:
835 libusb_ref_device(device
); // Released in OnPlatformDeviceAdded.
836 if (self
->task_runner_
->BelongsToCurrentThread()) {
837 self
->OnPlatformDeviceAdded(device
);
839 self
->task_runner_
->PostTask(
840 FROM_HERE
, base::Bind(&UsbServiceImpl::OnPlatformDeviceAdded
,
841 base::Unretained(self
), device
));
844 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT
:
845 libusb_ref_device(device
); // Released in OnPlatformDeviceRemoved.
846 if (self
->task_runner_
->BelongsToCurrentThread()) {
847 self
->OnPlatformDeviceRemoved(device
);
849 self
->task_runner_
->PostTask(
850 FROM_HERE
, base::Bind(&UsbServiceImpl::OnPlatformDeviceRemoved
,
851 base::Unretained(self
), device
));
861 void UsbServiceImpl::OnPlatformDeviceAdded(PlatformUsbDevice platform_device
) {
862 DCHECK(CalledOnValidThread());
863 DCHECK(!ContainsKey(platform_devices_
, platform_device
));
864 EnumerateDevice(platform_device
, base::Bind(&base::DoNothing
));
865 libusb_unref_device(platform_device
);
868 void UsbServiceImpl::OnPlatformDeviceRemoved(
869 PlatformUsbDevice platform_device
) {
870 DCHECK(CalledOnValidThread());
871 PlatformDeviceMap::iterator it
= platform_devices_
.find(platform_device
);
872 if (it
!= platform_devices_
.end()) {
873 RemoveDevice(it
->second
);
875 DCHECK(ContainsKey(devices_being_enumerated_
, platform_device
));
876 devices_being_enumerated_
.erase(platform_device
);
878 libusb_unref_device(platform_device
);
881 } // namespace device