blob: c0440026b32a584020903819d5126b56f2a992d0 [file] [log] [blame]
/* Copyright 2019 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "hardware_verifier/cli.h"
#include <iostream>
#include <sstream>
#include <string>
#include <base/files/file_path.h>
#include <base/logging.h>
#include <base/optional.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/util/json_util.h>
#include <runtime_probe/proto_bindings/runtime_probe.pb.h>
#include "hardware_verifier/hardware_verifier.pb.h"
#include "hardware_verifier/hw_verification_spec_getter_impl.h"
#include "hardware_verifier/observer.h"
#include "hardware_verifier/probe_result_getter_impl.h"
#include "hardware_verifier/verifier_impl.h"
namespace hardware_verifier {
namespace {
base::Optional<std::string> OutputInTextFormat(
HwVerificationReport hw_verification_report, bool pii) {
std::stringstream ss;
const auto generic_device_info = hw_verification_report.generic_device_info();
hw_verification_report.clear_generic_device_info();
// Output the AVL qualification status in JSON format.
auto json_print_opts = google::protobuf::util::JsonPrintOptions();
json_print_opts.add_whitespace = true;
json_print_opts.always_print_primitive_fields = true;
std::string json_output_data;
const auto convert_status = google::protobuf::util::MessageToJsonString(
hw_verification_report, &json_output_data, json_print_opts);
if (!convert_status.ok()) {
LOG(ERROR) << "Failed to output the qualification report in JSON: "
<< convert_status.ToString() << ".";
return base::nullopt;
}
ss << "[Component Qualification Status]\n" << json_output_data;
if (pii) {
// Output the generic device info in prototxt format.
ss << "\n[Generic Device Info]\n";
// Enclose google::protobuf::io::OstreamOutputStream in another nested
// scope so that its data will be flushed while being destroyed.
google::protobuf::io::OstreamOutputStream ostream_output_stream{&ss};
if (!google::protobuf::TextFormat::Print(generic_device_info,
&ostream_output_stream)) {
LOG(ERROR)
<< "Failed to output the generic device info in prototxt format.";
return base::nullopt;
}
}
return ss.str();
}
} // namespace
CLI::CLI()
: pr_getter_(std::make_unique<ProbeResultGetterImpl>()),
vp_getter_(std::make_unique<HwVerificationSpecGetterImpl>()),
verifier_(std::make_unique<VerifierImpl>()),
output_stream_(&std::cout) {}
CLIVerificationResult CLI::Run(const std::string& probe_result_file,
const std::string& hw_verification_spec_file,
const CLIOutputFormat output_format,
bool pii) {
LOG(INFO) << "Get the verification payload.";
base::Optional<HwVerificationSpec> hw_verification_spec;
if (hw_verification_spec_file.empty()) {
hw_verification_spec = vp_getter_->GetDefault();
} else {
hw_verification_spec =
vp_getter_->GetFromFile(base::FilePath(hw_verification_spec_file));
}
if (!hw_verification_spec) {
return CLIVerificationResult::kInvalidHwVerificationSpecFile;
}
LOG(INFO) << "Get the probe result.";
base::Optional<runtime_probe::ProbeResult> probe_result;
auto observer = Observer::GetInstance();
if (probe_result_file.empty()) {
observer->StartTimer(hardware_verifier::kMetricTimeToProbe);
probe_result = pr_getter_->GetFromRuntimeProbe();
observer->StopTimer(hardware_verifier::kMetricTimeToProbe);
if (!probe_result) {
return CLIVerificationResult::kProbeFail;
}
} else {
probe_result = pr_getter_->GetFromFile(base::FilePath(probe_result_file));
if (!probe_result) {
return CLIVerificationResult::kInvalidProbeResultFile;
}
}
LOG(INFO) << "Verify the probe result by the verification payload.";
const auto verifier_result =
verifier_->Verify(probe_result.value(), hw_verification_spec.value());
if (!verifier_result) {
return CLIVerificationResult::kProbeResultHwVerificationSpecMisalignment;
}
auto hw_verification_report = verifier_result.value();
if (!pii) {
// Remove PII data.
for (auto& mutable_component :
*(hw_verification_report.mutable_found_component_infos())) {
mutable_component.clear_component_uuid();
}
hw_verification_report.clear_generic_device_info();
}
LOG(INFO) << "Output the report.";
switch (output_format) {
case CLIOutputFormat::kProtoBin: {
std::string s;
if (!hw_verification_report.SerializeToString(&s)) {
return CLIVerificationResult::kUnknownError;
}
LOG(INFO) << "Output the report in protobuf binary format, " << s.size()
<< "bytes.";
*output_stream_ << s;
break;
}
case CLIOutputFormat::kText: {
auto output_data = OutputInTextFormat(hw_verification_report, pii);
if (!output_data.has_value()) {
return CLIVerificationResult::kUnknownError;
}
LOG(INFO) << "Output the report in text format:";
LOG(INFO) << output_data.value();
*output_stream_ << output_data.value();
}
}
LOG(INFO) << "Send to Observer.";
observer->RecordHwVerificationReport(hw_verification_report);
return (hw_verification_report.is_compliant() ? CLIVerificationResult::kPass
: CLIVerificationResult::kFail);
}
} // namespace hardware_verifier