blob: ee4f7e159d30ac7e2d488c145e30a7d2f2cee0b7 [file] [log] [blame]
Yong Hongcc481892019-05-16 20:26:05 +08001/* Copyright 2019 The Chromium OS 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 */
5
6#include "hardware_verifier/verifier_impl.h"
7
8#include <map>
Yong Hong85a4dff2019-05-25 04:22:47 +08009#include <set>
Yong Hongcc481892019-05-16 20:26:05 +080010#include <string>
11#include <utility>
12
13#include <base/logging.h>
14#include <base/optional.h>
15
16namespace hardware_verifier {
17
Yong Hong85a4dff2019-05-25 04:22:47 +080018namespace {
19
20constexpr auto kGenericComponentName = "generic";
Stimim Chenacdd9962020-05-11 17:00:27 +080021constexpr auto kNoMatchComponentName = "NO_MATCH";
22
23void AddFoundComponentInfo(
24 HwVerificationReport* hw_verification_report,
25 const runtime_probe::ProbeRequest_SupportCategory& component_category,
26 const std::string& comp_name,
27 const QualificationStatus status) {
28 auto* found_comp_info = hw_verification_report->add_found_component_infos();
29 found_comp_info->set_component_category(component_category);
30 found_comp_info->set_component_uuid(comp_name);
31 found_comp_info->set_qualification_status(status);
32 if (status != QualificationStatus::QUALIFIED) {
33 hw_verification_report->set_is_compliant(false);
34 }
35}
Yong Hong85a4dff2019-05-25 04:22:47 +080036
37} // namespace
38
39VerifierImpl::VerifierImpl() {
40 using CppType = google::protobuf::FieldDescriptor::CppType;
41 constexpr int kCppTypeMsg = CppType::CPPTYPE_MESSAGE;
42 constexpr int kCppTypeStr = CppType::CPPTYPE_STRING;
43
44 // Resolve |comp_category_infos_| in the constructor.
45 const auto* category_enum_desc =
46 runtime_probe::ProbeRequest_SupportCategory_descriptor();
47 comp_category_infos_.resize(category_enum_desc->value_count());
48
49 const auto* probe_result_desc = runtime_probe::ProbeResult::descriptor();
50 const auto* generic_device_info_desc =
51 HwVerificationReport_GenericDeviceInfo::descriptor();
52 for (int i = 0; i < category_enum_desc->value_count(); ++i) {
53 auto* comp_category_info = &comp_category_infos_[i];
54 const auto& comp_category_name = category_enum_desc->value(i)->name();
55
56 comp_category_info->enum_value = category_enum_desc->value(i)->number();
57 comp_category_info->enum_name = comp_category_name;
58
59 const auto* field_desc =
60 probe_result_desc->FindFieldByName(comp_category_name);
61 DCHECK(field_desc && field_desc->cpp_type() == kCppTypeMsg &&
62 field_desc->is_repeated())
63 << "Field (" << comp_category_name << ") must be a repeated field for "
64 << "the HW components in |runtime_probe::ProbeResult|.";
65 comp_category_info->probe_result_comp_field = field_desc;
66
67 const auto* probe_result_comp_desc = field_desc->message_type();
68 field_desc = probe_result_comp_desc->FindFieldByName("name");
69 DCHECK(field_desc && field_desc->cpp_type() == kCppTypeStr &&
70 field_desc->is_optional())
71 << "Field (" << comp_category_name
72 << ") should contain a string of the name of the component.";
73 comp_category_info->probe_result_comp_name_field = field_desc;
74
75 field_desc = probe_result_comp_desc->FindFieldByName("values");
76 DCHECK(field_desc && field_desc->cpp_type() == kCppTypeMsg &&
77 field_desc->is_optional())
78 << "Field (" << comp_category_name
79 << ") should contain a message field for the component values.";
80 comp_category_info->probe_result_comp_values_field = field_desc;
81
82 field_desc = generic_device_info_desc->FindFieldByName(comp_category_name);
83 if (field_desc) {
84 DCHECK(field_desc->cpp_type() == kCppTypeMsg && field_desc->is_repeated())
85 << "|hardware_verifier::HwVerificationReport_GenericDeviceInfo| "
86 << "should contain a repeated field for the generic ("
87 << comp_category_name << ") components.";
88 } else {
89 VLOG(1) << "(" << comp_category_name << ") field is not found in "
90 << "|hardware_verifier::HwVerificationReport_GenericDeviceInfo|, "
91 << "will ignore the generic component of that category.";
92 }
93 comp_category_info->report_comp_values_field = field_desc;
94 }
95}
96
Yong Hongcc481892019-05-16 20:26:05 +080097base::Optional<HwVerificationReport> VerifierImpl::Verify(
98 const runtime_probe::ProbeResult& probe_result,
99 const HwVerificationSpec& hw_verification_spec) const {
Stimim Chenacdd9962020-05-11 17:00:27 +0800100 // A dictionary of 'expected_component_category => seen'.
101 std::map<int, bool> seen_comp;
102 // Collect the categories of generic components we found.
103 std::set<int> seen_generic_comp;
104
Yong Hongcc481892019-05-16 20:26:05 +0800105 // A dictionary which maps (component_category, component_uuid) to its
106 // qualification status.
107 std::map<int, std::map<std::string, QualificationStatus>> qual_status_dict;
Yong Hong85a4dff2019-05-25 04:22:47 +0800108 for (const auto& comp_info : hw_verification_spec.component_infos()) {
109 const auto& category = comp_info.component_category();
110 const auto& uuid = comp_info.component_uuid();
111 const auto& qualification_status = comp_info.qualification_status();
Yong Hongcc481892019-05-16 20:26:05 +0800112 const auto& insert_result =
113 qual_status_dict[static_cast<int>(category)].emplace(
114 uuid, qualification_status);
115 if (!insert_result.second) {
116 LOG(ERROR)
117 << "The verification spec contains duplicated component infos.";
118 return base::nullopt;
119 }
Stimim Chenacdd9962020-05-11 17:00:27 +0800120
121 // We expect to see this component in probe result.
122 seen_comp[category] = false;
Yong Hongcc481892019-05-16 20:26:05 +0800123 }
124
Yong Hong85a4dff2019-05-25 04:22:47 +0800125 // A dictionary which maps component_category to the field names in the
126 // whitelist.
127 std::map<int, std::set<std::string>> generic_comp_value_whitelists;
128 for (const auto& spec_info :
129 hw_verification_spec.generic_component_value_whitelists()) {
130 const auto& insert_result = generic_comp_value_whitelists.emplace(
131 spec_info.component_category(),
132 std::set<std::string>(spec_info.field_names().cbegin(),
133 spec_info.field_names().cend()));
134 if (!insert_result.second) {
135 LOG(ERROR) << "Duplicated whitelist tables for category (num="
136 << spec_info.component_category() << ") are detected in the "
137 << "verification spec.";
138 return base::nullopt;
139 }
140 }
141
Yong Hongcc481892019-05-16 20:26:05 +0800142 HwVerificationReport hw_verification_report;
143 hw_verification_report.set_is_compliant(true);
Yong Hong85a4dff2019-05-25 04:22:47 +0800144 auto* generic_device_info =
145 hw_verification_report.mutable_generic_device_info();
146 const auto* generic_device_info_refl = generic_device_info->GetReflection();
Yong Hongcc481892019-05-16 20:26:05 +0800147
Yong Hongcc481892019-05-16 20:26:05 +0800148 const auto* probe_result_refl = probe_result.GetReflection();
Yong Hong85a4dff2019-05-25 04:22:47 +0800149 for (const auto& comp_category_info : comp_category_infos_) {
150 const auto& comp_name_to_qual_status =
151 qual_status_dict[comp_category_info.enum_value];
Yong Hongcc481892019-05-16 20:26:05 +0800152
Yong Hong85a4dff2019-05-25 04:22:47 +0800153 // the default whitelist is empty.
154 const auto& generic_comp_value_whitelist =
155 generic_comp_value_whitelists[comp_category_info.enum_value];
Yong Hongcc481892019-05-16 20:26:05 +0800156
Yong Hong85a4dff2019-05-25 04:22:47 +0800157 const auto& num_comps = probe_result_refl->FieldSize(
158 probe_result, comp_category_info.probe_result_comp_field);
159 for (int i = 0; i < num_comps; ++i) {
160 const auto& comp = probe_result_refl->GetRepeatedMessage(
161 probe_result, comp_category_info.probe_result_comp_field, i);
Yong Hongcc481892019-05-16 20:26:05 +0800162 const auto* comp_refl = comp.GetReflection();
Yong Hong85a4dff2019-05-25 04:22:47 +0800163 const auto& comp_name = comp_refl->GetString(
164 comp, comp_category_info.probe_result_comp_name_field);
Yong Hongcc481892019-05-16 20:26:05 +0800165
Yong Hong85a4dff2019-05-25 04:22:47 +0800166 // If the component name is "generic", add it to |generic_device_info|
167 // in the report.
168 if (comp_name == kGenericComponentName) {
Stimim Chenacdd9962020-05-11 17:00:27 +0800169 seen_generic_comp.insert(comp_category_info.enum_value);
Yong Hong85a4dff2019-05-25 04:22:47 +0800170 if (!comp_category_info.report_comp_values_field) {
171 VLOG(1) << "Ignore the generic component of ("
172 << comp_category_info.enum_name << ") category.";
173 } else {
174 // Duplicate the original values and filter the fields by the
175 // whitelist.
176 auto* dup_comp_values = generic_device_info_refl->AddMessage(
177 generic_device_info, comp_category_info.report_comp_values_field);
178 dup_comp_values->CopyFrom(comp_refl->GetMessage(
179 comp, comp_category_info.probe_result_comp_values_field));
180
181 const auto* dup_comp_values_refl = dup_comp_values->GetReflection();
182 const auto* dup_comp_values_desc = dup_comp_values->GetDescriptor();
183 for (int j = 0; j < dup_comp_values_desc->field_count(); ++j) {
184 const auto* field = dup_comp_values_desc->field(j);
185 if (!generic_comp_value_whitelist.count(field->name())) {
186 dup_comp_values_refl->ClearField(dup_comp_values, field);
187 }
188 }
189 }
190 continue;
Yong Hongcc481892019-05-16 20:26:05 +0800191 }
Yong Hong85a4dff2019-05-25 04:22:47 +0800192
193 // If the component name is not "generic", do the regular qualification
194 // status check.
Yong Hongcc481892019-05-16 20:26:05 +0800195 const auto& qual_status_it = comp_name_to_qual_status.find(comp_name);
196 if (qual_status_it == comp_name_to_qual_status.end()) {
197 LOG(ERROR) << "The probe result contains unregonizable components "
Yong Hong85a4dff2019-05-25 04:22:47 +0800198 << "(category=" << comp_category_info.enum_name
199 << ", uuid=" << comp_name << ").";
Yong Hongcc481892019-05-16 20:26:05 +0800200 return base::nullopt;
201 }
Stimim Chenacdd9962020-05-11 17:00:27 +0800202 // TODO(b147654337): How about components that are "missing", that is:
203 // - It is expected on the system (according to SKU or MODEL).
204 // - We cannot find this in generic nor non-generic components.
205 AddFoundComponentInfo(
206 &hw_verification_report,
Yong Hongcc481892019-05-16 20:26:05 +0800207 static_cast<runtime_probe::ProbeRequest_SupportCategory>(
Stimim Chenacdd9962020-05-11 17:00:27 +0800208 comp_category_info.enum_value),
209 comp_name, qual_status_it->second);
210 seen_comp[comp_category_info.enum_value] = true;
211 }
212 }
213
214 for (const auto& it : seen_comp) {
215 // We have found a generic component in this category, but this doesn't have
216 // any qualification status.
217 if (!it.second && seen_generic_comp.count(it.first)) {
218 AddFoundComponentInfo(
219 &hw_verification_report,
220 static_cast<runtime_probe::ProbeRequest_SupportCategory>(it.first),
221 kNoMatchComponentName, QualificationStatus::NO_MATCH);
Yong Hongcc481892019-05-16 20:26:05 +0800222 }
223 }
224
225 // TODO(yhong): Implement the SKU specific checks.
226 return hw_verification_report;
227}
228
229} // namespace hardware_verifier