Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3605)

Unified Diff: device/usb/usb_service_impl.cc

Issue 1253163005: Try to read BOS and WebUSB descriptors from USB devices. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « device/usb/usb_device_impl.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: device/usb/usb_service_impl.cc
diff --git a/device/usb/usb_service_impl.cc b/device/usb/usb_service_impl.cc
index 2261ad6930bdd1b246daf7e3abc957a9994131a9..0a3e3f232820a83478ec9fb8bb65967412b8c130 100644
--- a/device/usb/usb_service_impl.cc
+++ b/device/usb/usb_service_impl.cc
@@ -20,6 +20,7 @@
#include "components/device_event_log/device_event_log.h"
#include "device/usb/usb_device_handle.h"
#include "device/usb/usb_error.h"
+#include "device/usb/webusb_descriptors.h"
#include "third_party/libusb/src/libusb/libusb.h"
#if defined(OS_WIN)
@@ -33,10 +34,25 @@
#include "device/udev_linux/scoped_udev.h"
#endif // USE_UDEV
+using net::IOBufferWithSize;
+
namespace device {
namespace {
+// Standard USB requests and descriptor types:
+const uint16_t kUsbVersion2_1 = 0x0210;
+const uint8_t kGetDescriptorRequest = 0x06;
+const uint8_t kStringDescriptorType = 0x03;
+const uint8_t kBosDescriptorType = 0x0F;
+
+// WebUSB requests:
+const uint8_t kGetAllowedOriginsRequest = 0x01;
+const uint8_t kGetLandingPageRequest = 0x02;
+const uint8_t kUrlDescriptorType = 0x03;
+
+const int kControlTransferTimeout = 60000; // 1 minute
+
#if defined(OS_WIN)
// Wrapper around a HDEVINFO that automatically destroys it.
@@ -165,71 +181,6 @@ void GetDeviceListOnBlockingThread(
base::Bind(callback, platform_devices, device_count));
}
-#if defined(USE_UDEV)
-
-void EnumerateUdevDevice(scoped_refptr<UsbDeviceImpl> device,
- scoped_refptr<base::SequencedTaskRunner> task_runner,
- const base::Closure& success_closure,
- const base::Closure& failure_closure) {
- ScopedUdevPtr udev(udev_new());
- ScopedUdevEnumeratePtr udev_enumerate(udev_enumerate_new(udev.get()));
-
- udev_enumerate_add_match_subsystem(udev_enumerate.get(), "usb");
- if (udev_enumerate_scan_devices(udev_enumerate.get()) != 0) {
- task_runner->PostTask(FROM_HERE, failure_closure);
- return;
- }
-
- std::string bus_number =
- base::IntToString(libusb_get_bus_number(device->platform_device()));
- std::string device_address =
- base::IntToString(libusb_get_device_address(device->platform_device()));
- udev_list_entry* devices =
- udev_enumerate_get_list_entry(udev_enumerate.get());
- for (udev_list_entry* i = devices; i != NULL;
- i = udev_list_entry_get_next(i)) {
- ScopedUdevDevicePtr udev_device(
- udev_device_new_from_syspath(udev.get(), udev_list_entry_get_name(i)));
- if (udev_device) {
- const char* value =
- udev_device_get_sysattr_value(udev_device.get(), "busnum");
- if (!value || bus_number != value) {
- continue;
- }
- value = udev_device_get_sysattr_value(udev_device.get(), "devnum");
- if (!value || device_address != value) {
- continue;
- }
-
- value = udev_device_get_sysattr_value(udev_device.get(), "manufacturer");
- if (value) {
- device->set_manufacturer_string(base::UTF8ToUTF16(value));
- }
- value = udev_device_get_sysattr_value(udev_device.get(), "product");
- if (value) {
- device->set_product_string(base::UTF8ToUTF16(value));
- }
- value = udev_device_get_sysattr_value(udev_device.get(), "serial");
- if (value) {
- device->set_serial_number(base::UTF8ToUTF16(value));
- }
-
- value = udev_device_get_devnode(udev_device.get());
- if (value) {
- device->set_device_path(value);
- task_runner->PostTask(FROM_HERE, success_closure);
- return;
- }
-
- break;
- }
- }
-
- task_runner->PostTask(FROM_HERE, failure_closure);
-}
-
-#else
-
void OnReadStringDescriptor(
const base::Callback<void(const base::string16&)>& callback,
UsbTransferStatus status,
@@ -254,11 +205,157 @@ void ReadStringDescriptor(
uint8 index,
uint16 language_id,
const base::Callback<void(const base::string16&)>& callback) {
- scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(256);
+ scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(256);
+ device_handle->ControlTransfer(
+ USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE,
+ kGetDescriptorRequest, kStringDescriptorType << 8 | index, language_id,
+ buffer, buffer->size(), kControlTransferTimeout,
+ base::Bind(&OnReadStringDescriptor, callback));
+}
+
+void OnReadWebUsbLandingPage(scoped_refptr<UsbDevice> device,
+ const base::Closure& callback,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length) {
+ if (status != USB_TRANSFER_COMPLETED || length < 2) {
+ callback.Run();
+ return;
+ }
+
+ uint8_t string_length = buffer->data()[0];
+ if (string_length < 2 || string_length > length ||
+ buffer->data()[1] != kUrlDescriptorType) {
+ callback.Run();
+ return;
+ }
+
+ GURL url(std::string(&buffer->data()[2], string_length - 2));
+ if (url.is_valid()) {
+ UsbDeviceImpl* device_impl = static_cast<UsbDeviceImpl*>(device.get());
+ device_impl->set_webusb_landing_page(url);
+ }
+ callback.Run();
+}
+
+void ReadWebUsbLandingPage(scoped_refptr<UsbDeviceHandle> device_handle,
+ const base::Closure& callback,
+ uint8 vendor_code) {
+ scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(256);
+ device_handle->ControlTransfer(
+ USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
+ vendor_code, 0, kGetLandingPageRequest, buffer, buffer->size(),
+ kControlTransferTimeout,
+ base::Bind(&OnReadWebUsbLandingPage, device_handle->GetDevice(),
+ callback));
+}
+
+void OnReadWebUsbAllowedOrigins(scoped_refptr<UsbDevice> device,
+ const base::Closure& callback,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length) {
+ if (status != USB_TRANSFER_COMPLETED) {
+ USB_LOG(EVENT) << "Failed to read WebUSB allowed origins.";
+ callback.Run();
+ return;
+ }
+
+ scoped_ptr<WebUsbDescriptorSet> descriptors(new WebUsbDescriptorSet());
+ if (descriptors->Parse(
+ std::vector<uint8>(buffer->data(), buffer->data() + length))) {
+ UsbDeviceImpl* device_impl = static_cast<UsbDeviceImpl*>(device.get());
+ device_impl->set_webusb_allowed_origins(descriptors.Pass());
+ }
+ callback.Run();
+}
+
+void OnReadWebUsbAllowedOriginsHeader(
+ scoped_refptr<UsbDeviceHandle> device_handle,
+ const base::Closure& callback,
+ uint8 vendor_code,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length) {
+ if (status != USB_TRANSFER_COMPLETED || length != 4) {
+ USB_LOG(EVENT) << "Failed to read WebUSB allowed origins header.";
+ callback.Run();
+ return;
+ }
+
+ uint16 new_length = buffer->data()[2] | (buffer->data()[3] << 8);
+ scoped_refptr<IOBufferWithSize> new_buffer = new IOBufferWithSize(new_length);
+ device_handle->ControlTransfer(
+ USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
+ vendor_code, 0, kGetAllowedOriginsRequest, new_buffer, new_buffer->size(),
+ kControlTransferTimeout,
+ base::Bind(&OnReadWebUsbAllowedOrigins, device_handle->GetDevice(),
+ callback));
+}
+
+void ReadWebUsbAllowedOrigins(scoped_refptr<UsbDeviceHandle> device_handle,
+ const base::Closure& callback,
+ uint8 vendor_code) {
+ scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(4);
+ device_handle->ControlTransfer(
+ USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
+ vendor_code, 0, kGetAllowedOriginsRequest, buffer, buffer->size(),
+ kControlTransferTimeout,
+ base::Bind(&OnReadWebUsbAllowedOriginsHeader, device_handle, callback,
+ vendor_code));
+}
+
+void OnReadBosDescriptor(scoped_refptr<UsbDeviceHandle> device_handle,
+ const base::Closure& callback,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length) {
+ if (status != USB_TRANSFER_COMPLETED) {
+ USB_LOG(EVENT) << "Failed to read BOS descriptor.";
+ callback.Run();
+ return;
+ }
+
+ WebUsbPlatformCapabilityDescriptor descriptor;
+ if (!descriptor.ParseFromBosDescriptor(
+ std::vector<uint8>(buffer->data(), buffer->data() + length))) {
+ callback.Run();
+ return;
+ }
+
+ base::Closure barrier = base::BarrierClosure(2, callback);
+ ReadWebUsbLandingPage(device_handle, barrier, descriptor.vendor_code);
+ ReadWebUsbAllowedOrigins(device_handle, barrier, descriptor.vendor_code);
+}
+
+void OnReadBosDescriptorHeader(scoped_refptr<UsbDeviceHandle> device_handle,
+ const base::Closure& callback,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length) {
+ if (status != USB_TRANSFER_COMPLETED || length != 5) {
+ USB_LOG(EVENT) << "Failed to read BOS descriptor header.";
+ callback.Run();
+ return;
+ }
+
+ uint16 new_length = buffer->data()[2] | (buffer->data()[3] << 8);
+ scoped_refptr<IOBufferWithSize> new_buffer = new IOBufferWithSize(new_length);
+ device_handle->ControlTransfer(
+ USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE,
+ kGetDescriptorRequest, kBosDescriptorType << 8, 0, new_buffer,
+ new_buffer->size(), kControlTransferTimeout,
+ base::Bind(&OnReadBosDescriptor, device_handle, callback));
+}
+
+void ReadBosDescriptor(scoped_refptr<UsbDeviceHandle> device_handle,
+ const base::Closure& callback) {
+ scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(5);
device_handle->ControlTransfer(
USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE,
- 6 /* GET_DESCRIPTOR */, 3 /* STRING */ << 8 | index, language_id, buffer,
- 256, 60, base::Bind(&OnReadStringDescriptor, callback));
+ kGetDescriptorRequest, kBosDescriptorType << 8, 0, buffer, buffer->size(),
+ kControlTransferTimeout,
+ base::Bind(&OnReadBosDescriptorHeader, device_handle, callback));
}
void CloseHandleAndRunContinuation(scoped_refptr<UsbDeviceHandle> device_handle,
@@ -277,11 +374,12 @@ void SaveStringAndRunContinuation(
continuation.Run();
}
+// This function runs |barrier| once for every string it tries to read.
void OnReadLanguageIds(scoped_refptr<UsbDeviceHandle> device_handle,
uint8 manufacturer,
uint8 product,
uint8 serial_number,
- const base::Closure& success_closure,
+ const base::Closure& barrier,
const base::string16& languages) {
// Default to English unless the device provides a language and then just pick
// the first one.
@@ -292,57 +390,144 @@ void OnReadLanguageIds(scoped_refptr<UsbDeviceHandle> device_handle,
scoped_refptr<UsbDeviceImpl> device =
static_cast<UsbDeviceImpl*>(device_handle->GetDevice().get());
- base::Closure continuation =
- base::BarrierClosure(3, base::Bind(&CloseHandleAndRunContinuation,
- device_handle, success_closure));
- if (manufacturer == 0) {
- continuation.Run();
- } else {
+ if (manufacturer != 0) {
ReadStringDescriptor(
device_handle, manufacturer, language_id,
base::Bind(&SaveStringAndRunContinuation,
base::Bind(&UsbDeviceImpl::set_manufacturer_string, device),
- continuation));
+ barrier));
}
- if (product == 0) {
- continuation.Run();
- } else {
+ if (product != 0) {
ReadStringDescriptor(
device_handle, product, language_id,
base::Bind(&SaveStringAndRunContinuation,
base::Bind(&UsbDeviceImpl::set_product_string, device),
- continuation));
+ barrier));
}
- if (serial_number == 0) {
- continuation.Run();
- } else {
+ if (serial_number != 0) {
ReadStringDescriptor(
device_handle, serial_number, language_id,
base::Bind(&SaveStringAndRunContinuation,
base::Bind(&UsbDeviceImpl::set_serial_number, device),
- continuation));
+ barrier));
}
}
-void ReadDeviceLanguage(uint8 manufacturer,
- uint8 product,
- uint8 serial_number,
- const base::Closure& success_closure,
- const base::Closure& failure_closure,
- scoped_refptr<UsbDeviceHandle> device_handle) {
+void OnDeviceOpenedReadDescriptors(
+ uint8 manufacturer,
+ uint8 product,
+ uint8 serial_number,
+ bool read_bos_descriptors,
+ const base::Closure& success_closure,
+ const base::Closure& failure_closure,
+ scoped_refptr<UsbDeviceHandle> device_handle) {
if (device_handle) {
- ReadStringDescriptor(
- device_handle, 0, 0,
- base::Bind(&OnReadLanguageIds, device_handle, manufacturer, product,
- serial_number, success_closure));
+ int count = 0;
+ if (manufacturer != 0)
+ count++;
+ if (product != 0)
+ count++;
+ if (serial_number != 0)
+ count++;
+ if (read_bos_descriptors)
+ count++;
+ DCHECK_GT(count, 0);
+
+ base::Closure barrier =
+ base::BarrierClosure(count, base::Bind(&CloseHandleAndRunContinuation,
+ device_handle, success_closure));
+
+ if (manufacturer != 0 || product != 0 || serial_number != 0) {
+ ReadStringDescriptor(
+ device_handle, 0, 0,
+ base::Bind(&OnReadLanguageIds, device_handle, manufacturer, product,
+ serial_number, barrier));
+ }
+
+ if (read_bos_descriptors) {
+ ReadBosDescriptor(device_handle, barrier);
+ }
} else {
failure_closure.Run();
}
}
+#if defined(USE_UDEV)
+
+void EnumerateUdevDevice(scoped_refptr<UsbDeviceImpl> device,
+ bool read_bos_descriptors,
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ const base::Closure& success_closure,
+ const base::Closure& failure_closure) {
+ ScopedUdevPtr udev(udev_new());
+ ScopedUdevEnumeratePtr udev_enumerate(udev_enumerate_new(udev.get()));
+
+ udev_enumerate_add_match_subsystem(udev_enumerate.get(), "usb");
+ if (udev_enumerate_scan_devices(udev_enumerate.get()) != 0) {
+ task_runner->PostTask(FROM_HERE, failure_closure);
+ return;
+ }
+
+ std::string bus_number =
+ base::IntToString(libusb_get_bus_number(device->platform_device()));
+ std::string device_address =
+ base::IntToString(libusb_get_device_address(device->platform_device()));
+ udev_list_entry* devices =
+ udev_enumerate_get_list_entry(udev_enumerate.get());
+ for (udev_list_entry* i = devices; i != NULL;
+ i = udev_list_entry_get_next(i)) {
+ ScopedUdevDevicePtr udev_device(
+ udev_device_new_from_syspath(udev.get(), udev_list_entry_get_name(i)));
+ if (udev_device) {
+ const char* value =
+ udev_device_get_sysattr_value(udev_device.get(), "busnum");
+ if (!value || bus_number != value) {
+ continue;
+ }
+ value = udev_device_get_sysattr_value(udev_device.get(), "devnum");
+ if (!value || device_address != value) {
+ continue;
+ }
+
+ value = udev_device_get_sysattr_value(udev_device.get(), "manufacturer");
+ if (value) {
+ device->set_manufacturer_string(base::UTF8ToUTF16(value));
+ }
+ value = udev_device_get_sysattr_value(udev_device.get(), "product");
+ if (value) {
+ device->set_product_string(base::UTF8ToUTF16(value));
+ }
+ value = udev_device_get_sysattr_value(udev_device.get(), "serial");
+ if (value) {
+ device->set_serial_number(base::UTF8ToUTF16(value));
+ }
+
+ value = udev_device_get_devnode(udev_device.get());
+ if (value) {
+ device->set_device_path(value);
+
+ if (read_bos_descriptors) {
+ task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbDevice::Open, device,
+ base::Bind(&OnDeviceOpenedReadDescriptors, 0, 0, 0,
+ true, success_closure, failure_closure)));
+ } else {
+ task_runner->PostTask(FROM_HERE, success_closure);
+ }
+ return;
+ }
+
+ break;
+ }
+ }
+
+ task_runner->PostTask(FROM_HERE, failure_closure);
+}
+
#endif // USE_UDEV
} // namespace
@@ -573,20 +758,22 @@ void UsbServiceImpl::EnumerateDevice(PlatformUsbDevice platform_device,
base::Closure add_device =
base::Bind(&UsbServiceImpl::AddDevice, weak_factory_.GetWeakPtr(),
refresh_complete, device);
+ bool read_bos_descriptors = descriptor.bcdUSB >= kUsbVersion2_1;
#if defined(USE_UDEV)
blocking_task_runner_->PostTask(
- FROM_HERE, base::Bind(&EnumerateUdevDevice, device, task_runner_,
- add_device, refresh_complete));
+ FROM_HERE,
+ base::Bind(&EnumerateUdevDevice, device, read_bos_descriptors,
+ task_runner_, add_device, refresh_complete));
#else
if (descriptor.iManufacturer == 0 && descriptor.iProduct == 0 &&
- descriptor.iSerialNumber == 0) {
- // Don't bother disturbing the device if it has no string descriptors to
- // offer.
+ descriptor.iSerialNumber == 0 && !read_bos_descriptors) {
+ // Don't bother disturbing the device if it has no descriptors to offer.
add_device.Run();
} else {
- device->Open(base::Bind(&ReadDeviceLanguage, descriptor.iManufacturer,
- descriptor.iProduct, descriptor.iSerialNumber,
+ device->Open(base::Bind(&OnDeviceOpenedReadDescriptors,
+ descriptor.iManufacturer, descriptor.iProduct,
+ descriptor.iSerialNumber, read_bos_descriptors,
add_device, refresh_complete));
}
#endif
« no previous file with comments | « device/usb/usb_device_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698