Allows any USB device with an ADB interface to connect to a VM.
Some Samsung phones have multiple USB interfaces, the presence of which formerly
suppressed our notification on Add. The notifications are no longer suppressed,
nor are ADB-supporting devices blocked from sharing with a VM.
Bug: 943429
Change-Id: I203d80d38529010bb8ddb1e7427db3dd0620537e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1530215
Commit-Queue: Nicholas Verne <nverne@chromium.org>
Reviewed-by: Joel Hockey <joelhockey@chromium.org>
Reviewed-by: Timothy Loh <timloh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#641821}
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector.cc b/chrome/browser/chromeos/usb/cros_usb_detector.cc
index 06e928b..ab564ab 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector.cc
+++ b/chrome/browser/chromeos/usb/cros_usb_detector.cc
@@ -217,6 +217,15 @@
UsbFilterByClassCode(USB_CLASS_VIDEO));
guest_os_classes_without_notif_.emplace_back(
UsbFilterByClassCode(USB_CLASS_PERSONAL_HEALTHCARE));
+
+ // If a device has an adb interface, we always allow it.
+ const int kAdbSubclass = 0x42;
+ const int kAdbProtocol = 0x1;
+ adb_device_filter_ = UsbFilterByClassCode(USB_CLASS_VENDOR_SPEC);
+ adb_device_filter_->has_subclass_code = true;
+ adb_device_filter_->subclass_code = kAdbSubclass;
+ adb_device_filter_->has_protocol_code = true;
+ adb_device_filter_->protocol_code = kAdbProtocol;
}
CrosUsbDetector::~CrosUsbDetector() {
@@ -274,6 +283,24 @@
weak_ptr_factory_.GetWeakPtr()));
}
+bool CrosUsbDetector::ShouldShowNotification(
+ const device::mojom::UsbDeviceInfo& device_info) {
+ if (device::UsbDeviceFilterMatches(*adb_device_filter_, device_info)) {
+ return true;
+ }
+ return !device::UsbDeviceFilterMatchesAny(guest_os_classes_without_notif_,
+ device_info);
+}
+
+bool CrosUsbDetector::IsDeviceSharable(
+ const device::mojom::UsbDeviceInfo& device_info) {
+ if (device::UsbDeviceFilterMatches(*adb_device_filter_, device_info)) {
+ return true;
+ }
+ return !device::UsbDeviceFilterMatchesAny(guest_os_classes_blocked_,
+ device_info);
+}
+
void CrosUsbDetector::OnDeviceChecked(
device::mojom::UsbDeviceInfoPtr device_info,
bool hide_notification,
@@ -297,8 +324,7 @@
SignalSharedUsbDeviceObservers();
// Some devices should not trigger the notification.
- if (hide_notification || device::UsbDeviceFilterMatchesAny(
- guest_os_classes_without_notif_, *device_info)) {
+ if (hide_notification || !ShouldShowNotification(*device_info)) {
return;
}
ShowNotificationForDevice(std::move(device_info));
@@ -310,8 +336,7 @@
void CrosUsbDetector::OnDeviceAdded(device::mojom::UsbDeviceInfoPtr device_info,
bool hide_notification) {
- if (device::UsbDeviceFilterMatchesAny(guest_os_classes_blocked_,
- *device_info)) {
+ if (!IsDeviceSharable(*device_info)) {
return; // Guest OS does not handle this kind of device.
}
device_manager_->CheckAccess(
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector.h b/chrome/browser/chromeos/usb/cros_usb_detector.h
index f4651df..426678f 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector.h
+++ b/chrome/browser/chromeos/usb/cros_usb_detector.h
@@ -140,6 +140,11 @@
uint8_t guest_port,
crostini::CrostiniResult result);
+ // Returns true when a device should show a notification when attached.
+ bool ShouldShowNotification(const device::mojom::UsbDeviceInfo& device_info);
+ // Returns true when a device can be shared.
+ bool IsDeviceSharable(const device::mojom::UsbDeviceInfo& device_info);
+
device::mojom::UsbDeviceManagerPtr device_manager_;
mojo::AssociatedBinding<device::mojom::UsbDeviceManagerClient>
client_binding_;
@@ -147,6 +152,7 @@
std::vector<device::mojom::UsbDeviceFilterPtr> guest_os_classes_blocked_;
std::vector<device::mojom::UsbDeviceFilterPtr>
guest_os_classes_without_notif_;
+ device::mojom::UsbDeviceFilterPtr adb_device_filter_;
// A mapping from GUID -> UsbDeviceInfo for each attached USB device
std::map<std::string, device::mojom::UsbDeviceInfoPtr> available_device_info_;
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc b/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
index 9db1527..5ab7f4f 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
+++ b/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
@@ -45,26 +45,40 @@
const int kUsbConfigWithInterfaces = 1;
-scoped_refptr<device::FakeUsbDeviceInfo> CreateTestDeviceOfClass(
- uint8_t device_class) {
+struct InterfaceCodes {
+ InterfaceCodes(uint8_t device_class,
+ uint8_t subclass_code,
+ uint8_t protocol_code)
+ : device_class(device_class),
+ subclass_code(subclass_code),
+ protocol_code(protocol_code) {}
+ uint8_t device_class;
+ uint8_t subclass_code;
+ uint8_t protocol_code;
+};
+
+scoped_refptr<device::FakeUsbDeviceInfo> CreateTestDeviceFromCodes(
+ uint8_t device_class,
+ const std::vector<InterfaceCodes>& interface_codes) {
+ auto config = device::mojom::UsbConfigurationInfo::New();
+ config->configuration_value = kUsbConfigWithInterfaces;
// The usb_utils do not filter by device class, only by configurations, and
// the FakeUsbDeviceInfo does not set up configurations for a fake device's
// class code. This helper sets up a configuration to match a devices class
// code so that USB devices can be filtered out.
- auto alternate = device::mojom::UsbAlternateInterfaceInfo::New();
- alternate->alternate_setting = 0;
- alternate->class_code = device_class;
- alternate->subclass_code = 0xff;
- alternate->protocol_code = 0xff;
+ for (size_t i = 0; i < interface_codes.size(); ++i) {
+ auto alternate = device::mojom::UsbAlternateInterfaceInfo::New();
+ alternate->alternate_setting = 0;
+ alternate->class_code = interface_codes[i].device_class;
+ alternate->subclass_code = interface_codes[i].subclass_code;
+ alternate->protocol_code = interface_codes[i].protocol_code;
- auto interface = device::mojom::UsbInterfaceInfo::New();
- interface->interface_number = 0;
- interface->alternates.push_back(std::move(alternate));
+ auto interface = device::mojom::UsbInterfaceInfo::New();
+ interface->interface_number = i;
+ interface->alternates.push_back(std::move(alternate));
- auto config = device::mojom::UsbConfigurationInfo::New();
- config->configuration_value = kUsbConfigWithInterfaces;
-
- config->interfaces.push_back(std::move(interface));
+ config->interfaces.push_back(std::move(interface));
+ }
std::vector<device::mojom::UsbConfigurationInfoPtr> configs;
configs.push_back(std::move(config));
@@ -76,6 +90,12 @@
return device;
}
+scoped_refptr<device::FakeUsbDeviceInfo> CreateTestDeviceOfClass(
+ uint8_t device_class) {
+ return CreateTestDeviceFromCodes(device_class,
+ {InterfaceCodes(device_class, 0xff, 0xff)});
+}
+
} // namespace
class CrosUsbDetectorTest : public BrowserWithTestWindowTest {
@@ -201,6 +221,27 @@
// TODO(jopra): Check that the device is not available for sharing.
}
+TEST_F(CrosUsbDetectorTest, UsbDeviceClassAdbAdded) {
+ ConnectToDeviceManager();
+ base::RunLoop().RunUntilIdle();
+
+ const int kAdbClass = 0xff;
+ const int kAdbSubclass = 0x42;
+ const int kAdbProtocol = 0x1;
+ // Adb interface as well as a forbidden interface
+ scoped_refptr<device::FakeUsbDeviceInfo> device = CreateTestDeviceFromCodes(
+ /* USB_CLASS_HID */ 0x03,
+ {InterfaceCodes(kAdbClass, kAdbSubclass, kAdbProtocol),
+ InterfaceCodes(0x03, 0xff, 0xff)});
+
+ device_manager_.AddDevice(device);
+ base::RunLoop().RunUntilIdle();
+
+ std::string notification_id =
+ chromeos::CrosUsbDetector::MakeNotificationId(device->guid());
+ ASSERT_TRUE(display_service_->GetNotification(notification_id));
+}
+
TEST_F(CrosUsbDetectorTest, UsbDeviceClassWithoutNotificationAdded) {
ConnectToDeviceManager();
base::RunLoop().RunUntilIdle();