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(
base::Owned(node_connection_info), buffer));
return;
} 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();
auto request_buffer = base::MakeRefCounted<base::RefCountedBytes>(size);
USB_DESCRIPTOR_REQUEST* descriptor_request =
......
......@@ -118,8 +118,6 @@ void UsbDeviceWin::OnReadStringDescriptors(
std::unique_ptr<std::map<uint8_t, base::string16>> string_map) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
device_handle->Close();
if (i_manufacturer)
device_info_->manufacturer_name = (*string_map)[i_manufacturer];
if (i_product)
......@@ -128,15 +126,37 @@ void UsbDeviceWin::OnReadStringDescriptors(
device_info_->serial_number = (*string_map)[i_serial_number];
if (usb_version() >= kUsbVersion2_1) {
Open(base::BindOnce(&UsbDeviceWin::OnOpenedToReadWebUsbDescriptors, this,
std::move(callback)));
ReadWebUsbCapabilityDescriptor(
device_handle,
base::BindOnce(&UsbDeviceWin::OnReadWebUsbCapabilityDescriptor, this,
std::move(callback), device_handle));
} 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);
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,
uint8_t vendor_code,
uint8_t landing_page_id,
scoped_refptr<UsbDeviceHandle> device_handle) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
......@@ -147,12 +167,13 @@ void UsbDeviceWin::OnOpenedToReadWebUsbDescriptors(
return;
}
ReadWebUsbDescriptors(
device_handle, base::BindOnce(&UsbDeviceWin::OnReadWebUsbDescriptors,
this, std::move(callback), device_handle));
ReadWebUsbLandingPage(
vendor_code, landing_page_id, device_handle,
base::BindOnce(&UsbDeviceWin::OnReadWebUsbLandingPage, this,
std::move(callback), device_handle));
}
void UsbDeviceWin::OnReadWebUsbDescriptors(
void UsbDeviceWin::OnReadWebUsbLandingPage(
base::OnceCallback<void(bool)> callback,
scoped_refptr<UsbDeviceHandle> device_handle,
const GURL& landing_page) {
......
......@@ -17,6 +17,7 @@
namespace device {
struct UsbDeviceDescriptor;
struct WebUsbPlatformCapabilityDescriptor;
class UsbDeviceWin : public UsbDevice {
public:
......@@ -54,10 +55,16 @@ class UsbDeviceWin : public UsbDevice {
uint8_t i_product,
uint8_t i_serial_number,
std::unique_ptr<std::map<uint8_t, base::string16>> string_map);
void OnOpenedToReadWebUsbDescriptors(
void OnReadWebUsbCapabilityDescriptor(
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);
void OnReadWebUsbDescriptors(base::OnceCallback<void(bool)> callback,
void OnReadWebUsbLandingPage(base::OnceCallback<void(bool)> callback,
scoped_refptr<UsbDeviceHandle> device_handle,
const GURL& landing_page);
......
......@@ -4,6 +4,8 @@
#include "services/device/usb/webusb_descriptors.h"
#include <limits>
#include "base/bind.h"
#include "base/callback.h"
#include "base/logging.h"
......@@ -11,6 +13,7 @@
#include "base/stl_util.h"
#include "components/device_event_log/device_event_log.h"
#include "services/device/usb/usb_device_handle.h"
#include "url/gurl.h"
namespace device {
......@@ -39,13 +42,16 @@ const uint8_t kWebUsbCapabilityUUID[16] = {
0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,
0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65};
const size_t kMaxControlTransferLength = std::numeric_limits<uint8_t>::max();
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)>;
void OnReadLandingPage(uint8_t landing_page_id,
ReadWebUsbDescriptorsCallback callback,
ReadLandingPageCallback callback,
UsbTransferStatus status,
scoped_refptr<base::RefCountedBytes> buffer,
size_t length) {
......@@ -62,52 +68,35 @@ void OnReadLandingPage(uint8_t landing_page_id,
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,
ReadWebUsbDescriptorsCallback callback,
ReadCompatabilityDescriptorCallback callback,
UsbTransferStatus status,
scoped_refptr<base::RefCountedBytes> buffer,
size_t length) {
if (status != UsbTransferStatus::COMPLETED) {
USB_LOG(EVENT) << "Failed to read BOS descriptor.";
std::move(callback).Run(GURL());
std::move(callback).Run(base::nullopt);
return;
}
WebUsbPlatformCapabilityDescriptor descriptor;
if (!descriptor.ParseFromBosDescriptor(
std::vector<uint8_t>(buffer->front(), buffer->front() + length))) {
std::move(callback).Run(GURL());
std::move(callback).Run(base::nullopt);
return;
}
if (descriptor.landing_page_id) {
ReadLandingPage(descriptor.vendor_code, descriptor.landing_page_id,
device_handle, std::move(callback));
} else {
std::move(callback).Run(GURL());
}
std::move(callback).Run(descriptor);
}
void OnReadBosDescriptorHeader(scoped_refptr<UsbDeviceHandle> device_handle,
ReadWebUsbDescriptorsCallback callback,
ReadCompatabilityDescriptorCallback callback,
UsbTransferStatus status,
scoped_refptr<base::RefCountedBytes> buffer,
size_t length) {
if (status != UsbTransferStatus::COMPLETED || length != 5) {
USB_LOG(EVENT) << "Failed to read BOS descriptor header.";
std::move(callback).Run(GURL());
std::move(callback).Run(base::nullopt);
return;
}
......@@ -121,6 +110,19 @@ void OnReadBosDescriptorHeader(scoped_refptr<UsbDeviceHandle> device_handle,
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
WebUsbPlatformCapabilityDescriptor::WebUsbPlatformCapabilityDescriptor()
......@@ -251,8 +253,22 @@ bool ParseWebUsbUrlDescriptor(const std::vector<uint8_t>& bytes, GURL* output) {
return true;
}
void ReadWebUsbDescriptors(scoped_refptr<UsbDeviceHandle> device_handle,
ReadWebUsbDescriptorsCallback callback) {
void ReadWebUsbLandingPage(uint8_t vendor_code,
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);
device_handle->ControlTransfer(
UsbTransferDirection::INBOUND, UsbControlTransferType::STANDARD,
......@@ -262,4 +278,11 @@ void ReadWebUsbDescriptors(scoped_refptr<UsbDeviceHandle> device_handle,
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
......@@ -11,7 +11,9 @@
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "url/gurl.h"
#include "base/optional.h"
class GURL;
namespace device {
......@@ -26,11 +28,22 @@ struct WebUsbPlatformCapabilityDescriptor {
uint16_t version;
uint8_t vendor_code;
uint8_t landing_page_id;
GURL landing_page;
};
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(
scoped_refptr<UsbDeviceHandle> device_handle,
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