// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/quick_start/quick_start_metrics.h"
#include <memory>
#include <string>
#include "base/metrics/histogram_functions.h"
#include "base/timer/elapsed_timer.h"
#include "chromeos/ash/components/quick_start/logging.h"
#include "components/metrics/structured/structured_events.h"
#include "components/metrics/structured/structured_metrics_client.h"
#include "google_apis/gaia/google_service_auth_error.h"
namespace ash::quick_start {
namespace {
namespace cros_events = metrics::structured::events::v2::cr_os_events;
constexpr const char kChallengeBytesFetchDurationHistogramName[] =
"QuickStart.ChallengeBytes.FetchDuration";
constexpr const char kChallengeBytesFailureReasonHistogramName[] =
"QuickStart.ChallengeBytes.FailureReason";
constexpr const char kChallengeBytesFetchResultHistogramName[] =
"QuickStart.ChallengeBytes.FetchResult";
constexpr const char kAttestationCertificateFailureReasonHistogramName[] =
"QuickStart.AttestationCertificate.FailureReason";
constexpr const char kAttestationCertificateFetchResultHistogramName[] =
"QuickStart.AttestationCertificate.FetchResult";
constexpr const char kAttestationCertificateFetchDurationHistogramName[] =
"QuickStart.AttestationCertificate.FetchDuration";
constexpr const char kWifiTransferResultHistogramName[] =
"QuickStart.WifiTransferResult";
constexpr const char kWifiTransferResultFailureReasonHistogramName[] =
"QuickStart.WifiTransferResult.FailureReason";
constexpr const char kFastPairAdvertisementEndedSucceededHistogramName[] =
"QuickStart.FastPairAdvertisementEnded.Succeeded";
constexpr const char kFastPairAdvertisementEndedDurationHistogramName[] =
"QuickStart.FastPairAdvertisementEnded.Duration";
constexpr const char kFastPairAdvertisementEndedErrorCodeHistogramName[] =
"QuickStart.FastPairAdvertisementEnded.ErrorCode";
constexpr const char kFastPairAdvertisementStartedSucceededHistogramName[] =
"QuickStart.FastPairAdvertisementStarted.Succeeded";
constexpr const char kFastPairAdvertisementStartedErrorCodeHistogramName[] =
"QuickStart.FastPairAdvertisementStarted.ErrorCode";
constexpr const char
kNearbyConnectionsAdvertisementEndedSucceededHistogramName[] =
"QuickStart.NearbyConnectionsAdvertisementEnded.Succeeded";
constexpr const char
kNearbyConnectionsAdvertisementEndedDurationHistogramName[] =
"QuickStart.NearbyConnectionsAdvertisementEnded.Duration";
constexpr const char
kNearbyConnectionsAdvertisementEndedErrorCodeHistogramName[] =
"QuickStart.NearbyConnectionsAdvertisementEnded.ErrorCode";
constexpr const char
kNearbyConnectionsAdvertisementStartedSucceededHistogramName[] =
"QuickStart.NearbyConnectionsAdvertisementStarted.Succeeded";
constexpr const char
kNearbyConnectionsAdvertisementStartedErrorCodeHistogramName[] =
"QuickStart.NearbyConnectionsAdvertisementStarted.ErrorCode";
constexpr const char kAuthenticationMethodHistogramName[] =
"QuickStart.AuthenticationMethod";
constexpr const char kMessageReceivedWifiCredentials[] =
"QuickStart.MessageReceived.WifiCredentials";
constexpr const char kMessageReceivedBootstrapConfigurations[] =
"QuickStart.MessageReceived.BootstrapConfigurations";
constexpr const char kMessageReceivedHandshake[] =
"QuickStart.MessageReceived.Handshake";
constexpr const char kMessageReceivedNotifySourceOfUpdate[] =
"QuickStart.MessageReceived.NotifySourceOfUpdate";
constexpr const char kMessageReceivedGetInfo[] =
"QuickStart.MessageReceived.GetInfo";
constexpr const char kMessageReceivedAssertion[] =
"QuickStart.MessageReceived.Assertion";
constexpr const char kMessageReceivedBootstrapStateCancel[] =
"QuickStart.MessageReceived.BootstrapStateCancel";
constexpr const char kMessageReceivedBootstrapStateComplete[] =
"QuickStart.MessageReceived.BootstrapStateComplete";
constexpr const char kMessageReceivedDesiredMessageTypeName[] =
"QuickStart.MessageReceived.DesiredMessageType";
constexpr const char kMessageSentMessageTypeName[] =
"QuickStart.MessageSent.MessageType";
constexpr const char kHandshakeResultSucceededName[] =
"QuickStart.HandshakeResult.Succeeded";
constexpr const char kHandshakeResultDurationName[] =
"QuickStart.HandshakeResult.Duration";
constexpr const char kHandshakeResultErrorCodeName[] =
"QuickStart.HandshakeResult.ErrorCode";
constexpr const char kHandshakeStartedName[] = "QuickStart.HandshakeStarted";
constexpr const char kGaiaTransferResultName[] =
"QuickStart.GaiaTransferResult";
constexpr const char kGaiaTransferResultFailureReasonName[] =
"QuickStart.GaiaTransferResult.FailureReason";
constexpr const char kGaiaAuthenticationResultHistogramName[] =
"QuickStart.GaiaAuthentication.Result";
constexpr const char kGaiaAuthenticationDurationHistogramName[] =
"QuickStart.GaiaAuthentication.Duration";
constexpr const char kScreenOpened[] = "QuickStart.ScreenOpened";
constexpr const char kScreenClosedAddChild[] =
"QuickStart.ScreenClosed.AddChild";
constexpr const char
kScreenClosedCheckingForUpdateAndDeterminingDeviceConfiguration[] =
"QuickStart.ScreenClosed."
"CheckingForUpdateAndDeterminingDeviceConfiguration";
constexpr const char kScreenClosedChooseChromebookSetup[] =
"QuickStart.ScreenClosed.ChooseChromebookSetup";
constexpr const char kScreenClosedConsumerUpdate[] =
"QuickStart.ScreenClosed.ConsumerUpdate";
constexpr const char kScreenClosedGaiaInfoScreen[] =
"QuickStart.ScreenClosed.GaiaInfoScreen";
constexpr const char kScreenClosedGaiaScreen[] =
"QuickStart.ScreenClosed.GaiaScreen";
constexpr const char kScreenClosedNetworkScreen[] =
"QuickStart.ScreenClosed.NetworkScreen";
constexpr const char kScreenClosedNone[] = "QuickStart.ScreenClosed.None";
constexpr const char kScreenClosedOther[] = "QuickStart.ScreenClosed.Other";
constexpr const char kScreenClosedQSComplete[] =
"QuickStart.ScreenClosed.QSComplete";
constexpr const char kScreenClosedQSConnectingToWifi[] =
"QuickStart.ScreenClosed.QSConnectingToWifi";
constexpr const char kScreenClosedQSResumingConnectionAfterUpdate[] =
"QuickStart.ScreenClosed.QSResumingConnectionAfterUpdate";
constexpr const char kScreenClosedQSSelectGoogleAccount[] =
"QuickStart.ScreenClosed.QSSelectGoogleAccount";
constexpr const char kScreenClosedQSSetUpWithAndroidPhone[] =
"QuickStart.ScreenClosed.QSSetUpWithAndroidPhone";
constexpr const char kScreenClosedQSWifiCredentialsReceived[] =
"QuickStart.ScreenClosed.QSWifiCredentialsReceived";
constexpr const char kScreenClosedReviewPrivacyAndTerms[] =
"QuickStart.ScreenClosed.ReviewPrivacyAndTerms";
constexpr const char kScreenClosedSetupDevicePIN[] =
"QuickStart.ScreenClosed.SetupDevicePIN";
constexpr const char kScreenClosedUnifiedSetup[] =
"QuickStart.ScreenClosed.UnifiedSetup";
constexpr const char kScreenClosedWelcomeScreen[] =
"QuickStart.ScreenClosed.WelcomeScreen";
constexpr const char kScreenClosedQSGettingGoogleAccountInfo[] =
"QuickStart.ScreenClosed.QSGettingGoogleAccountInfo";
constexpr const char kScreenClosedQSCreatingAccount[] =
"QuickStart.ScreenClosed.QSCreatingAccount";
constexpr const char kScreenClosedQSFallbackURL[] =
"QuickStart.ScreenClosed.QSFallbackURL";
constexpr const char kAbortFlowReasonHistogramName[] =
"QuickStart.FlowAborted.Reason";
constexpr const char kEntryPointHistogramName[] = "QuickStart.EntryPoint";
constexpr const char kConsumerUpdateStartedHistogramName[] =
"QuickStart.ConsumerUpdateStarted";
constexpr const char kConsumerUpdateCancelledHistogramName[] =
"QuickStart.ConsumerUpdateCancelled";
constexpr const char kForcedUpdateStartedHistogramName[] =
"QuickStart.ForcedUpdateStarted";
std::string MapMessageTypeToMetric(
QuickStartMetrics::MessageType message_type) {
switch (message_type) {
case QuickStartMetrics::MessageType::kWifiCredentials:
return kMessageReceivedWifiCredentials;
case QuickStartMetrics::MessageType::kBootstrapConfigurations:
return kMessageReceivedBootstrapConfigurations;
case QuickStartMetrics::MessageType::kHandshake:
return kMessageReceivedHandshake;
case QuickStartMetrics::MessageType::kNotifySourceOfUpdate:
return kMessageReceivedNotifySourceOfUpdate;
case QuickStartMetrics::MessageType::kGetInfo:
return kMessageReceivedGetInfo;
case QuickStartMetrics::MessageType::kAssertion:
return kMessageReceivedAssertion;
case QuickStartMetrics::MessageType::kBootstrapStateCancel:
return kMessageReceivedBootstrapStateCancel;
case QuickStartMetrics::MessageType::kBootstrapStateComplete:
return kMessageReceivedBootstrapStateComplete;
}
}
std::string MapScreenNameToMetric(QuickStartMetrics::ScreenName screen_name) {
switch (screen_name) {
case QuickStartMetrics::ScreenName::kNone:
return kScreenClosedNone;
case QuickStartMetrics::ScreenName::kWelcomeScreen:
return kScreenClosedWelcomeScreen;
case QuickStartMetrics::ScreenName::kNetworkScreen:
return kScreenClosedNetworkScreen;
case QuickStartMetrics::ScreenName::kGaiaScreen:
return kScreenClosedGaiaScreen;
case QuickStartMetrics::ScreenName::kQSSetUpWithAndroidPhone:
return kScreenClosedQSSetUpWithAndroidPhone;
case QuickStartMetrics::ScreenName::kQSConnectingToWifi:
return kScreenClosedQSConnectingToWifi;
case QuickStartMetrics::ScreenName::
kCheckingForUpdateAndDeterminingDeviceConfiguration:
return kScreenClosedCheckingForUpdateAndDeterminingDeviceConfiguration;
case QuickStartMetrics::ScreenName::kChooseChromebookSetup:
return kScreenClosedChooseChromebookSetup;
case QuickStartMetrics::ScreenName::kConsumerUpdate:
return kScreenClosedConsumerUpdate;
case QuickStartMetrics::ScreenName::kQSResumingConnectionAfterUpdate:
return kScreenClosedQSResumingConnectionAfterUpdate;
case QuickStartMetrics::ScreenName::kQSGettingGoogleAccountInfo:
return kScreenClosedQSGettingGoogleAccountInfo;
case QuickStartMetrics::ScreenName::kQSComplete:
return kScreenClosedQSComplete;
case QuickStartMetrics::ScreenName::kSetupDevicePIN:
return kScreenClosedSetupDevicePIN;
case QuickStartMetrics::ScreenName::kAddChild:
return kScreenClosedAddChild;
case QuickStartMetrics::ScreenName::kReviewPrivacyAndTerms:
return kScreenClosedReviewPrivacyAndTerms;
case QuickStartMetrics::ScreenName::kUnifiedSetup:
return kScreenClosedUnifiedSetup;
case QuickStartMetrics::ScreenName::kGaiaInfoScreen:
return kScreenClosedGaiaInfoScreen;
case QuickStartMetrics::ScreenName::kQSWifiCredentialsReceived:
return kScreenClosedQSWifiCredentialsReceived;
case QuickStartMetrics::ScreenName::kQSSelectGoogleAccount:
return kScreenClosedQSSelectGoogleAccount;
case QuickStartMetrics::ScreenName::kQSCreatingAccount:
return kScreenClosedQSCreatingAccount;
case QuickStartMetrics::ScreenName::kQSFallbackURL:
return kScreenClosedQSFallbackURL;
case QuickStartMetrics::ScreenName::kOther:
[[fallthrough]];
default:
return kScreenClosedOther;
}
}
} // namespace
// static
QuickStartMetrics::MessageType QuickStartMetrics::MapResponseToMessageType(
QuickStartResponseType response_type) {
switch (response_type) {
case QuickStartResponseType::kWifiCredentials:
return MessageType::kWifiCredentials;
case QuickStartResponseType::kBootstrapConfigurations:
return MessageType::kBootstrapConfigurations;
case QuickStartResponseType::kHandshake:
return MessageType::kHandshake;
case QuickStartResponseType::kNotifySourceOfUpdate:
return MessageType::kNotifySourceOfUpdate;
case QuickStartResponseType::kGetInfo:
return MessageType::kGetInfo;
case QuickStartResponseType::kAssertion:
return MessageType::kAssertion;
case QuickStartResponseType::kBootstrapStateCancel:
return MessageType::kBootstrapStateCancel;
case QuickStartResponseType::kBootstrapStateComplete:
return MessageType::kBootstrapStateComplete;
}
}
// static
QuickStartMetrics::ScreenClosedReason
QuickStartMetrics::MapAbortFlowReasonToScreenClosedReason(
AbortFlowReason reason) {
switch (reason) {
case AbortFlowReason::USER_CLICKED_BACK:
return ScreenClosedReason::kUserClickedBack;
case AbortFlowReason::USER_CLICKED_CANCEL:
return ScreenClosedReason::kUserCancelled;
case AbortFlowReason::SIGNIN_SCHOOL:
[[fallthrough]];
case AbortFlowReason::ADD_CHILD:
[[fallthrough]];
case AbortFlowReason::ENTERPRISE_ENROLLMENT:
return ScreenClosedReason::kAdvancedInFlow;
case AbortFlowReason::ERROR:
return ScreenClosedReason::kError;
}
}
// static
void QuickStartMetrics::RecordWifiTransferResult(
bool succeeded,
std::optional<WifiTransferResultFailureReason> failure_reason) {
if (succeeded) {
CHECK(!failure_reason.has_value());
} else {
CHECK(failure_reason.has_value());
base::UmaHistogramEnumeration(kWifiTransferResultFailureReasonHistogramName,
failure_reason.value());
}
base::UmaHistogramBoolean(kWifiTransferResultHistogramName, succeeded);
metrics::structured::StructuredMetricsClient::Record(
cros_events::QuickStart_GetWifiCredentials().SetSuccess(succeeded));
}
// static
void QuickStartMetrics::RecordAbortFlowReason(AbortFlowReason reason) {
base::UmaHistogramEnumeration(kAbortFlowReasonHistogramName, reason);
metrics::structured::StructuredMetricsClient::Record(
std::move(cros_events::QuickStart_FlowAborted().SetReason(
static_cast<cros_events::QuickStartAbortFlowReason>(reason))));
}
// static
void QuickStartMetrics::RecordGaiaTransferStarted() {
metrics::structured::StructuredMetricsClient::Record(
cros_events::QuickStart_AccountTransferStarted());
}
// static
void QuickStartMetrics::RecordGaiaTransferResult(
bool succeeded,
std::optional<GaiaTransferResultFailureReason> failure_reason) {
if (succeeded) {
CHECK(!failure_reason.has_value());
} else {
CHECK(failure_reason.has_value());
base::UmaHistogramEnumeration(kGaiaTransferResultFailureReasonName,
failure_reason.value());
}
base::UmaHistogramBoolean(kGaiaTransferResultName, succeeded);
metrics::structured::StructuredMetricsClient::Record(
cros_events::QuickStart_AccountTransferComplete().SetSuccess(succeeded));
}
// static
void QuickStartMetrics::RecordEntryPoint(EntryPoint entry_point) {
base::UmaHistogramEnumeration(kEntryPointHistogramName, entry_point);
metrics::structured::StructuredMetricsClient::Record(
std::move(cros_events::QuickStart_Initiated().SetEntryPoint(
static_cast<cros_events::QuickStartEntryPoint>(entry_point))));
}
// static
void QuickStartMetrics::RecordAuthenticationMethod(
AuthenticationMethod auth_method) {
base::UmaHistogramEnumeration(kAuthenticationMethodHistogramName,
auth_method);
}
// static
void QuickStartMetrics::RecordUpdateStarted(bool is_forced) {
if (is_forced) {
base::UmaHistogramBoolean(kForcedUpdateStartedHistogramName, true);
metrics::structured::StructuredMetricsClient::Record(
cros_events::QuickStart_InstallForcedUpdate());
} else {
base::UmaHistogramBoolean(kConsumerUpdateStartedHistogramName, true);
metrics::structured::StructuredMetricsClient::Record(
cros_events::QuickStart_InstallConsumerUpdate());
}
}
// static
void QuickStartMetrics::RecordConsumerUpdateCancelled() {
base::UmaHistogramBoolean(kConsumerUpdateCancelledHistogramName, true);
metrics::structured::StructuredMetricsClient::Record(
cros_events::QuickStart_ConsumerUpdateCancelled());
}
// static
void QuickStartMetrics::RecordEstablishConnection(bool success,
bool is_automatic_resume) {
if (is_automatic_resume) {
metrics::structured::StructuredMetricsClient::Record(std::move(
cros_events::QuickStart_AutomaticResumeAfterUpdate().SetSuccess(
success)));
} else {
metrics::structured::StructuredMetricsClient::Record(std::move(
cros_events::QuickStart_EstablishConnection().SetSuccess(success)));
}
}
QuickStartMetrics::QuickStartMetrics() = default;
QuickStartMetrics::~QuickStartMetrics() = default;
void QuickStartMetrics::RecordScreenOpened(ScreenName screen) {
base::UmaHistogramEnumeration(kScreenOpened, screen);
metrics::structured::StructuredMetricsClient::Record(
std::move(cros_events::QuickStart_ScreenOpened().SetScreenName(
static_cast<cros_events::QuickStartScreenName>(screen))));
screen_opened_view_duration_timer_ = std::make_unique<base::ElapsedTimer>();
last_screen_opened_ = screen;
}
void QuickStartMetrics::RecordScreenClosed(ScreenName screen,
ScreenClosedReason reason) {
if (screen_opened_view_duration_timer_ == nullptr) {
QS_LOG(ERROR) << "RecordScreenClosed called but now "
"screen_opened_view_duration_timer_ set. screen: "
<< screen;
return;
}
if (screen != last_screen_opened_) {
QS_LOG(ERROR) << "RecordScreenClosed called but screen does not match "
"last_screen_opened_. last_screen_opened_: "
<< last_screen_opened_ << " closed screen: " << screen;
return;
}
metrics::structured::StructuredMetricsClient::Record(
std::move(cros_events::QuickStart_ScreenClosed().SetScreenName(
static_cast<cros_events::QuickStartScreenName>(screen))));
base::UmaHistogramEnumeration(MapScreenNameToMetric(screen) + ".Reason",
reason);
base::UmaHistogramTimes(MapScreenNameToMetric(screen) + ".ViewDuration",
screen_opened_view_duration_timer_->Elapsed());
screen_opened_view_duration_timer_.reset();
}
void QuickStartMetrics::RecordChallengeBytesRequested() {
CHECK(!challenge_bytes_fetch_timer_)
<< "Only 1 challenge bytes request can be active at a time";
challenge_bytes_fetch_timer_ = std::make_unique<base::ElapsedTimer>();
}
void QuickStartMetrics::RecordChallengeBytesRequestEnded(
const GoogleServiceAuthError& status) {
CHECK(challenge_bytes_fetch_timer_)
<< "Challenge bytes request timer was not active. Unexpected "
"response.";
const bool is_success = status.state() == GoogleServiceAuthError::State::NONE;
base::UmaHistogramBoolean(kChallengeBytesFetchResultHistogramName,
/*sample=*/is_success);
base::UmaHistogramEnumeration(kChallengeBytesFailureReasonHistogramName,
/*sample=*/status.state(),
GoogleServiceAuthError::NUM_STATES);
base::UmaHistogramTimes(kChallengeBytesFetchDurationHistogramName,
challenge_bytes_fetch_timer_->Elapsed());
challenge_bytes_fetch_timer_.reset();
}
void QuickStartMetrics::RecordAttestationCertificateRequested() {
CHECK(!attestation_certificate_timer_)
<< "Only 1 attestation certificate request can be active at a time";
attestation_certificate_timer_ = std::make_unique<base::ElapsedTimer>();
}
void QuickStartMetrics::RecordAttestationCertificateRequestEnded(
std::optional<AttestationCertificateRequestErrorCode> error_code) {
CHECK(attestation_certificate_timer_)
<< "Attestation certificate request timer was not active. Unexpected "
"response.";
if (error_code) {
base::UmaHistogramEnumeration(
kAttestationCertificateFailureReasonHistogramName, error_code.value());
base::UmaHistogramBoolean(kAttestationCertificateFetchResultHistogramName,
false);
} else {
base::UmaHistogramBoolean(kAttestationCertificateFetchResultHistogramName,
true);
}
base::UmaHistogramTimes(kAttestationCertificateFetchDurationHistogramName,
attestation_certificate_timer_->Elapsed());
attestation_certificate_timer_.reset();
}
void QuickStartMetrics::RecordGaiaAuthenticationStarted() {
CHECK(!gaia_authentication_timer_)
<< "Only 1 Gaia authentication request can be active at a time";
gaia_authentication_timer_ = std::make_unique<base::ElapsedTimer>();
}
void QuickStartMetrics::RecordGaiaAuthenticationRequestEnded(
const GaiaAuthenticationResult& result) {
CHECK(gaia_authentication_timer_) << "Gaia authentication request timer was "
"not active. Unexpected response.";
base::UmaHistogramEnumeration(kGaiaAuthenticationResultHistogramName, result);
base::UmaHistogramTimes(kGaiaAuthenticationDurationHistogramName,
gaia_authentication_timer_->Elapsed());
gaia_authentication_timer_.reset();
}
void QuickStartMetrics::RecordFastPairAdvertisementStarted(
bool succeeded,
std::optional<FastPairAdvertisingErrorCode> error_code) {
// Timer may already exist if user has cancelled/re-entered Quick Start
// multiple times before establishing a connection.
if (fast_pair_advertising_timer_) {
fast_pair_advertising_timer_.reset();
}
if (succeeded) {
CHECK(!error_code.has_value());
fast_pair_advertising_timer_ = std::make_unique<base::ElapsedTimer>();
} else {
CHECK(error_code.has_value());
base::UmaHistogramEnumeration(
kFastPairAdvertisementStartedErrorCodeHistogramName,
error_code.value());
}
base::UmaHistogramBoolean(kFastPairAdvertisementStartedSucceededHistogramName,
succeeded);
}
void QuickStartMetrics::RecordFastPairAdvertisementEnded(
bool succeeded,
std::optional<FastPairAdvertisingErrorCode> error_code) {
CHECK(fast_pair_advertising_timer_);
base::TimeDelta duration = fast_pair_advertising_timer_->Elapsed();
if (succeeded) {
CHECK(!error_code.has_value());
base::UmaHistogramMediumTimes(
kFastPairAdvertisementEndedDurationHistogramName, duration);
} else {
CHECK(error_code.has_value());
base::UmaHistogramEnumeration(
kFastPairAdvertisementEndedErrorCodeHistogramName, error_code.value());
}
base::UmaHistogramBoolean(kFastPairAdvertisementEndedSucceededHistogramName,
succeeded);
fast_pair_advertising_timer_.reset();
}
void QuickStartMetrics::RecordNearbyConnectionsAdvertisementStarted(
bool succeeded,
std::optional<NearbyConnectionsAdvertisingErrorCode> error_code) {
// Timer may already exist if user has cancelled/re-entered Quick Start
// multiple times before establishing a connection.
if (nearby_connections_advertising_timer_) {
nearby_connections_advertising_timer_.reset();
}
if (succeeded) {
CHECK(!error_code.has_value());
nearby_connections_advertising_timer_ =
std::make_unique<base::ElapsedTimer>();
} else {
CHECK(error_code.has_value());
base::UmaHistogramEnumeration(
kNearbyConnectionsAdvertisementStartedErrorCodeHistogramName,
error_code.value());
}
base::UmaHistogramBoolean(
kNearbyConnectionsAdvertisementStartedSucceededHistogramName, succeeded);
}
void QuickStartMetrics::RecordNearbyConnectionsAdvertisementEnded(
bool succeeded,
std::optional<NearbyConnectionsAdvertisingErrorCode> error_code) {
CHECK(nearby_connections_advertising_timer_);
base::TimeDelta duration = nearby_connections_advertising_timer_->Elapsed();
if (succeeded) {
CHECK(!error_code.has_value());
base::UmaHistogramMediumTimes(
kNearbyConnectionsAdvertisementEndedDurationHistogramName, duration);
} else {
CHECK(error_code.has_value());
base::UmaHistogramEnumeration(
kNearbyConnectionsAdvertisementEndedErrorCodeHistogramName,
error_code.value());
}
base::UmaHistogramBoolean(
kNearbyConnectionsAdvertisementEndedSucceededHistogramName, succeeded);
nearby_connections_advertising_timer_.reset();
}
void QuickStartMetrics::RecordHandshakeStarted() {
base::UmaHistogramBoolean(kHandshakeStartedName, true);
if (handshake_elapsed_timer_) {
handshake_elapsed_timer_.reset();
}
handshake_elapsed_timer_ = std::make_unique<base::ElapsedTimer>();
}
void QuickStartMetrics::RecordHandshakeResult(
bool succeeded,
std::optional<HandshakeErrorCode> error_code) {
CHECK(handshake_elapsed_timer_);
if (!succeeded) {
CHECK(error_code.has_value());
base::UmaHistogramEnumeration(kHandshakeResultErrorCodeName,
error_code.value());
}
base::UmaHistogramBoolean(kHandshakeResultSucceededName, succeeded);
base::UmaHistogramTimes(kHandshakeResultDurationName,
handshake_elapsed_timer_->Elapsed());
handshake_elapsed_timer_.reset();
}
void QuickStartMetrics::RecordMessageSent(MessageType message_type) {
message_elapsed_timer_ = std::make_unique<base::ElapsedTimer>();
base::UmaHistogramEnumeration(kMessageSentMessageTypeName, message_type);
}
void QuickStartMetrics::RecordMessageReceived(
MessageType desired_message_type,
bool succeeded,
std::optional<MessageReceivedErrorCode> error_code) {
std::string metric_name = MapMessageTypeToMetric(desired_message_type);
if (succeeded) {
CHECK(!error_code.has_value());
} else {
CHECK(error_code.has_value());
base::UmaHistogramEnumeration(metric_name + ".ErrorCode",
error_code.value());
}
base::UmaHistogramBoolean(metric_name + ".Succeeded", succeeded);
if (message_elapsed_timer_) {
base::UmaHistogramTimes(metric_name + ".ListenDuration",
message_elapsed_timer_->Elapsed());
}
base::UmaHistogramEnumeration(kMessageReceivedDesiredMessageTypeName,
desired_message_type);
message_elapsed_timer_.reset();
}
std::ostream& operator<<(
std::ostream& stream,
const QuickStartMetrics::ScreenName& metrics_screen_name) {
switch (metrics_screen_name) {
case QuickStartMetrics::ScreenName::kOther:
stream << "[other]";
break;
case QuickStartMetrics::ScreenName::kNone:
stream << "[none]";
break;
case QuickStartMetrics::ScreenName::kWelcomeScreen:
stream << "[welcome screen]";
break;
case QuickStartMetrics::ScreenName::kNetworkScreen:
stream << "[network screen]";
break;
case QuickStartMetrics::ScreenName::kGaiaScreen:
stream << "[gaia screen]";
break;
case QuickStartMetrics::ScreenName::kQSSetUpWithAndroidPhone:
stream << "[QS setup with Android phone]";
break;
case QuickStartMetrics::ScreenName::kQSConnectingToWifi:
stream << "[QS connecting to wifi]";
break;
case QuickStartMetrics::ScreenName::
kCheckingForUpdateAndDeterminingDeviceConfiguration:
stream << "[checking for update and determining device configuration]";
break;
case QuickStartMetrics::ScreenName::kChooseChromebookSetup:
stream << "[choose Chromebook setup]";
break;
case QuickStartMetrics::ScreenName::kConsumerUpdate:
stream << "[consumer update]";
break;
case QuickStartMetrics::ScreenName::kQSResumingConnectionAfterUpdate:
stream << "[QS resuming connection after update]";
break;
case QuickStartMetrics::ScreenName::kQSGettingGoogleAccountInfo:
stream << "[QS getting Google account info]";
break;
case QuickStartMetrics::ScreenName::kQSComplete:
stream << "[QS complete]";
break;
case QuickStartMetrics::ScreenName::kSetupDevicePIN:
stream << "[setup device PIN]";
break;
case QuickStartMetrics::ScreenName::kAddChild:
stream << "[add child]";
break;
case QuickStartMetrics::ScreenName::kReviewPrivacyAndTerms:
stream << "[review privacy and terms]";
break;
case QuickStartMetrics::ScreenName::kUnifiedSetup:
stream << "[unified setup]";
break;
case QuickStartMetrics::ScreenName::kGaiaInfoScreen:
stream << "[gaia info screen]";
break;
case QuickStartMetrics::ScreenName::kQSWifiCredentialsReceived:
stream << "[QS wifi credentials received]";
break;
case QuickStartMetrics::ScreenName::kQSSelectGoogleAccount:
stream << "[QS select Google account]";
break;
case QuickStartMetrics::ScreenName::kQSCreatingAccount:
stream << "[QS creating account]";
break;
case QuickStartMetrics::ScreenName::kQSFallbackURL:
stream << "[QS fallback URL]";
break;
}
return stream;
}
} // namespace ash::quick_start