blob: c0440026b32a584020903819d5126b56f2a992d0 [file] [log] [blame]
Yong Hongcb45e082019-01-30 18:55:16 +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/cli.h"
7
8#include <iostream>
Yong Hong8532b522020-03-05 17:23:20 +08009#include <sstream>
Yong Hong8d168b02019-05-23 19:54:23 +080010#include <string>
Yong Hongcb45e082019-01-30 18:55:16 +080011
12#include <base/files/file_path.h>
13#include <base/logging.h>
14#include <base/optional.h>
15#include <google/protobuf/io/zero_copy_stream_impl.h>
Yong Hong85a4dff2019-05-25 04:22:47 +080016#include <google/protobuf/text_format.h>
Yong Hong8d168b02019-05-23 19:54:23 +080017#include <google/protobuf/util/json_util.h>
Yong Hongcb45e082019-01-30 18:55:16 +080018#include <runtime_probe/proto_bindings/runtime_probe.pb.h>
19
20#include "hardware_verifier/hardware_verifier.pb.h"
Yong Hongf4872de2019-01-30 19:04:18 +080021#include "hardware_verifier/hw_verification_spec_getter_impl.h"
Wei-Han Chen5af45462020-03-20 18:06:11 +080022#include "hardware_verifier/observer.h"
Yong Hong5d7d6d92019-01-30 19:07:36 +080023#include "hardware_verifier/probe_result_getter_impl.h"
Yong Hongcc481892019-05-16 20:26:05 +080024#include "hardware_verifier/verifier_impl.h"
Yong Hongcb45e082019-01-30 18:55:16 +080025
26namespace hardware_verifier {
27
Yong Hong85a4dff2019-05-25 04:22:47 +080028namespace {
29
Yong Hong8532b522020-03-05 17:23:20 +080030base::Optional<std::string> OutputInTextFormat(
Kevin Linef321a52020-09-01 18:31:52 +080031 HwVerificationReport hw_verification_report, bool pii) {
Yong Hong8532b522020-03-05 17:23:20 +080032 std::stringstream ss;
Yong Hong85a4dff2019-05-25 04:22:47 +080033 const auto generic_device_info = hw_verification_report.generic_device_info();
34 hw_verification_report.clear_generic_device_info();
35
36 // Output the AVL qualification status in JSON format.
37 auto json_print_opts = google::protobuf::util::JsonPrintOptions();
38 json_print_opts.add_whitespace = true;
39 json_print_opts.always_print_primitive_fields = true;
40 std::string json_output_data;
41 const auto convert_status = google::protobuf::util::MessageToJsonString(
42 hw_verification_report, &json_output_data, json_print_opts);
43 if (!convert_status.ok()) {
44 LOG(ERROR) << "Failed to output the qualification report in JSON: "
45 << convert_status.ToString() << ".";
Yong Hong8532b522020-03-05 17:23:20 +080046 return base::nullopt;
Yong Hong85a4dff2019-05-25 04:22:47 +080047 }
Yong Hong8532b522020-03-05 17:23:20 +080048 ss << "[Component Qualification Status]\n" << json_output_data;
Yong Hong85a4dff2019-05-25 04:22:47 +080049
Kevin Linef321a52020-09-01 18:31:52 +080050 if (pii) {
51 // Output the generic device info in prototxt format.
52 ss << "\n[Generic Device Info]\n";
Yong Hong8532b522020-03-05 17:23:20 +080053 // Enclose google::protobuf::io::OstreamOutputStream in another nested
54 // scope so that its data will be flushed while being destroyed.
55 google::protobuf::io::OstreamOutputStream ostream_output_stream{&ss};
56 if (!google::protobuf::TextFormat::Print(generic_device_info,
57 &ostream_output_stream)) {
58 LOG(ERROR)
59 << "Failed to output the generic device info in prototxt format.";
60 return base::nullopt;
61 }
Yong Hong85a4dff2019-05-25 04:22:47 +080062 }
Yong Hong8532b522020-03-05 17:23:20 +080063 return ss.str();
Yong Hong85a4dff2019-05-25 04:22:47 +080064}
65
66} // namespace
67
Yong Hongcb45e082019-01-30 18:55:16 +080068CLI::CLI()
Yong Hong5d7d6d92019-01-30 19:07:36 +080069 : pr_getter_(std::make_unique<ProbeResultGetterImpl>()),
Yong Hongf4872de2019-01-30 19:04:18 +080070 vp_getter_(std::make_unique<HwVerificationSpecGetterImpl>()),
Yong Hongcc481892019-05-16 20:26:05 +080071 verifier_(std::make_unique<VerifierImpl>()),
Yong Hongcb45e082019-01-30 18:55:16 +080072 output_stream_(&std::cout) {}
73
74CLIVerificationResult CLI::Run(const std::string& probe_result_file,
75 const std::string& hw_verification_spec_file,
Kevin Linef321a52020-09-01 18:31:52 +080076 const CLIOutputFormat output_format,
77 bool pii) {
Kevin Lin2805ce92020-10-19 16:18:41 +080078 LOG(INFO) << "Get the verification payload.";
79 base::Optional<HwVerificationSpec> hw_verification_spec;
80 if (hw_verification_spec_file.empty()) {
81 hw_verification_spec = vp_getter_->GetDefault();
82 } else {
83 hw_verification_spec =
84 vp_getter_->GetFromFile(base::FilePath(hw_verification_spec_file));
85 }
86 if (!hw_verification_spec) {
87 return CLIVerificationResult::kInvalidHwVerificationSpecFile;
88 }
89
Yong Hongcb45e082019-01-30 18:55:16 +080090 LOG(INFO) << "Get the probe result.";
91 base::Optional<runtime_probe::ProbeResult> probe_result;
Wei-Han Chen918b3ba2020-03-20 18:26:37 +080092 auto observer = Observer::GetInstance();
93
Yong Hongcb45e082019-01-30 18:55:16 +080094 if (probe_result_file.empty()) {
Wei-Han Chen5af45462020-03-20 18:06:11 +080095 observer->StartTimer(hardware_verifier::kMetricTimeToProbe);
Yong Hongcb45e082019-01-30 18:55:16 +080096 probe_result = pr_getter_->GetFromRuntimeProbe();
Wei-Han Chen5af45462020-03-20 18:06:11 +080097 observer->StopTimer(hardware_verifier::kMetricTimeToProbe);
Wei-Han Chen9a4f7592020-01-21 16:23:27 +080098
Yong Hongcb45e082019-01-30 18:55:16 +080099 if (!probe_result) {
100 return CLIVerificationResult::kProbeFail;
101 }
102 } else {
103 probe_result = pr_getter_->GetFromFile(base::FilePath(probe_result_file));
104 if (!probe_result) {
105 return CLIVerificationResult::kInvalidProbeResultFile;
106 }
107 }
108
Yong Hongcb45e082019-01-30 18:55:16 +0800109 LOG(INFO) << "Verify the probe result by the verification payload.";
110 const auto verifier_result =
111 verifier_->Verify(probe_result.value(), hw_verification_spec.value());
112 if (!verifier_result) {
113 return CLIVerificationResult::kProbeResultHwVerificationSpecMisalignment;
114 }
Kevin Linef321a52020-09-01 18:31:52 +0800115 auto hw_verification_report = verifier_result.value();
116
117 if (!pii) {
118 // Remove PII data.
119 for (auto& mutable_component :
120 *(hw_verification_report.mutable_found_component_infos())) {
121 mutable_component.clear_component_uuid();
122 }
123 hw_verification_report.clear_generic_device_info();
124 }
Yong Hongcb45e082019-01-30 18:55:16 +0800125
126 LOG(INFO) << "Output the report.";
127 switch (output_format) {
Yong Hong8532b522020-03-05 17:23:20 +0800128 case CLIOutputFormat::kProtoBin: {
129 std::string s;
130 if (!hw_verification_report.SerializeToString(&s)) {
Yong Hongcb45e082019-01-30 18:55:16 +0800131 return CLIVerificationResult::kUnknownError;
132 }
Yong Hong8532b522020-03-05 17:23:20 +0800133 LOG(INFO) << "Output the report in protobuf binary format, " << s.size()
134 << "bytes.";
135 *output_stream_ << s;
Yong Hongcb45e082019-01-30 18:55:16 +0800136 break;
Yong Hong8532b522020-03-05 17:23:20 +0800137 }
138 case CLIOutputFormat::kText: {
Kevin Linef321a52020-09-01 18:31:52 +0800139 auto output_data = OutputInTextFormat(hw_verification_report, pii);
Yong Hong8532b522020-03-05 17:23:20 +0800140 if (!output_data.has_value()) {
Yong Hongcb45e082019-01-30 18:55:16 +0800141 return CLIVerificationResult::kUnknownError;
142 }
Yong Hong8532b522020-03-05 17:23:20 +0800143 LOG(INFO) << "Output the report in text format:";
144 LOG(INFO) << output_data.value();
145 *output_stream_ << output_data.value();
146 }
Yong Hongcb45e082019-01-30 18:55:16 +0800147 }
148
Stimim Chen464418f2020-04-20 10:37:08 +0800149 LOG(INFO) << "Send to Observer.";
150 observer->RecordHwVerificationReport(hw_verification_report);
151
Yong Hongcb45e082019-01-30 18:55:16 +0800152 return (hw_verification_report.is_compliant() ? CLIVerificationResult::kPass
153 : CLIVerificationResult::kFail);
154}
155
156} // namespace hardware_verifier