hid_device_info.cc 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // Copyright 2014 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_device_info.h"
  5. #include "base/containers/contains.h"
  6. #include "base/guid.h"
  7. #include "build/build_config.h"
  8. #include "services/device/public/cpp/hid/hid_blocklist.h"
  9. #include "services/device/public/cpp/hid/hid_report_descriptor.h"
  10. namespace device {
  11. namespace {
  12. const std::vector<mojom::HidReportDescriptionPtr>& ReportsForType(
  13. const mojom::HidCollectionInfoPtr& collection,
  14. HidReportType report_type) {
  15. switch (report_type) {
  16. case HidReportType::kInput:
  17. return collection->input_reports;
  18. case HidReportType::kOutput:
  19. return collection->output_reports;
  20. case HidReportType::kFeature:
  21. return collection->feature_reports;
  22. }
  23. }
  24. } // namespace
  25. HidDeviceInfo::PlatformDeviceIdEntry::PlatformDeviceIdEntry(
  26. base::flat_set<uint8_t> report_ids,
  27. HidPlatformDeviceId platform_device_id)
  28. : report_ids(std::move(report_ids)),
  29. platform_device_id(platform_device_id) {}
  30. HidDeviceInfo::PlatformDeviceIdEntry::PlatformDeviceIdEntry(
  31. const PlatformDeviceIdEntry& entry) = default;
  32. HidDeviceInfo::PlatformDeviceIdEntry&
  33. HidDeviceInfo::PlatformDeviceIdEntry::operator=(
  34. const PlatformDeviceIdEntry& entry) = default;
  35. HidDeviceInfo::PlatformDeviceIdEntry::~PlatformDeviceIdEntry() = default;
  36. HidDeviceInfo::HidDeviceInfo(HidPlatformDeviceId platform_device_id,
  37. const std::string& physical_device_id,
  38. uint16_t vendor_id,
  39. uint16_t product_id,
  40. const std::string& product_name,
  41. const std::string& serial_number,
  42. mojom::HidBusType bus_type,
  43. base::span<const uint8_t> report_descriptor,
  44. std::string device_node) {
  45. std::vector<mojom::HidCollectionInfoPtr> collections;
  46. bool has_report_id;
  47. size_t max_input_report_size;
  48. size_t max_output_report_size;
  49. size_t max_feature_report_size;
  50. HidReportDescriptor descriptor_parser(report_descriptor);
  51. descriptor_parser.GetDetails(&collections, &has_report_id,
  52. &max_input_report_size, &max_output_report_size,
  53. &max_feature_report_size);
  54. auto protected_input_report_ids = HidBlocklist::Get().GetProtectedReportIds(
  55. HidBlocklist::kReportTypeInput, vendor_id, product_id, collections);
  56. auto protected_output_report_ids = HidBlocklist::Get().GetProtectedReportIds(
  57. HidBlocklist::kReportTypeOutput, vendor_id, product_id, collections);
  58. auto protected_feature_report_ids = HidBlocklist::Get().GetProtectedReportIds(
  59. HidBlocklist::kReportTypeFeature, vendor_id, product_id, collections);
  60. auto is_excluded_by_blocklist =
  61. HidBlocklist::Get().IsVendorProductBlocked(vendor_id, product_id);
  62. std::vector<uint8_t> report_ids;
  63. if (has_report_id) {
  64. for (const auto& collection : collections) {
  65. report_ids.insert(report_ids.end(), collection->report_ids.begin(),
  66. collection->report_ids.end());
  67. }
  68. } else {
  69. report_ids.push_back(0);
  70. }
  71. platform_device_id_map_.emplace_back(report_ids, platform_device_id);
  72. device_ = mojom::HidDeviceInfo::New(
  73. base::GenerateGUID(), physical_device_id, vendor_id, product_id,
  74. product_name, serial_number, bus_type,
  75. std::vector<uint8_t>(report_descriptor.begin(), report_descriptor.end()),
  76. std::move(collections), has_report_id, max_input_report_size,
  77. max_output_report_size, max_feature_report_size, device_node,
  78. protected_input_report_ids, protected_output_report_ids,
  79. protected_feature_report_ids, is_excluded_by_blocklist);
  80. }
  81. HidDeviceInfo::HidDeviceInfo(HidPlatformDeviceId platform_device_id,
  82. const std::string& physical_device_id,
  83. const std::string& interface_id,
  84. uint16_t vendor_id,
  85. uint16_t product_id,
  86. const std::string& product_name,
  87. const std::string& serial_number,
  88. mojom::HidBusType bus_type,
  89. mojom::HidCollectionInfoPtr collection,
  90. size_t max_input_report_size,
  91. size_t max_output_report_size,
  92. size_t max_feature_report_size)
  93. : interface_id_(interface_id) {
  94. bool has_report_id = !collection->report_ids.empty();
  95. if (has_report_id) {
  96. platform_device_id_map_.emplace_back(collection->report_ids,
  97. platform_device_id);
  98. } else {
  99. platform_device_id_map_.emplace_back(std::vector<uint8_t>{0},
  100. platform_device_id);
  101. }
  102. std::vector<mojom::HidCollectionInfoPtr> collections;
  103. collections.push_back(std::move(collection));
  104. auto protected_input_report_ids = HidBlocklist::Get().GetProtectedReportIds(
  105. HidBlocklist::kReportTypeInput, vendor_id, product_id, collections);
  106. auto protected_output_report_ids = HidBlocklist::Get().GetProtectedReportIds(
  107. HidBlocklist::kReportTypeOutput, vendor_id, product_id, collections);
  108. auto protected_feature_report_ids = HidBlocklist::Get().GetProtectedReportIds(
  109. HidBlocklist::kReportTypeFeature, vendor_id, product_id, collections);
  110. auto is_excluded_by_blocklist =
  111. HidBlocklist::Get().IsVendorProductBlocked(vendor_id, product_id);
  112. device_ = mojom::HidDeviceInfo::New(
  113. base::GenerateGUID(), physical_device_id, vendor_id, product_id,
  114. product_name, serial_number, bus_type,
  115. /*report_descriptor=*/std::vector<uint8_t>{}, std::move(collections),
  116. has_report_id, max_input_report_size, max_output_report_size,
  117. max_feature_report_size, /*device_node=*/"", protected_input_report_ids,
  118. protected_output_report_ids, protected_feature_report_ids,
  119. is_excluded_by_blocklist);
  120. }
  121. HidDeviceInfo::~HidDeviceInfo() = default;
  122. void HidDeviceInfo::AppendDeviceInfo(scoped_refptr<HidDeviceInfo> device_info) {
  123. // Check that |device_info| has an interface ID and it matches ours.
  124. DCHECK(interface_id_);
  125. DCHECK(device_info->interface_id());
  126. DCHECK_EQ(*interface_id_, *device_info->interface_id());
  127. // Check that the device-level properties are identical.
  128. DCHECK_EQ(device_->physical_device_id, device_info->physical_device_id());
  129. DCHECK_EQ(device_->vendor_id, device_info->vendor_id());
  130. DCHECK_EQ(device_->product_id, device_info->product_id());
  131. DCHECK_EQ(device_->product_name, device_info->product_name());
  132. DCHECK_EQ(device_->serial_number, device_info->serial_number());
  133. DCHECK_EQ(device_->bus_type, device_info->bus_type());
  134. // Append collections from |device_info|.
  135. for (const auto& collection : device_info->collections())
  136. device_->collections.push_back(collection->Clone());
  137. // Append platform device IDs from |device_info|.
  138. for (const auto& entry : device_info->platform_device_id_map()) {
  139. platform_device_id_map_.push_back(
  140. {entry.report_ids, entry.platform_device_id});
  141. }
  142. // Update the maximum report sizes.
  143. device_->max_input_report_size = std::max(
  144. device_->max_input_report_size, device_info->max_input_report_size());
  145. device_->max_output_report_size = std::max(
  146. device_->max_output_report_size, device_info->max_output_report_size());
  147. device_->max_feature_report_size = std::max(
  148. device_->max_feature_report_size, device_info->max_feature_report_size());
  149. // Update the protected report IDs.
  150. device_->protected_input_report_ids =
  151. HidBlocklist::Get().GetProtectedReportIds(
  152. HidBlocklist::kReportTypeInput, device_->vendor_id,
  153. device_->product_id, device_->collections);
  154. device_->protected_output_report_ids =
  155. HidBlocklist::Get().GetProtectedReportIds(
  156. HidBlocklist::kReportTypeOutput, device_->vendor_id,
  157. device_->product_id, device_->collections);
  158. device_->protected_feature_report_ids =
  159. HidBlocklist::Get().GetProtectedReportIds(
  160. HidBlocklist::kReportTypeFeature, device_->vendor_id,
  161. device_->product_id, device_->collections);
  162. device_->is_excluded_by_blocklist =
  163. HidBlocklist::Get().IsVendorProductBlocked(device_->vendor_id,
  164. device_->product_id);
  165. }
  166. const mojom::HidCollectionInfo* HidDeviceInfo::FindCollectionWithReport(
  167. uint8_t report_id,
  168. HidReportType report_type) {
  169. if (!device_->has_report_id) {
  170. // `report_id` must be zero if the device does not use numbered reports.
  171. if (report_id != 0)
  172. return nullptr;
  173. // Return the first collection with a report of type `report_type`, or
  174. // nullptr if there is no report of that type.
  175. auto find_it = base::ranges::find_if(
  176. device_->collections, [=](const auto& collection) {
  177. const auto& reports = ReportsForType(collection, report_type);
  178. return !reports.empty();
  179. });
  180. if (find_it == device_->collections.end())
  181. return nullptr;
  182. DCHECK(find_it->get());
  183. return find_it->get();
  184. }
  185. // `report_id` must be non-zero if the device uses numbered reports.
  186. if (report_id == 0)
  187. return nullptr;
  188. // Return the collection containing a report with `report_id` and type
  189. // `report_type`, or nullptr if it is not in any collection.
  190. auto find_it =
  191. base::ranges::find_if(device_->collections, [=](const auto& collection) {
  192. const auto& reports = ReportsForType(collection, report_type);
  193. return base::Contains(reports, report_id, [](const auto& report) {
  194. return report->report_id;
  195. });
  196. });
  197. if (find_it == device_->collections.end())
  198. return nullptr;
  199. DCHECK(find_it->get());
  200. return find_it->get();
  201. }
  202. } // namespace device