hid_service_linux_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/device/hid/hid_service_linux.h"
  5. #include "base/files/file_util.h"
  6. #include "base/files/scoped_temp_dir.h"
  7. #include "base/test/bind.h"
  8. #include "base/test/task_environment.h"
  9. #include "device/udev_linux/fake_udev_loader.h"
  10. #include "testing/gtest/include/gtest/gtest.h"
  11. namespace device {
  12. namespace {
  13. constexpr char kSubsystemBluetooth[] = "bluetooth";
  14. constexpr char kSubsystemHid[] = "hid";
  15. constexpr char kSubsystemHidraw[] = "hidraw";
  16. constexpr char kSubsystemMisc[] = "misc";
  17. constexpr char kSubsystemUsb[] = "usb";
  18. constexpr char kDevnodeHidraw0[] = "/dev/hidraw0";
  19. constexpr char kDevtypeUsbDevice[] = "usb_device";
  20. constexpr char kDevtypeUsbInterface[] = "usb_interface";
  21. constexpr char kDevtypeLink[] = "link";
  22. constexpr char kPropertyValueHidName[] = "product-name";
  23. class HidServiceLinuxTest : public testing::Test {
  24. public:
  25. void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
  26. void AddFakeDevice(base::FilePath syspath,
  27. std::string subsystem,
  28. absl::optional<std::string> devnode = absl::nullopt,
  29. absl::optional<std::string> devtype = absl::nullopt,
  30. std::map<std::string, std::string> properties = {}) {
  31. fake_udev_.AddFakeDevice("fake-device", syspath.value(),
  32. std::move(subsystem), std::move(devnode),
  33. std::move(devtype), /*sysattrs=*/{},
  34. std::move(properties));
  35. }
  36. base::FilePath GetTempDir() { return temp_dir_.GetPath(); }
  37. private:
  38. testing::FakeUdevLoader fake_udev_;
  39. base::test::TaskEnvironment task_environment_{
  40. base::test::TaskEnvironment::MainThreadType::IO};
  41. base::ScopedTempDir temp_dir_;
  42. };
  43. } // namespace
  44. TEST_F(HidServiceLinuxTest, EnumerateUsbHidDevice) {
  45. constexpr char kPropertyValueHidId[] = "0003:0000ABCD:00001234";
  46. constexpr char kPropertyValueHidUniq[] = "serial-number";
  47. // Construct paths for the hidraw device and its ancestors up to the USB
  48. // device.
  49. auto usb_device_path =
  50. GetTempDir().Append("sys/devices/pci0000:00/0000:00:0.0/usb2/1-1");
  51. auto usb_interface_path = usb_device_path.Append("1-1:1.1");
  52. auto hid_path = usb_interface_path.Append("0003:ABCD:1234.0000");
  53. auto hidraw_path = hid_path.Append("hidraw/hidraw0");
  54. // The HID service reads the report descriptor from a file in the |hid_path|
  55. // directory.
  56. auto report_descriptor_path = hid_path.Append("report_descriptor");
  57. uint8_t data = 0;
  58. ASSERT_TRUE(base::CreateDirectory(hid_path));
  59. ASSERT_TRUE(
  60. base::WriteFile(report_descriptor_path, base::make_span(&data, 1)));
  61. // Add the fake HID device as well as its ancestors up to the USB device node.
  62. // Ancestors must be added starting from the closest to the root to ensure
  63. // that ancestor device info is available when the hidraw device is added.
  64. AddFakeDevice(usb_device_path, kSubsystemUsb, /*devnode=*/absl::nullopt,
  65. kDevtypeUsbDevice);
  66. AddFakeDevice(usb_interface_path, kSubsystemUsb, /*devnode=*/absl::nullopt,
  67. kDevtypeUsbInterface);
  68. AddFakeDevice(hid_path, kSubsystemHid, /*devnode=*/absl::nullopt,
  69. /*devtype=*/absl::nullopt, /*properties=*/
  70. {
  71. {"HID_ID", kPropertyValueHidId},
  72. {"HID_UNIQ", kPropertyValueHidUniq},
  73. {"HID_NAME", kPropertyValueHidName},
  74. });
  75. AddFakeDevice(hidraw_path, kSubsystemHidraw, kDevnodeHidraw0);
  76. std::vector<mojom::HidDeviceInfoPtr> devices;
  77. base::RunLoop loop;
  78. auto hid_service = std::make_unique<HidServiceLinux>();
  79. hid_service->GetDevices(
  80. base::BindLambdaForTesting([&](std::vector<mojom::HidDeviceInfoPtr> d) {
  81. devices = std::move(d);
  82. loop.Quit();
  83. }));
  84. loop.Run();
  85. ASSERT_EQ(devices.size(), 1u);
  86. EXPECT_EQ(devices[0]->physical_device_id, usb_device_path.value());
  87. EXPECT_EQ(devices[0]->vendor_id, 0xabcd);
  88. EXPECT_EQ(devices[0]->product_id, 0x1234);
  89. EXPECT_EQ(devices[0]->product_name, kPropertyValueHidName);
  90. EXPECT_EQ(devices[0]->serial_number, kPropertyValueHidUniq);
  91. EXPECT_EQ(devices[0]->bus_type, mojom::HidBusType::kHIDBusTypeUSB);
  92. ASSERT_EQ(devices[0]->report_descriptor.size(), 1u);
  93. EXPECT_EQ(devices[0]->report_descriptor[0], 0u);
  94. EXPECT_TRUE(devices[0]->collections.empty());
  95. EXPECT_FALSE(devices[0]->has_report_id);
  96. EXPECT_EQ(devices[0]->max_input_report_size, 0u);
  97. EXPECT_EQ(devices[0]->max_output_report_size, 0u);
  98. EXPECT_EQ(devices[0]->max_feature_report_size, 0u);
  99. EXPECT_EQ(devices[0]->device_node, kDevnodeHidraw0);
  100. EXPECT_TRUE(devices[0]->protected_input_report_ids);
  101. EXPECT_TRUE(devices[0]->protected_input_report_ids->empty());
  102. EXPECT_TRUE(devices[0]->protected_output_report_ids);
  103. EXPECT_TRUE(devices[0]->protected_output_report_ids->empty());
  104. EXPECT_TRUE(devices[0]->protected_feature_report_ids);
  105. EXPECT_TRUE(devices[0]->protected_feature_report_ids->empty());
  106. }
  107. TEST_F(HidServiceLinuxTest, EnumerateBluetoothClassicHidDevice) {
  108. constexpr char kPropertyValueHidId[] = "0005:0000ABCD:00001234";
  109. constexpr char kPropertyValueHidUniq[] = "aa:bb:cc:dd:ee:ff";
  110. // Construct paths for the hidraw device and its ancestors up to the Bluetooth
  111. // link.
  112. auto bt_link_path = GetTempDir().Append(
  113. "sys/devices/pci0000:00/0000:00:0.0/usb2/1-1/1-1:1.0/bluetooth/hci0/"
  114. "hci0:0");
  115. auto hid_path = bt_link_path.Append("0005:ABCD:1234.0000");
  116. auto hidraw_path = hid_path.Append("hidraw/hidraw0");
  117. // The HID service reads the report descriptor from a file in the |hid_path|
  118. // directory.
  119. auto report_descriptor_path = hid_path.Append("report_descriptor");
  120. uint8_t data = 0;
  121. ASSERT_TRUE(base::CreateDirectory(hid_path));
  122. ASSERT_TRUE(
  123. base::WriteFile(report_descriptor_path, base::make_span(&data, 1)));
  124. // Add the fake HID device as well as its ancestors up to the Bluetooth link.
  125. // Ancestors must be added starting from the closest to the root to ensure
  126. // that ancestor device info is available when the hidraw device is added.
  127. AddFakeDevice(bt_link_path, kSubsystemBluetooth, /*devnode=*/absl::nullopt,
  128. kDevtypeLink);
  129. AddFakeDevice(hid_path, kSubsystemHid, /*devnode=*/absl::nullopt,
  130. /*devtype=*/absl::nullopt, /*properties=*/
  131. {
  132. {"HID_ID", kPropertyValueHidId},
  133. {"HID_UNIQ", kPropertyValueHidUniq},
  134. {"HID_NAME", kPropertyValueHidName},
  135. });
  136. AddFakeDevice(hidraw_path, kSubsystemHidraw, kDevnodeHidraw0);
  137. std::vector<mojom::HidDeviceInfoPtr> devices;
  138. base::RunLoop loop;
  139. auto hid_service = std::make_unique<HidServiceLinux>();
  140. hid_service->GetDevices(
  141. base::BindLambdaForTesting([&](std::vector<mojom::HidDeviceInfoPtr> d) {
  142. devices = std::move(d);
  143. loop.Quit();
  144. }));
  145. loop.Run();
  146. ASSERT_EQ(devices.size(), 1u);
  147. EXPECT_EQ(devices[0]->physical_device_id, hid_path.value());
  148. EXPECT_EQ(devices[0]->vendor_id, 0xabcd);
  149. EXPECT_EQ(devices[0]->product_id, 0x1234);
  150. EXPECT_EQ(devices[0]->product_name, kPropertyValueHidName);
  151. EXPECT_EQ(devices[0]->serial_number, kPropertyValueHidUniq);
  152. EXPECT_EQ(devices[0]->bus_type, mojom::HidBusType::kHIDBusTypeBluetooth);
  153. ASSERT_EQ(devices[0]->report_descriptor.size(), 1u);
  154. EXPECT_EQ(devices[0]->report_descriptor[0], 0u);
  155. EXPECT_TRUE(devices[0]->collections.empty());
  156. EXPECT_FALSE(devices[0]->has_report_id);
  157. EXPECT_EQ(devices[0]->max_input_report_size, 0u);
  158. EXPECT_EQ(devices[0]->max_output_report_size, 0u);
  159. EXPECT_EQ(devices[0]->max_feature_report_size, 0u);
  160. EXPECT_EQ(devices[0]->device_node, kDevnodeHidraw0);
  161. EXPECT_TRUE(devices[0]->protected_input_report_ids);
  162. EXPECT_TRUE(devices[0]->protected_input_report_ids->empty());
  163. EXPECT_TRUE(devices[0]->protected_output_report_ids);
  164. EXPECT_TRUE(devices[0]->protected_output_report_ids->empty());
  165. EXPECT_TRUE(devices[0]->protected_feature_report_ids);
  166. EXPECT_TRUE(devices[0]->protected_feature_report_ids->empty());
  167. }
  168. TEST_F(HidServiceLinuxTest, EnumerateBleHidDevice) {
  169. constexpr char kPropertyValueHidId[] = "0005:0000ABCD:00001234";
  170. constexpr char kPropertyValueHidUniq[] = "aa:bb:cc:dd:ee:ff";
  171. // Construct paths for the hidraw device and its ancestors up to the uhid
  172. // device node.
  173. auto uhid_path = GetTempDir().Append("sys/devices/virtual/misc/uhid/");
  174. auto hid_path = uhid_path.Append("0005:ABCD:1234.0000");
  175. auto hidraw_path = hid_path.Append("hidraw/hidraw0");
  176. // The HID service reads the report descriptor from a file in the |hid_path|
  177. // directory.
  178. auto report_descriptor_path = hid_path.Append("report_descriptor");
  179. uint8_t data = 0;
  180. ASSERT_TRUE(base::CreateDirectory(hid_path));
  181. ASSERT_TRUE(
  182. base::WriteFile(report_descriptor_path, base::make_span(&data, 1)));
  183. // Add the fake HID device as well as its ancestors up to the Bluetooth link.
  184. // Ancestors must be added starting from the closest to the root to ensure
  185. // that ancestor device info is available when the hidraw device is added.
  186. AddFakeDevice(uhid_path, kSubsystemMisc);
  187. AddFakeDevice(hid_path, kSubsystemHid, /*devnode=*/absl::nullopt,
  188. /*devtype=*/absl::nullopt, /*properties=*/
  189. {
  190. {"HID_ID", kPropertyValueHidId},
  191. {"HID_UNIQ", kPropertyValueHidUniq},
  192. {"HID_NAME", kPropertyValueHidName},
  193. });
  194. AddFakeDevice(hidraw_path, kSubsystemHidraw, kDevnodeHidraw0);
  195. std::vector<mojom::HidDeviceInfoPtr> devices;
  196. base::RunLoop loop;
  197. auto hid_service = std::make_unique<HidServiceLinux>();
  198. hid_service->GetDevices(
  199. base::BindLambdaForTesting([&](std::vector<mojom::HidDeviceInfoPtr> d) {
  200. devices = std::move(d);
  201. loop.Quit();
  202. }));
  203. loop.Run();
  204. ASSERT_EQ(devices.size(), 1u);
  205. EXPECT_EQ(devices[0]->physical_device_id, hid_path.value());
  206. EXPECT_EQ(devices[0]->vendor_id, 0xabcd);
  207. EXPECT_EQ(devices[0]->product_id, 0x1234);
  208. EXPECT_EQ(devices[0]->product_name, kPropertyValueHidName);
  209. EXPECT_EQ(devices[0]->serial_number, kPropertyValueHidUniq);
  210. EXPECT_EQ(devices[0]->bus_type, mojom::HidBusType::kHIDBusTypeBluetooth);
  211. ASSERT_EQ(devices[0]->report_descriptor.size(), 1u);
  212. EXPECT_EQ(devices[0]->report_descriptor[0], 0u);
  213. EXPECT_TRUE(devices[0]->collections.empty());
  214. EXPECT_FALSE(devices[0]->has_report_id);
  215. EXPECT_EQ(devices[0]->max_input_report_size, 0u);
  216. EXPECT_EQ(devices[0]->max_output_report_size, 0u);
  217. EXPECT_EQ(devices[0]->max_feature_report_size, 0u);
  218. EXPECT_EQ(devices[0]->device_node, kDevnodeHidraw0);
  219. EXPECT_TRUE(devices[0]->protected_input_report_ids);
  220. EXPECT_TRUE(devices[0]->protected_input_report_ids->empty());
  221. EXPECT_TRUE(devices[0]->protected_output_report_ids);
  222. EXPECT_TRUE(devices[0]->protected_output_report_ids->empty());
  223. EXPECT_TRUE(devices[0]->protected_feature_report_ids);
  224. EXPECT_TRUE(devices[0]->protected_feature_report_ids->empty());
  225. }
  226. } // namespace device