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/bind.h"
11 #include "base/location.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "components/device_event_log/device_event_log.h"
19 #include "device/usb/usb_error.h"
20 #include "third_party/libusb/src/libusb/libusb.h"
26 #include "base/strings/string_util.h"
30 #include "device/udev_linux/scoped_udev.h"
39 void ReadDeviceStrings(PlatformUsbDevice platform_device
,
40 libusb_device_descriptor
* descriptor
,
41 base::string16
* manufacturer_string
,
42 base::string16
* product_string
,
43 base::string16
* serial_number
,
44 std::string
* device_node
) {
45 ScopedUdevPtr
udev(udev_new());
46 ScopedUdevEnumeratePtr
enumerate(udev_enumerate_new(udev
.get()));
48 udev_enumerate_add_match_subsystem(enumerate
.get(), "usb");
49 if (udev_enumerate_scan_devices(enumerate
.get()) != 0) {
52 std::string bus_number
=
53 base::IntToString(libusb_get_bus_number(platform_device
));
54 std::string device_address
=
55 base::IntToString(libusb_get_device_address(platform_device
));
56 udev_list_entry
* devices
= udev_enumerate_get_list_entry(enumerate
.get());
57 for (udev_list_entry
* i
= devices
; i
!= NULL
;
58 i
= udev_list_entry_get_next(i
)) {
59 ScopedUdevDevicePtr
device(
60 udev_device_new_from_syspath(udev
.get(), udev_list_entry_get_name(i
)));
62 const char* value
= udev_device_get_sysattr_value(device
.get(), "busnum");
63 if (!value
|| bus_number
!= value
) {
66 value
= udev_device_get_sysattr_value(device
.get(), "devnum");
67 if (!value
|| device_address
!= value
) {
71 value
= udev_device_get_devnode(device
.get());
75 value
= udev_device_get_sysattr_value(device
.get(), "manufacturer");
77 *manufacturer_string
= base::UTF8ToUTF16(value
);
79 value
= udev_device_get_sysattr_value(device
.get(), "product");
81 *product_string
= base::UTF8ToUTF16(value
);
83 value
= udev_device_get_sysattr_value(device
.get(), "serial");
85 *serial_number
= base::UTF8ToUTF16(value
);
94 uint16
ReadDeviceLanguage(PlatformUsbDeviceHandle handle
) {
95 uint16 language_id
= 0x0409;
98 libusb_get_string_descriptor(handle
, 0, 0, &buffer
[0], sizeof(buffer
));
100 USB_LOG(EVENT
) << "Failed to get supported string languages: "
101 << ConvertPlatformUsbErrorToString(size
);
102 } else if (size
>= 4) {
103 // Just pick the first supported language.
104 language_id
= buffer
[2] | (buffer
[3] << 8);
106 USB_LOG(EVENT
) << "List of available string languages invalid.";
112 void ReadDeviceString(PlatformUsbDeviceHandle handle
,
115 base::string16
* string
) {
116 if (string_id
== 0) {
121 int size
= libusb_get_string_descriptor(handle
, string_id
, language_id
,
122 &buffer
[0], sizeof(buffer
));
124 USB_LOG(EVENT
) << "Failed to read string " << (int)string_id
125 << " from the device: "
126 << ConvertPlatformUsbErrorToString(size
);
127 } else if (size
> 2) {
128 *string
= base::string16(reinterpret_cast<base::char16
*>(&buffer
[2]),
131 USB_LOG(EVENT
) << "String descriptor " << string_id
<< " is invalid.";
135 void ReadDeviceStrings(PlatformUsbDevice platform_device
,
136 libusb_device_descriptor
* descriptor
,
137 base::string16
* manufacturer_string
,
138 base::string16
* product_string
,
139 base::string16
* serial_number
,
140 std::string
* device_node
) {
141 if (descriptor
->iManufacturer
== 0 && descriptor
->iProduct
== 0 &&
142 descriptor
->iSerialNumber
== 0) {
143 // Don't bother distrubing the device if it doesn't have any string
144 // descriptors we care about.
148 PlatformUsbDeviceHandle handle
;
149 int rv
= libusb_open(platform_device
, &handle
);
150 if (rv
!= LIBUSB_SUCCESS
) {
151 USB_LOG(EVENT
) << "Failed to open device to read string descriptors: "
152 << ConvertPlatformUsbErrorToString(rv
);
156 uint16 language_id
= ReadDeviceLanguage(handle
);
157 ReadDeviceString(handle
, descriptor
->iManufacturer
, language_id
,
158 manufacturer_string
);
159 ReadDeviceString(handle
, descriptor
->iProduct
, language_id
, product_string
);
160 ReadDeviceString(handle
, descriptor
->iSerialNumber
, language_id
,
162 libusb_close(handle
);
169 // Wrapper around a HDEVINFO that automatically destroys it.
170 class ScopedDeviceInfoList
{
172 explicit ScopedDeviceInfoList(HDEVINFO handle
) : handle_(handle
) {}
174 ~ScopedDeviceInfoList() {
176 SetupDiDestroyDeviceInfoList(handle_
);
180 bool valid() { return handle_
!= INVALID_HANDLE_VALUE
; }
182 HDEVINFO
get() { return handle_
; }
187 DISALLOW_COPY_AND_ASSIGN(ScopedDeviceInfoList
);
190 // Wrapper around an SP_DEVINFO_DATA that initializes it properly and
191 // automatically deletes it.
192 class ScopedDeviceInfo
{
195 memset(&dev_info_data_
, 0, sizeof(dev_info_data_
));
196 dev_info_data_
.cbSize
= sizeof(dev_info_data_
);
199 ~ScopedDeviceInfo() {
200 if (dev_info_set_
!= INVALID_HANDLE_VALUE
) {
201 SetupDiDeleteDeviceInfo(dev_info_set_
, &dev_info_data_
);
205 // Once the SP_DEVINFO_DATA has been populated it must be freed using the
206 // HDEVINFO it was created from.
207 void set_valid(HDEVINFO dev_info_set
) {
208 DCHECK(dev_info_set_
== INVALID_HANDLE_VALUE
);
209 DCHECK(dev_info_set
!= INVALID_HANDLE_VALUE
);
210 dev_info_set_
= dev_info_set
;
213 PSP_DEVINFO_DATA
get() { return &dev_info_data_
; }
216 HDEVINFO dev_info_set_
= INVALID_HANDLE_VALUE
;
217 SP_DEVINFO_DATA dev_info_data_
;
220 bool IsWinUsbInterface(const std::string
& device_path
) {
221 ScopedDeviceInfoList
dev_info_list(SetupDiCreateDeviceInfoList(NULL
, NULL
));
222 if (!dev_info_list
.valid()) {
223 USB_PLOG(ERROR
) << "Failed to create a device information set";
227 // This will add the device to |dev_info_list| so we can query driver info.
228 if (!SetupDiOpenDeviceInterfaceA(dev_info_list
.get(), device_path
.c_str(), 0,
230 USB_PLOG(ERROR
) << "Failed to get device interface data for "
235 ScopedDeviceInfo dev_info
;
236 if (!SetupDiEnumDeviceInfo(dev_info_list
.get(), 0, dev_info
.get())) {
237 USB_PLOG(ERROR
) << "Failed to get device info for " << device_path
;
240 dev_info
.set_valid(dev_info_list
.get());
244 if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list
.get(), dev_info
.get(),
245 SPDRP_SERVICE
, ®_data_type
,
246 &buffer
[0], sizeof buffer
, NULL
)) {
247 USB_PLOG(ERROR
) << "Failed to get device service property";
250 if (reg_data_type
!= REG_SZ
) {
251 USB_LOG(ERROR
) << "Unexpected data type for driver service: "
256 USB_LOG(DEBUG
) << "Driver for " << device_path
<< " is " << buffer
<< ".";
257 if (base::strncasecmp("WinUSB", (const char*)&buffer
[0], sizeof "WinUSB") ==
269 UsbService
* UsbServiceImpl::Create(
270 scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner
) {
271 PlatformUsbContext context
= NULL
;
272 const int rv
= libusb_init(&context
);
273 if (rv
!= LIBUSB_SUCCESS
) {
274 USB_LOG(ERROR
) << "Failed to initialize libusb: "
275 << ConvertPlatformUsbErrorToString(rv
);
282 return new UsbServiceImpl(context
, blocking_task_runner
);
285 UsbServiceImpl::UsbServiceImpl(
286 PlatformUsbContext context
,
287 scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner
)
288 : context_(new UsbContext(context
)),
289 task_runner_(base::ThreadTaskRunnerHandle::Get()),
290 blocking_task_runner_(blocking_task_runner
),
292 device_observer_(this),
294 weak_factory_(this) {
295 base::MessageLoop::current()->AddDestructionObserver(this);
297 int rv
= libusb_hotplug_register_callback(
299 static_cast<libusb_hotplug_event
>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
|
300 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT
),
301 LIBUSB_HOTPLUG_ENUMERATE
, LIBUSB_HOTPLUG_MATCH_ANY
,
302 LIBUSB_HOTPLUG_MATCH_ANY
, LIBUSB_HOTPLUG_MATCH_ANY
,
303 &UsbServiceImpl::HotplugCallback
, this, &hotplug_handle_
);
304 if (rv
== LIBUSB_SUCCESS
) {
305 hotplug_enabled_
= true;
307 // libusb will call the hotplug callback for each device currently
308 // enumerated. Once this is complete enumeration_ready_ can be set to true
309 // but we must first wait for any tasks posted to blocking_task_runner_ to
311 blocking_task_runner_
->PostTaskAndReply(
312 FROM_HERE
, base::Bind(&base::DoNothing
),
313 base::Bind(&UsbServiceImpl::RefreshDevicesComplete
,
314 weak_factory_
.GetWeakPtr(), nullptr, 0));
318 DeviceMonitorWin
* device_monitor
= DeviceMonitorWin::GetForAllInterfaces();
319 if (device_monitor
) {
320 device_observer_
.Add(device_monitor
);
326 UsbServiceImpl::~UsbServiceImpl() {
327 base::MessageLoop::current()->RemoveDestructionObserver(this);
329 if (hotplug_enabled_
) {
330 libusb_hotplug_deregister_callback(context_
->context(), hotplug_handle_
);
332 for (const auto& map_entry
: devices_
) {
333 map_entry
.second
->OnDisconnect();
337 scoped_refptr
<UsbDevice
> UsbServiceImpl::GetDeviceById(uint32 unique_id
) {
338 DCHECK(CalledOnValidThread());
339 DeviceMap::iterator it
= devices_
.find(unique_id
);
340 if (it
!= devices_
.end()) {
346 void UsbServiceImpl::GetDevices(const GetDevicesCallback
& callback
) {
347 DCHECK(CalledOnValidThread());
349 if (!enumeration_ready_
) {
350 // On startup wait for the first enumeration,
351 pending_enumerations_
.push_back(callback
);
352 } else if (hotplug_enabled_
) {
353 // The device list is updated live when hotplug events are supported.
354 std::vector
<scoped_refptr
<UsbDevice
>> devices
;
355 for (const auto& map_entry
: devices_
) {
356 devices
.push_back(map_entry
.second
);
358 callback
.Run(devices
);
360 // Only post one re-enumeration task at a time.
361 if (pending_enumerations_
.empty()) {
364 pending_enumerations_
.push_back(callback
);
370 void UsbServiceImpl::OnDeviceAdded(const GUID
& class_guid
,
371 const std::string
& device_path
) {
372 // Only the root node of a composite USB device has the class GUID
373 // GUID_DEVINTERFACE_USB_DEVICE but we want to wait until WinUSB is loaded.
374 // This first pass filter will catch anything that's sitting on the USB bus
375 // (including devices on 3rd party USB controllers) to avoid the more
376 // expensive driver check that needs to be done on the FILE thread.
377 if (device_path
.find("usb") != std::string::npos
) {
378 RefreshDevices(device_path
);
382 void UsbServiceImpl::OnDeviceRemoved(const GUID
& class_guid
,
383 const std::string
& device_path
) {
384 // The root USB device node is removed last
385 if (class_guid
== GUID_DEVINTERFACE_USB_DEVICE
) {
392 void UsbServiceImpl::WillDestroyCurrentMessageLoop() {
393 DCHECK(CalledOnValidThread());
397 void UsbServiceImpl::RefreshDevices(const std::string
& new_device_path
) {
398 DCHECK(CalledOnValidThread());
400 std::set
<PlatformUsbDevice
> current_devices
;
401 for (const auto& map_entry
: platform_devices_
) {
402 current_devices
.insert(map_entry
.first
);
404 blocking_task_runner_
->PostTask(
405 FROM_HERE
, base::Bind(&UsbServiceImpl::RefreshDevicesOnBlockingThread
,
406 weak_factory_
.GetWeakPtr(), new_device_path
,
407 task_runner_
, context_
, current_devices
));
411 void UsbServiceImpl::RefreshDevicesOnBlockingThread(
412 base::WeakPtr
<UsbServiceImpl
> usb_service
,
413 const std::string
& new_device_path
,
414 scoped_refptr
<base::SequencedTaskRunner
> task_runner
,
415 scoped_refptr
<UsbContext
> usb_context
,
416 const std::set
<PlatformUsbDevice
>& previous_devices
) {
417 if (!new_device_path
.empty()) {
419 if (!IsWinUsbInterface(new_device_path
)) {
420 // Wait to call libusb_get_device_list until libusb will be able to find
421 // a WinUSB interface for the device.
424 #endif // defined(OS_WIN)
427 libusb_device
** platform_devices
= NULL
;
428 const ssize_t device_count
=
429 libusb_get_device_list(usb_context
->context(), &platform_devices
);
430 if (device_count
< 0) {
431 USB_LOG(ERROR
) << "Failed to get device list: "
432 << ConvertPlatformUsbErrorToString(device_count
);
433 task_runner
->PostTask(FROM_HERE
,
434 base::Bind(&UsbServiceImpl::RefreshDevicesComplete
,
435 usb_service
, nullptr, 0));
440 for (ssize_t i
= 0; i
< device_count
; ++i
) {
441 PlatformUsbDevice platform_device
= platform_devices
[i
];
442 if (previous_devices
.find(platform_device
) == previous_devices
.end()) {
443 libusb_ref_device(platform_device
);
444 AddDeviceOnBlockingThread(usb_service
, task_runner
, platform_device
);
448 // |platform_devices| will be freed in this callback.
449 task_runner
->PostTask(
450 FROM_HERE
, base::Bind(&UsbServiceImpl::RefreshDevicesComplete
,
451 usb_service
, platform_devices
, device_count
));
455 void UsbServiceImpl::AddDeviceOnBlockingThread(
456 base::WeakPtr
<UsbServiceImpl
> usb_service
,
457 scoped_refptr
<base::SequencedTaskRunner
> task_runner
,
458 PlatformUsbDevice platform_device
) {
459 libusb_device_descriptor descriptor
;
460 int rv
= libusb_get_device_descriptor(platform_device
, &descriptor
);
461 if (rv
== LIBUSB_SUCCESS
) {
462 base::string16 manufacturer_string
;
463 base::string16 product_string
;
464 base::string16 serial_number
;
465 std::string device_node
;
466 ReadDeviceStrings(platform_device
, &descriptor
, &manufacturer_string
,
467 &product_string
, &serial_number
, &device_node
);
469 task_runner
->PostTask(
470 FROM_HERE
, base::Bind(&UsbServiceImpl::AddDevice
, usb_service
,
471 platform_device
, descriptor
.idVendor
,
472 descriptor
.idProduct
, manufacturer_string
,
473 product_string
, serial_number
, device_node
));
475 USB_LOG(EVENT
) << "Failed to get device descriptor: "
476 << ConvertPlatformUsbErrorToString(rv
);
477 libusb_unref_device(platform_device
);
481 void UsbServiceImpl::RefreshDevicesComplete(libusb_device
** platform_devices
,
482 ssize_t device_count
) {
483 if (platform_devices
) {
484 // Mark devices seen in this enumeration.
485 for (ssize_t i
= 0; i
< device_count
; ++i
) {
486 const PlatformDeviceMap::iterator it
=
487 platform_devices_
.find(platform_devices
[i
]);
488 if (it
!= platform_devices_
.end()) {
489 it
->second
->set_visited(true);
493 // Remove devices not seen in this enumeration.
494 for (PlatformDeviceMap::iterator it
= platform_devices_
.begin();
495 it
!= platform_devices_
.end();
496 /* incremented internally */) {
497 PlatformDeviceMap::iterator current
= it
++;
498 const scoped_refptr
<UsbDeviceImpl
>& device
= current
->second
;
499 if (device
->was_visited()) {
500 device
->set_visited(false);
502 RemoveDevice(device
);
506 libusb_free_device_list(platform_devices
, true);
509 enumeration_ready_
= true;
511 if (!pending_enumerations_
.empty()) {
512 std::vector
<scoped_refptr
<UsbDevice
>> devices
;
513 for (const auto& map_entry
: devices_
) {
514 devices
.push_back(map_entry
.second
);
517 std::vector
<GetDevicesCallback
> pending_enumerations
;
518 pending_enumerations
.swap(pending_enumerations_
);
519 for (const GetDevicesCallback
& callback
: pending_enumerations
) {
520 callback
.Run(devices
);
525 void UsbServiceImpl::AddDevice(PlatformUsbDevice platform_device
,
528 base::string16 manufacturer_string
,
529 base::string16 product_string
,
530 base::string16 serial_number
,
531 std::string device_node
) {
534 unique_id
= ++next_unique_id_
;
535 } while (devices_
.find(unique_id
) != devices_
.end());
537 scoped_refptr
<UsbDeviceImpl
> device(
538 new UsbDeviceImpl(context_
, platform_device
, vendor_id
, product_id
,
539 unique_id
, manufacturer_string
, product_string
,
540 serial_number
, device_node
, blocking_task_runner_
));
542 platform_devices_
[platform_device
] = device
;
543 devices_
[unique_id
] = device
;
545 USB_LOG(USER
) << "USB device added: vendor=" << device
->vendor_id() << " \""
546 << device
->manufacturer_string()
547 << "\", product=" << device
->product_id() << " \""
548 << device
->product_string() << "\", serial=\""
549 << device
->serial_number()
550 << "\", uniqueId=" << device
->unique_id();
552 if (enumeration_ready_
) {
553 NotifyDeviceAdded(device
);
556 libusb_unref_device(platform_device
);
559 void UsbServiceImpl::RemoveDevice(scoped_refptr
<UsbDeviceImpl
> device
) {
560 platform_devices_
.erase(device
->platform_device());
561 devices_
.erase(device
->unique_id());
563 USB_LOG(USER
) << "USB device removed: uniqueId=" << device
->unique_id();
565 NotifyDeviceRemoved(device
);
566 device
->OnDisconnect();
570 int LIBUSB_CALL
UsbServiceImpl::HotplugCallback(libusb_context
* context
,
571 PlatformUsbDevice device
,
572 libusb_hotplug_event event
,
574 // It is safe to access the UsbServiceImpl* here because libusb takes a lock
575 // around registering, deregistering and calling hotplug callback functions
576 // and so guarantees that this function will not be called by the event
577 // processing thread after it has been deregistered.
578 UsbServiceImpl
* self
= reinterpret_cast<UsbServiceImpl
*>(user_data
);
580 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
:
581 libusb_ref_device(device
); // Released in OnPlatformDeviceAdded.
582 if (self
->task_runner_
->BelongsToCurrentThread()) {
583 self
->OnPlatformDeviceAdded(device
);
585 self
->task_runner_
->PostTask(
586 FROM_HERE
, base::Bind(&UsbServiceImpl::OnPlatformDeviceAdded
,
587 base::Unretained(self
), device
));
590 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT
:
591 libusb_ref_device(device
); // Released in OnPlatformDeviceRemoved.
592 if (self
->task_runner_
->BelongsToCurrentThread()) {
593 self
->OnPlatformDeviceRemoved(device
);
595 self
->task_runner_
->PostTask(
596 FROM_HERE
, base::Bind(&UsbServiceImpl::OnPlatformDeviceRemoved
,
597 base::Unretained(self
), device
));
607 void UsbServiceImpl::OnPlatformDeviceAdded(PlatformUsbDevice platform_device
) {
608 DCHECK(CalledOnValidThread());
609 DCHECK(!ContainsKey(platform_devices_
, platform_device
));
610 blocking_task_runner_
->PostTask(
612 base::Bind(&UsbServiceImpl::AddDeviceOnBlockingThread
,
613 weak_factory_
.GetWeakPtr(), task_runner_
, platform_device
));
615 // libusb_unref_device(platform_device) is called by the task above.
618 void UsbServiceImpl::OnPlatformDeviceRemoved(
619 PlatformUsbDevice platform_device
) {
620 DCHECK(CalledOnValidThread());
621 PlatformDeviceMap::iterator it
= platform_devices_
.find(platform_device
);
622 if (it
!= platform_devices_
.end()) {
623 scoped_refptr
<UsbDeviceImpl
> device
= it
->second
;
624 // Serialize with calls to AddDeviceOnBlockingThread.
625 blocking_task_runner_
->PostTaskAndReply(
626 FROM_HERE
, base::Bind(&base::DoNothing
),
627 base::Bind(&UsbServiceImpl::RemoveDevice
, weak_factory_
.GetWeakPtr(),
633 libusb_unref_device(platform_device
);
636 } // namespace device