Commit 427c9aee authored by Reilly Grant's avatar Reilly Grant Committed by Commit Bot

[chrome.usb] Clear device on connection error

When a USB device is disconnected Mojo connections to it are closed. The
UsbDeviceResource object should listen for this connection failures and
clear the InterfacePtr as otherwise calls are still allowed but their
callbacks will never be executed.

Bug: 968111
Change-Id: I9e704b8b9bf0c067167374bb9910f83d566cdb7b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1636725Reviewed-by: default avatarKen Rockot <rockot@google.com>
Commit-Queue: Reilly Grant <reillyg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#665029}
parent 9c31a714
......@@ -290,6 +290,21 @@ IN_PROC_BROWSER_TEST_F(UsbApiTest, InvalidTimeout) {
ASSERT_TRUE(RunAppTest("api_test/usb/invalid_timeout"));
}
IN_PROC_BROWSER_TEST_F(UsbApiTest, CallsAfterDisconnect) {
ExtensionTestMessageListener ready_listener("ready", false);
ExtensionTestMessageListener result_listener("success", false);
result_listener.set_failure_message("failure");
EXPECT_CALL(mock_device_, OpenInternal(_))
.WillOnce(InvokeCallback<0>(UsbOpenDeviceError::OK));
ASSERT_TRUE(LoadApp("api_test/usb/calls_after_disconnect"));
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
fake_usb_manager_.RemoveDevice(fake_device_);
ASSERT_TRUE(result_listener.WaitUntilSatisfied());
}
IN_PROC_BROWSER_TEST_F(UsbApiTest, OnDeviceAdded) {
ExtensionTestMessageListener load_listener("loaded", false);
ExtensionTestMessageListener result_listener("success", false);
......
......@@ -34,9 +34,10 @@ ApiResourceManager<UsbDeviceResource>::GetFactoryInstance() {
UsbDeviceResource::UsbDeviceResource(const std::string& owner_extension_id,
const std::string& guid,
device::mojom::UsbDevicePtr device)
: ApiResource(owner_extension_id),
guid_(guid),
device_(std::move(device)) {}
: ApiResource(owner_extension_id), guid_(guid), device_(std::move(device)) {
device_.set_connection_error_handler(base::BindOnce(
&UsbDeviceResource::OnConnectionError, base::Unretained(this)));
}
UsbDeviceResource::~UsbDeviceResource() {}
......@@ -44,4 +45,8 @@ bool UsbDeviceResource::IsPersistent() const {
return false;
}
void UsbDeviceResource::OnConnectionError() {
device_.reset();
}
} // namespace extensions
......@@ -38,6 +38,8 @@ class UsbDeviceResource : public ApiResource {
friend class ApiResourceManager<UsbDeviceResource>;
static const char* service_name() { return "UsbDeviceResourceManager"; }
void OnConnectionError();
const std::string guid_;
device::mojom::UsbDevicePtr device_;
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
let connectionHandle;
chrome.usb.onDeviceRemoved.addListener(() => {
chrome.usb.bulkTransfer(connectionHandle, {
direction: "in",
endpoint: 1,
length: 8 }, result => {
if (chrome.runtime.lastError.message == "No such connection.") {
chrome.test.sendMessage("success");
return;
}
console.error("Expected transfer failure.");
chrome.test.sendMessage("failure");
});
});
chrome.usb.getDevices({}, devices => {
if (devices.length !== 1) {
console.error("Expected a single device.");
chrome.test.sendMessage("failure");
}
device = devices[0];
chrome.usb.openDevice(device, connection => {
if (connection === undefined) {
console.error("Failed to open device.");
chrome.test.sendMessage("failure");
return;
}
connectionHandle = connection;
chrome.test.sendMessage("ready");
});
});
{
"name": "Calls to chrome.usb methods after device disconnect",
"manifest_version": 2,
"version": "0.1",
"description": "Calls to chrome.usb methods after device disconnect",
"app": {
"background": {
"scripts": ["background.js"]
}
},
"permissions": [
"usb",
// This is a test device emulated by the mocks enabled for the test.
{ "usbDevices": [{ "vendorId": 0, "productId": 0 }]}
]
}
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