123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- // Copyright 2021 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 "services/device/hid/hid_service_linux.h"
- #include "base/files/file_util.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/test/bind.h"
- #include "base/test/task_environment.h"
- #include "device/udev_linux/fake_udev_loader.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace device {
- namespace {
- constexpr char kSubsystemBluetooth[] = "bluetooth";
- constexpr char kSubsystemHid[] = "hid";
- constexpr char kSubsystemHidraw[] = "hidraw";
- constexpr char kSubsystemMisc[] = "misc";
- constexpr char kSubsystemUsb[] = "usb";
- constexpr char kDevnodeHidraw0[] = "/dev/hidraw0";
- constexpr char kDevtypeUsbDevice[] = "usb_device";
- constexpr char kDevtypeUsbInterface[] = "usb_interface";
- constexpr char kDevtypeLink[] = "link";
- constexpr char kPropertyValueHidName[] = "product-name";
- class HidServiceLinuxTest : public testing::Test {
- public:
- void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
- void AddFakeDevice(base::FilePath syspath,
- std::string subsystem,
- absl::optional<std::string> devnode = absl::nullopt,
- absl::optional<std::string> devtype = absl::nullopt,
- std::map<std::string, std::string> properties = {}) {
- fake_udev_.AddFakeDevice("fake-device", syspath.value(),
- std::move(subsystem), std::move(devnode),
- std::move(devtype), /*sysattrs=*/{},
- std::move(properties));
- }
- base::FilePath GetTempDir() { return temp_dir_.GetPath(); }
- private:
- testing::FakeUdevLoader fake_udev_;
- base::test::TaskEnvironment task_environment_{
- base::test::TaskEnvironment::MainThreadType::IO};
- base::ScopedTempDir temp_dir_;
- };
- } // namespace
- TEST_F(HidServiceLinuxTest, EnumerateUsbHidDevice) {
- constexpr char kPropertyValueHidId[] = "0003:0000ABCD:00001234";
- constexpr char kPropertyValueHidUniq[] = "serial-number";
- // Construct paths for the hidraw device and its ancestors up to the USB
- // device.
- auto usb_device_path =
- GetTempDir().Append("sys/devices/pci0000:00/0000:00:0.0/usb2/1-1");
- auto usb_interface_path = usb_device_path.Append("1-1:1.1");
- auto hid_path = usb_interface_path.Append("0003:ABCD:1234.0000");
- auto hidraw_path = hid_path.Append("hidraw/hidraw0");
- // The HID service reads the report descriptor from a file in the |hid_path|
- // directory.
- auto report_descriptor_path = hid_path.Append("report_descriptor");
- uint8_t data = 0;
- ASSERT_TRUE(base::CreateDirectory(hid_path));
- ASSERT_TRUE(
- base::WriteFile(report_descriptor_path, base::make_span(&data, 1)));
- // Add the fake HID device as well as its ancestors up to the USB device node.
- // Ancestors must be added starting from the closest to the root to ensure
- // that ancestor device info is available when the hidraw device is added.
- AddFakeDevice(usb_device_path, kSubsystemUsb, /*devnode=*/absl::nullopt,
- kDevtypeUsbDevice);
- AddFakeDevice(usb_interface_path, kSubsystemUsb, /*devnode=*/absl::nullopt,
- kDevtypeUsbInterface);
- AddFakeDevice(hid_path, kSubsystemHid, /*devnode=*/absl::nullopt,
- /*devtype=*/absl::nullopt, /*properties=*/
- {
- {"HID_ID", kPropertyValueHidId},
- {"HID_UNIQ", kPropertyValueHidUniq},
- {"HID_NAME", kPropertyValueHidName},
- });
- AddFakeDevice(hidraw_path, kSubsystemHidraw, kDevnodeHidraw0);
- std::vector<mojom::HidDeviceInfoPtr> devices;
- base::RunLoop loop;
- auto hid_service = std::make_unique<HidServiceLinux>();
- hid_service->GetDevices(
- base::BindLambdaForTesting([&](std::vector<mojom::HidDeviceInfoPtr> d) {
- devices = std::move(d);
- loop.Quit();
- }));
- loop.Run();
- ASSERT_EQ(devices.size(), 1u);
- EXPECT_EQ(devices[0]->physical_device_id, usb_device_path.value());
- EXPECT_EQ(devices[0]->vendor_id, 0xabcd);
- EXPECT_EQ(devices[0]->product_id, 0x1234);
- EXPECT_EQ(devices[0]->product_name, kPropertyValueHidName);
- EXPECT_EQ(devices[0]->serial_number, kPropertyValueHidUniq);
- EXPECT_EQ(devices[0]->bus_type, mojom::HidBusType::kHIDBusTypeUSB);
- ASSERT_EQ(devices[0]->report_descriptor.size(), 1u);
- EXPECT_EQ(devices[0]->report_descriptor[0], 0u);
- EXPECT_TRUE(devices[0]->collections.empty());
- EXPECT_FALSE(devices[0]->has_report_id);
- EXPECT_EQ(devices[0]->max_input_report_size, 0u);
- EXPECT_EQ(devices[0]->max_output_report_size, 0u);
- EXPECT_EQ(devices[0]->max_feature_report_size, 0u);
- EXPECT_EQ(devices[0]->device_node, kDevnodeHidraw0);
- EXPECT_TRUE(devices[0]->protected_input_report_ids);
- EXPECT_TRUE(devices[0]->protected_input_report_ids->empty());
- EXPECT_TRUE(devices[0]->protected_output_report_ids);
- EXPECT_TRUE(devices[0]->protected_output_report_ids->empty());
- EXPECT_TRUE(devices[0]->protected_feature_report_ids);
- EXPECT_TRUE(devices[0]->protected_feature_report_ids->empty());
- }
- TEST_F(HidServiceLinuxTest, EnumerateBluetoothClassicHidDevice) {
- constexpr char kPropertyValueHidId[] = "0005:0000ABCD:00001234";
- constexpr char kPropertyValueHidUniq[] = "aa:bb:cc:dd:ee:ff";
- // Construct paths for the hidraw device and its ancestors up to the Bluetooth
- // link.
- auto bt_link_path = GetTempDir().Append(
- "sys/devices/pci0000:00/0000:00:0.0/usb2/1-1/1-1:1.0/bluetooth/hci0/"
- "hci0:0");
- auto hid_path = bt_link_path.Append("0005:ABCD:1234.0000");
- auto hidraw_path = hid_path.Append("hidraw/hidraw0");
- // The HID service reads the report descriptor from a file in the |hid_path|
- // directory.
- auto report_descriptor_path = hid_path.Append("report_descriptor");
- uint8_t data = 0;
- ASSERT_TRUE(base::CreateDirectory(hid_path));
- ASSERT_TRUE(
- base::WriteFile(report_descriptor_path, base::make_span(&data, 1)));
- // Add the fake HID device as well as its ancestors up to the Bluetooth link.
- // Ancestors must be added starting from the closest to the root to ensure
- // that ancestor device info is available when the hidraw device is added.
- AddFakeDevice(bt_link_path, kSubsystemBluetooth, /*devnode=*/absl::nullopt,
- kDevtypeLink);
- AddFakeDevice(hid_path, kSubsystemHid, /*devnode=*/absl::nullopt,
- /*devtype=*/absl::nullopt, /*properties=*/
- {
- {"HID_ID", kPropertyValueHidId},
- {"HID_UNIQ", kPropertyValueHidUniq},
- {"HID_NAME", kPropertyValueHidName},
- });
- AddFakeDevice(hidraw_path, kSubsystemHidraw, kDevnodeHidraw0);
- std::vector<mojom::HidDeviceInfoPtr> devices;
- base::RunLoop loop;
- auto hid_service = std::make_unique<HidServiceLinux>();
- hid_service->GetDevices(
- base::BindLambdaForTesting([&](std::vector<mojom::HidDeviceInfoPtr> d) {
- devices = std::move(d);
- loop.Quit();
- }));
- loop.Run();
- ASSERT_EQ(devices.size(), 1u);
- EXPECT_EQ(devices[0]->physical_device_id, hid_path.value());
- EXPECT_EQ(devices[0]->vendor_id, 0xabcd);
- EXPECT_EQ(devices[0]->product_id, 0x1234);
- EXPECT_EQ(devices[0]->product_name, kPropertyValueHidName);
- EXPECT_EQ(devices[0]->serial_number, kPropertyValueHidUniq);
- EXPECT_EQ(devices[0]->bus_type, mojom::HidBusType::kHIDBusTypeBluetooth);
- ASSERT_EQ(devices[0]->report_descriptor.size(), 1u);
- EXPECT_EQ(devices[0]->report_descriptor[0], 0u);
- EXPECT_TRUE(devices[0]->collections.empty());
- EXPECT_FALSE(devices[0]->has_report_id);
- EXPECT_EQ(devices[0]->max_input_report_size, 0u);
- EXPECT_EQ(devices[0]->max_output_report_size, 0u);
- EXPECT_EQ(devices[0]->max_feature_report_size, 0u);
- EXPECT_EQ(devices[0]->device_node, kDevnodeHidraw0);
- EXPECT_TRUE(devices[0]->protected_input_report_ids);
- EXPECT_TRUE(devices[0]->protected_input_report_ids->empty());
- EXPECT_TRUE(devices[0]->protected_output_report_ids);
- EXPECT_TRUE(devices[0]->protected_output_report_ids->empty());
- EXPECT_TRUE(devices[0]->protected_feature_report_ids);
- EXPECT_TRUE(devices[0]->protected_feature_report_ids->empty());
- }
- TEST_F(HidServiceLinuxTest, EnumerateBleHidDevice) {
- constexpr char kPropertyValueHidId[] = "0005:0000ABCD:00001234";
- constexpr char kPropertyValueHidUniq[] = "aa:bb:cc:dd:ee:ff";
- // Construct paths for the hidraw device and its ancestors up to the uhid
- // device node.
- auto uhid_path = GetTempDir().Append("sys/devices/virtual/misc/uhid/");
- auto hid_path = uhid_path.Append("0005:ABCD:1234.0000");
- auto hidraw_path = hid_path.Append("hidraw/hidraw0");
- // The HID service reads the report descriptor from a file in the |hid_path|
- // directory.
- auto report_descriptor_path = hid_path.Append("report_descriptor");
- uint8_t data = 0;
- ASSERT_TRUE(base::CreateDirectory(hid_path));
- ASSERT_TRUE(
- base::WriteFile(report_descriptor_path, base::make_span(&data, 1)));
- // Add the fake HID device as well as its ancestors up to the Bluetooth link.
- // Ancestors must be added starting from the closest to the root to ensure
- // that ancestor device info is available when the hidraw device is added.
- AddFakeDevice(uhid_path, kSubsystemMisc);
- AddFakeDevice(hid_path, kSubsystemHid, /*devnode=*/absl::nullopt,
- /*devtype=*/absl::nullopt, /*properties=*/
- {
- {"HID_ID", kPropertyValueHidId},
- {"HID_UNIQ", kPropertyValueHidUniq},
- {"HID_NAME", kPropertyValueHidName},
- });
- AddFakeDevice(hidraw_path, kSubsystemHidraw, kDevnodeHidraw0);
- std::vector<mojom::HidDeviceInfoPtr> devices;
- base::RunLoop loop;
- auto hid_service = std::make_unique<HidServiceLinux>();
- hid_service->GetDevices(
- base::BindLambdaForTesting([&](std::vector<mojom::HidDeviceInfoPtr> d) {
- devices = std::move(d);
- loop.Quit();
- }));
- loop.Run();
- ASSERT_EQ(devices.size(), 1u);
- EXPECT_EQ(devices[0]->physical_device_id, hid_path.value());
- EXPECT_EQ(devices[0]->vendor_id, 0xabcd);
- EXPECT_EQ(devices[0]->product_id, 0x1234);
- EXPECT_EQ(devices[0]->product_name, kPropertyValueHidName);
- EXPECT_EQ(devices[0]->serial_number, kPropertyValueHidUniq);
- EXPECT_EQ(devices[0]->bus_type, mojom::HidBusType::kHIDBusTypeBluetooth);
- ASSERT_EQ(devices[0]->report_descriptor.size(), 1u);
- EXPECT_EQ(devices[0]->report_descriptor[0], 0u);
- EXPECT_TRUE(devices[0]->collections.empty());
- EXPECT_FALSE(devices[0]->has_report_id);
- EXPECT_EQ(devices[0]->max_input_report_size, 0u);
- EXPECT_EQ(devices[0]->max_output_report_size, 0u);
- EXPECT_EQ(devices[0]->max_feature_report_size, 0u);
- EXPECT_EQ(devices[0]->device_node, kDevnodeHidraw0);
- EXPECT_TRUE(devices[0]->protected_input_report_ids);
- EXPECT_TRUE(devices[0]->protected_input_report_ids->empty());
- EXPECT_TRUE(devices[0]->protected_output_report_ids);
- EXPECT_TRUE(devices[0]->protected_output_report_ids->empty());
- EXPECT_TRUE(devices[0]->protected_feature_report_ids);
- EXPECT_TRUE(devices[0]->protected_feature_report_ids->empty());
- }
- } // namespace device
|