Add configs that depend on linux builder and linux builder (dbg).
[chromium-blink-merge.git] / device / usb / usb_service_impl.cc
blob414ce1c0cb0e24b68252304ba43c9d284314ec43
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"
7 #include <algorithm>
8 #include <list>
9 #include <set>
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"
26 #if defined(OS_WIN)
27 #include <setupapi.h>
28 #include <usbiodef.h>
30 #include "base/strings/string_util.h"
31 #endif // OS_WIN
33 #if defined(USE_UDEV)
34 #include "device/udev_linux/scoped_udev.h"
35 #endif // USE_UDEV
37 using net::IOBufferWithSize;
39 namespace device {
41 namespace {
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;
49 // WebUSB requests:
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
56 #if defined(OS_WIN)
58 // Wrapper around a HDEVINFO that automatically destroys it.
59 class ScopedDeviceInfoList {
60 public:
61 explicit ScopedDeviceInfoList(HDEVINFO handle) : handle_(handle) {}
63 ~ScopedDeviceInfoList() {
64 if (valid()) {
65 SetupDiDestroyDeviceInfoList(handle_);
69 bool valid() { return handle_ != INVALID_HANDLE_VALUE; }
71 HDEVINFO get() { return handle_; }
73 private:
74 HDEVINFO 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 {
82 public:
83 ScopedDeviceInfo() {
84 memset(&dev_info_data_, 0, sizeof(dev_info_data_));
85 dev_info_data_.cbSize = sizeof(dev_info_data_);
88 ~ScopedDeviceInfo() {
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_; }
104 private:
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";
113 return false;
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,
118 NULL)) {
119 USB_PLOG(ERROR) << "Failed to get device interface data for "
120 << device_path;
121 return false;
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;
127 return false;
129 dev_info.set_valid(dev_info_list.get());
131 DWORD reg_data_type;
132 BYTE buffer[256];
133 if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list.get(), dev_info.get(),
134 SPDRP_SERVICE, &reg_data_type,
135 &buffer[0], sizeof buffer, NULL)) {
136 USB_PLOG(ERROR) << "Failed to get device service property";
137 return false;
139 if (reg_data_type != REG_SZ) {
140 USB_LOG(ERROR) << "Unexpected data type for driver service: "
141 << reg_data_type;
142 return false;
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))
148 return true;
149 return false;
152 #endif // OS_WIN
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) {
159 #if defined(OS_WIN)
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));
165 return;
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));
177 return;
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,
188 size_t length) {
189 if (status != USB_TRANSFER_COMPLETED || length < 2) {
190 callback.Run(base::string16());
191 } else {
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,
205 uint8 index,
206 uint16 language_id,
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,
220 size_t length) {
221 if (status != USB_TRANSFER_COMPLETED || length < 2) {
222 callback.Run();
223 return;
226 uint8_t string_length = buffer->data()[0];
227 if (string_length < 2 || string_length > length ||
228 buffer->data()[1] != kUrlDescriptorType) {
229 callback.Run();
230 return;
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);
238 callback.Run();
241 void ReadWebUsbLandingPage(scoped_refptr<UsbDeviceHandle> device_handle,
242 const base::Closure& callback,
243 uint8 vendor_code) {
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(),
250 callback));
253 void OnReadWebUsbAllowedOrigins(scoped_refptr<UsbDevice> device,
254 const base::Closure& callback,
255 UsbTransferStatus status,
256 scoped_refptr<net::IOBuffer> buffer,
257 size_t length) {
258 if (status != USB_TRANSFER_COMPLETED) {
259 USB_LOG(EVENT) << "Failed to read WebUSB allowed origins.";
260 callback.Run();
261 return;
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());
270 callback.Run();
273 void OnReadWebUsbAllowedOriginsHeader(
274 scoped_refptr<UsbDeviceHandle> device_handle,
275 const base::Closure& callback,
276 uint8 vendor_code,
277 UsbTransferStatus status,
278 scoped_refptr<net::IOBuffer> buffer,
279 size_t length) {
280 if (status != USB_TRANSFER_COMPLETED || length != 4) {
281 USB_LOG(EVENT) << "Failed to read WebUSB allowed origins header.";
282 callback.Run();
283 return;
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(),
293 callback));
296 void ReadWebUsbAllowedOrigins(scoped_refptr<UsbDeviceHandle> device_handle,
297 const base::Closure& callback,
298 uint8 vendor_code) {
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,
305 vendor_code));
308 void OnReadBosDescriptor(scoped_refptr<UsbDeviceHandle> device_handle,
309 const base::Closure& callback,
310 UsbTransferStatus status,
311 scoped_refptr<net::IOBuffer> buffer,
312 size_t length) {
313 if (status != USB_TRANSFER_COMPLETED) {
314 USB_LOG(EVENT) << "Failed to read BOS descriptor.";
315 callback.Run();
316 return;
319 WebUsbPlatformCapabilityDescriptor descriptor;
320 if (!descriptor.ParseFromBosDescriptor(
321 std::vector<uint8>(buffer->data(), buffer->data() + length))) {
322 callback.Run();
323 return;
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,
335 size_t length) {
336 if (status != USB_TRANSFER_COMPLETED || length != 5) {
337 USB_LOG(EVENT) << "Failed to read BOS descriptor header.";
338 callback.Run();
339 return;
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();
364 continuation.Run();
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);
374 continuation.Run();
377 // This function runs |barrier| once for every string it tries to read.
378 void OnReadLanguageIds(scoped_refptr<UsbDeviceHandle> device_handle,
379 uint8 manufacturer,
380 uint8 product,
381 uint8 serial_number,
382 const base::Closure& barrier,
383 const base::string16& languages) {
384 // Default to English unless the device provides a language and then just pick
385 // the first one.
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),
399 barrier));
402 if (product != 0) {
403 ReadStringDescriptor(
404 device_handle, product, language_id,
405 base::Bind(&SaveStringAndRunContinuation,
406 base::Bind(&UsbDeviceImpl::set_product_string, device),
407 barrier));
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),
415 barrier));
419 void OnDeviceOpenedReadDescriptors(
420 uint8 manufacturer,
421 uint8 product,
422 uint8 serial_number,
423 bool read_bos_descriptors,
424 const base::Closure& success_closure,
425 const base::Closure& failure_closure,
426 scoped_refptr<UsbDeviceHandle> device_handle) {
427 if (device_handle) {
428 int count = 0;
429 if (manufacturer != 0)
430 count++;
431 if (product != 0)
432 count++;
433 if (serial_number != 0)
434 count++;
435 if (read_bos_descriptors)
436 count++;
437 DCHECK_GT(count, 0);
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(
445 device_handle, 0, 0,
446 base::Bind(&OnReadLanguageIds, device_handle, manufacturer, product,
447 serial_number, barrier));
450 if (read_bos_descriptors) {
451 ReadBosDescriptor(device_handle, barrier);
453 } else {
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);
471 return;
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)));
484 if (udev_device) {
485 const char* value =
486 udev_device_get_sysattr_value(udev_device.get(), "busnum");
487 if (!value || bus_number != value) {
488 continue;
490 value = udev_device_get_sysattr_value(udev_device.get(), "devnum");
491 if (!value || device_address != value) {
492 continue;
495 value = udev_device_get_sysattr_value(udev_device.get(), "manufacturer");
496 if (value) {
497 device->set_manufacturer_string(base::UTF8ToUTF16(value));
499 value = udev_device_get_sysattr_value(udev_device.get(), "product");
500 if (value) {
501 device->set_product_string(base::UTF8ToUTF16(value));
503 value = udev_device_get_sysattr_value(udev_device.get(), "serial");
504 if (value) {
505 device->set_serial_number(base::UTF8ToUTF16(value));
508 value = udev_device_get_devnode(udev_device.get());
509 if (value) {
510 device->set_device_path(value);
512 if (read_bos_descriptors) {
513 task_runner->PostTask(
514 FROM_HERE,
515 base::Bind(&UsbDevice::Open, device,
516 base::Bind(&OnDeviceOpenedReadDescriptors, 0, 0, 0,
517 true, success_closure, failure_closure)));
518 } else {
519 task_runner->PostTask(FROM_HERE, success_closure);
521 return;
524 break;
528 task_runner->PostTask(FROM_HERE, failure_closure);
531 #endif // USE_UDEV
533 } // namespace
535 UsbServiceImpl::UsbServiceImpl(
536 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
537 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
538 blocking_task_runner_(blocking_task_runner),
539 #if defined(OS_WIN)
540 device_observer_(this),
541 #endif
542 weak_factory_(this) {
543 base::MessageLoop::current()->AddDestructionObserver(this);
545 PlatformUsbContext platform_context = nullptr;
546 int rv = libusb_init(&platform_context);
547 if (rv != LIBUSB_SUCCESS || !platform_context) {
548 USB_LOG(DEBUG) << "Failed to initialize libusb: "
549 << ConvertPlatformUsbErrorToString(rv);
550 return;
552 context_ = new UsbContext(platform_context);
554 rv = libusb_hotplug_register_callback(
555 context_->context(),
556 static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
557 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
558 static_cast<libusb_hotplug_flag>(0), LIBUSB_HOTPLUG_MATCH_ANY,
559 LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
560 &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_);
561 if (rv == LIBUSB_SUCCESS) {
562 hotplug_enabled_ = true;
565 RefreshDevices();
566 #if defined(OS_WIN)
567 DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces();
568 if (device_monitor) {
569 device_observer_.Add(device_monitor);
571 #endif // OS_WIN
574 UsbServiceImpl::~UsbServiceImpl() {
575 base::MessageLoop::current()->RemoveDestructionObserver(this);
577 if (hotplug_enabled_) {
578 libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_);
580 for (const auto& map_entry : devices_) {
581 map_entry.second->OnDisconnect();
585 scoped_refptr<UsbDevice> UsbServiceImpl::GetDevice(const std::string& guid) {
586 DCHECK(CalledOnValidThread());
587 DeviceMap::iterator it = devices_.find(guid);
588 if (it != devices_.end()) {
589 return it->second;
591 return NULL;
594 void UsbServiceImpl::GetDevices(const GetDevicesCallback& callback) {
595 DCHECK(CalledOnValidThread());
597 if (!context_) {
598 task_runner_->PostTask(
599 FROM_HERE,
600 base::Bind(callback, std::vector<scoped_refptr<UsbDevice>>()));
601 return;
604 if (hotplug_enabled_ && !enumeration_in_progress_) {
605 // The device list is updated live when hotplug events are supported.
606 std::vector<scoped_refptr<UsbDevice>> devices;
607 for (const auto& map_entry : devices_) {
608 devices.push_back(map_entry.second);
610 task_runner_->PostTask(FROM_HERE, base::Bind(callback, devices));
611 } else {
612 pending_enumeration_callbacks_.push_back(callback);
613 RefreshDevices();
617 #if defined(OS_WIN)
619 void UsbServiceImpl::OnDeviceAdded(const GUID& class_guid,
620 const std::string& device_path) {
621 // Only the root node of a composite USB device has the class GUID
622 // GUID_DEVINTERFACE_USB_DEVICE but we want to wait until WinUSB is loaded.
623 // This first pass filter will catch anything that's sitting on the USB bus
624 // (including devices on 3rd party USB controllers) to avoid the more
625 // expensive driver check that needs to be done on the FILE thread.
626 if (device_path.find("usb") != std::string::npos) {
627 pending_path_enumerations_.push(device_path);
628 RefreshDevices();
632 void UsbServiceImpl::OnDeviceRemoved(const GUID& class_guid,
633 const std::string& device_path) {
634 // The root USB device node is removed last.
635 if (class_guid == GUID_DEVINTERFACE_USB_DEVICE) {
636 RefreshDevices();
640 #endif // OS_WIN
642 void UsbServiceImpl::WillDestroyCurrentMessageLoop() {
643 DCHECK(CalledOnValidThread());
644 delete this;
647 void UsbServiceImpl::RefreshDevices() {
648 DCHECK(CalledOnValidThread());
649 DCHECK(context_);
651 if (enumeration_in_progress_) {
652 return;
655 enumeration_in_progress_ = true;
656 DCHECK(devices_being_enumerated_.empty());
658 std::string device_path;
659 if (!pending_path_enumerations_.empty()) {
660 device_path = pending_path_enumerations_.front();
661 pending_path_enumerations_.pop();
664 blocking_task_runner_->PostTask(
665 FROM_HERE,
666 base::Bind(&GetDeviceListOnBlockingThread, device_path, context_,
667 task_runner_, base::Bind(&UsbServiceImpl::OnDeviceList,
668 weak_factory_.GetWeakPtr())));
671 void UsbServiceImpl::OnDeviceList(libusb_device** platform_devices,
672 size_t device_count) {
673 DCHECK(CalledOnValidThread());
674 if (!platform_devices) {
675 RefreshDevicesComplete();
676 return;
679 base::Closure refresh_complete =
680 base::BarrierClosure(static_cast<int>(device_count),
681 base::Bind(&UsbServiceImpl::RefreshDevicesComplete,
682 weak_factory_.GetWeakPtr()));
683 std::list<PlatformUsbDevice> new_devices;
685 // Look for new and existing devices.
686 for (size_t i = 0; i < device_count; ++i) {
687 PlatformUsbDevice platform_device = platform_devices[i];
688 auto it = platform_devices_.find(platform_device);
690 if (it == platform_devices_.end()) {
691 libusb_ref_device(platform_device);
692 new_devices.push_back(platform_device);
693 } else {
694 it->second->set_visited(true);
695 refresh_complete.Run();
699 // Remove devices not seen in this enumeration.
700 for (PlatformDeviceMap::iterator it = platform_devices_.begin();
701 it != platform_devices_.end();
702 /* incremented internally */) {
703 PlatformDeviceMap::iterator current = it++;
704 const scoped_refptr<UsbDeviceImpl>& device = current->second;
705 if (device->was_visited()) {
706 device->set_visited(false);
707 } else {
708 RemoveDevice(device);
712 for (PlatformUsbDevice platform_device : new_devices) {
713 EnumerateDevice(platform_device, refresh_complete);
716 libusb_free_device_list(platform_devices, true);
719 void UsbServiceImpl::RefreshDevicesComplete() {
720 DCHECK(CalledOnValidThread());
721 DCHECK(enumeration_in_progress_);
723 enumeration_ready_ = true;
724 enumeration_in_progress_ = false;
725 devices_being_enumerated_.clear();
727 if (!pending_enumeration_callbacks_.empty()) {
728 std::vector<scoped_refptr<UsbDevice>> devices;
729 for (const auto& map_entry : devices_) {
730 devices.push_back(map_entry.second);
733 std::vector<GetDevicesCallback> callbacks;
734 callbacks.swap(pending_enumeration_callbacks_);
735 for (const GetDevicesCallback& callback : callbacks) {
736 callback.Run(devices);
740 if (!pending_path_enumerations_.empty()) {
741 RefreshDevices();
745 void UsbServiceImpl::EnumerateDevice(PlatformUsbDevice platform_device,
746 const base::Closure& refresh_complete) {
747 DCHECK(context_);
748 devices_being_enumerated_.insert(platform_device);
750 libusb_device_descriptor descriptor;
751 int rv = libusb_get_device_descriptor(platform_device, &descriptor);
752 if (rv == LIBUSB_SUCCESS) {
753 scoped_refptr<UsbDeviceImpl> device(
754 new UsbDeviceImpl(context_, platform_device, descriptor.idVendor,
755 descriptor.idProduct, blocking_task_runner_));
757 base::Closure add_device =
758 base::Bind(&UsbServiceImpl::AddDevice, weak_factory_.GetWeakPtr(),
759 refresh_complete, device);
760 bool read_bos_descriptors = descriptor.bcdUSB >= kUsbVersion2_1;
762 #if defined(USE_UDEV)
763 blocking_task_runner_->PostTask(
764 FROM_HERE,
765 base::Bind(&EnumerateUdevDevice, device, read_bos_descriptors,
766 task_runner_, add_device, refresh_complete));
767 #else
768 if (descriptor.iManufacturer == 0 && descriptor.iProduct == 0 &&
769 descriptor.iSerialNumber == 0 && !read_bos_descriptors) {
770 // Don't bother disturbing the device if it has no descriptors to offer.
771 add_device.Run();
772 } else {
773 device->Open(base::Bind(&OnDeviceOpenedReadDescriptors,
774 descriptor.iManufacturer, descriptor.iProduct,
775 descriptor.iSerialNumber, read_bos_descriptors,
776 add_device, refresh_complete));
778 #endif
779 } else {
780 USB_LOG(EVENT) << "Failed to get device descriptor: "
781 << ConvertPlatformUsbErrorToString(rv);
782 refresh_complete.Run();
786 void UsbServiceImpl::AddDevice(const base::Closure& refresh_complete,
787 scoped_refptr<UsbDeviceImpl> device) {
788 auto it = devices_being_enumerated_.find(device->platform_device());
789 if (it == devices_being_enumerated_.end()) {
790 // Device was removed while being enumerated.
791 refresh_complete.Run();
792 return;
795 platform_devices_[device->platform_device()] = device;
796 DCHECK(!ContainsKey(devices_, device->guid()));
797 devices_[device->guid()] = device;
799 USB_LOG(USER) << "USB device added: vendor=" << device->vendor_id() << " \""
800 << device->manufacturer_string()
801 << "\", product=" << device->product_id() << " \""
802 << device->product_string() << "\", serial=\""
803 << device->serial_number() << "\", guid=" << device->guid();
805 if (enumeration_ready_) {
806 NotifyDeviceAdded(device);
809 refresh_complete.Run();
812 void UsbServiceImpl::RemoveDevice(scoped_refptr<UsbDeviceImpl> device) {
813 platform_devices_.erase(device->platform_device());
814 devices_.erase(device->guid());
816 USB_LOG(USER) << "USB device removed: guid=" << device->guid();
818 NotifyDeviceRemoved(device);
819 device->OnDisconnect();
822 // static
823 int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context,
824 PlatformUsbDevice device,
825 libusb_hotplug_event event,
826 void* user_data) {
827 // It is safe to access the UsbServiceImpl* here because libusb takes a lock
828 // around registering, deregistering and calling hotplug callback functions
829 // and so guarantees that this function will not be called by the event
830 // processing thread after it has been deregistered.
831 UsbServiceImpl* self = reinterpret_cast<UsbServiceImpl*>(user_data);
832 switch (event) {
833 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
834 libusb_ref_device(device); // Released in OnPlatformDeviceAdded.
835 if (self->task_runner_->BelongsToCurrentThread()) {
836 self->OnPlatformDeviceAdded(device);
837 } else {
838 self->task_runner_->PostTask(
839 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceAdded,
840 base::Unretained(self), device));
842 break;
843 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
844 libusb_ref_device(device); // Released in OnPlatformDeviceRemoved.
845 if (self->task_runner_->BelongsToCurrentThread()) {
846 self->OnPlatformDeviceRemoved(device);
847 } else {
848 self->task_runner_->PostTask(
849 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceRemoved,
850 base::Unretained(self), device));
852 break;
853 default:
854 NOTREACHED();
857 return 0;
860 void UsbServiceImpl::OnPlatformDeviceAdded(PlatformUsbDevice platform_device) {
861 DCHECK(CalledOnValidThread());
862 DCHECK(!ContainsKey(platform_devices_, platform_device));
863 EnumerateDevice(platform_device, base::Bind(&base::DoNothing));
864 libusb_unref_device(platform_device);
867 void UsbServiceImpl::OnPlatformDeviceRemoved(
868 PlatformUsbDevice platform_device) {
869 DCHECK(CalledOnValidThread());
870 PlatformDeviceMap::iterator it = platform_devices_.find(platform_device);
871 if (it != platform_devices_.end()) {
872 RemoveDevice(it->second);
873 } else {
874 DCHECK(ContainsKey(devices_being_enumerated_, platform_device));
875 devices_being_enumerated_.erase(platform_device);
877 libusb_unref_device(platform_device);
880 } // namespace device