| // 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. |
| |
| #ifndef CHROMEOS_ASH_COMPONENTS_QUICK_START_QUICK_START_METRICS_H_ |
| #define CHROMEOS_ASH_COMPONENTS_QUICK_START_QUICK_START_METRICS_H_ |
| |
| #include <optional> |
| |
| #include "base/time/time.h" |
| #include "base/timer/elapsed_timer.h" |
| #include "chromeos/ash/components/quick_start/quick_start_response_type.h" |
| |
| class GoogleServiceAuthError; |
| |
| namespace ash::quick_start { |
| |
| class QuickStartMetrics { |
| public: |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml as well as a |
| // CrOSEvents enum defined in |
| // //components/metrics/structured/structured_events.h, and should always |
| // reflect them (do not change one without changing the others). Entries |
| // should never be modified or deleted. Only additions possible. |
| enum class ScreenName { |
| kOther = 0, // We don't expect this value to ever be emitted. |
| kNone = 1, // There is no previous screen when automatically resuming after |
| // an update. |
| kWelcomeScreen = 2, // Quick Start entry point 1. |
| kNetworkScreen = 3, // Quick Start entry point 2, or in the middle of Quick |
| // Start when the host device is not connected to wifi. |
| kGaiaScreen = 4, // Quick Start entry point 4 (See kGaiaInfoScreen for |
| // entry point 3). |
| kQSSetUpWithAndroidPhone = 5, // Beginning of Quick Start flow. |
| kQSConnectingToWifi = 6, // Transferring wifi with Quick Start. |
| kCheckingForUpdateAndDeterminingDeviceConfiguration = 7, // Critical Update |
| kChooseChromebookSetup = 8, |
| kConsumerUpdate = 9, |
| kQSConnectingToPhone = |
| 10, // UI when advertising without a QR code, either when automatically |
| // resuming after an update or at the start of PIN flow. |
| kQSGettingGoogleAccountInfo = 11, |
| kQSComplete = 12, |
| kSetupDevicePIN = 13, // After Quick Start flow is complete. |
| kAddChild = 14, // Only for Unicorn accounts. |
| kReviewPrivacyAndTerms = 15, // Only for Unicorn accounts. |
| kUnifiedSetup = 16, // After Quick Start flow is complete, connect host |
| // phone to account. |
| kGaiaInfoScreen = 17, // Quick Start entry point 3 |
| kQSWifiCredentialsReceived = 18, // Quick Start UI when wifi credentials |
| // transfer succeeds. |
| kQSSelectGoogleAccount = 19, // Quick Start UI informing user to confirm |
| // account on phone. |
| kQSCreatingAccount = 20, // Quick Start UI attempting to login with |
| // transferred account details. |
| kQSFallbackURL = 21, // Quick Start screen when when a signin challenge |
| // must be completed on the target device. |
| kMaxValue = kQSFallbackURL |
| }; |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml, and should always |
| // reflect it (do not change one without changing the other). Entries should |
| // be never modified or deleted. Only additions possible. |
| // |
| // LINT.IfChange(ScreenClosedReason) |
| enum ScreenClosedReason { |
| kAdvancedInFlow, // User moved to next screen as expected via flow. |
| kUserCancelled, // User clicked cancel. |
| kUserClickedBack, // User clicked back. |
| kSetupComplete, // User finished Quick Start. |
| kError, // An error occurred. |
| kMaxValue = kError |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/quickstart/enums.xml:ScreenClosedReason) |
| |
| enum class ExitReason { |
| kAdvancedInFlow, |
| kUserCancelled, |
| }; |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml, and should always |
| // reflect it (do not change one without changing the other). Entries should |
| // be never modified or deleted. Only additions possible. |
| // |
| // LINT.IfChange(QuickStartAuthenticationMethod) |
| enum class AuthenticationMethod { |
| kPin = 0, |
| kQRCode = 1, |
| kResumeAfterUpdate = 2, |
| kMaxValue = kResumeAfterUpdate, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/quickstart/enums.xml:QuickStartAuthenticationMethod) |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml and should always |
| // reflect it (do not change one without changing the other). Entries should |
| // be never modified or deleted. Only additions possible. The UMA enum cannot |
| // use |device::BluetoothAdvertisement::ErrorCode| directly, because it is |
| // missing the required |kMaxValue| field. |
| // |
| // LINT.IfChange(QuickStartFastPairAdvertisingErrorCode) |
| enum class FastPairAdvertisingErrorCode { |
| kUnsupportedPlatform = 0, |
| kAdvertisementAlreadyExists = 1, |
| kAdvertisementDoesNotExist = 2, |
| kAdvertisementInvalidLength = 3, |
| kStartingAdvertisement = 4, |
| kResetAdvertising = 5, |
| kAdapterPoweredOff = 6, |
| kInvalidAdvertisementInterval = 7, |
| kInvalidAdvertisementErrorCode = 8, |
| kMaxValue = kInvalidAdvertisementErrorCode, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/quickstart/enums.xml:QuickStartFastPairAdvertisingErrorCode) |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml and should always |
| // reflect it (do not change one without changing the other). Entries should |
| // be never modified or deleted. Only additions possible. |
| // |
| // LINT.IfChange(QuickStartNearbyConnectionsAdvertisingErrorCode) |
| enum class NearbyConnectionsAdvertisingErrorCode { |
| kError = 0, |
| kOutOfOrderApiCall = 1, |
| kAlreadyHaveActiveStrategy = 2, |
| kAlreadyAdvertising = 3, |
| kBluetoothError = 4, |
| kBleError = 5, |
| kUnknown = 6, |
| kTimeout = 7, |
| kOther = 8, |
| kMaxValue = kOther, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/quickstart/enums.xml:QuickStartNearbyConnectionsAdvertisingErrorCode) |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml, and should always |
| // reflect it (do not change one without changing the other). Entries should |
| // be never modified or deleted. Only additions possible. |
| // |
| // LINT.IfChange(QuickStartHandshakeResultErrorCode) |
| enum class HandshakeErrorCode { |
| kFailedToReadResponse = 0, |
| kFailedToParse = 1, |
| kFailedToDecryptAuthPayload = 2, |
| kFailedToParseAuthPayload = 3, |
| kUnexpectedAuthPayloadRole = 4, |
| kUnexpectedAuthPayloadAuthToken = 5, |
| kInvalidHandshakeErrorCode = 6, |
| kMaxValue = kInvalidHandshakeErrorCode, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/quickstart/enums.xml:QuickStartHandshakeResultErrorCode) |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml, and should always |
| // reflect it (do not change one without changing the other). Entries should |
| // be never modified or deleted. Only additions possible. |
| // |
| // LINT.IfChange(QuickStartMessageType) |
| enum class MessageType { |
| kWifiCredentials = 0, |
| kBootstrapConfigurations = 1, |
| kHandshake = 2, |
| kNotifySourceOfUpdate = 3, |
| kGetInfo = 4, |
| kAssertion = 5, |
| kBootstrapStateCancel = 6, |
| kBootstrapStateComplete = 7, |
| kMaxValue = kBootstrapStateComplete, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/quickstart/enums.xml:QuickStartMessageType) |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml, and should always |
| // reflect it (do not change one without changing the other). Entries should |
| // be never modified or deleted. Only additions possible. |
| // |
| // LINT.IfChange(QuickStartMessageReceivedErrorCode) |
| enum class MessageReceivedErrorCode { |
| kTimeOut = 0, |
| kDeserializationFailure = 1, |
| kUnknownError = 2, |
| kMaxValue = kUnknownError, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/quickstart/enums.xml:QuickStartMessageReceivedErrorCode) |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml, and should always |
| // reflect it (do not change one without changing the other). Entries should |
| // be never modified or deleted. Only additions possible. |
| // |
| // LINT.IfChange(QuickStartAttestationCertificateFetchFailureReason) |
| enum class AttestationCertificateRequestErrorCode { |
| kUnknownError = 0, |
| kBadRequest = 1, |
| kAttestationNotSupportedOnDevice = 2, |
| kMaxValue = kAttestationNotSupportedOnDevice, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/quickstart/enums.xml:QuickStartAttestationCertificateFetchFailureReason) |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml, and should always |
| // reflect it (do not change one without changing the other). Entries should |
| // be never modified or deleted. Only additions possible. |
| // |
| // LINT.IfChange(QuickStartGaiaAuthenticationResult) |
| enum class GaiaAuthenticationResult { |
| kUnknownError = 0, |
| kSuccess = 1, |
| kResponseParsingError = 2, |
| kRejection = 3, |
| kAdditionalChallengesOnSource = 4, |
| kAdditionalChallengesOnTarget = 5, |
| kMaxValue = kAdditionalChallengesOnTarget, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/quickstart/enums.xml:QuickStartGaiaAuthenticationResult) |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml, and should always |
| // reflect it (do not change one without changing the other). Entries should |
| // be never modified or deleted. Only additions possible. |
| // |
| // LINT.IfChange(QuickStartWifiTransferResultFailureReason) |
| enum class WifiTransferResultFailureReason { |
| kConnectionDroppedDuringAttempt = 0, |
| kEmptyResponseBytes = 1, |
| kUnableToReadAsJSON = 2, |
| kWifiNetworkInformationNotFound = 3, |
| kSsidNotFound = 4, |
| kEmptySsid = 5, |
| kSecurityTypeNotFound = 6, |
| kInvalidSecurityType = 7, |
| kPasswordFoundAndOpenNetwork = 8, |
| kPasswordNotFoundAndNotOpenNetwork = 9, |
| kWifiHideStatusNotFound = 10, |
| kMaxValue = kWifiHideStatusNotFound, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/quickstart/enums.xml:QuickStartWifiTransferResultFailureReason) |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml, and should always |
| // reflect it (do not change one without changing the other). Entries should |
| // be never modified or deleted. Only additions possible. |
| // |
| // LINT.IfChange(QuickStartGaiaTransferResultFailureReason) |
| enum class GaiaTransferResultFailureReason { |
| kNoAccountOnPhone = 0, |
| kFailedFetchingChallengeBytesFromGaia = 1, |
| kConnectionLost = 2, |
| kGaiaAssertionNotReceived = 3, |
| kFailedFetchingAttestationCertificate = 4, |
| kFailedFetchingRefreshToken = 5, |
| kFallbackURLRequired = 6, |
| kErrorReceivingFIDOAssertion = 7, |
| kObfuscatedGaiaIdMissing = 8, |
| kMaxValue = kObfuscatedGaiaIdMissing, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/quickstart/enums.xml:QuickStartGaiaTransferResultFailureReason) |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml as well as a |
| // CrOSEvents enum defined in |
| // //components/metrics/structured/structured_events.h, and should always |
| // reflect them (do not change one without changing the others). Entries |
| // should never be modified or deleted. Only additions possible. |
| enum class AbortFlowReason { |
| USER_CLICKED_BACK = 0, |
| USER_CLICKED_CANCEL = 1, |
| SIGNIN_SCHOOL = 2, |
| ENTERPRISE_ENROLLMENT = 3, |
| ERROR = 4, |
| // Child accounts are not yet supported. |
| ADD_CHILD = 5, |
| kMaxValue = ADD_CHILD, |
| }; |
| |
| // This enum is tied directly to a UMA enum defined in |
| // //tools/metrics/histograms/metadata/quickstart/enums.xml as well as a |
| // CrOSEvents enum defined in |
| // //components/metrics/structured/structured_events.h, and should always |
| // reflect them (do not change one without changing the others). Entries |
| // should never be modified or deleted. Only additions possible. |
| enum class EntryPoint { |
| WELCOME_SCREEN = 0, |
| NETWORK_SCREEN = 1, |
| GAIA_INFO_SCREEN = 2, |
| GAIA_SCREEN = 3, |
| AUTO_RESUME_AFTER_UPDATE = 4, |
| kMaxValue = AUTO_RESUME_AFTER_UPDATE, |
| }; |
| |
| // Helper function that returns the MessageType equivalent of |
| // QuickStartResponseType. |
| static MessageType MapResponseToMessageType( |
| QuickStartResponseType response_type); |
| |
| static ScreenClosedReason MapAbortFlowReasonToScreenClosedReason( |
| AbortFlowReason reason); |
| |
| static void RecordWifiTransferResult( |
| bool succeeded, |
| std::optional<WifiTransferResultFailureReason> failure_reason); |
| |
| static void RecordGaiaTransferStarted(); |
| |
| static void RecordCapturePortalEncountered(int32_t session_id); |
| |
| static void RecordRedirectToEnterpriseEnrollment(int32_t session_id); |
| |
| static void RecordForcedUpdateRequired(int32_t session_id); |
| |
| static void RecordGaiaTransferResult( |
| bool succeeded, |
| std::optional<GaiaTransferResultFailureReason> failure_reason); |
| |
| static void RecordEntryPoint(EntryPoint entry_point); |
| |
| static void RecordEntryPointVisible(EntryPoint entry_point); |
| |
| static void RecordAuthenticationMethod(AuthenticationMethod auth_method); |
| |
| static void RecordAbortFlowReason(AbortFlowReason reason); |
| |
| static void RecordUpdateStarted(bool is_forced); |
| |
| static void RecordConsumerUpdateCancelled(); |
| |
| static void RecordEstablishConnection(bool success, bool is_automatic_resume); |
| |
| static void RecordSetupComplete(); |
| |
| QuickStartMetrics(); |
| QuickStartMetrics(const QuickStartMetrics&) = delete; |
| const QuickStartMetrics& operator=(const QuickStartMetrics&) = delete; |
| virtual ~QuickStartMetrics(); |
| |
| void RecordScreenOpened(ScreenName screen); |
| |
| void RecordScreenClosed(ScreenName screen, ScreenClosedReason reason); |
| |
| // Records the start of an attempt to fetch challenge bytes from Gaia. |
| // Challenge bytes are later used to generate a Remote Attestation certificate |
| // and a FIDO assertion. |
| void RecordChallengeBytesRequested(); |
| |
| // Records the end of an attempt to fetch challenge bytes from Gaia. |
| // `status` is the overall status of the fetch. It is set to |
| // `GoogleServiceAuthError::State::NONE` if the request was successful. |
| void RecordChallengeBytesRequestEnded(const GoogleServiceAuthError& status); |
| |
| void RecordAttestationCertificateRequested(); |
| |
| // Records the end of a Remote Attestation certificate request. `error_code` |
| // is empty if the request was successful - otherwise it contains the details |
| // of the error. |
| void RecordAttestationCertificateRequestEnded( |
| std::optional<AttestationCertificateRequestErrorCode> error_code); |
| |
| void RecordGaiaAuthenticationStarted(); |
| |
| void RecordGaiaAuthenticationRequestEnded( |
| const GaiaAuthenticationResult& result); |
| |
| void RecordFastPairAdvertisementStarted( |
| bool succeeded, |
| std::optional<FastPairAdvertisingErrorCode> error_code); |
| |
| void RecordFastPairAdvertisementEnded( |
| bool succeeded, |
| std::optional<FastPairAdvertisingErrorCode> error_code); |
| |
| void RecordNearbyConnectionsAdvertisementStarted( |
| bool succeeded, |
| std::optional<NearbyConnectionsAdvertisingErrorCode> error_code); |
| |
| void RecordNearbyConnectionsAdvertisementEnded( |
| bool succeeded, |
| std::optional<NearbyConnectionsAdvertisingErrorCode> error_code); |
| |
| void RecordHandshakeStarted(); |
| |
| void RecordHandshakeResult(bool succeeded, |
| std::optional<HandshakeErrorCode> error_code); |
| |
| void RecordMessageSent(MessageType message_type); |
| |
| void RecordMessageReceived( |
| MessageType desired_message_type, |
| bool succeeded, |
| std::optional<MessageReceivedErrorCode> error_code); |
| |
| private: |
| ScreenName last_screen_opened_ = ScreenName::kNone; |
| // Timer to keep track of Fast Pair advertising duration. Should be |
| // constructed when advertising starts and destroyed when advertising |
| // finishes. |
| std::unique_ptr<base::ElapsedTimer> fast_pair_advertising_timer_; |
| |
| // Timer to keep track of Nearby Connections advertising duration. Should be |
| // constructed when advertising starts and destroyed when advertising |
| // finishes. |
| std::unique_ptr<base::ElapsedTimer> nearby_connections_advertising_timer_; |
| |
| // Timer to keep track of duration spent viewing a screen. Should be |
| // constructed when a screen is opened and destroyed when that screen is |
| // closed. |
| std::unique_ptr<base::ElapsedTimer> screen_opened_view_duration_timer_; |
| |
| // Timer to keep track of handshake duration. Should be constructed when |
| // the handshake starts and destroyed when the handshake finishes. |
| std::unique_ptr<base::ElapsedTimer> handshake_elapsed_timer_; |
| |
| // Timer to keep track of the duration of request/response pairs. Should be |
| // constructed when the request is sent and destroyed when the response is |
| // received. |
| std::unique_ptr<base::ElapsedTimer> message_elapsed_timer_; |
| |
| // Timer to keep track of challenge bytes fetch requests. It should be set at |
| // the start of a challenge bytes fetch and destroyed when a response is |
| // received. |
| std::unique_ptr<base::ElapsedTimer> challenge_bytes_fetch_timer_; |
| |
| // Timer to keep track of remote attestation certificate fetch requests. It |
| // should be set at the start of a certificate fetch and destroyed when a |
| // response is received. |
| std::unique_ptr<base::ElapsedTimer> attestation_certificate_timer_; |
| |
| // Timer to keep track of Gaia authentication requests. It should be set at |
| // the start of a Gaia authentication request and destroyed when a response is |
| // received. |
| std::unique_ptr<base::ElapsedTimer> gaia_authentication_timer_; |
| }; |
| |
| std::ostream& operator<<( |
| std::ostream& stream, |
| const QuickStartMetrics::ScreenName& metrics_screen_name); |
| |
| } // namespace ash::quick_start |
| |
| #endif // CHROMEOS_ASH_COMPONENTS_QUICK_START_QUICK_START_METRICS_H_ |