Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 1 | // Copyright 2023 The ChromiumOS Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Yong Hong | b3c8357 | 2024-12-10 02:23:52 | [diff] [blame] | 5 | #include "libsegmentation/feature_management_hwid.h" |
| 6 | |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 7 | #include <optional> |
| 8 | |
| 9 | #include <base/logging.h> |
Allen Shih | 87ce1a1 | 2025-04-17 05:22:34 | [diff] [blame] | 10 | #include <brillo/hwid/hwid_utils.h> |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 11 | |
| 12 | #include "libsegmentation/device_info.pb.h" |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 13 | #include "libsegmentation/feature_management_interface.h" |
| 14 | #include "libsegmentation/feature_management_util.h" |
| 15 | |
| 16 | namespace segmentation { |
| 17 | |
| 18 | using chromiumos::feature_management::api::software::DeviceSelection; |
| 19 | using chromiumos::feature_management::api::software::SelectionBundle; |
| 20 | |
| 21 | std::optional<DeviceSelection> FeatureManagementHwid::GetSelectionFromHWID( |
| 22 | const SelectionBundle& selection_bundle_, |
| 23 | const std::string& user_readable_hwid, |
| 24 | bool check_prefix_only) { |
| 25 | const std::optional<std::string> hwid = |
Allen Shih | 87ce1a1 | 2025-04-17 05:22:34 | [diff] [blame] | 26 | brillo::hwid::DecodeHWID(user_readable_hwid); |
George Burgess IV | 3f50420 | 2024-11-06 16:26:43 | [diff] [blame] | 27 | if (!hwid) { |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 28 | return std::nullopt; |
George Burgess IV | 3f50420 | 2024-11-06 16:26:43 | [diff] [blame] | 29 | } |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 30 | for (const auto& selection : selection_bundle_.selections()) { |
| 31 | for (const auto& hwid_profile : selection.hwid_profiles()) { |
| 32 | // Look into the database for a prefix match. |
| 33 | bool prefix_match = false; |
| 34 | for (const auto& prefix : hwid_profile.prefixes()) { |
| 35 | if (user_readable_hwid.rfind(prefix, 0) == 0) { |
| 36 | prefix_match = true; |
| 37 | break; |
| 38 | } |
| 39 | } |
George Burgess IV | 3f50420 | 2024-11-06 16:26:43 | [diff] [blame] | 40 | if (!prefix_match) { |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 41 | continue; |
George Burgess IV | 3f50420 | 2024-11-06 16:26:43 | [diff] [blame] | 42 | } |
| 43 | if (check_prefix_only) { |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 44 | return selection; |
George Burgess IV | 3f50420 | 2024-11-06 16:26:43 | [diff] [blame] | 45 | } |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 46 | |
| 47 | bool all_requirement_met = true; |
| 48 | for (const auto& requirement : hwid_profile.encoding_requirements()) { |
| 49 | std::string bit_value = ""; |
| 50 | for (auto bit_location : requirement.bit_locations()) { |
| 51 | bit_value.append(1, bit_location < hwid.value().size() |
| 52 | ? hwid.value()[bit_location] |
| 53 | : '0'); |
| 54 | } |
| 55 | bool pattern_found = false; |
| 56 | for (auto required_value : requirement.required_values()) { |
| 57 | if (bit_value == required_value) { |
| 58 | pattern_found = true; |
| 59 | break; |
| 60 | } |
| 61 | } |
| 62 | if (!pattern_found) { |
| 63 | all_requirement_met = false; |
| 64 | break; |
| 65 | } |
| 66 | } |
| 67 | if (all_requirement_met) { |
| 68 | return selection; |
| 69 | } |
| 70 | } |
| 71 | } |
| 72 | return std::nullopt; |
| 73 | } |
| 74 | |
| 75 | libsegmentation::DeviceInfo_FeatureLevel HwComplianceVersionToFeatureLevel( |
| 76 | int32_t hw_compliance_version) { |
| 77 | switch (hw_compliance_version) { |
| 78 | case 0: |
| 79 | return libsegmentation::DeviceInfo_FeatureLevel:: |
| 80 | DeviceInfo_FeatureLevel_FEATURE_LEVEL_0; |
| 81 | case 1: |
| 82 | return libsegmentation::DeviceInfo_FeatureLevel:: |
| 83 | DeviceInfo_FeatureLevel_FEATURE_LEVEL_1; |
Yong Hong | b3c8357 | 2024-12-10 02:23:52 | [diff] [blame] | 84 | case 2: |
| 85 | return libsegmentation::DeviceInfo_FeatureLevel:: |
| 86 | DeviceInfo_FeatureLevel_FEATURE_LEVEL_2; |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 87 | default: |
| 88 | return libsegmentation::DeviceInfo_FeatureLevel:: |
| 89 | DeviceInfo_FeatureLevel_FEATURE_LEVEL_UNKNOWN; |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | libsegmentation::DeviceInfo_ScopeLevel HwComplianceVersionToScopeLevel( |
| 94 | bool is_chassis_x_branded) { |
George Burgess IV | 3f50420 | 2024-11-06 16:26:43 | [diff] [blame] | 95 | if (is_chassis_x_branded) { |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 96 | return libsegmentation::DeviceInfo_ScopeLevel:: |
| 97 | DeviceInfo_ScopeLevel_SCOPE_LEVEL_1; |
George Burgess IV | 3f50420 | 2024-11-06 16:26:43 | [diff] [blame] | 98 | } |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 99 | |
| 100 | return libsegmentation::DeviceInfo_ScopeLevel:: |
| 101 | DeviceInfo_ScopeLevel_SCOPE_LEVEL_0; |
| 102 | } |
| 103 | |
| 104 | libsegmentation::DeviceInfo FeatureManagementHwid::GetDeviceInfo( |
| 105 | FeatureManagementHwid::GetDeviceSelectionFn get_selection, |
| 106 | bool is_chassis_x_branded, |
| 107 | int32_t hw_compliance_version) { |
| 108 | libsegmentation::DeviceInfo device_info_result; |
| 109 | |
| 110 | // Implementing decision tree from go/cros-tiering-dd. |
| 111 | if (is_chassis_x_branded || hw_compliance_version > 0) { |
| 112 | if (is_chassis_x_branded) { |
| 113 | device_info_result.set_feature_level( |
| 114 | HwComplianceVersionToFeatureLevel(hw_compliance_version)); |
| 115 | device_info_result.set_scope_level(HwComplianceVersionToScopeLevel(true)); |
| 116 | } else { |
Gwendal Grignou | dc011ea | 2023-07-25 00:36:27 | [diff] [blame] | 117 | if (get_selection(/* check_prefix_only */ true)) { |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 118 | device_info_result.set_feature_level( |
| 119 | HwComplianceVersionToFeatureLevel(hw_compliance_version)); |
| 120 | } else { |
| 121 | device_info_result.set_feature_level( |
| 122 | libsegmentation::DeviceInfo_FeatureLevel:: |
| 123 | DeviceInfo_FeatureLevel_FEATURE_LEVEL_0); |
| 124 | } |
| 125 | device_info_result.set_scope_level( |
| 126 | HwComplianceVersionToScopeLevel(false)); |
| 127 | } |
| 128 | } else { |
Gwendal Grignou | dc011ea | 2023-07-25 00:36:27 | [diff] [blame] | 129 | std::optional<DeviceSelection> selection = |
| 130 | get_selection(/* check_prefix_only */ false); |
Gwendal Grignou | f9533dd | 2023-06-08 04:31:47 | [diff] [blame] | 131 | if (selection) { |
| 132 | device_info_result.set_feature_level( |
| 133 | HwComplianceVersionToFeatureLevel(selection->feature_level())); |
| 134 | } else { |
| 135 | device_info_result.set_feature_level( |
| 136 | libsegmentation::DeviceInfo_FeatureLevel:: |
| 137 | DeviceInfo_FeatureLevel_FEATURE_LEVEL_0); |
| 138 | } |
| 139 | device_info_result.set_scope_level(HwComplianceVersionToScopeLevel(false)); |
| 140 | } |
| 141 | return device_info_result; |
| 142 | } |
| 143 | |
| 144 | } // namespace segmentation |