Commit dfa33c8f authored by Reilly Grant's avatar Reilly Grant Committed by Commit Bot

[usb] Read BOS descriptors from the hub driver on Windows

An advantage of the new Windows USB backend is that it can use the
descriptors that are cached by the USB hub driver. In this patch I split
the ReadWebUsbDescriptors() function in two so that the Binary Object
Store descriptor (which is standard) can be read from this cache and the
device only needs to be opened to read the custom WebUSB landing page
descriptor.

This will avoid opening all USB 2.1 and higher devices and instead only
open those that advertise support for a WebUSB landing page.

Bug: 637404
Change-Id: I58cedea166da3cf719c471873cb1fc4faa1549bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2125530
Commit-Queue: Reilly Grant <reillyg@chromium.org>
Reviewed-by: default avatarOvidio de Jesús Ruiz-Henríquez <odejesush@chromium.org>
Cr-Commit-Position: refs/heads/master@{#754575}
parent 99aa72a7
...@@ -332,7 +332,8 @@ void UsbDeviceHandleWin::ControlTransfer( ...@@ -332,7 +332,8 @@ void UsbDeviceHandleWin::ControlTransfer(
base::Owned(node_connection_info), buffer)); base::Owned(node_connection_info), buffer));
return; return;
} else if (((value >> 8) == USB_CONFIGURATION_DESCRIPTOR_TYPE) || } else if (((value >> 8) == USB_CONFIGURATION_DESCRIPTOR_TYPE) ||
((value >> 8) == USB_STRING_DESCRIPTOR_TYPE)) { ((value >> 8) == USB_STRING_DESCRIPTOR_TYPE) ||
((value >> 8) == USB_BOS_DESCRIPTOR_TYPE)) {
size_t size = sizeof(USB_DESCRIPTOR_REQUEST) + buffer->size(); size_t size = sizeof(USB_DESCRIPTOR_REQUEST) + buffer->size();
auto request_buffer = base::MakeRefCounted<base::RefCountedBytes>(size); auto request_buffer = base::MakeRefCounted<base::RefCountedBytes>(size);
USB_DESCRIPTOR_REQUEST* descriptor_request = USB_DESCRIPTOR_REQUEST* descriptor_request =
......
...@@ -118,8 +118,6 @@ void UsbDeviceWin::OnReadStringDescriptors( ...@@ -118,8 +118,6 @@ void UsbDeviceWin::OnReadStringDescriptors(
std::unique_ptr<std::map<uint8_t, base::string16>> string_map) { std::unique_ptr<std::map<uint8_t, base::string16>> string_map) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
device_handle->Close();
if (i_manufacturer) if (i_manufacturer)
device_info_->manufacturer_name = (*string_map)[i_manufacturer]; device_info_->manufacturer_name = (*string_map)[i_manufacturer];
if (i_product) if (i_product)
...@@ -128,15 +126,37 @@ void UsbDeviceWin::OnReadStringDescriptors( ...@@ -128,15 +126,37 @@ void UsbDeviceWin::OnReadStringDescriptors(
device_info_->serial_number = (*string_map)[i_serial_number]; device_info_->serial_number = (*string_map)[i_serial_number];
if (usb_version() >= kUsbVersion2_1) { if (usb_version() >= kUsbVersion2_1) {
Open(base::BindOnce(&UsbDeviceWin::OnOpenedToReadWebUsbDescriptors, this, ReadWebUsbCapabilityDescriptor(
std::move(callback))); device_handle,
base::BindOnce(&UsbDeviceWin::OnReadWebUsbCapabilityDescriptor, this,
std::move(callback), device_handle));
} else { } else {
device_handle->Close();
std::move(callback).Run(true);
}
}
void UsbDeviceWin::OnReadWebUsbCapabilityDescriptor(
base::OnceCallback<void(bool)> callback,
scoped_refptr<UsbDeviceHandle> device_handle,
const base::Optional<WebUsbPlatformCapabilityDescriptor>& descriptor) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
device_handle->Close();
if (!descriptor || !descriptor->landing_page_id) {
std::move(callback).Run(true); std::move(callback).Run(true);
return;
} }
Open(base::BindOnce(&UsbDeviceWin::OnOpenedToReadWebUsbLandingPage, this,
std::move(callback), descriptor->vendor_code,
descriptor->landing_page_id));
} }
void UsbDeviceWin::OnOpenedToReadWebUsbDescriptors( void UsbDeviceWin::OnOpenedToReadWebUsbLandingPage(
base::OnceCallback<void(bool)> callback, base::OnceCallback<void(bool)> callback,
uint8_t vendor_code,
uint8_t landing_page_id,
scoped_refptr<UsbDeviceHandle> device_handle) { scoped_refptr<UsbDeviceHandle> device_handle) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
...@@ -147,12 +167,13 @@ void UsbDeviceWin::OnOpenedToReadWebUsbDescriptors( ...@@ -147,12 +167,13 @@ void UsbDeviceWin::OnOpenedToReadWebUsbDescriptors(
return; return;
} }
ReadWebUsbDescriptors( ReadWebUsbLandingPage(
device_handle, base::BindOnce(&UsbDeviceWin::OnReadWebUsbDescriptors, vendor_code, landing_page_id, device_handle,
this, std::move(callback), device_handle)); base::BindOnce(&UsbDeviceWin::OnReadWebUsbLandingPage, this,
std::move(callback), device_handle));
} }
void UsbDeviceWin::OnReadWebUsbDescriptors( void UsbDeviceWin::OnReadWebUsbLandingPage(
base::OnceCallback<void(bool)> callback, base::OnceCallback<void(bool)> callback,
scoped_refptr<UsbDeviceHandle> device_handle, scoped_refptr<UsbDeviceHandle> device_handle,
const GURL& landing_page) { const GURL& landing_page) {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
namespace device { namespace device {
struct UsbDeviceDescriptor; struct UsbDeviceDescriptor;
struct WebUsbPlatformCapabilityDescriptor;
class UsbDeviceWin : public UsbDevice { class UsbDeviceWin : public UsbDevice {
public: public:
...@@ -54,10 +55,16 @@ class UsbDeviceWin : public UsbDevice { ...@@ -54,10 +55,16 @@ class UsbDeviceWin : public UsbDevice {
uint8_t i_product, uint8_t i_product,
uint8_t i_serial_number, uint8_t i_serial_number,
std::unique_ptr<std::map<uint8_t, base::string16>> string_map); std::unique_ptr<std::map<uint8_t, base::string16>> string_map);
void OnOpenedToReadWebUsbDescriptors( void OnReadWebUsbCapabilityDescriptor(
base::OnceCallback<void(bool)> callback, base::OnceCallback<void(bool)> callback,
scoped_refptr<UsbDeviceHandle> device_handle,
const base::Optional<WebUsbPlatformCapabilityDescriptor>& descriptor);
void OnOpenedToReadWebUsbLandingPage(
base::OnceCallback<void(bool)> callback,
uint8_t vendor_code,
uint8_t landing_page_id,
scoped_refptr<UsbDeviceHandle> device_handle); scoped_refptr<UsbDeviceHandle> device_handle);
void OnReadWebUsbDescriptors(base::OnceCallback<void(bool)> callback, void OnReadWebUsbLandingPage(base::OnceCallback<void(bool)> callback,
scoped_refptr<UsbDeviceHandle> device_handle, scoped_refptr<UsbDeviceHandle> device_handle,
const GURL& landing_page); const GURL& landing_page);
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "services/device/usb/webusb_descriptors.h" #include "services/device/usb/webusb_descriptors.h"
#include <limits>
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/logging.h" #include "base/logging.h"
...@@ -11,6 +13,7 @@ ...@@ -11,6 +13,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "components/device_event_log/device_event_log.h" #include "components/device_event_log/device_event_log.h"
#include "services/device/usb/usb_device_handle.h" #include "services/device/usb/usb_device_handle.h"
#include "url/gurl.h"
namespace device { namespace device {
...@@ -39,13 +42,16 @@ const uint8_t kWebUsbCapabilityUUID[16] = { ...@@ -39,13 +42,16 @@ const uint8_t kWebUsbCapabilityUUID[16] = {
0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,
0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65}; 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65};
const size_t kMaxControlTransferLength = std::numeric_limits<uint8_t>::max();
const int kControlTransferTimeoutMs = 2000; // 2 seconds const int kControlTransferTimeoutMs = 2000; // 2 seconds
using ReadWebUsbDescriptorsCallback = using ReadCompatabilityDescriptorCallback = base::OnceCallback<void(
const base::Optional<WebUsbPlatformCapabilityDescriptor>& descriptor)>;
using ReadLandingPageCallback =
base::OnceCallback<void(const GURL& landing_page)>; base::OnceCallback<void(const GURL& landing_page)>;
void OnReadLandingPage(uint8_t landing_page_id, void OnReadLandingPage(uint8_t landing_page_id,
ReadWebUsbDescriptorsCallback callback, ReadLandingPageCallback callback,
UsbTransferStatus status, UsbTransferStatus status,
scoped_refptr<base::RefCountedBytes> buffer, scoped_refptr<base::RefCountedBytes> buffer,
size_t length) { size_t length) {
...@@ -62,52 +68,35 @@ void OnReadLandingPage(uint8_t landing_page_id, ...@@ -62,52 +68,35 @@ void OnReadLandingPage(uint8_t landing_page_id,
std::move(callback).Run(url); std::move(callback).Run(url);
} }
void ReadLandingPage(uint8_t vendor_code,
uint8_t landing_page_id,
scoped_refptr<UsbDeviceHandle> device_handle,
ReadWebUsbDescriptorsCallback callback) {
auto buffer = base::MakeRefCounted<base::RefCountedBytes>(255);
device_handle->ControlTransfer(
UsbTransferDirection::INBOUND, UsbControlTransferType::VENDOR,
UsbControlTransferRecipient::DEVICE, vendor_code, landing_page_id,
kGetUrlRequest, buffer, kControlTransferTimeoutMs,
base::BindOnce(&OnReadLandingPage, landing_page_id, std::move(callback)));
}
void OnReadBosDescriptor(scoped_refptr<UsbDeviceHandle> device_handle, void OnReadBosDescriptor(scoped_refptr<UsbDeviceHandle> device_handle,
ReadWebUsbDescriptorsCallback callback, ReadCompatabilityDescriptorCallback callback,
UsbTransferStatus status, UsbTransferStatus status,
scoped_refptr<base::RefCountedBytes> buffer, scoped_refptr<base::RefCountedBytes> buffer,
size_t length) { size_t length) {
if (status != UsbTransferStatus::COMPLETED) { if (status != UsbTransferStatus::COMPLETED) {
USB_LOG(EVENT) << "Failed to read BOS descriptor."; USB_LOG(EVENT) << "Failed to read BOS descriptor.";
std::move(callback).Run(GURL()); std::move(callback).Run(base::nullopt);
return; return;
} }
WebUsbPlatformCapabilityDescriptor descriptor; WebUsbPlatformCapabilityDescriptor descriptor;
if (!descriptor.ParseFromBosDescriptor( if (!descriptor.ParseFromBosDescriptor(
std::vector<uint8_t>(buffer->front(), buffer->front() + length))) { std::vector<uint8_t>(buffer->front(), buffer->front() + length))) {
std::move(callback).Run(GURL()); std::move(callback).Run(base::nullopt);
return; return;
} }
if (descriptor.landing_page_id) { std::move(callback).Run(descriptor);
ReadLandingPage(descriptor.vendor_code, descriptor.landing_page_id,
device_handle, std::move(callback));
} else {
std::move(callback).Run(GURL());
}
} }
void OnReadBosDescriptorHeader(scoped_refptr<UsbDeviceHandle> device_handle, void OnReadBosDescriptorHeader(scoped_refptr<UsbDeviceHandle> device_handle,
ReadWebUsbDescriptorsCallback callback, ReadCompatabilityDescriptorCallback callback,
UsbTransferStatus status, UsbTransferStatus status,
scoped_refptr<base::RefCountedBytes> buffer, scoped_refptr<base::RefCountedBytes> buffer,
size_t length) { size_t length) {
if (status != UsbTransferStatus::COMPLETED || length != 5) { if (status != UsbTransferStatus::COMPLETED || length != 5) {
USB_LOG(EVENT) << "Failed to read BOS descriptor header."; USB_LOG(EVENT) << "Failed to read BOS descriptor header.";
std::move(callback).Run(GURL()); std::move(callback).Run(base::nullopt);
return; return;
} }
...@@ -121,6 +110,19 @@ void OnReadBosDescriptorHeader(scoped_refptr<UsbDeviceHandle> device_handle, ...@@ -121,6 +110,19 @@ void OnReadBosDescriptorHeader(scoped_refptr<UsbDeviceHandle> device_handle,
base::BindOnce(&OnReadBosDescriptor, device_handle, std::move(callback))); base::BindOnce(&OnReadBosDescriptor, device_handle, std::move(callback)));
} }
void OnReadWebUsbCapabilityDescriptor(
scoped_refptr<UsbDeviceHandle> device_handle,
ReadLandingPageCallback callback,
const base::Optional<WebUsbPlatformCapabilityDescriptor>& descriptor) {
if (!descriptor || !descriptor->landing_page_id) {
std::move(callback).Run(GURL());
return;
}
ReadWebUsbLandingPage(descriptor->vendor_code, descriptor->landing_page_id,
device_handle, std::move(callback));
}
} // namespace } // namespace
WebUsbPlatformCapabilityDescriptor::WebUsbPlatformCapabilityDescriptor() WebUsbPlatformCapabilityDescriptor::WebUsbPlatformCapabilityDescriptor()
...@@ -251,8 +253,22 @@ bool ParseWebUsbUrlDescriptor(const std::vector<uint8_t>& bytes, GURL* output) { ...@@ -251,8 +253,22 @@ bool ParseWebUsbUrlDescriptor(const std::vector<uint8_t>& bytes, GURL* output) {
return true; return true;
} }
void ReadWebUsbDescriptors(scoped_refptr<UsbDeviceHandle> device_handle, void ReadWebUsbLandingPage(uint8_t vendor_code,
ReadWebUsbDescriptorsCallback callback) { uint8_t landing_page_id,
scoped_refptr<UsbDeviceHandle> device_handle,
ReadLandingPageCallback callback) {
auto buffer =
base::MakeRefCounted<base::RefCountedBytes>(kMaxControlTransferLength);
device_handle->ControlTransfer(
UsbTransferDirection::INBOUND, UsbControlTransferType::VENDOR,
UsbControlTransferRecipient::DEVICE, vendor_code, landing_page_id,
kGetUrlRequest, buffer, kControlTransferTimeoutMs,
base::BindOnce(&OnReadLandingPage, landing_page_id, std::move(callback)));
}
void ReadWebUsbCapabilityDescriptor(
scoped_refptr<UsbDeviceHandle> device_handle,
ReadCompatabilityDescriptorCallback callback) {
auto buffer = base::MakeRefCounted<base::RefCountedBytes>(5); auto buffer = base::MakeRefCounted<base::RefCountedBytes>(5);
device_handle->ControlTransfer( device_handle->ControlTransfer(
UsbTransferDirection::INBOUND, UsbControlTransferType::STANDARD, UsbTransferDirection::INBOUND, UsbControlTransferType::STANDARD,
...@@ -262,4 +278,11 @@ void ReadWebUsbDescriptors(scoped_refptr<UsbDeviceHandle> device_handle, ...@@ -262,4 +278,11 @@ void ReadWebUsbDescriptors(scoped_refptr<UsbDeviceHandle> device_handle,
std::move(callback))); std::move(callback)));
} }
void ReadWebUsbDescriptors(scoped_refptr<UsbDeviceHandle> device_handle,
ReadLandingPageCallback callback) {
ReadWebUsbCapabilityDescriptor(
device_handle, base::BindOnce(&OnReadWebUsbCapabilityDescriptor,
device_handle, std::move(callback)));
}
} // namespace device } // namespace device
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "url/gurl.h" #include "base/optional.h"
class GURL;
namespace device { namespace device {
...@@ -26,11 +28,22 @@ struct WebUsbPlatformCapabilityDescriptor { ...@@ -26,11 +28,22 @@ struct WebUsbPlatformCapabilityDescriptor {
uint16_t version; uint16_t version;
uint8_t vendor_code; uint8_t vendor_code;
uint8_t landing_page_id; uint8_t landing_page_id;
GURL landing_page;
}; };
bool ParseWebUsbUrlDescriptor(const std::vector<uint8_t>& bytes, GURL* output); bool ParseWebUsbUrlDescriptor(const std::vector<uint8_t>& bytes, GURL* output);
void ReadWebUsbLandingPage(
uint8_t vendor_code,
uint8_t landing_page_id,
scoped_refptr<UsbDeviceHandle> device_handle,
base::OnceCallback<void(const GURL& landing_page)> callback);
void ReadWebUsbCapabilityDescriptor(
scoped_refptr<UsbDeviceHandle> device_handle,
base::OnceCallback<void(
const base::Optional<WebUsbPlatformCapabilityDescriptor>& descriptor)>
callback);
void ReadWebUsbDescriptors( void ReadWebUsbDescriptors(
scoped_refptr<UsbDeviceHandle> device_handle, scoped_refptr<UsbDeviceHandle> device_handle,
base::OnceCallback<void(const GURL& landing_page)> callback); base::OnceCallback<void(const GURL& landing_page)> callback);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment