Mojofication on //device/hid.
In this CL: 1) Add the HidManager and HidConnection interfaces in hid.mojom, and implements those mojo interfaces in //device/hid. 2) Convert the clients in //extensions to use hid mojo interfaces. 3) Change the type of HidUsageAndPage::usage_page to uint16_t. 4) Rewrite the hid_apitest base on the new added mojo interfaces. TODO: 1) Move client library files into device/hid/public/cpp. 2) Host HidService by DeviceService instead of DeviceClient. 3) Mojofy //device/u2f Or just move it into DeviceService. BUG=728223 Change-Id: I1de1b5211f7ef37f54d4bc18c7995a3b47cc7da2 Reviewed-on: https://chromium-review.googlesource.com/648949 Reviewed-by: Tom Sepez <tsepez@chromium.org> Reviewed-by: Reilly Grant <reillyg@chromium.org> Commit-Queue: Ke He <ke.he@intel.com> Cr-Commit-Position: refs/heads/master@{#502109}
This commit is contained in:
chrome/browser/extensions/api
content/public/app/mojo
device/hid
BUILD.gnhid_connection_impl.cchid_connection_impl.hhid_manager_impl.cchid_manager_impl.hhid_service.hhid_usage_and_page.h
public
extensions
services/device
@ -12,7 +12,6 @@
|
||||
#include "chrome/test/base/testing_profile.h"
|
||||
#include "device/base/mock_device_client.h"
|
||||
#include "device/hid/hid_device_info.h"
|
||||
#include "device/hid/mock_hid_service.h"
|
||||
#include "device/hid/public/interfaces/hid.mojom.h"
|
||||
#include "device/usb/mock_usb_device.h"
|
||||
#include "device/usb/mock_usb_service.h"
|
||||
@ -40,9 +39,17 @@ const uint64_t kTestDeviceIds[] = {1, 2, 3, 4};
|
||||
const char* kTestDeviceIds[] = {"A", "B", "C", "D"};
|
||||
#endif
|
||||
|
||||
class FakeHidDeviceManager : public HidDeviceManager {
|
||||
public:
|
||||
explicit FakeHidDeviceManager(content::BrowserContext* context)
|
||||
: HidDeviceManager(context) {}
|
||||
|
||||
void LazyInitialize() override {}
|
||||
};
|
||||
|
||||
std::unique_ptr<KeyedService> CreateHidDeviceManager(
|
||||
content::BrowserContext* context) {
|
||||
return base::MakeUnique<HidDeviceManager>(context);
|
||||
return base::MakeUnique<FakeHidDeviceManager>(context);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -74,20 +81,15 @@ class DevicePermissionsManagerTest : public testing::Test {
|
||||
device4_ = new HidDeviceInfo(
|
||||
kTestDeviceIds[0], 0, 0, "Test HID Device", "abcde",
|
||||
device::mojom::HidBusType::kHIDBusTypeUSB, std::vector<uint8_t>());
|
||||
device_client_.hid_service()->AddDevice(device4_);
|
||||
device5_ = new HidDeviceInfo(kTestDeviceIds[1], 0, 0, "Test HID Device", "",
|
||||
device::mojom::HidBusType::kHIDBusTypeUSB,
|
||||
std::vector<uint8_t>());
|
||||
device_client_.hid_service()->AddDevice(device5_);
|
||||
device6_ = new HidDeviceInfo(
|
||||
kTestDeviceIds[2], 0, 0, "Test HID Device", "67890",
|
||||
device::mojom::HidBusType::kHIDBusTypeUSB, std::vector<uint8_t>());
|
||||
device_client_.hid_service()->AddDevice(device6_);
|
||||
device7_ = new HidDeviceInfo(kTestDeviceIds[3], 0, 0, "Test HID Device", "",
|
||||
device::mojom::HidBusType::kHIDBusTypeUSB,
|
||||
std::vector<uint8_t>());
|
||||
device_client_.hid_service()->AddDevice(device7_);
|
||||
device_client_.hid_service()->FirstEnumerationComplete();
|
||||
}
|
||||
|
||||
void TearDown() override { env_.reset(nullptr); }
|
||||
@ -209,11 +211,8 @@ TEST_F(DevicePermissionsManagerTest, DisconnectDevice) {
|
||||
device_client_.usb_service()->RemoveDevice(device0_);
|
||||
device_client_.usb_service()->RemoveDevice(device1_);
|
||||
|
||||
// Wait until HidDeviceManager::GetDevicesCallback is run. HidService
|
||||
// won't send notifications to its observers before that.
|
||||
base::RunLoop().RunUntilIdle();
|
||||
device_client_.hid_service()->RemoveDevice(device4_->platform_device_id());
|
||||
device_client_.hid_service()->RemoveDevice(device5_->platform_device_id());
|
||||
manager->RemoveEntryByHidDeviceGUID(device4_->device_guid());
|
||||
manager->RemoveEntryByHidDeviceGUID(device5_->device_guid());
|
||||
|
||||
// Device 0 will be accessible when it is reconnected because it can be
|
||||
// recognized by its serial number.
|
||||
|
@ -77,6 +77,7 @@
|
||||
"device": [
|
||||
"device:battery_monitor",
|
||||
"device:generic_sensor",
|
||||
"device:hid",
|
||||
"device:nfc",
|
||||
"device:serial",
|
||||
"device:vibration",
|
||||
|
@ -11,6 +11,8 @@ source_set("hid") {
|
||||
"hid_collection_info.h",
|
||||
"hid_connection.cc",
|
||||
"hid_connection.h",
|
||||
"hid_connection_impl.cc",
|
||||
"hid_connection_impl.h",
|
||||
"hid_connection_linux.cc",
|
||||
"hid_connection_linux.h",
|
||||
"hid_connection_mac.cc",
|
||||
@ -21,6 +23,8 @@ source_set("hid") {
|
||||
"hid_device_filter.h",
|
||||
"hid_device_info.cc",
|
||||
"hid_device_info.h",
|
||||
"hid_manager_impl.cc",
|
||||
"hid_manager_impl.h",
|
||||
"hid_report_descriptor.cc",
|
||||
"hid_report_descriptor.h",
|
||||
"hid_report_descriptor_item.cc",
|
||||
|
113
device/hid/hid_connection_impl.cc
Normal file
113
device/hid/hid_connection_impl.cc
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#include "device/hid/hid_connection_impl.h"
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
|
||||
namespace device {
|
||||
|
||||
HidConnectionImpl::HidConnectionImpl(
|
||||
scoped_refptr<device::HidConnection> connection)
|
||||
: hid_connection_(std::move(connection)), weak_factory_(this) {}
|
||||
|
||||
HidConnectionImpl::~HidConnectionImpl() {
|
||||
DCHECK(hid_connection_);
|
||||
|
||||
// Close |hid_connection_| on destruction because this class is owned by a
|
||||
// mojo::StrongBinding and will be destroyed when the pipe is closed.
|
||||
hid_connection_->Close();
|
||||
}
|
||||
|
||||
void HidConnectionImpl::Read(ReadCallback callback) {
|
||||
DCHECK(hid_connection_);
|
||||
hid_connection_->Read(base::BindOnce(&HidConnectionImpl::OnRead,
|
||||
weak_factory_.GetWeakPtr(),
|
||||
std::move(callback)));
|
||||
}
|
||||
|
||||
void HidConnectionImpl::OnRead(ReadCallback callback,
|
||||
bool success,
|
||||
scoped_refptr<net::IOBuffer> buffer,
|
||||
size_t size) {
|
||||
if (!success) {
|
||||
std::move(callback).Run(false, 0, base::nullopt);
|
||||
return;
|
||||
}
|
||||
DCHECK(buffer);
|
||||
|
||||
std::vector<uint8_t> data(buffer->data() + 1, buffer->data() + size);
|
||||
std::move(callback).Run(true, buffer->data()[0], data);
|
||||
}
|
||||
|
||||
void HidConnectionImpl::Write(uint8_t report_id,
|
||||
const std::vector<uint8_t>& buffer,
|
||||
WriteCallback callback) {
|
||||
DCHECK(hid_connection_);
|
||||
|
||||
auto io_buffer =
|
||||
base::MakeRefCounted<net::IOBufferWithSize>(buffer.size() + 1);
|
||||
io_buffer->data()[0] = report_id;
|
||||
|
||||
const char* data = reinterpret_cast<const char*>(buffer.data());
|
||||
memcpy(io_buffer->data() + 1, data, buffer.size());
|
||||
|
||||
hid_connection_->Write(
|
||||
io_buffer, io_buffer->size(),
|
||||
base::BindOnce(&HidConnectionImpl::OnWrite, weak_factory_.GetWeakPtr(),
|
||||
std::move(callback)));
|
||||
}
|
||||
|
||||
void HidConnectionImpl::OnWrite(WriteCallback callback, bool success) {
|
||||
std::move(callback).Run(success);
|
||||
}
|
||||
|
||||
void HidConnectionImpl::GetFeatureReport(uint8_t report_id,
|
||||
GetFeatureReportCallback callback) {
|
||||
DCHECK(hid_connection_);
|
||||
hid_connection_->GetFeatureReport(
|
||||
report_id,
|
||||
base::BindOnce(&HidConnectionImpl::OnGetFeatureReport,
|
||||
weak_factory_.GetWeakPtr(), std::move(callback)));
|
||||
}
|
||||
|
||||
void HidConnectionImpl::OnGetFeatureReport(GetFeatureReportCallback callback,
|
||||
bool success,
|
||||
scoped_refptr<net::IOBuffer> buffer,
|
||||
size_t size) {
|
||||
if (!success) {
|
||||
std::move(callback).Run(false, base::nullopt);
|
||||
return;
|
||||
}
|
||||
DCHECK(buffer);
|
||||
|
||||
std::vector<uint8_t> data(buffer->data(), buffer->data() + size);
|
||||
std::move(callback).Run(true, data);
|
||||
}
|
||||
|
||||
void HidConnectionImpl::SendFeatureReport(uint8_t report_id,
|
||||
const std::vector<uint8_t>& buffer,
|
||||
SendFeatureReportCallback callback) {
|
||||
DCHECK(hid_connection_);
|
||||
|
||||
auto io_buffer =
|
||||
base::MakeRefCounted<net::IOBufferWithSize>(buffer.size() + 1);
|
||||
io_buffer->data()[0] = report_id;
|
||||
|
||||
const char* data = reinterpret_cast<const char*>(buffer.data());
|
||||
memcpy(io_buffer->data() + 1, data, buffer.size());
|
||||
|
||||
hid_connection_->SendFeatureReport(
|
||||
io_buffer, io_buffer->size(),
|
||||
base::BindOnce(&HidConnectionImpl::OnSendFeatureReport,
|
||||
weak_factory_.GetWeakPtr(), std::move(callback)));
|
||||
}
|
||||
|
||||
void HidConnectionImpl::OnSendFeatureReport(SendFeatureReportCallback callback,
|
||||
bool success) {
|
||||
std::move(callback).Run(success);
|
||||
}
|
||||
|
||||
} // namespace device
|
54
device/hid/hid_connection_impl.h
Normal file
54
device/hid/hid_connection_impl.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#ifndef DEVICE_HID_HID_CONNECTION_IMPL_H_
|
||||
#define DEVICE_HID_HID_CONNECTION_IMPL_H_
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "device/hid/hid_connection.h"
|
||||
#include "device/hid/public/interfaces/hid.mojom.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
|
||||
namespace device {
|
||||
|
||||
// HidConnectionImpl is reponsible for handling mojo communications from
|
||||
// clients. It delegates to HidConnection the real work of creating
|
||||
// connections in different platforms.
|
||||
class HidConnectionImpl : public device::mojom::HidConnection {
|
||||
public:
|
||||
explicit HidConnectionImpl(scoped_refptr<device::HidConnection> connection);
|
||||
~HidConnectionImpl() final;
|
||||
|
||||
// device::mojom::HidConnection implementation:
|
||||
void Read(ReadCallback callback) override;
|
||||
void Write(uint8_t report_id,
|
||||
const std::vector<uint8_t>& buffer,
|
||||
WriteCallback callback) override;
|
||||
void GetFeatureReport(uint8_t report_id,
|
||||
GetFeatureReportCallback callback) override;
|
||||
void SendFeatureReport(uint8_t report_id,
|
||||
const std::vector<uint8_t>& buffer,
|
||||
SendFeatureReportCallback callback) override;
|
||||
|
||||
private:
|
||||
void OnRead(ReadCallback callback,
|
||||
bool success,
|
||||
scoped_refptr<net::IOBuffer> buffer,
|
||||
size_t size);
|
||||
void OnWrite(WriteCallback callback, bool success);
|
||||
void OnGetFeatureReport(GetFeatureReportCallback callback,
|
||||
bool success,
|
||||
scoped_refptr<net::IOBuffer> buffer,
|
||||
size_t size);
|
||||
void OnSendFeatureReport(SendFeatureReportCallback callback, bool success);
|
||||
|
||||
scoped_refptr<device::HidConnection> hid_connection_;
|
||||
base::WeakPtrFactory<HidConnectionImpl> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(HidConnectionImpl);
|
||||
};
|
||||
|
||||
} // namespace device
|
||||
|
||||
#endif // DEVICE_HID_HID_CONNECTION_IMPL_H_
|
101
device/hid/hid_manager_impl.cc
Normal file
101
device/hid/hid_manager_impl.cc
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#include "device/hid/hid_manager_impl.h"
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/callback_helpers.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "device/base/device_client.h"
|
||||
#include "device/hid/hid_connection_impl.h"
|
||||
#include "mojo/public/cpp/bindings/strong_binding.h"
|
||||
|
||||
namespace device {
|
||||
|
||||
HidManagerImpl::HidManagerImpl()
|
||||
// TODO(ke.he@intel.com): Temporarily we still keep the HidService being
|
||||
// owned and hosted in ChromeDeviceClient. The device service is shutdown
|
||||
// earlier than ChromeDeviceClient, it is safe to hold a raw pointer of
|
||||
// HidService here. After //device/u2f be mojofied or be moved into device
|
||||
// service, we will remove HidService from the ChromeDeviceClient and let
|
||||
// HidManagerImpl to own the HidService.
|
||||
: hid_service_(DeviceClient::Get()->GetHidService()),
|
||||
hid_service_observer_(this),
|
||||
weak_factory_(this) {
|
||||
DCHECK(hid_service_);
|
||||
hid_service_observer_.Add(hid_service_);
|
||||
}
|
||||
|
||||
HidManagerImpl::~HidManagerImpl() {}
|
||||
|
||||
void HidManagerImpl::AddBinding(device::mojom::HidManagerRequest request) {
|
||||
bindings_.AddBinding(this, std::move(request));
|
||||
}
|
||||
|
||||
void HidManagerImpl::GetDevicesAndSetClient(
|
||||
device::mojom::HidManagerClientAssociatedPtrInfo client,
|
||||
GetDevicesCallback callback) {
|
||||
hid_service_->GetDevices(AdaptCallbackForRepeating(base::BindOnce(
|
||||
&HidManagerImpl::CreateDeviceList, weak_factory_.GetWeakPtr(),
|
||||
std::move(callback), std::move(client))));
|
||||
}
|
||||
|
||||
void HidManagerImpl::GetDevices(GetDevicesCallback callback) {
|
||||
hid_service_->GetDevices(AdaptCallbackForRepeating(base::BindOnce(
|
||||
&HidManagerImpl::CreateDeviceList, weak_factory_.GetWeakPtr(),
|
||||
std::move(callback), nullptr)));
|
||||
}
|
||||
|
||||
void HidManagerImpl::CreateDeviceList(
|
||||
GetDevicesCallback callback,
|
||||
device::mojom::HidManagerClientAssociatedPtrInfo client,
|
||||
std::vector<device::mojom::HidDeviceInfoPtr> devices) {
|
||||
std::move(callback).Run(std::move(devices));
|
||||
|
||||
if (!client.is_valid())
|
||||
return;
|
||||
|
||||
device::mojom::HidManagerClientAssociatedPtr client_ptr;
|
||||
client_ptr.Bind(std::move(client));
|
||||
clients_.AddPtr(std::move(client_ptr));
|
||||
}
|
||||
|
||||
void HidManagerImpl::Connect(const std::string& device_guid,
|
||||
ConnectCallback callback) {
|
||||
hid_service_->Connect(device_guid,
|
||||
AdaptCallbackForRepeating(base::BindOnce(
|
||||
&HidManagerImpl::CreateConnection,
|
||||
weak_factory_.GetWeakPtr(), std::move(callback))));
|
||||
}
|
||||
|
||||
void HidManagerImpl::CreateConnection(
|
||||
ConnectCallback callback,
|
||||
scoped_refptr<device::HidConnection> connection) {
|
||||
if (!connection) {
|
||||
std::move(callback).Run(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
device::mojom::HidConnectionPtr client;
|
||||
mojo::MakeStrongBinding(base::MakeUnique<HidConnectionImpl>(connection),
|
||||
mojo::MakeRequest(&client));
|
||||
std::move(callback).Run(std::move(client));
|
||||
}
|
||||
|
||||
void HidManagerImpl::OnDeviceAdded(device::mojom::HidDeviceInfoPtr device) {
|
||||
device::mojom::HidDeviceInfo* device_info = device.get();
|
||||
clients_.ForAllPtrs([device_info](device::mojom::HidManagerClient* client) {
|
||||
client->DeviceAdded(device_info->Clone());
|
||||
});
|
||||
}
|
||||
|
||||
void HidManagerImpl::OnDeviceRemoved(device::mojom::HidDeviceInfoPtr device) {
|
||||
device::mojom::HidDeviceInfo* device_info = device.get();
|
||||
clients_.ForAllPtrs([device_info](device::mojom::HidManagerClient* client) {
|
||||
client->DeviceRemoved(device_info->Clone());
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace device
|
63
device/hid/hid_manager_impl.h
Normal file
63
device/hid/hid_manager_impl.h
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#ifndef DEVICE_HID_HID_MANAGER_IMPL_H_
|
||||
#define DEVICE_HID_HID_MANAGER_IMPL_H_
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/scoped_observer.h"
|
||||
#include "device/hid/hid_device_info.h"
|
||||
#include "device/hid/hid_service.h"
|
||||
#include "device/hid/public/interfaces/hid.mojom.h"
|
||||
#include "mojo/public/cpp/bindings/binding_set.h"
|
||||
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
|
||||
|
||||
namespace device {
|
||||
|
||||
// HidManagerImpl is owned by Device Service. It is reponsible for handling mojo
|
||||
// communications from clients. It delegates to HidService the real work of
|
||||
// talking with different platforms.
|
||||
class HidManagerImpl : public device::mojom::HidManager,
|
||||
public device::HidService::Observer {
|
||||
public:
|
||||
HidManagerImpl();
|
||||
~HidManagerImpl() override;
|
||||
|
||||
void AddBinding(device::mojom::HidManagerRequest request);
|
||||
|
||||
// device::mojom::HidManager implementation:
|
||||
void GetDevicesAndSetClient(
|
||||
device::mojom::HidManagerClientAssociatedPtrInfo client,
|
||||
GetDevicesCallback callback) override;
|
||||
void GetDevices(GetDevicesCallback callback) override;
|
||||
void Connect(const std::string& device_guid,
|
||||
ConnectCallback callback) override;
|
||||
|
||||
private:
|
||||
void CreateDeviceList(GetDevicesCallback callback,
|
||||
device::mojom::HidManagerClientAssociatedPtrInfo client,
|
||||
std::vector<device::mojom::HidDeviceInfoPtr> devices);
|
||||
|
||||
void CreateConnection(ConnectCallback callback,
|
||||
scoped_refptr<HidConnection> connection);
|
||||
|
||||
// HidService::Observer:
|
||||
void OnDeviceAdded(device::mojom::HidDeviceInfoPtr device_info) override;
|
||||
void OnDeviceRemoved(device::mojom::HidDeviceInfoPtr device_info) override;
|
||||
|
||||
HidService* hid_service_;
|
||||
mojo::BindingSet<device::mojom::HidManager> bindings_;
|
||||
mojo::AssociatedInterfacePtrSet<device::mojom::HidManagerClient> clients_;
|
||||
ScopedObserver<device::HidService, device::HidService::Observer>
|
||||
hid_service_observer_;
|
||||
|
||||
base::WeakPtrFactory<HidManagerImpl> weak_factory_;
|
||||
DISALLOW_COPY_AND_ASSIGN(HidManagerImpl);
|
||||
};
|
||||
|
||||
} // namespace device
|
||||
|
||||
#endif // DEVICE_HID_HID_MANAGER_IMPL_H_
|
@ -34,9 +34,6 @@ class HidService {
|
||||
// GetDevicesCallback. Earlier might cause OnDeviceAdded() and
|
||||
// OnDeviceRemoved() to be called before the GetDevicesCallback, while later
|
||||
// might cause missing OnDeviceAdded() and OnDeviceRemoved() notifications.
|
||||
// TODO(ke.he@intel.com): In the mojofication of HidService, clients should
|
||||
// pass an mojom::ObserverPtr in the GetDevices() interface, HidService adds
|
||||
// the observer immediately after calling the GetDevicesCallback.
|
||||
class Observer {
|
||||
public:
|
||||
virtual void OnDeviceAdded(device::mojom::HidDeviceInfoPtr info);
|
||||
|
@ -120,12 +120,12 @@ struct HidUsageAndPage {
|
||||
};
|
||||
|
||||
HidUsageAndPage() {}
|
||||
HidUsageAndPage(uint16_t usage, Page usage_page)
|
||||
HidUsageAndPage(uint16_t usage, uint16_t usage_page)
|
||||
: usage(usage), usage_page(usage_page) {}
|
||||
~HidUsageAndPage() {}
|
||||
|
||||
uint16_t usage;
|
||||
Page usage_page;
|
||||
uint16_t usage_page;
|
||||
|
||||
// Indicates whether this usage is protected by Chrome.
|
||||
bool IsProtected() const;
|
||||
|
@ -9,45 +9,9 @@ enum HidBusType {
|
||||
kHIDBusTypeBluetooth = 1,
|
||||
};
|
||||
|
||||
enum HidPage {
|
||||
PageUndefined = 0x00,
|
||||
PageGenericDesktop = 0x01,
|
||||
PageSimulation = 0x02,
|
||||
PageVirtualReality = 0x03,
|
||||
PageSport = 0x04,
|
||||
PageGame = 0x05,
|
||||
PageKeyboard = 0x07,
|
||||
PageLed = 0x08,
|
||||
PageButton = 0x09,
|
||||
PageOrdinal = 0x0A,
|
||||
PageTelephony = 0x0B,
|
||||
PageConsumer = 0x0C,
|
||||
PageDigitizer = 0x0D,
|
||||
PagePidPage = 0x0F,
|
||||
PageUnicode = 0x10,
|
||||
PageAlphanumericDisplay = 0x14,
|
||||
PageMedicalInstruments = 0x40,
|
||||
PageMonitor0 = 0x80,
|
||||
PageMonitor1 = 0x81,
|
||||
PageMonitor2 = 0x82,
|
||||
PageMonitor3 = 0x83,
|
||||
PagePower0 = 0x84,
|
||||
PagePower1 = 0x85,
|
||||
PagePower2 = 0x86,
|
||||
PagePower3 = 0x87,
|
||||
PageBarCodeScanner = 0x8C,
|
||||
PageScale = 0x8D,
|
||||
PageMagneticStripeReader = 0x8E,
|
||||
PageReservedPointOfSale = 0x8F,
|
||||
PageCameraControl = 0x90,
|
||||
PageArcade = 0x91,
|
||||
PageVendor = 0xFF00,
|
||||
PageMediaCenter = 0xFFBC
|
||||
};
|
||||
|
||||
struct HidUsageAndPage {
|
||||
uint16 usage;
|
||||
HidPage usage_page;
|
||||
uint16 usage_page;
|
||||
};
|
||||
|
||||
struct HidCollectionInfo {
|
||||
@ -70,3 +34,43 @@ struct HidDeviceInfo {
|
||||
uint64 max_feature_report_size;
|
||||
string device_node;
|
||||
};
|
||||
|
||||
interface HidManagerClient{
|
||||
// Notifies the client that a device is added.
|
||||
DeviceAdded(HidDeviceInfo device_info);
|
||||
|
||||
// Notifies the client that a device is being removed, called before
|
||||
// removing the device from HidService.
|
||||
DeviceRemoved(HidDeviceInfo device_info);
|
||||
};
|
||||
|
||||
interface HidManager {
|
||||
// Enumerates available devices and set as a client of HidManager.
|
||||
// The implementation of HidManager guarantees that the returned callback
|
||||
// will always be posted earlier than DeviceAdded() and DeviceRemoved().
|
||||
GetDevicesAndSetClient(associated HidManagerClient client) =>
|
||||
(array<HidDeviceInfo> devices);
|
||||
|
||||
// Enumerates available devices only.
|
||||
GetDevices() => (array<HidDeviceInfo> devices);
|
||||
|
||||
// Opens a connection to a device by given guid. The callback will be run
|
||||
// with null on failure.
|
||||
Connect(string device_guid) => (HidConnection? connection);
|
||||
};
|
||||
|
||||
interface HidConnection {
|
||||
// The report_id is returned as 0 if not supported by the device.
|
||||
Read() => (bool success, uint8 report_id, array<uint8>? buffer);
|
||||
|
||||
// Pass the report_id as 0 if not supported by the device.
|
||||
Write(uint8 report_id, array<uint8> buffer) => (bool success);
|
||||
|
||||
// The buffer will contain whatever report data was received from the device.
|
||||
// This may include the report ID. The report ID is not stripped because a
|
||||
// device may respond with other data in place of the report ID.
|
||||
GetFeatureReport(uint8 report_id) => (bool success, array<uint8>? buffer);
|
||||
|
||||
// Pass the report_id as 0 if not supported by the device.
|
||||
SendFeatureReport(uint8 report_id, array<uint8> buffer) => (bool success);
|
||||
};
|
||||
|
@ -6,202 +6,13 @@
|
||||
|
||||
namespace mojo {
|
||||
|
||||
// static
|
||||
device::mojom::HidPage
|
||||
EnumTraits<device::mojom::HidPage, device::HidUsageAndPage::Page>::ToMojom(
|
||||
device::HidUsageAndPage::Page input) {
|
||||
switch (input) {
|
||||
case device::HidUsageAndPage::Page::kPageUndefined:
|
||||
return device::mojom::HidPage::PageUndefined;
|
||||
case device::HidUsageAndPage::Page::kPageGenericDesktop:
|
||||
return device::mojom::HidPage::PageGenericDesktop;
|
||||
case device::HidUsageAndPage::Page::kPageSimulation:
|
||||
return device::mojom::HidPage::PageSimulation;
|
||||
case device::HidUsageAndPage::Page::kPageVirtualReality:
|
||||
return device::mojom::HidPage::PageVirtualReality;
|
||||
case device::HidUsageAndPage::Page::kPageSport:
|
||||
return device::mojom::HidPage::PageSport;
|
||||
case device::HidUsageAndPage::Page::kPageGame:
|
||||
return device::mojom::HidPage::PageGame;
|
||||
case device::HidUsageAndPage::Page::kPageKeyboard:
|
||||
return device::mojom::HidPage::PageKeyboard;
|
||||
case device::HidUsageAndPage::Page::kPageLed:
|
||||
return device::mojom::HidPage::PageLed;
|
||||
case device::HidUsageAndPage::Page::kPageButton:
|
||||
return device::mojom::HidPage::PageButton;
|
||||
case device::HidUsageAndPage::Page::kPageOrdinal:
|
||||
return device::mojom::HidPage::PageOrdinal;
|
||||
case device::HidUsageAndPage::Page::kPageTelephony:
|
||||
return device::mojom::HidPage::PageTelephony;
|
||||
case device::HidUsageAndPage::Page::kPageConsumer:
|
||||
return device::mojom::HidPage::PageConsumer;
|
||||
case device::HidUsageAndPage::Page::kPageDigitizer:
|
||||
return device::mojom::HidPage::PageDigitizer;
|
||||
case device::HidUsageAndPage::Page::kPagePidPage:
|
||||
return device::mojom::HidPage::PagePidPage;
|
||||
case device::HidUsageAndPage::Page::kPageUnicode:
|
||||
return device::mojom::HidPage::PageUnicode;
|
||||
case device::HidUsageAndPage::Page::kPageAlphanumericDisplay:
|
||||
return device::mojom::HidPage::PageAlphanumericDisplay;
|
||||
case device::HidUsageAndPage::Page::kPageMedicalInstruments:
|
||||
return device::mojom::HidPage::PageMedicalInstruments;
|
||||
case device::HidUsageAndPage::Page::kPageMonitor0:
|
||||
return device::mojom::HidPage::PageMonitor0;
|
||||
case device::HidUsageAndPage::Page::kPageMonitor1:
|
||||
return device::mojom::HidPage::PageMonitor1;
|
||||
case device::HidUsageAndPage::Page::kPageMonitor2:
|
||||
return device::mojom::HidPage::PageMonitor2;
|
||||
case device::HidUsageAndPage::Page::kPageMonitor3:
|
||||
return device::mojom::HidPage::PageMonitor3;
|
||||
case device::HidUsageAndPage::Page::kPagePower0:
|
||||
return device::mojom::HidPage::PagePower0;
|
||||
case device::HidUsageAndPage::Page::kPagePower1:
|
||||
return device::mojom::HidPage::PagePower1;
|
||||
case device::HidUsageAndPage::Page::kPagePower2:
|
||||
return device::mojom::HidPage::PagePower2;
|
||||
case device::HidUsageAndPage::Page::kPagePower3:
|
||||
return device::mojom::HidPage::PagePower3;
|
||||
case device::HidUsageAndPage::Page::kPageBarCodeScanner:
|
||||
return device::mojom::HidPage::PageBarCodeScanner;
|
||||
case device::HidUsageAndPage::Page::kPageScale:
|
||||
return device::mojom::HidPage::PageScale;
|
||||
case device::HidUsageAndPage::Page::kPageMagneticStripeReader:
|
||||
return device::mojom::HidPage::PageMagneticStripeReader;
|
||||
case device::HidUsageAndPage::Page::kPageReservedPointOfSale:
|
||||
return device::mojom::HidPage::PageReservedPointOfSale;
|
||||
case device::HidUsageAndPage::Page::kPageCameraControl:
|
||||
return device::mojom::HidPage::PageCameraControl;
|
||||
case device::HidUsageAndPage::Page::kPageArcade:
|
||||
return device::mojom::HidPage::PageArcade;
|
||||
case device::HidUsageAndPage::Page::kPageVendor:
|
||||
return device::mojom::HidPage::PageVendor;
|
||||
case device::HidUsageAndPage::Page::kPageMediaCenter:
|
||||
return device::mojom::HidPage::PageMediaCenter;
|
||||
}
|
||||
|
||||
NOTREACHED();
|
||||
return device::mojom::HidPage::PageUndefined;
|
||||
}
|
||||
|
||||
// static
|
||||
bool EnumTraits<device::mojom::HidPage, device::HidUsageAndPage::Page>::
|
||||
FromMojom(device::mojom::HidPage input,
|
||||
device::HidUsageAndPage::Page* output) {
|
||||
switch (input) {
|
||||
case device::mojom::HidPage::PageUndefined:
|
||||
*output = device::HidUsageAndPage::Page::kPageUndefined;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageGenericDesktop:
|
||||
*output = device::HidUsageAndPage::Page::kPageGenericDesktop;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageSimulation:
|
||||
*output = device::HidUsageAndPage::Page::kPageSimulation;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageVirtualReality:
|
||||
*output = device::HidUsageAndPage::Page::kPageVirtualReality;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageSport:
|
||||
*output = device::HidUsageAndPage::Page::kPageSport;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageGame:
|
||||
*output = device::HidUsageAndPage::Page::kPageGame;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageKeyboard:
|
||||
*output = device::HidUsageAndPage::Page::kPageKeyboard;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageLed:
|
||||
*output = device::HidUsageAndPage::Page::kPageLed;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageButton:
|
||||
*output = device::HidUsageAndPage::Page::kPageButton;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageOrdinal:
|
||||
*output = device::HidUsageAndPage::Page::kPageOrdinal;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageTelephony:
|
||||
*output = device::HidUsageAndPage::Page::kPageTelephony;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageConsumer:
|
||||
*output = device::HidUsageAndPage::Page::kPageConsumer;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageDigitizer:
|
||||
*output = device::HidUsageAndPage::Page::kPageDigitizer;
|
||||
return true;
|
||||
case device::mojom::HidPage::PagePidPage:
|
||||
*output = device::HidUsageAndPage::Page::kPagePidPage;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageUnicode:
|
||||
*output = device::HidUsageAndPage::Page::kPageUnicode;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageAlphanumericDisplay:
|
||||
*output = device::HidUsageAndPage::Page::kPageAlphanumericDisplay;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageMedicalInstruments:
|
||||
*output = device::HidUsageAndPage::Page::kPageMedicalInstruments;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageMonitor0:
|
||||
*output = device::HidUsageAndPage::Page::kPageMonitor0;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageMonitor1:
|
||||
*output = device::HidUsageAndPage::Page::kPageMonitor1;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageMonitor2:
|
||||
*output = device::HidUsageAndPage::Page::kPageMonitor2;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageMonitor3:
|
||||
*output = device::HidUsageAndPage::Page::kPageMonitor3;
|
||||
return true;
|
||||
case device::mojom::HidPage::PagePower0:
|
||||
*output = device::HidUsageAndPage::Page::kPagePower0;
|
||||
return true;
|
||||
case device::mojom::HidPage::PagePower1:
|
||||
*output = device::HidUsageAndPage::Page::kPagePower1;
|
||||
return true;
|
||||
case device::mojom::HidPage::PagePower2:
|
||||
*output = device::HidUsageAndPage::Page::kPagePower2;
|
||||
return true;
|
||||
case device::mojom::HidPage::PagePower3:
|
||||
*output = device::HidUsageAndPage::Page::kPagePower3;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageBarCodeScanner:
|
||||
*output = device::HidUsageAndPage::Page::kPageBarCodeScanner;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageScale:
|
||||
*output = device::HidUsageAndPage::Page::kPageScale;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageMagneticStripeReader:
|
||||
*output = device::HidUsageAndPage::Page::kPageMagneticStripeReader;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageReservedPointOfSale:
|
||||
*output = device::HidUsageAndPage::Page::kPageReservedPointOfSale;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageCameraControl:
|
||||
*output = device::HidUsageAndPage::Page::kPageCameraControl;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageArcade:
|
||||
*output = device::HidUsageAndPage::Page::kPageArcade;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageVendor:
|
||||
*output = device::HidUsageAndPage::Page::kPageVendor;
|
||||
return true;
|
||||
case device::mojom::HidPage::PageMediaCenter:
|
||||
*output = device::HidUsageAndPage::Page::kPageMediaCenter;
|
||||
return true;
|
||||
}
|
||||
|
||||
NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool StructTraits<
|
||||
device::mojom::HidUsageAndPageDataView,
|
||||
device::HidUsageAndPage>::Read(device::mojom::HidUsageAndPageDataView data,
|
||||
device::HidUsageAndPage* out) {
|
||||
out->usage = data.usage();
|
||||
|
||||
if (!data.ReadUsagePage(&out->usage_page))
|
||||
return false;
|
||||
out->usage_page = data.usage_page();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -15,19 +15,11 @@
|
||||
|
||||
namespace mojo {
|
||||
|
||||
template <>
|
||||
struct EnumTraits<device::mojom::HidPage, device::HidUsageAndPage::Page> {
|
||||
static device::mojom::HidPage ToMojom(device::HidUsageAndPage::Page input);
|
||||
static bool FromMojom(device::mojom::HidPage input,
|
||||
device::HidUsageAndPage::Page* output);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct StructTraits<device::mojom::HidUsageAndPageDataView,
|
||||
device::HidUsageAndPage> {
|
||||
static uint16_t usage(const device::HidUsageAndPage& r) { return r.usage; }
|
||||
static const device::HidUsageAndPage::Page& usage_page(
|
||||
const device::HidUsageAndPage& r) {
|
||||
static uint16_t usage_page(const device::HidUsageAndPage& r) {
|
||||
return r.usage_page;
|
||||
}
|
||||
static bool Read(device::mojom::HidUsageAndPageDataView data,
|
||||
|
@ -366,6 +366,7 @@ source_set("browser_sources") {
|
||||
"//extensions/strings",
|
||||
"//google_apis",
|
||||
"//ppapi/features",
|
||||
"//services/device/public/interfaces",
|
||||
"//services/preferences/public/cpp",
|
||||
"//services/service_manager/public/cpp",
|
||||
"//ui/display",
|
||||
@ -433,7 +434,7 @@ source_set("browser_tests") {
|
||||
"//content/test:test_support",
|
||||
"//device/base:mocks",
|
||||
"//device/bluetooth:mocks",
|
||||
"//device/hid:mocks",
|
||||
"//device/hid",
|
||||
"//device/usb:test_support",
|
||||
"//extensions:test_support",
|
||||
"//extensions/common",
|
||||
@ -441,6 +442,8 @@ source_set("browser_tests") {
|
||||
"//extensions/shell:app_shell_lib",
|
||||
"//extensions/shell:browser_tests",
|
||||
"//net:test_support",
|
||||
"//services/device/public/interfaces",
|
||||
"//services/service_manager/public/cpp",
|
||||
]
|
||||
|
||||
if (is_mac) {
|
||||
|
@ -12,9 +12,10 @@
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/common/service_manager_connection.h"
|
||||
#include "device/base/device_client.h"
|
||||
#include "device/hid/hid_device_filter.h"
|
||||
#include "device/hid/hid_service.h"
|
||||
#include "device/hid/public/interfaces/hid.mojom.h"
|
||||
#include "device/usb/public/cpp/filter_utils.h"
|
||||
#include "device/usb/usb_device.h"
|
||||
@ -22,6 +23,10 @@
|
||||
#include "device/usb/usb_service.h"
|
||||
#include "extensions/browser/api/device_permissions_manager.h"
|
||||
#include "extensions/common/extension.h"
|
||||
#include "mojo/public/cpp/bindings/associated_binding.h"
|
||||
#include "mojo/public/cpp/bindings/interface_request.h"
|
||||
#include "services/device/public/interfaces/constants.mojom.h"
|
||||
#include "services/service_manager/public/cpp/connector.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
||||
#if defined(OS_CHROMEOS)
|
||||
@ -30,7 +35,6 @@
|
||||
#endif // defined(OS_CHROMEOS)
|
||||
|
||||
using device::HidDeviceFilter;
|
||||
using device::HidService;
|
||||
using device::UsbDevice;
|
||||
using device::mojom::UsbDeviceFilterPtr;
|
||||
using device::UsbService;
|
||||
@ -176,7 +180,7 @@ class HidDeviceInfo : public DevicePermissionsPrompt::Prompt::DeviceInfo {
|
||||
};
|
||||
|
||||
class HidDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
|
||||
public device::HidService::Observer {
|
||||
public device::mojom::HidManagerClient {
|
||||
public:
|
||||
HidDevicePermissionsPrompt(
|
||||
const Extension* extension,
|
||||
@ -185,9 +189,10 @@ class HidDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
|
||||
const std::vector<HidDeviceFilter>& filters,
|
||||
const DevicePermissionsPrompt::HidDevicesCallback& callback)
|
||||
: Prompt(extension, context, multiple),
|
||||
initialized_(false),
|
||||
filters_(filters),
|
||||
callback_(callback),
|
||||
service_observer_(this) {}
|
||||
binding_(this) {}
|
||||
|
||||
private:
|
||||
~HidDevicePermissionsPrompt() override {}
|
||||
@ -197,13 +202,31 @@ class HidDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
|
||||
DevicePermissionsPrompt::Prompt::Observer* observer) override {
|
||||
DevicePermissionsPrompt::Prompt::SetObserver(observer);
|
||||
|
||||
if (observer) {
|
||||
HidService* service = device::DeviceClient::Get()->GetHidService();
|
||||
if (service && !service_observer_.IsObserving(service)) {
|
||||
service->GetDevices(base::Bind(
|
||||
&HidDevicePermissionsPrompt::OnDevicesEnumerated, this, service));
|
||||
}
|
||||
if (observer)
|
||||
LazyInitialize();
|
||||
}
|
||||
|
||||
void LazyInitialize() {
|
||||
if (initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
DCHECK(content::ServiceManagerConnection::GetForProcess());
|
||||
|
||||
service_manager::Connector* connector =
|
||||
content::ServiceManagerConnection::GetForProcess()->GetConnector();
|
||||
connector->BindInterface(device::mojom::kServiceName,
|
||||
mojo::MakeRequest(&hid_manager_));
|
||||
|
||||
device::mojom::HidManagerClientAssociatedPtrInfo client;
|
||||
binding_.Bind(mojo::MakeRequest(&client));
|
||||
|
||||
hid_manager_->GetDevicesAndSetClient(
|
||||
std::move(client),
|
||||
base::BindOnce(&HidDevicePermissionsPrompt::OnDevicesEnumerated, this));
|
||||
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
void Dismissed() override {
|
||||
@ -226,8 +249,8 @@ class HidDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
|
||||
callback_.Reset();
|
||||
}
|
||||
|
||||
// device::HidService::Observer implementation:
|
||||
void OnDeviceAdded(device::mojom::HidDeviceInfoPtr device) override {
|
||||
// device::mojom::HidManagerClient implementation:
|
||||
void DeviceAdded(device::mojom::HidDeviceInfoPtr device) override {
|
||||
if (HasUnprotectedCollections(*device) &&
|
||||
(filters_.empty() || HidDeviceFilter::MatchesAny(*device, filters_))) {
|
||||
auto device_info = base::MakeUnique<HidDeviceInfo>(std::move(device));
|
||||
@ -245,7 +268,7 @@ class HidDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
|
||||
}
|
||||
}
|
||||
|
||||
void OnDeviceRemoved(device::mojom::HidDeviceInfoPtr device) override {
|
||||
void DeviceRemoved(device::mojom::HidDeviceInfoPtr device) override {
|
||||
for (auto it = devices_.begin(); it != devices_.end(); ++it) {
|
||||
HidDeviceInfo* entry = static_cast<HidDeviceInfo*>((*it).get());
|
||||
if (entry->device()->guid == device->guid) {
|
||||
@ -260,12 +283,9 @@ class HidDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
|
||||
}
|
||||
|
||||
void OnDevicesEnumerated(
|
||||
HidService* service,
|
||||
std::vector<device::mojom::HidDeviceInfoPtr> devices) {
|
||||
for (auto& device : devices) {
|
||||
OnDeviceAdded(std::move(device));
|
||||
}
|
||||
service_observer_.Add(service);
|
||||
for (auto& device : devices)
|
||||
DeviceAdded(std::move(device));
|
||||
}
|
||||
|
||||
bool HasUnprotectedCollections(const device::mojom::HidDeviceInfo& device) {
|
||||
@ -277,9 +297,11 @@ class HidDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool initialized_;
|
||||
std::vector<HidDeviceFilter> filters_;
|
||||
device::mojom::HidManagerPtr hid_manager_;
|
||||
DevicePermissionsPrompt::HidDevicesCallback callback_;
|
||||
ScopedObserver<HidService, HidService::Observer> service_observer_;
|
||||
mojo::AssociatedBinding<device::mojom::HidManagerClient> binding_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -12,21 +12,16 @@
|
||||
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/values.h"
|
||||
#include "device/base/device_client.h"
|
||||
#include "device/hid/hid_connection.h"
|
||||
#include "device/hid/hid_device_filter.h"
|
||||
#include "device/hid/hid_service.h"
|
||||
#include "extensions/browser/api/api_resource_manager.h"
|
||||
#include "extensions/browser/api/device_permissions_prompt.h"
|
||||
#include "extensions/browser/api/extensions_api_client.h"
|
||||
#include "extensions/common/api/hid.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "extensions/utility/scoped_callback_runner.h"
|
||||
|
||||
namespace hid = extensions::api::hid;
|
||||
|
||||
using device::HidConnection;
|
||||
using device::HidDeviceFilter;
|
||||
using device::HidService;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -36,9 +31,7 @@ const char kErrorFailedToOpenDevice[] = "Failed to open HID device.";
|
||||
const char kErrorConnectionNotFound[] = "Connection not established.";
|
||||
const char kErrorTransfer[] = "Transfer failed.";
|
||||
|
||||
std::unique_ptr<base::Value> PopulateHidConnection(
|
||||
int connection_id,
|
||||
scoped_refptr<HidConnection> connection) {
|
||||
std::unique_ptr<base::Value> PopulateHidConnection(int connection_id) {
|
||||
hid::HidConnectInfo connection_value;
|
||||
connection_value.connection_id = connection_id;
|
||||
return connection_value.ToValue();
|
||||
@ -176,17 +169,14 @@ ExtensionFunction::ResponseAction HidConnectFunction::Run() {
|
||||
return RespondNow(Error(kErrorPermissionDenied));
|
||||
}
|
||||
|
||||
HidService* hid_service = device::DeviceClient::Get()->GetHidService();
|
||||
CHECK(hid_service);
|
||||
|
||||
hid_service->Connect(
|
||||
device_manager->Connect(
|
||||
device_info->guid,
|
||||
base::Bind(&HidConnectFunction::OnConnectComplete, this));
|
||||
base::BindOnce(&HidConnectFunction::OnConnectComplete, this));
|
||||
return RespondLater();
|
||||
}
|
||||
|
||||
void HidConnectFunction::OnConnectComplete(
|
||||
scoped_refptr<HidConnection> connection) {
|
||||
device::mojom::HidConnectionPtr connection) {
|
||||
if (!connection) {
|
||||
Respond(Error(kErrorFailedToOpenDevice));
|
||||
return;
|
||||
@ -194,8 +184,8 @@ void HidConnectFunction::OnConnectComplete(
|
||||
|
||||
DCHECK(connection_manager_);
|
||||
int connection_id = connection_manager_->Add(
|
||||
new HidConnectionResource(extension_id(), connection));
|
||||
Respond(OneArgument(PopulateHidConnection(connection_id, connection)));
|
||||
new HidConnectionResource(extension_id(), std::move(connection)));
|
||||
Respond(OneArgument(PopulateHidConnection(connection_id)));
|
||||
}
|
||||
|
||||
HidDisconnectFunction::HidDisconnectFunction() {}
|
||||
@ -241,7 +231,7 @@ ExtensionFunction::ResponseAction HidConnectionIoFunction::Run() {
|
||||
return RespondNow(Error(kErrorConnectionNotFound));
|
||||
}
|
||||
|
||||
StartWork(resource->connection().get());
|
||||
StartWork(resource->connection());
|
||||
return RespondLater();
|
||||
}
|
||||
|
||||
@ -257,20 +247,24 @@ bool HidReceiveFunction::ReadParameters() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void HidReceiveFunction::StartWork(HidConnection* connection) {
|
||||
connection->Read(base::Bind(&HidReceiveFunction::OnFinished, this));
|
||||
void HidReceiveFunction::StartWork(device::mojom::HidConnection* connection) {
|
||||
connection->Read(ScopedCallbackRunner(
|
||||
base::BindOnce(&HidReceiveFunction::OnFinished, this), false, 0,
|
||||
base::nullopt));
|
||||
}
|
||||
|
||||
void HidReceiveFunction::OnFinished(bool success,
|
||||
scoped_refptr<net::IOBuffer> buffer,
|
||||
size_t size) {
|
||||
void HidReceiveFunction::OnFinished(
|
||||
bool success,
|
||||
uint8_t report_id,
|
||||
const base::Optional<std::vector<uint8_t>>& buffer) {
|
||||
if (success) {
|
||||
DCHECK_GE(size, 1u);
|
||||
int report_id = reinterpret_cast<uint8_t*>(buffer->data())[0];
|
||||
DCHECK(buffer);
|
||||
DCHECK_GE(buffer->size(), 0u);
|
||||
|
||||
Respond(TwoArguments(
|
||||
std::make_unique<base::Value>(report_id),
|
||||
base::Value::CreateWithCopiedBuffer(buffer->data() + 1, size - 1)));
|
||||
base::Value::CreateWithCopiedBuffer(
|
||||
reinterpret_cast<const char*>(buffer->data()), buffer->size())));
|
||||
} else {
|
||||
Respond(Error(kErrorTransfer));
|
||||
}
|
||||
@ -288,14 +282,14 @@ bool HidSendFunction::ReadParameters() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void HidSendFunction::StartWork(HidConnection* connection) {
|
||||
scoped_refptr<net::IOBufferWithSize> buffer(
|
||||
new net::IOBufferWithSize(parameters_->data.size() + 1));
|
||||
buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
|
||||
memcpy(buffer->data() + 1, parameters_->data.data(),
|
||||
parameters_->data.size());
|
||||
connection->Write(buffer, buffer->size(),
|
||||
base::Bind(&HidSendFunction::OnFinished, this));
|
||||
void HidSendFunction::StartWork(device::mojom::HidConnection* connection) {
|
||||
auto* data = reinterpret_cast<const uint8_t*>(parameters_->data.data());
|
||||
std::vector<uint8_t> buffer(data, data + parameters_->data.size());
|
||||
|
||||
connection->Write(
|
||||
static_cast<uint8_t>(parameters_->report_id), buffer,
|
||||
ScopedCallbackRunner(base::BindOnce(&HidSendFunction::OnFinished, this),
|
||||
false));
|
||||
}
|
||||
|
||||
void HidSendFunction::OnFinished(bool success) {
|
||||
@ -318,19 +312,22 @@ bool HidReceiveFeatureReportFunction::ReadParameters() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void HidReceiveFeatureReportFunction::StartWork(HidConnection* connection) {
|
||||
void HidReceiveFeatureReportFunction::StartWork(
|
||||
device::mojom::HidConnection* connection) {
|
||||
connection->GetFeatureReport(
|
||||
static_cast<uint8_t>(parameters_->report_id),
|
||||
base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this));
|
||||
ScopedCallbackRunner(
|
||||
base::BindOnce(&HidReceiveFeatureReportFunction::OnFinished, this),
|
||||
false, base::nullopt));
|
||||
}
|
||||
|
||||
void HidReceiveFeatureReportFunction::OnFinished(
|
||||
bool success,
|
||||
scoped_refptr<net::IOBuffer> buffer,
|
||||
size_t size) {
|
||||
const base::Optional<std::vector<uint8_t>>& buffer) {
|
||||
if (success) {
|
||||
Respond(
|
||||
OneArgument(base::Value::CreateWithCopiedBuffer(buffer->data(), size)));
|
||||
DCHECK(buffer);
|
||||
Respond(OneArgument(base::Value::CreateWithCopiedBuffer(
|
||||
reinterpret_cast<const char*>(buffer->data()), buffer->size())));
|
||||
} else {
|
||||
Respond(Error(kErrorTransfer));
|
||||
}
|
||||
@ -348,15 +345,16 @@ bool HidSendFeatureReportFunction::ReadParameters() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void HidSendFeatureReportFunction::StartWork(HidConnection* connection) {
|
||||
scoped_refptr<net::IOBufferWithSize> buffer(
|
||||
new net::IOBufferWithSize(parameters_->data.size() + 1));
|
||||
buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
|
||||
memcpy(buffer->data() + 1, parameters_->data.data(),
|
||||
parameters_->data.size());
|
||||
void HidSendFeatureReportFunction::StartWork(
|
||||
device::mojom::HidConnection* connection) {
|
||||
auto* data = reinterpret_cast<const uint8_t*>(parameters_->data.data());
|
||||
std::vector<uint8_t> buffer(data, data + parameters_->data.size());
|
||||
|
||||
connection->SendFeatureReport(
|
||||
buffer, buffer->size(),
|
||||
base::Bind(&HidSendFeatureReportFunction::OnFinished, this));
|
||||
static_cast<uint8_t>(parameters_->report_id), buffer,
|
||||
ScopedCallbackRunner(
|
||||
base::BindOnce(&HidSendFeatureReportFunction::OnFinished, this),
|
||||
false));
|
||||
}
|
||||
|
||||
void HidSendFeatureReportFunction::OnFinished(bool success) {
|
||||
|
@ -19,14 +19,6 @@
|
||||
#include "extensions/browser/extension_function.h"
|
||||
#include "extensions/common/api/hid.h"
|
||||
|
||||
namespace device {
|
||||
class HidConnection;
|
||||
} // namespace device
|
||||
|
||||
namespace net {
|
||||
class IOBuffer;
|
||||
} // namespace net
|
||||
|
||||
namespace extensions {
|
||||
|
||||
class DevicePermissionsPrompt;
|
||||
@ -80,7 +72,7 @@ class HidConnectFunction : public UIThreadExtensionFunction {
|
||||
// ExtensionFunction:
|
||||
ResponseAction Run() override;
|
||||
|
||||
void OnConnectComplete(scoped_refptr<device::HidConnection> connection);
|
||||
void OnConnectComplete(device::mojom::HidConnectionPtr connection);
|
||||
|
||||
ApiResourceManager<HidConnectionResource>* connection_manager_;
|
||||
|
||||
@ -113,7 +105,7 @@ class HidConnectionIoFunction : public UIThreadExtensionFunction {
|
||||
|
||||
// Returns true if params were successfully read from |args_|.
|
||||
virtual bool ReadParameters() = 0;
|
||||
virtual void StartWork(device::HidConnection* connection) = 0;
|
||||
virtual void StartWork(device::mojom::HidConnection* connection) = 0;
|
||||
|
||||
void set_connection_id(int connection_id) { connection_id_ = connection_id; }
|
||||
|
||||
@ -135,11 +127,11 @@ class HidReceiveFunction : public HidConnectionIoFunction {
|
||||
|
||||
// HidConnectionIoFunction:
|
||||
bool ReadParameters() override;
|
||||
void StartWork(device::HidConnection* connection) override;
|
||||
void StartWork(device::mojom::HidConnection* connection) override;
|
||||
|
||||
void OnFinished(bool success,
|
||||
scoped_refptr<net::IOBuffer> buffer,
|
||||
size_t size);
|
||||
uint8_t report_id,
|
||||
const base::Optional<std::vector<uint8_t>>& buffer);
|
||||
|
||||
std::unique_ptr<api::hid::Receive::Params> parameters_;
|
||||
|
||||
@ -157,7 +149,7 @@ class HidSendFunction : public HidConnectionIoFunction {
|
||||
|
||||
// HidConnectionIoFunction:
|
||||
bool ReadParameters() override;
|
||||
void StartWork(device::HidConnection* connection) override;
|
||||
void StartWork(device::mojom::HidConnection* connection) override;
|
||||
|
||||
void OnFinished(bool success);
|
||||
|
||||
@ -178,11 +170,10 @@ class HidReceiveFeatureReportFunction : public HidConnectionIoFunction {
|
||||
|
||||
// HidConnectionIoFunction:
|
||||
bool ReadParameters() override;
|
||||
void StartWork(device::HidConnection* connection) override;
|
||||
void StartWork(device::mojom::HidConnection* connection) override;
|
||||
|
||||
void OnFinished(bool success,
|
||||
scoped_refptr<net::IOBuffer> buffer,
|
||||
size_t size);
|
||||
const base::Optional<std::vector<uint8_t>>& buffer);
|
||||
|
||||
std::unique_ptr<api::hid::ReceiveFeatureReport::Params> parameters_;
|
||||
|
||||
@ -200,7 +191,7 @@ class HidSendFeatureReportFunction : public HidConnectionIoFunction {
|
||||
|
||||
// HidConnectionIoFunction:
|
||||
bool ReadParameters() override;
|
||||
void StartWork(device::HidConnection* connection) override;
|
||||
void StartWork(device::mojom::HidConnection* connection) override;
|
||||
|
||||
void OnFinished(bool success);
|
||||
|
||||
|
@ -11,27 +11,24 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "build/build_config.h"
|
||||
#include "device/base/mock_device_client.h"
|
||||
#include "device/hid/hid_collection_info.h"
|
||||
#include "device/hid/hid_connection.h"
|
||||
#include "device/hid/hid_device_info.h"
|
||||
#include "device/hid/hid_usage_and_page.h"
|
||||
#include "device/hid/mock_hid_service.h"
|
||||
#include "device/hid/public/interfaces/hid.mojom.h"
|
||||
#include "extensions/browser/api/device_permissions_prompt.h"
|
||||
#include "extensions/shell/browser/shell_extensions_api_client.h"
|
||||
#include "extensions/shell/test/shell_apitest.h"
|
||||
#include "extensions/test/extension_test_message_listener.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "mojo/public/cpp/bindings/binding_set.h"
|
||||
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
|
||||
#include "mojo/public/cpp/bindings/strong_binding.h"
|
||||
#include "services/device/public/interfaces/constants.mojom.h"
|
||||
#include "services/service_manager/public/cpp/service_context.h"
|
||||
|
||||
using base::ThreadTaskRunnerHandle;
|
||||
using device::HidCollectionInfo;
|
||||
using device::HidDeviceInfo;
|
||||
using device::HidPlatformDeviceId;
|
||||
using device::HidUsageAndPage;
|
||||
using device::MockDeviceClient;
|
||||
using net::IOBuffer;
|
||||
using testing::_;
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
const uint64_t kTestDeviceIds[] = {1, 2, 3, 4, 5};
|
||||
@ -54,75 +51,170 @@ const uint8_t kReportDescriptorWithIDs[] = {
|
||||
|
||||
namespace extensions {
|
||||
|
||||
class MockHidConnection : public device::HidConnection {
|
||||
class FakeHidConnectionImpl : public device::mojom::HidConnection {
|
||||
public:
|
||||
explicit MockHidConnection(scoped_refptr<HidDeviceInfo> device_info)
|
||||
: HidConnection(device_info) {}
|
||||
explicit FakeHidConnectionImpl(scoped_refptr<device::HidDeviceInfo> device)
|
||||
: device_(device) {}
|
||||
|
||||
void PlatformClose() override {}
|
||||
~FakeHidConnectionImpl() override = default;
|
||||
|
||||
void PlatformRead(ReadCallback callback) override {
|
||||
// device::mojom::HidConnection implemenation:
|
||||
void Read(device::mojom::HidConnection::ReadCallback callback) override {
|
||||
const char kResult[] = "This is a HID input report.";
|
||||
uint8_t report_id = device_info()->has_report_id() ? 1 : 0;
|
||||
scoped_refptr<IOBuffer> buffer(new IOBuffer(sizeof(kResult)));
|
||||
buffer->data()[0] = report_id;
|
||||
memcpy(buffer->data() + 1, kResult, sizeof(kResult) - 1);
|
||||
ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(std::move(callback), true, buffer, sizeof(kResult)));
|
||||
uint8_t report_id = device_->has_report_id() ? 1 : 0;
|
||||
|
||||
std::vector<uint8_t> buffer(kResult, kResult + sizeof(kResult) - 1);
|
||||
|
||||
std::move(callback).Run(true, report_id, buffer);
|
||||
}
|
||||
|
||||
void PlatformWrite(scoped_refptr<net::IOBuffer> buffer,
|
||||
size_t size,
|
||||
WriteCallback callback) override {
|
||||
void Write(uint8_t report_id,
|
||||
const std::vector<uint8_t>& buffer,
|
||||
device::mojom::HidConnection::WriteCallback callback) override {
|
||||
const char kExpected[] = "o-report"; // 8 bytes
|
||||
bool result = false;
|
||||
if (size == sizeof(kExpected)) {
|
||||
uint8_t report_id = buffer->data()[0];
|
||||
uint8_t expected_report_id = device_info()->has_report_id() ? 1 : 0;
|
||||
if (report_id == expected_report_id) {
|
||||
if (memcmp(buffer->data() + 1, kExpected, sizeof(kExpected) - 1) == 0) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
if (buffer.size() != sizeof(kExpected) - 1) {
|
||||
std::move(callback).Run(false);
|
||||
return;
|
||||
}
|
||||
ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::BindOnce(std::move(callback), result));
|
||||
|
||||
int expected_report_id = device_->has_report_id() ? 1 : 0;
|
||||
if (report_id != expected_report_id) {
|
||||
std::move(callback).Run(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (memcmp(buffer.data(), kExpected, sizeof(kExpected) - 1) != 0) {
|
||||
std::move(callback).Run(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::move(callback).Run(true);
|
||||
}
|
||||
|
||||
void PlatformGetFeatureReport(uint8_t report_id,
|
||||
ReadCallback callback) override {
|
||||
void GetFeatureReport(uint8_t report_id,
|
||||
device::mojom::HidConnection::GetFeatureReportCallback
|
||||
callback) override {
|
||||
uint8_t expected_report_id = device_->has_report_id() ? 1 : 0;
|
||||
if (report_id != expected_report_id) {
|
||||
std::move(callback).Run(false, base::nullopt);
|
||||
return;
|
||||
}
|
||||
|
||||
const char kResult[] = "This is a HID feature report.";
|
||||
scoped_refptr<IOBuffer> buffer(new IOBuffer(sizeof(kResult)));
|
||||
size_t offset = 0;
|
||||
if (device_info()->has_report_id()) {
|
||||
buffer->data()[offset++] = report_id;
|
||||
}
|
||||
memcpy(buffer->data() + offset, kResult, sizeof(kResult) - 1);
|
||||
ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::BindOnce(std::move(callback), true, buffer,
|
||||
sizeof(kResult) - 1 + offset));
|
||||
std::vector<uint8_t> buffer;
|
||||
if (device_->has_report_id())
|
||||
buffer.push_back(report_id);
|
||||
buffer.insert(buffer.end(), kResult, kResult + sizeof(kResult) - 1);
|
||||
|
||||
std::move(callback).Run(true, buffer);
|
||||
}
|
||||
|
||||
void PlatformSendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
|
||||
size_t size,
|
||||
WriteCallback callback) override {
|
||||
void SendFeatureReport(uint8_t report_id,
|
||||
const std::vector<uint8_t>& buffer,
|
||||
device::mojom::HidConnection::SendFeatureReportCallback
|
||||
callback) override {
|
||||
const char kExpected[] = "The app is setting this HID feature report.";
|
||||
bool result = false;
|
||||
if (size == sizeof(kExpected)) {
|
||||
uint8_t report_id = buffer->data()[0];
|
||||
uint8_t expected_report_id = device_info()->has_report_id() ? 1 : 0;
|
||||
if (report_id == expected_report_id &&
|
||||
memcmp(buffer->data() + 1, kExpected, sizeof(kExpected) - 1) == 0) {
|
||||
result = true;
|
||||
}
|
||||
if (buffer.size() != sizeof(kExpected) - 1) {
|
||||
std::move(callback).Run(false);
|
||||
return;
|
||||
}
|
||||
ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::BindOnce(std::move(callback), result));
|
||||
|
||||
int expected_report_id = device_->has_report_id() ? 1 : 0;
|
||||
if (report_id != expected_report_id) {
|
||||
std::move(callback).Run(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (memcmp(buffer.data(), kExpected, sizeof(kExpected) - 1) != 0) {
|
||||
std::move(callback).Run(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::move(callback).Run(true);
|
||||
}
|
||||
|
||||
private:
|
||||
~MockHidConnection() override {}
|
||||
scoped_refptr<device::HidDeviceInfo> device_;
|
||||
};
|
||||
|
||||
class FakeHidManager : public device::mojom::HidManager {
|
||||
public:
|
||||
FakeHidManager() {}
|
||||
~FakeHidManager() override = default;
|
||||
|
||||
void Bind(const std::string& interface_name,
|
||||
mojo::ScopedMessagePipeHandle handle,
|
||||
const service_manager::BindSourceInfo& source_info) {
|
||||
bindings_.AddBinding(this,
|
||||
device::mojom::HidManagerRequest(std::move(handle)));
|
||||
}
|
||||
|
||||
// device::mojom::HidManager implementation:
|
||||
void GetDevicesAndSetClient(
|
||||
device::mojom::HidManagerClientAssociatedPtrInfo client,
|
||||
device::mojom::HidManager::GetDevicesCallback callback) override {
|
||||
std::vector<device::mojom::HidDeviceInfoPtr> device_list;
|
||||
for (auto& map_entry : devices_)
|
||||
device_list.push_back(map_entry.second->device()->Clone());
|
||||
|
||||
std::move(callback).Run(std::move(device_list));
|
||||
|
||||
device::mojom::HidManagerClientAssociatedPtr client_ptr;
|
||||
client_ptr.Bind(std::move(client));
|
||||
clients_.AddPtr(std::move(client_ptr));
|
||||
}
|
||||
|
||||
void GetDevices(
|
||||
device::mojom::HidManager::GetDevicesCallback callback) override {
|
||||
// Clients of HidManager in extensions only use GetDevicesAndSetClient().
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void Connect(const std::string& device_guid,
|
||||
device::mojom::HidManager::ConnectCallback callback) override {
|
||||
scoped_refptr<device::HidDeviceInfo> device = devices_[device_guid];
|
||||
|
||||
// Strong binds a instance of FakeHidConnctionImpl.
|
||||
device::mojom::HidConnectionPtr client;
|
||||
mojo::MakeStrongBinding(base::MakeUnique<FakeHidConnectionImpl>(device),
|
||||
mojo::MakeRequest(&client));
|
||||
std::move(callback).Run(std::move(client));
|
||||
}
|
||||
|
||||
void AddDevice(scoped_refptr<device::HidDeviceInfo> device) {
|
||||
devices_[device->device_guid()] = device;
|
||||
|
||||
device::mojom::HidDeviceInfo* device_info = device->device().get();
|
||||
clients_.ForAllPtrs([device_info](device::mojom::HidManagerClient* client) {
|
||||
client->DeviceAdded(device_info->Clone());
|
||||
});
|
||||
}
|
||||
|
||||
void RemoveDevice(const HidPlatformDeviceId& platform_device_id) {
|
||||
std::string guid;
|
||||
scoped_refptr<device::HidDeviceInfo> device;
|
||||
for (const auto& map_entry : devices_) {
|
||||
if (map_entry.second->platform_device_id() == platform_device_id) {
|
||||
guid = map_entry.first;
|
||||
device = map_entry.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!guid.empty()) {
|
||||
device::mojom::HidDeviceInfo* device_info = device->device().get();
|
||||
clients_.ForAllPtrs(
|
||||
[device_info](device::mojom::HidManagerClient* client) {
|
||||
client->DeviceRemoved(device_info->Clone());
|
||||
});
|
||||
devices_.erase(guid);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, scoped_refptr<device::HidDeviceInfo>> devices_;
|
||||
mojo::AssociatedInterfacePtrSet<device::mojom::HidManagerClient> clients_;
|
||||
mojo::BindingSet<device::mojom::HidManager> bindings_;
|
||||
};
|
||||
|
||||
class TestDevicePermissionsPrompt
|
||||
@ -180,34 +272,18 @@ class HidApiTest : public ShellApiTest {
|
||||
void SetUpOnMainThread() override {
|
||||
ShellApiTest::SetUpOnMainThread();
|
||||
|
||||
// MockDeviceClient replaces ShellDeviceClient.
|
||||
device_client_.reset(new MockDeviceClient());
|
||||
fake_hid_manager_ = base::MakeUnique<FakeHidManager>();
|
||||
// Because Device Service also runs in this process(browser process), here
|
||||
// we can directly set our binder to intercept interface requests against
|
||||
// it.
|
||||
service_manager::ServiceContext::SetGlobalBinderForTesting(
|
||||
device::mojom::kServiceName, device::mojom::HidManager::Name_,
|
||||
base::Bind(&FakeHidManager::Bind,
|
||||
base::Unretained(fake_hid_manager_.get())));
|
||||
|
||||
ON_CALL(*device_client_->hid_service(), Connect(_, _))
|
||||
.WillByDefault(Invoke(this, &HidApiTest::Connect));
|
||||
ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&HidApiTest::LazyFirstEnumeration, base::Unretained(this)));
|
||||
}
|
||||
|
||||
void Connect(const std::string& device_guid,
|
||||
const device::HidService::ConnectCallback& callback) {
|
||||
const auto& devices = device_client_->hid_service()->devices();
|
||||
const auto& device_entry = devices.find(device_guid);
|
||||
scoped_refptr<MockHidConnection> connection;
|
||||
if (device_entry != devices.end()) {
|
||||
connection = new MockHidConnection(device_entry->second);
|
||||
}
|
||||
|
||||
ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
|
||||
base::Bind(callback, connection));
|
||||
}
|
||||
|
||||
void LazyFirstEnumeration() {
|
||||
AddDevice(kTestDeviceIds[0], 0x18D1, 0x58F0, false, "A");
|
||||
AddDevice(kTestDeviceIds[1], 0x18D1, 0x58F0, true, "B");
|
||||
AddDevice(kTestDeviceIds[2], 0x18D1, 0x58F1, false, "C");
|
||||
device_client_->hid_service()->FirstEnumerationComplete();
|
||||
}
|
||||
|
||||
void AddDevice(const HidPlatformDeviceId& platform_device_id,
|
||||
@ -224,13 +300,15 @@ class HidApiTest : public ShellApiTest {
|
||||
report_descriptor.insert(report_descriptor.begin(), kReportDescriptor,
|
||||
kReportDescriptor + sizeof(kReportDescriptor));
|
||||
}
|
||||
device_client_->hid_service()->AddDevice(new HidDeviceInfo(
|
||||
fake_hid_manager_->AddDevice(new device::HidDeviceInfo(
|
||||
platform_device_id, vendor_id, product_id, "Test Device", serial_number,
|
||||
device::mojom::HidBusType::kHIDBusTypeUSB, report_descriptor));
|
||||
}
|
||||
|
||||
FakeHidManager* GetFakeHidManager() { return fake_hid_manager_.get(); }
|
||||
|
||||
protected:
|
||||
std::unique_ptr<MockDeviceClient> device_client_;
|
||||
std::unique_ptr<FakeHidManager> fake_hid_manager_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(HidApiTest, HidApp) {
|
||||
@ -263,9 +341,9 @@ IN_PROC_BROWSER_TEST_F(HidApiTest, OnDeviceRemoved) {
|
||||
|
||||
// Device C was not returned by chrome.hid.getDevices, the app will not get
|
||||
// a notification.
|
||||
device_client_->hid_service()->RemoveDevice(kTestDeviceIds[2]);
|
||||
GetFakeHidManager()->RemoveDevice(kTestDeviceIds[2]);
|
||||
// Device A was returned, the app will get a notification.
|
||||
device_client_->hid_service()->RemoveDevice(kTestDeviceIds[0]);
|
||||
GetFakeHidManager()->RemoveDevice(kTestDeviceIds[0]);
|
||||
ASSERT_TRUE(result_listener.WaitUntilSatisfied());
|
||||
EXPECT_EQ("success", result_listener.message());
|
||||
}
|
||||
@ -278,7 +356,7 @@ IN_PROC_BROWSER_TEST_F(HidApiTest, GetUserSelectedDevices) {
|
||||
ASSERT_TRUE(open_listener.WaitUntilSatisfied());
|
||||
|
||||
ExtensionTestMessageListener remove_listener("removed", false);
|
||||
device_client_->hid_service()->RemoveDevice(kTestDeviceIds[0]);
|
||||
GetFakeHidManager()->RemoveDevice(kTestDeviceIds[0]);
|
||||
ASSERT_TRUE(remove_listener.WaitUntilSatisfied());
|
||||
|
||||
ExtensionTestMessageListener add_listener("added", false);
|
||||
|
@ -26,11 +26,10 @@ ApiResourceManager<HidConnectionResource>::GetFactoryInstance() {
|
||||
|
||||
HidConnectionResource::HidConnectionResource(
|
||||
const std::string& owner_extension_id,
|
||||
scoped_refptr<device::HidConnection> connection)
|
||||
: ApiResource(owner_extension_id), connection_(connection) {}
|
||||
device::mojom::HidConnectionPtr connection)
|
||||
: ApiResource(owner_extension_id), connection_(std::move(connection)) {}
|
||||
|
||||
HidConnectionResource::~HidConnectionResource() {
|
||||
connection_->Close();
|
||||
}
|
||||
|
||||
bool HidConnectionResource::IsPersistent() const {
|
||||
|
@ -25,19 +25,17 @@ class HidConnectionResource : public ApiResource {
|
||||
content::BrowserThread::UI;
|
||||
|
||||
HidConnectionResource(const std::string& owner_extension_id,
|
||||
scoped_refptr<device::HidConnection> connection);
|
||||
device::mojom::HidConnectionPtr connection);
|
||||
~HidConnectionResource() override;
|
||||
|
||||
scoped_refptr<device::HidConnection> connection() const {
|
||||
return connection_;
|
||||
}
|
||||
device::mojom::HidConnection* connection() const { return connection_.get(); }
|
||||
|
||||
bool IsPersistent() const override;
|
||||
|
||||
static const char* service_name() { return "HidConnectionResourceManager"; }
|
||||
|
||||
private:
|
||||
scoped_refptr<device::HidConnection> connection_;
|
||||
device::mojom::HidConnectionPtr connection_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(HidConnectionResource);
|
||||
};
|
||||
|
@ -15,12 +15,17 @@
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/common/service_manager_connection.h"
|
||||
#include "device/base/device_client.h"
|
||||
#include "device/hid/hid_device_filter.h"
|
||||
#include "device/hid/hid_service.h"
|
||||
#include "extensions/browser/api/device_permissions_manager.h"
|
||||
#include "extensions/common/permissions/permissions_data.h"
|
||||
#include "extensions/common/permissions/usb_device_permission.h"
|
||||
#include "extensions/utility/scoped_callback_runner.h"
|
||||
#include "mojo/public/cpp/bindings/interface_request.h"
|
||||
#include "services/device/public/interfaces/constants.mojom.h"
|
||||
#include "services/service_manager/public/cpp/connector.h"
|
||||
|
||||
namespace hid = extensions::api::hid;
|
||||
|
||||
@ -93,9 +98,7 @@ struct HidDeviceManager::GetApiDevicesParams {
|
||||
};
|
||||
|
||||
HidDeviceManager::HidDeviceManager(content::BrowserContext* context)
|
||||
: browser_context_(context),
|
||||
hid_service_observer_(this),
|
||||
weak_factory_(this) {
|
||||
: browser_context_(context), binding_(this), weak_factory_(this) {
|
||||
event_router_ = EventRouter::Get(context);
|
||||
if (event_router_) {
|
||||
event_router_->RegisterObserver(this, hid::OnDeviceAdded::kEventName);
|
||||
@ -162,6 +165,14 @@ const device::mojom::HidDeviceInfo* HidDeviceManager::GetDeviceInfo(
|
||||
return device_iter->second.get();
|
||||
}
|
||||
|
||||
void HidDeviceManager::Connect(const std::string& device_guid,
|
||||
ConnectCallback callback) {
|
||||
DCHECK(initialized_);
|
||||
|
||||
hid_manager_->Connect(device_guid,
|
||||
ScopedCallbackRunner(std::move(callback), nullptr));
|
||||
}
|
||||
|
||||
bool HidDeviceManager::HasPermission(
|
||||
const Extension* extension,
|
||||
const device::mojom::HidDeviceInfo& device_info,
|
||||
@ -210,7 +221,7 @@ void HidDeviceManager::Shutdown() {
|
||||
void HidDeviceManager::OnListenerAdded(const EventListenerInfo& details) {
|
||||
LazyInitialize();
|
||||
}
|
||||
void HidDeviceManager::OnDeviceAdded(device::mojom::HidDeviceInfoPtr device) {
|
||||
void HidDeviceManager::DeviceAdded(device::mojom::HidDeviceInfoPtr device) {
|
||||
DCHECK(thread_checker_.CalledOnValidThread());
|
||||
DCHECK_LT(next_resource_id_, std::numeric_limits<int>::max());
|
||||
int new_id = next_resource_id_++;
|
||||
@ -234,7 +245,7 @@ void HidDeviceManager::OnDeviceAdded(device::mojom::HidDeviceInfoPtr device) {
|
||||
}
|
||||
}
|
||||
|
||||
void HidDeviceManager::OnDeviceRemoved(device::mojom::HidDeviceInfoPtr device) {
|
||||
void HidDeviceManager::DeviceRemoved(device::mojom::HidDeviceInfoPtr device) {
|
||||
DCHECK(thread_checker_.CalledOnValidThread());
|
||||
const auto& resource_entry = resource_ids_.find(device->guid);
|
||||
DCHECK(resource_entry != resource_ids_.end());
|
||||
@ -266,10 +277,27 @@ void HidDeviceManager::LazyInitialize() {
|
||||
return;
|
||||
}
|
||||
|
||||
HidService* hid_service = device::DeviceClient::Get()->GetHidService();
|
||||
DCHECK(hid_service);
|
||||
hid_service->GetDevices(base::Bind(&HidDeviceManager::OnEnumerationComplete,
|
||||
weak_factory_.GetWeakPtr(), hid_service));
|
||||
DCHECK(!hid_manager_);
|
||||
|
||||
// |hid_manager_| is initialized and safe to use whether or not the
|
||||
// connection is successful.
|
||||
device::mojom::HidManagerRequest request = mojo::MakeRequest(&hid_manager_);
|
||||
device::mojom::HidManagerClientAssociatedPtrInfo client;
|
||||
binding_.Bind(mojo::MakeRequest(&client));
|
||||
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
DCHECK(content::ServiceManagerConnection::GetForProcess());
|
||||
auto* connector =
|
||||
content::ServiceManagerConnection::GetForProcess()->GetConnector();
|
||||
connector->BindInterface(device::mojom::kServiceName, std::move(request));
|
||||
|
||||
std::vector<device::mojom::HidDeviceInfoPtr> empty_devices;
|
||||
hid_manager_->GetDevicesAndSetClient(
|
||||
std::move(client),
|
||||
ScopedCallbackRunner(
|
||||
base::BindOnce(&HidDeviceManager::OnEnumerationComplete,
|
||||
weak_factory_.GetWeakPtr()),
|
||||
std::move(empty_devices)));
|
||||
|
||||
initialized_ = true;
|
||||
}
|
||||
@ -305,12 +333,12 @@ std::unique_ptr<base::ListValue> HidDeviceManager::CreateApiDeviceList(
|
||||
}
|
||||
|
||||
void HidDeviceManager::OnEnumerationComplete(
|
||||
HidService* hid_service,
|
||||
std::vector<device::mojom::HidDeviceInfoPtr> devices) {
|
||||
DCHECK(resource_ids_.empty());
|
||||
DCHECK(devices_.empty());
|
||||
|
||||
for (auto& device_info : devices) {
|
||||
OnDeviceAdded(std::move(device_info));
|
||||
DeviceAdded(std::move(device_info));
|
||||
}
|
||||
enumeration_ready_ = true;
|
||||
|
||||
@ -320,8 +348,6 @@ void HidDeviceManager::OnEnumerationComplete(
|
||||
params->callback.Run(std::move(devices));
|
||||
}
|
||||
pending_enumerations_.clear();
|
||||
|
||||
hid_service_observer_.Add(hid_service);
|
||||
}
|
||||
|
||||
void HidDeviceManager::DispatchEvent(
|
||||
|
@ -13,12 +13,12 @@
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/scoped_observer.h"
|
||||
#include "base/threading/thread_checker.h"
|
||||
#include "device/hid/hid_service.h"
|
||||
#include "device/hid/public/interfaces/hid.mojom.h"
|
||||
#include "extensions/browser/browser_context_keyed_api_factory.h"
|
||||
#include "extensions/browser/event_router.h"
|
||||
#include "extensions/browser/extension_event_histogram_value.h"
|
||||
#include "extensions/common/api/hid.h"
|
||||
#include "mojo/public/cpp/bindings/associated_binding.h"
|
||||
|
||||
namespace device {
|
||||
class HidDeviceFilter;
|
||||
@ -28,15 +28,17 @@ namespace extensions {
|
||||
|
||||
class Extension;
|
||||
|
||||
// This service maps devices enumerated by device::HidService to resource IDs
|
||||
// This class maps devices enumerated by device::HidManager to resource IDs
|
||||
// returned by the chrome.hid API.
|
||||
class HidDeviceManager : public BrowserContextKeyedAPI,
|
||||
public device::HidService::Observer,
|
||||
public device::mojom::HidManagerClient,
|
||||
public EventRouter::Observer {
|
||||
public:
|
||||
typedef base::Callback<void(std::unique_ptr<base::ListValue>)>
|
||||
GetApiDevicesCallback;
|
||||
|
||||
using ConnectCallback = device::mojom::HidManager::ConnectCallback;
|
||||
|
||||
explicit HidDeviceManager(content::BrowserContext* context);
|
||||
~HidDeviceManager() override;
|
||||
|
||||
@ -63,16 +65,17 @@ class HidDeviceManager : public BrowserContextKeyedAPI,
|
||||
|
||||
const device::mojom::HidDeviceInfo* GetDeviceInfo(int resource_id);
|
||||
|
||||
void Connect(const std::string& device_guid, ConnectCallback callback);
|
||||
|
||||
// Checks if |extension| has permission to open |device_info|. Set
|
||||
// |update_last_used| to update the timestamp in the DevicePermissionsManager.
|
||||
bool HasPermission(const Extension* extension,
|
||||
const device::mojom::HidDeviceInfo& device_info,
|
||||
bool update_last_used);
|
||||
|
||||
// Wait to perform an initial enumeration and register a HidService::Observer
|
||||
// until the first API customer makes a request or registers an event
|
||||
// listener.
|
||||
void LazyInitialize();
|
||||
// Lazily perform an initial enumeration and set client to HidManager when
|
||||
// the first API customer makes a request or registers an event listener.
|
||||
virtual void LazyInitialize();
|
||||
|
||||
private:
|
||||
friend class BrowserContextKeyedAPIFactory<HidDeviceManager>;
|
||||
@ -94,9 +97,9 @@ class HidDeviceManager : public BrowserContextKeyedAPI,
|
||||
// EventRouter::Observer:
|
||||
void OnListenerAdded(const EventListenerInfo& details) override;
|
||||
|
||||
// HidService::Observer:
|
||||
void OnDeviceAdded(device::mojom::HidDeviceInfoPtr device) override;
|
||||
void OnDeviceRemoved(device::mojom::HidDeviceInfoPtr device) override;
|
||||
// device::mojom::HidManagerClient implementation:
|
||||
void DeviceAdded(device::mojom::HidDeviceInfoPtr device) override;
|
||||
void DeviceRemoved(device::mojom::HidDeviceInfoPtr device) override;
|
||||
|
||||
// Builds a list of device info objects representing the currently enumerated
|
||||
// devices, taking into account the permissions held by the given extension
|
||||
@ -105,7 +108,6 @@ class HidDeviceManager : public BrowserContextKeyedAPI,
|
||||
const Extension* extension,
|
||||
const std::vector<device::HidDeviceFilter>& filters);
|
||||
void OnEnumerationComplete(
|
||||
device::HidService* hid_service,
|
||||
std::vector<device::mojom::HidDeviceInfoPtr> devices);
|
||||
|
||||
void DispatchEvent(events::HistogramValue histogram_value,
|
||||
@ -117,8 +119,8 @@ class HidDeviceManager : public BrowserContextKeyedAPI,
|
||||
content::BrowserContext* browser_context_ = nullptr;
|
||||
EventRouter* event_router_ = nullptr;
|
||||
bool initialized_ = false;
|
||||
ScopedObserver<device::HidService, device::HidService::Observer>
|
||||
hid_service_observer_;
|
||||
device::mojom::HidManagerPtr hid_manager_;
|
||||
mojo::AssociatedBinding<device::mojom::HidManagerClient> binding_;
|
||||
bool enumeration_ready_ = false;
|
||||
std::vector<std::unique_ptr<GetApiDevicesParams>> pending_enumerations_;
|
||||
int next_resource_id_ = 0;
|
||||
|
@ -23,11 +23,4 @@ device::UsbService* ShellDeviceClient::GetUsbService() {
|
||||
return usb_service_.get();
|
||||
}
|
||||
|
||||
device::HidService* ShellDeviceClient::GetHidService() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
if (!hid_service_)
|
||||
hid_service_ = device::HidService::Create();
|
||||
return hid_service_.get();
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
|
@ -21,10 +21,8 @@ class ShellDeviceClient : device::DeviceClient {
|
||||
|
||||
// device::DeviceClient implementation
|
||||
device::UsbService* GetUsbService() override;
|
||||
device::HidService* GetHidService() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<device::HidService> hid_service_;
|
||||
std::unique_ptr<device::UsbService> usb_service_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ShellDeviceClient);
|
||||
|
@ -27,6 +27,7 @@ source_set("lib") {
|
||||
|
||||
deps = [
|
||||
"//base",
|
||||
"//device/hid",
|
||||
"//device/sensors",
|
||||
"//device/sensors/public/interfaces",
|
||||
"//services/device/fingerprint",
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "build/build_config.h"
|
||||
#include "device/hid/hid_manager_impl.h"
|
||||
#include "device/sensors/device_sensor_host.h"
|
||||
#include "mojo/public/cpp/system/message_pipe.h"
|
||||
#include "services/device/fingerprint/fingerprint.h"
|
||||
@ -84,6 +85,8 @@ DeviceService::~DeviceService() {
|
||||
void DeviceService::OnStart() {
|
||||
registry_.AddInterface<mojom::Fingerprint>(base::Bind(
|
||||
&DeviceService::BindFingerprintRequest, base::Unretained(this)));
|
||||
registry_.AddInterface<mojom::HidManager>(base::Bind(
|
||||
&DeviceService::BindHidManagerRequest, base::Unretained(this)));
|
||||
registry_.AddInterface<mojom::OrientationSensor>(base::Bind(
|
||||
&DeviceService::BindOrientationSensorRequest, base::Unretained(this)));
|
||||
registry_.AddInterface<mojom::OrientationAbsoluteSensor>(
|
||||
@ -148,6 +151,12 @@ void DeviceService::BindVibrationManagerRequest(
|
||||
}
|
||||
#endif
|
||||
|
||||
void DeviceService::BindHidManagerRequest(mojom::HidManagerRequest request) {
|
||||
if (!hid_manager_)
|
||||
hid_manager_ = base::MakeUnique<HidManagerImpl>();
|
||||
hid_manager_->AddBinding(std::move(request));
|
||||
}
|
||||
|
||||
void DeviceService::BindFingerprintRequest(mojom::FingerprintRequest request) {
|
||||
Fingerprint::Create(std::move(request));
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define SERVICES_DEVICE_DEVICE_SERVICE_H_
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "device/hid/public/interfaces/hid.mojom.h"
|
||||
#include "device/screen_orientation/public/interfaces/screen_orientation.mojom.h"
|
||||
#include "device/sensors/public/interfaces/orientation.mojom.h"
|
||||
#include "mojo/public/cpp/bindings/binding_set.h"
|
||||
@ -33,6 +34,7 @@ class SingleThreadTaskRunner;
|
||||
|
||||
namespace device {
|
||||
|
||||
class HidManagerImpl;
|
||||
class PowerMonitorMessageBroadcaster;
|
||||
class TimeZoneMonitor;
|
||||
|
||||
@ -73,6 +75,8 @@ class DeviceService : public service_manager::Service {
|
||||
|
||||
void BindFingerprintRequest(mojom::FingerprintRequest request);
|
||||
|
||||
void BindHidManagerRequest(mojom::HidManagerRequest request);
|
||||
|
||||
void BindOrientationSensorRequest(mojom::OrientationSensorRequest request);
|
||||
|
||||
void BindOrientationAbsoluteSensorRequest(
|
||||
@ -100,6 +104,7 @@ class DeviceService : public service_manager::Service {
|
||||
|
||||
void BindSerialIoHandlerRequest(mojom::SerialIoHandlerRequest request);
|
||||
|
||||
std::unique_ptr<HidManagerImpl> hid_manager_;
|
||||
std::unique_ptr<PowerMonitorMessageBroadcaster>
|
||||
power_monitor_message_broadcaster_;
|
||||
std::unique_ptr<TimeZoneMonitor> time_zone_monitor_;
|
||||
|
@ -5,6 +5,7 @@
|
||||
"service_manager:connector": {
|
||||
"provides": {
|
||||
"device:battery_monitor": [ "device::mojom::BatteryMonitor" ],
|
||||
"device:hid": [ "device::mojom::HidManager" ],
|
||||
"device:fingerprint": [ "device::mojom::Fingerprint" ],
|
||||
"device:generic_sensor": [ "device::mojom::SensorProvider" ],
|
||||
"device:nfc": [ "device::mojom::NFCProvider" ],
|
||||
|
Reference in New Issue
Block a user