Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 1 | /* 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 Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 9 | #include <sstream> |
Yong Hong | 8d168b0 | 2019-05-23 19:54:23 +0800 | [diff] [blame] | 10 | #include <string> |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 11 | |
| 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 Hong | 85a4dff | 2019-05-25 04:22:47 +0800 | [diff] [blame] | 16 | #include <google/protobuf/text_format.h> |
Yong Hong | 8d168b0 | 2019-05-23 19:54:23 +0800 | [diff] [blame] | 17 | #include <google/protobuf/util/json_util.h> |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 18 | #include <runtime_probe/proto_bindings/runtime_probe.pb.h> |
| 19 | |
| 20 | #include "hardware_verifier/hardware_verifier.pb.h" |
Yong Hong | f4872de | 2019-01-30 19:04:18 +0800 | [diff] [blame] | 21 | #include "hardware_verifier/hw_verification_spec_getter_impl.h" |
Wei-Han Chen | 5af4546 | 2020-03-20 18:06:11 +0800 | [diff] [blame] | 22 | #include "hardware_verifier/observer.h" |
Yong Hong | 5d7d6d9 | 2019-01-30 19:07:36 +0800 | [diff] [blame] | 23 | #include "hardware_verifier/probe_result_getter_impl.h" |
Yong Hong | cc48189 | 2019-05-16 20:26:05 +0800 | [diff] [blame] | 24 | #include "hardware_verifier/verifier_impl.h" |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 25 | |
| 26 | namespace hardware_verifier { |
| 27 | |
Yong Hong | 85a4dff | 2019-05-25 04:22:47 +0800 | [diff] [blame] | 28 | namespace { |
| 29 | |
Yong Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 30 | base::Optional<std::string> OutputInTextFormat( |
Kevin Lin | ef321a5 | 2020-09-01 18:31:52 +0800 | [diff] [blame] | 31 | HwVerificationReport hw_verification_report, bool pii) { |
Yong Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 32 | std::stringstream ss; |
Yong Hong | 85a4dff | 2019-05-25 04:22:47 +0800 | [diff] [blame] | 33 | 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 Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 46 | return base::nullopt; |
Yong Hong | 85a4dff | 2019-05-25 04:22:47 +0800 | [diff] [blame] | 47 | } |
Yong Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 48 | ss << "[Component Qualification Status]\n" << json_output_data; |
Yong Hong | 85a4dff | 2019-05-25 04:22:47 +0800 | [diff] [blame] | 49 | |
Kevin Lin | ef321a5 | 2020-09-01 18:31:52 +0800 | [diff] [blame] | 50 | if (pii) { |
| 51 | // Output the generic device info in prototxt format. |
| 52 | ss << "\n[Generic Device Info]\n"; |
Yong Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 53 | // 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 Hong | 85a4dff | 2019-05-25 04:22:47 +0800 | [diff] [blame] | 62 | } |
Yong Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 63 | return ss.str(); |
Yong Hong | 85a4dff | 2019-05-25 04:22:47 +0800 | [diff] [blame] | 64 | } |
| 65 | |
| 66 | } // namespace |
| 67 | |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 68 | CLI::CLI() |
Yong Hong | 5d7d6d9 | 2019-01-30 19:07:36 +0800 | [diff] [blame] | 69 | : pr_getter_(std::make_unique<ProbeResultGetterImpl>()), |
Yong Hong | f4872de | 2019-01-30 19:04:18 +0800 | [diff] [blame] | 70 | vp_getter_(std::make_unique<HwVerificationSpecGetterImpl>()), |
Yong Hong | cc48189 | 2019-05-16 20:26:05 +0800 | [diff] [blame] | 71 | verifier_(std::make_unique<VerifierImpl>()), |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 72 | output_stream_(&std::cout) {} |
| 73 | |
| 74 | CLIVerificationResult CLI::Run(const std::string& probe_result_file, |
| 75 | const std::string& hw_verification_spec_file, |
Kevin Lin | ef321a5 | 2020-09-01 18:31:52 +0800 | [diff] [blame] | 76 | const CLIOutputFormat output_format, |
| 77 | bool pii) { |
Kevin Lin | 2805ce9 | 2020-10-19 16:18:41 +0800 | [diff] [blame] | 78 | 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 Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 90 | LOG(INFO) << "Get the probe result."; |
| 91 | base::Optional<runtime_probe::ProbeResult> probe_result; |
Wei-Han Chen | 918b3ba | 2020-03-20 18:26:37 +0800 | [diff] [blame] | 92 | auto observer = Observer::GetInstance(); |
| 93 | |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 94 | if (probe_result_file.empty()) { |
Wei-Han Chen | 5af4546 | 2020-03-20 18:06:11 +0800 | [diff] [blame] | 95 | observer->StartTimer(hardware_verifier::kMetricTimeToProbe); |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 96 | probe_result = pr_getter_->GetFromRuntimeProbe(); |
Wei-Han Chen | 5af4546 | 2020-03-20 18:06:11 +0800 | [diff] [blame] | 97 | observer->StopTimer(hardware_verifier::kMetricTimeToProbe); |
Wei-Han Chen | 9a4f759 | 2020-01-21 16:23:27 +0800 | [diff] [blame] | 98 | |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 99 | 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 Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 109 | 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 Lin | ef321a5 | 2020-09-01 18:31:52 +0800 | [diff] [blame] | 115 | 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 Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 125 | |
| 126 | LOG(INFO) << "Output the report."; |
| 127 | switch (output_format) { |
Yong Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 128 | case CLIOutputFormat::kProtoBin: { |
| 129 | std::string s; |
| 130 | if (!hw_verification_report.SerializeToString(&s)) { |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 131 | return CLIVerificationResult::kUnknownError; |
| 132 | } |
Yong Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 133 | LOG(INFO) << "Output the report in protobuf binary format, " << s.size() |
| 134 | << "bytes."; |
| 135 | *output_stream_ << s; |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 136 | break; |
Yong Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 137 | } |
| 138 | case CLIOutputFormat::kText: { |
Kevin Lin | ef321a5 | 2020-09-01 18:31:52 +0800 | [diff] [blame] | 139 | auto output_data = OutputInTextFormat(hw_verification_report, pii); |
Yong Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 140 | if (!output_data.has_value()) { |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 141 | return CLIVerificationResult::kUnknownError; |
| 142 | } |
Yong Hong | 8532b52 | 2020-03-05 17:23:20 +0800 | [diff] [blame] | 143 | LOG(INFO) << "Output the report in text format:"; |
| 144 | LOG(INFO) << output_data.value(); |
| 145 | *output_stream_ << output_data.value(); |
| 146 | } |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 147 | } |
| 148 | |
Stimim Chen | 464418f | 2020-04-20 10:37:08 +0800 | [diff] [blame] | 149 | LOG(INFO) << "Send to Observer."; |
| 150 | observer->RecordHwVerificationReport(hw_verification_report); |
| 151 | |
Yong Hong | cb45e08 | 2019-01-30 18:55:16 +0800 | [diff] [blame] | 152 | return (hw_verification_report.is_compliant() ? CLIVerificationResult::kPass |
| 153 | : CLIVerificationResult::kFail); |
| 154 | } |
| 155 | |
| 156 | } // namespace hardware_verifier |