blob: 4b2ab0b5fbbb5ff4b1b59ec1aa35a81a016701a1 [file] [log] [blame]
// Copyright 2018 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 "biod/biod_metrics.h"
#include <libec/fingerprint/fp_sensor_errors.h>
#include <metrics/metrics_library.h>
#include "biod/biod_storage.h"
#include "biod/updater/update_reason.h"
#include "biod/utils.h"
namespace biod {
namespace metrics {
constexpr char kFpUnlockEnabled[] = "Fingerprint.UnlockEnabled";
constexpr char kFpEnrolledFingerCount[] =
"Fingerprint.Unlock.EnrolledFingerCount";
constexpr char kFpMatchDurationCapture[] =
"Fingerprint.Unlock.Match.Duration.Capture";
constexpr char kFpMatchDurationMatcher[] =
"Fingerprint.Unlock.Match.Duration.Matcher";
constexpr char kFpMatchDurationOverall[] =
"Fingerprint.Unlock.Match.Duration.Overall";
constexpr char kFpNoMatchDurationCapture[] =
"Fingerprint.Unlock.NoMatch.Duration.Capture";
constexpr char kFpNoMatchDurationMatcher[] =
"Fingerprint.Unlock.NoMatch.Duration.Matcher";
constexpr char kFpNoMatchDurationOverall[] =
"Fingerprint.Unlock.NoMatch.Duration.Overall";
constexpr char kFpMatchIgnoredDueToPowerButtonPress[] =
"Fingerprint.Unlock.MatchIgnoredDueToPowerButtonPress";
constexpr char kResetContextMode[] = "Fingerprint.Reset.ResetContextMode";
constexpr char kSetContextMode[] = "Fingerprint.SetContext.SetContextMode";
constexpr char kSetContextSuccess[] = "Fingerprint.SetContext.Success";
constexpr char kUpdaterStatus[] = "Fingerprint.Updater.Status";
constexpr char kUpdaterReason[] = "Fingerprint.Updater.Reason";
constexpr char kUpdaterDurationNoUpdate[] =
"Fingerprint.Updater.NoUpdate.Duration.Overall";
constexpr char kUpdaterDurationUpdate[] =
"Fingerprint.Updater.Update.Duration.Overall";
constexpr char kFpReadPositiveMatchSecretSuccessOnMatch[] =
"Fingerprint.Unlock.ReadPositiveMatchSecret.Success";
constexpr char kFpPositiveMatchSecretCorrect[] =
"Fingerprint.Unlock.Match.PositiveMatchSecretCorrect";
constexpr char kRecordFormatVersionMetric[] =
"Fingerprint.Unlock.RecordFormatVersion";
constexpr char kNumDeadPixels[] = "Fingerprint.Sensor.NumDeadPixels";
constexpr char kUploadTemplateSuccess[] = "Fingerprint.UploadTemplate.Success";
// See
// https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md#count-histograms_choosing-number-of-buckets
constexpr int kDefaultNumBuckets = 50;
// Upper boundary to use in EC result related histograms. This follows
// "enum ec_status" in ec_commands.h. We do not use EC_RES_MAX because that
// value is too large for the histogram.
constexpr int kMaxEcResultCode = 20;
} // namespace metrics
BiodMetrics::BiodMetrics() : metrics_lib_(std::make_unique<MetricsLibrary>()) {}
bool BiodMetrics::SendEnrolledFingerCount(int finger_count) {
return metrics_lib_->SendEnumToUMA(metrics::kFpEnrolledFingerCount,
finger_count, 10);
}
bool BiodMetrics::SendFpUnlockEnabled(bool enabled) {
return metrics_lib_->SendBoolToUMA(metrics::kFpUnlockEnabled, enabled);
}
bool BiodMetrics::SendFpLatencyStats(
bool matched, const CrosFpDeviceInterface::FpStats& stats) {
bool rc = true;
rc = metrics_lib_->SendToUMA(matched ? metrics::kFpMatchDurationCapture
: metrics::kFpNoMatchDurationCapture,
stats.capture_ms, 0, 200, 20) &&
rc;
rc = metrics_lib_->SendToUMA(matched ? metrics::kFpMatchDurationMatcher
: metrics::kFpNoMatchDurationMatcher,
stats.matcher_ms, 100, 800, 50) &&
rc;
rc = metrics_lib_->SendToUMA(matched ? metrics::kFpMatchDurationOverall
: metrics::kFpNoMatchDurationOverall,
stats.overall_ms, 100, 1000, 50) &&
rc;
return rc;
}
bool BiodMetrics::SendFwUpdaterStatus(FwUpdaterStatus status,
updater::UpdateReason reason,
int overall_ms) {
// The following presents the updater timing tests results for nocturne,
// which uses the dartmonkey board with a large 2M firmware image on a
// Cortex M7:
// * no update takes about 60ms at boot
// * 10s boot-splash-screen timeout with update RO+RW takes about 83s.
// * 10s boot-splash-screen timeout with update RW(~35s) takes about 44s.
// * 10s boot-splash-screen timeout with update RO(~32s) takes about 39s.
// Note, we strive to allocate as few bins as possible, so we let the target
// resolution steer our bucket counts.
constexpr int kNoUpdateMaxMSec = 500;
constexpr int kNoUpdateResolutionMSec = 10;
constexpr int kNoUpdateBuckets = kNoUpdateMaxMSec / kNoUpdateResolutionMSec;
constexpr int kUpdateMaxMSec = 2 * 60 * 1000;
constexpr int kUpdateResolutionMSec = 2400;
constexpr int kUpdateBuckets = kUpdateMaxMSec / kUpdateResolutionMSec;
bool rc = true;
// TODO(crbug.com/1218246) Change UMA enum name kUpdaterStatus if new enums
// for FWUpdaterStatus are added to avoid data discontinuity, then use
// kMaxValue+1 rather than kMaxValue (or templated SendEnumToUMA()).
if (!metrics_lib_->SendEnumToUMA(metrics::kUpdaterStatus, to_utype(status),
to_utype(FwUpdaterStatus::kMaxValue))) {
rc = false;
}
if (status == FwUpdaterStatus::kUnnecessary) {
if (!metrics_lib_->SendToUMA(metrics::kUpdaterDurationNoUpdate, overall_ms,
0, kNoUpdateMaxMSec, kNoUpdateBuckets)) {
rc = false;
}
} else {
if (!metrics_lib_->SendToUMA(metrics::kUpdaterDurationUpdate, overall_ms, 0,
kUpdateMaxMSec, kUpdateBuckets)) {
rc = false;
}
}
if (!metrics_lib_->SendEnumToUMA(metrics::kUpdaterReason, reason)) {
rc = false;
}
return rc;
}
bool BiodMetrics::SendIgnoreMatchEventOnPowerButtonPress(bool is_ignored) {
return metrics_lib_->SendBoolToUMA(
metrics::kFpMatchIgnoredDueToPowerButtonPress, is_ignored);
}
bool BiodMetrics::SendReadPositiveMatchSecretSuccess(bool success) {
return metrics_lib_->SendBoolToUMA(
metrics::kFpReadPositiveMatchSecretSuccessOnMatch, success);
}
bool BiodMetrics::SendPositiveMatchSecretCorrect(bool correct) {
return metrics_lib_->SendBoolToUMA(metrics::kFpPositiveMatchSecretCorrect,
correct);
}
bool BiodMetrics::SendRecordFormatVersion(int version) {
// TODO(crbug.com/1218246) Change UMA enum name kRecordFormatVersionMetric if
// kRecordFormatVersion changes to avoid data discontinuity, then use
// kRecordFormatVersion+1 rather than kRecordFormatVersion for
// 'exclusive_max'.
return metrics_lib_->SendEnumToUMA(metrics::kRecordFormatVersionMetric,
version, kRecordFormatVersion);
}
void BiodMetrics::SetMetricsLibraryForTesting(
std::unique_ptr<MetricsLibraryInterface> metrics_lib) {
metrics_lib_ = std::move(metrics_lib);
}
bool BiodMetrics::SendResetContextMode(const ec::FpMode& mode) {
return metrics_lib_->SendEnumToUMA(metrics::kResetContextMode, mode.EnumVal(),
mode.MaxEnumVal());
}
bool BiodMetrics::SendSetContextMode(const ec::FpMode& mode) {
return metrics_lib_->SendEnumToUMA(metrics::kSetContextMode, mode.EnumVal(),
mode.MaxEnumVal());
}
bool BiodMetrics::SendSetContextSuccess(bool success) {
return metrics_lib_->SendBoolToUMA(metrics::kSetContextSuccess, success);
}
bool BiodMetrics::SendDeadPixelCount(int num_dead_pixels) {
constexpr int min_dead = 0;
constexpr int max_dead = ec::kMaxDeadPixels;
return metrics_lib_->SendToUMA(metrics::kNumDeadPixels, num_dead_pixels,
min_dead, max_dead,
metrics::kDefaultNumBuckets);
}
bool BiodMetrics::SendUploadTemplateResult(int ec_result) {
constexpr int min_ec_result_code = metrics::kCmdRunFailure;
return metrics_lib_->SendToUMA(
metrics::kUploadTemplateSuccess, ec_result, min_ec_result_code,
metrics::kMaxEcResultCode,
metrics::kMaxEcResultCode - min_ec_result_code + 1);
}
} // namespace biod