blob: 20c0bbe8b79577e1c5f0d92e17be88df091b3d49 [file] [log] [blame]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "rmad/metrics/metrics_utils_impl.h"
#include <map>
#include <string>
#include <vector>
#include <base/logging.h>
#include <base/memory/scoped_refptr.h>
#include <base/time/time.h>
#include <metrics/structured_events.h>
#include "rmad/constants.h"
#include "rmad/metrics/metrics_constants.h"
#include "rmad/metrics/state_metrics.h"
#include "rmad/utils/json_store.h"
using StructuredShimlessRmaReport =
metrics::structured::events::rmad::ShimlessRmaReport;
using StructuredReplacedComponent =
metrics::structured::events::rmad::ReplacedComponent;
using StructuredOccurredError =
metrics::structured::events::rmad::OccurredError;
using StructuredAdditionalActivity =
metrics::structured::events::rmad::AdditionalActivity;
using StructuredShimlessRmaStateReport =
metrics::structured::events::rmad::ShimlessRmaStateReport;
namespace rmad {
MetricsUtilsImpl::MetricsUtilsImpl(bool record_to_system)
: record_to_system_(record_to_system) {}
bool MetricsUtilsImpl::RecordShimlessRmaReport(
scoped_refptr<JsonStore> json_store) {
auto report = StructuredShimlessRmaReport();
double current_timestamp = base::Time::Now().InSecondsFSinceUnixEpoch();
double first_setup_timestamp;
if (!GetMetricsValue(json_store, kMetricsFirstSetupTimestamp,
&first_setup_timestamp)) {
LOG(ERROR) << "Failed to get timestamp of the first setup.";
return false;
}
report.SetOverallTime(current_timestamp - first_setup_timestamp);
double setup_timestamp;
if (!GetMetricsValue(json_store, kMetricsSetupTimestamp, &setup_timestamp) ||
!SetMetricsValue(json_store, kMetricsSetupTimestamp, current_timestamp)) {
LOG(ERROR) << "Failed to get and reset setup timestamp for measuring "
"running time.";
return false;
}
double running_time = 0.0;
// It could be the first time we have calculated the running time, thus the
// return value is ignored.
GetMetricsValue(json_store, kMetricsRunningTime, &running_time);
running_time += current_timestamp - setup_timestamp;
report.SetRunningTime(running_time);
if (bool is_complete;
GetMetricsValue(json_store, kMetricsIsComplete, &is_complete)) {
report.SetIsComplete(is_complete);
} else {
report.SetIsComplete(false);
}
RoVerificationStatus ro_verification;
if (std::string ro_verification_str;
GetMetricsValue(json_store, kMetricsRoFirmwareVerified,
&ro_verification_str) &&
RoVerificationStatus_Parse(ro_verification_str, &ro_verification)) {
report.SetRoVerificationStatus(ro_verification);
} else {
report.SetRoVerificationStatus(RMAD_RO_VERIFICATION_UNKNOWN);
}
ReturningOwner returning_owner;
if (std::string returning_owner_str;
GetMetricsValue(json_store, kMetricsReturningOwner,
&returning_owner_str) &&
ReturningOwner_Parse(returning_owner_str, &returning_owner)) {
report.SetReturningOwner(returning_owner);
} else {
report.SetReturningOwner(RMAD_RETURNING_OWNER_UNKNOWN);
}
MainboardReplacement mlb_replacement;
if (std::string mlb_replacement_str;
GetMetricsValue(json_store, kMetricsMlbReplacement,
&mlb_replacement_str) &&
MainboardReplacement_Parse(mlb_replacement_str, &mlb_replacement)) {
report.SetMainboardReplacement(mlb_replacement);
} else {
report.SetMainboardReplacement(RMAD_MLB_REPLACEMENT_UNKNOWN);
}
WpDisableMethod wp_disable_method;
if (std::string wp_disable_method_str;
GetMetricsValue(json_store, kMetricsWpDisableMethod,
&wp_disable_method_str) &&
WpDisableMethod_Parse(wp_disable_method_str, &wp_disable_method)) {
report.SetWriteProtectDisableMethod(wp_disable_method);
} else {
report.SetWriteProtectDisableMethod(RMAD_WP_DISABLE_METHOD_UNKNOWN);
}
if (record_to_system_ && !report.Record()) {
LOG(ERROR) << "Failed to record shimless rma report to metrics.";
return false;
}
return true;
}
bool MetricsUtilsImpl::RecordReplacedComponents(
scoped_refptr<JsonStore> json_store) {
// Ignore the else part, because we may not replace anything.
if (std::vector<std::string> replace_component_names;
MetricsUtils::GetMetricsValue(json_store, kMetricsReplacedComponents,
&replace_component_names)) {
for (const std::string& component_name : replace_component_names) {
if (RmadComponent component;
RmadComponent_Parse(component_name, &component)) {
auto structured_replace_component = StructuredReplacedComponent();
structured_replace_component.SetComponentCategory(component);
if (record_to_system_ && !structured_replace_component.Record()) {
LOG(ERROR) << "Failed to record replaced component to metrics.";
return false;
}
} else {
LOG(ERROR) << "Failed to parse [" << component_name
<< "] as component to append to metrics.";
return false;
}
}
}
return true;
}
bool MetricsUtilsImpl::RecordOccurredErrors(
scoped_refptr<JsonStore> json_store) {
// Ignore the else part, because we may have no errors.
if (std::vector<std::string> occurred_errors;
GetMetricsValue(json_store, kMetricsOccurredErrors, &occurred_errors)) {
for (const std::string& occurred_error : occurred_errors) {
if (RmadErrorCode error_code;
RmadErrorCode_Parse(occurred_error, &error_code)) {
auto structured_occurred_error = StructuredOccurredError();
structured_occurred_error.SetErrorType(error_code);
if (record_to_system_ && !structured_occurred_error.Record()) {
LOG(ERROR) << "Failed to record error code to metrics.";
return false;
}
} else {
LOG(ERROR) << "Failed to parse [" << occurred_error
<< "] as error code to append to metrics.";
return false;
}
}
}
return true;
}
bool MetricsUtilsImpl::RecordAdditionalActivities(
scoped_refptr<JsonStore> json_store) {
// Ignore the else part, because we may have no additional activities.
if (std::vector<std::string> additional_activities; GetMetricsValue(
json_store, kMetricsAdditionalActivities, &additional_activities)) {
for (std::string activity_name : additional_activities) {
AdditionalActivity additional_activity;
if (AdditionalActivity_Parse(activity_name, &additional_activity) &&
additional_activity != RMAD_ADDITIONAL_ACTIVITY_NOTHING) {
auto structured_additional_activity = StructuredAdditionalActivity();
structured_additional_activity.SetActivityType(additional_activity);
if (record_to_system_ && !structured_additional_activity.Record()) {
LOG(ERROR) << "Failed to record additional activity to metrics.";
return false;
}
} else {
LOG(ERROR) << "Failed to parse [" << activity_name
<< "] as additional activity to append to metrics.";
return false;
}
}
}
return true;
}
bool MetricsUtilsImpl::RecordShimlessRmaStateReport(
scoped_refptr<JsonStore> json_store) {
std::map<int, StateMetricsData> state_metrics;
if (GetMetricsValue(json_store, kStateMetrics, &state_metrics)) {
for (auto [state_case, data] : state_metrics) {
auto structured_state_report = StructuredShimlessRmaStateReport();
structured_state_report.SetStateCase(state_case);
structured_state_report.SetIsAborted(data.is_aborted);
if (data.overall_time < 0) {
LOG(ERROR) << state_case
<< ": Invalid overall time: " << data.overall_time;
return false;
}
structured_state_report.SetOverallTime(data.overall_time);
if (data.transition_count <= 0) {
LOG(ERROR) << state_case
<< ": Invalid transition count: " << data.transition_count;
return false;
}
structured_state_report.SetTransitionCount(data.transition_count);
if (data.get_log_count < 0) {
LOG(ERROR) << state_case
<< ": Invalid GetLog count: " << data.get_log_count;
return false;
}
structured_state_report.SetGetLogCount(data.get_log_count);
if (data.save_log_count < 0) {
LOG(ERROR) << state_case
<< ": Invalid SaveLog count: " << data.save_log_count;
return false;
}
structured_state_report.SetSaveLogCount(data.save_log_count);
if (record_to_system_ && !structured_state_report.Record()) {
LOG(ERROR) << state_case
<< ": Failed to record state report to metrics.";
return false;
}
}
}
return true;
}
bool MetricsUtilsImpl::RecordAll(scoped_refptr<JsonStore> json_store) {
return RecordShimlessRmaReport(json_store) &&
RecordOccurredErrors(json_store) &&
RecordReplacedComponents(json_store) &&
RecordAdditionalActivities(json_store) &&
RecordShimlessRmaStateReport(json_store);
}
} // namespace rmad