Add ICU message format support
[chromium-blink-merge.git] / device / usb / usb_service_impl.cc
blob0a3e3f232820a83478ec9fb8bb65967412b8c130
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 // static
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);
543 return nullptr;
545 if (!context) {
546 return nullptr;
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),
558 #if defined(OS_WIN)
559 device_observer_(this),
560 #endif
561 weak_factory_(this) {
562 base::MessageLoop::current()->AddDestructionObserver(this);
564 int rv = libusb_hotplug_register_callback(
565 context_->context(),
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;
575 RefreshDevices();
576 #if defined(OS_WIN)
577 DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces();
578 if (device_monitor) {
579 device_observer_.Add(device_monitor);
581 #endif // OS_WIN
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()) {
599 return it->second;
601 return NULL;
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);
614 } else {
615 pending_enumeration_callbacks_.push_back(callback);
616 RefreshDevices();
620 #if defined(OS_WIN)
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);
631 RefreshDevices();
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) {
639 RefreshDevices();
643 #endif // OS_WIN
645 void UsbServiceImpl::WillDestroyCurrentMessageLoop() {
646 DCHECK(CalledOnValidThread());
647 delete this;
650 void UsbServiceImpl::RefreshDevices() {
651 DCHECK(CalledOnValidThread());
653 if (enumeration_in_progress_) {
654 return;
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(
667 FROM_HERE,
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();
678 return;
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);
695 } else {
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);
709 } else {
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()) {
743 RefreshDevices();
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(
765 FROM_HERE,
766 base::Bind(&EnumerateUdevDevice, device, read_bos_descriptors,
767 task_runner_, add_device, refresh_complete));
768 #else
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.
772 add_device.Run();
773 } else {
774 device->Open(base::Bind(&OnDeviceOpenedReadDescriptors,
775 descriptor.iManufacturer, descriptor.iProduct,
776 descriptor.iSerialNumber, read_bos_descriptors,
777 add_device, refresh_complete));
779 #endif
780 } else {
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();
793 return;
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();
823 // static
824 int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context,
825 PlatformUsbDevice device,
826 libusb_hotplug_event event,
827 void* user_data) {
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);
833 switch (event) {
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);
838 } else {
839 self->task_runner_->PostTask(
840 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceAdded,
841 base::Unretained(self), device));
843 break;
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);
848 } else {
849 self->task_runner_->PostTask(
850 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceRemoved,
851 base::Unretained(self), device));
853 break;
854 default:
855 NOTREACHED();
858 return 0;
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);
874 } else {
875 DCHECK(ContainsKey(devices_being_enumerated_, platform_device));
876 devices_being_enumerated_.erase(platform_device);
878 libusb_unref_device(platform_device);
881 } // namespace device