1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_METRICS_RECORDER_H_ 6 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_METRICS_RECORDER_H_ 7 8 #include <stdint.h> 9 10 #include <map> 11 #include <memory> 12 #include <set> 13 #include <vector> 14 15 #include "base/macros.h" 16 #include "base/memory/ref_counted.h" 17 #include "base/optional.h" 18 #include "base/time/clock.h" 19 #include "components/autofill/core/common/mojom/autofill_types.mojom.h" 20 #include "components/autofill/core/common/signatures.h" 21 #include "components/password_manager/core/browser/password_form.h" 22 #include "components/password_manager/core/browser/password_manager_metrics_util.h" 23 #include "services/metrics/public/cpp/ukm_builders.h" 24 #include "services/metrics/public/cpp/ukm_recorder.h" 25 #include "url/gurl.h" 26 27 class PrefService; 28 29 namespace autofill { 30 struct FormData; 31 } 32 33 namespace password_manager { 34 35 struct InteractionsStats; 36 37 // The pupose of this class is to record various types of metrics about the 38 // behavior of the PasswordFormManager and its interaction with the user and 39 // the page. The recorder tracks events tied to the logical life of a password 40 // form, from parsing to having been saved. These events happen on different 41 // places in the code and the logical password form can be captured by multiple 42 // instances of real objects. To allow sharing the single recorder object among 43 // those, this class is refcounted. Reporting happens on destruction of the 44 // metrics recorder. Note that UKM metrics are reported for intervals of length 45 // metrics::GetUploadInterval(). Only metrics that are reported from the time 46 // of creating the PasswordFormMetricsRecorder until the end of current upload 47 // interval are recorded. Everything after the end of the current upload 48 // interval is discarded. For this reason, it is essential that references are 49 // not just kept until browser shutdown. 50 class PasswordFormMetricsRecorder 51 : public base::RefCounted<PasswordFormMetricsRecorder> { 52 public: 53 // Records UKM metrics and reports them on destruction. The |source_id| is 54 // the ID of the WebContents document that the forms belong to. 55 PasswordFormMetricsRecorder(bool is_main_frame_secure, 56 ukm::SourceId source_id, 57 PrefService* pref_service); 58 59 // ManagerAction - What does the PasswordFormManager do with this form? Either 60 // it fills it, or it doesn't. If it doesn't fill it, that's either 61 // because it has no match or it is disabled via the AUTOCOMPLETE=off 62 // attribute. Note that if we don't have an exact match, we still provide 63 // candidates that the user may end up choosing. 64 enum ManagerAction { 65 kManagerActionNone = 0, 66 kManagerActionAutofilled, 67 kManagerActionBlacklisted_Obsolete, 68 kManagerActionMax 69 }; 70 71 // Result - What happens to the form? 72 // 73 // These values are persisted to logs. Entries should not be renumbered and 74 // numeric values should never be reused. 75 // 76 // Needs to stay in sync with PasswordFormSubmissionResult in enums.xml. 77 enum class SubmitResult { 78 kNotSubmitted = 0, 79 kFailed = 1, 80 kPassed = 2, 81 }; 82 83 // Whether the password manager filled a credential on a form. 84 enum ManagerAutofillEvent { 85 // No credential existed that could be filled into a password form. 86 kManagerFillEventNoCredential = 0, 87 // A credential could have been autofilled into a password form but was not 88 // due to a policy. E.g. incognito mode requires a user interaction before 89 // filling can happen. PSL matches are not autofilled and also on password 90 // change forms we do not autofill. 91 kManagerFillEventBlockedOnInteraction, 92 // A credential was autofilled into a form. 93 kManagerFillEventAutofilled 94 }; 95 96 // What the form is used for. SubmittedFormType::kUnspecified is only set 97 // before the SetSubmittedFormType() is called, and should never be actually 98 // uploaded. 99 // 100 // These values are persisted to logs. Entries should not be renumbered and 101 // numeric values should never be reused. 102 // 103 // Needs to stay in sync with PasswordFormType in enums.xml. 104 enum class SubmittedFormType { 105 kLogin = 0, 106 kLoginNoUsername = 1, 107 kChangePasswordEnabled = 2, 108 kChangePasswordDisabled = 3, 109 kChangePasswordNoUsername = 4, 110 kSignup = 5, 111 kSignupNoUsername = 6, 112 kLoginAndSignup = 7, 113 kUnspecified = 8, 114 kCount = 9, 115 }; 116 117 // The reason why a password bubble was shown on the screen. 118 // 119 // These values are persisted to logs. Entries should not be renumbered and 120 // numeric values should never be reused. 121 // 122 // Needs to stay in sync with PasswordBubbleTrigger in enums.xml. 123 enum class BubbleTrigger { 124 kUnknown = 0, 125 // The password manager suggests the user to save a password and asks for 126 // confirmation. 127 kPasswordManagerSuggestionAutomatic = 1, 128 kPasswordManagerSuggestionManual = 2, 129 // The site asked the user to save a password via the credential management 130 // API. 131 kCredentialManagementAPIAutomatic = 3, 132 kCredentialManagementAPIManual = 4, 133 }; 134 135 // The reason why a password bubble was dismissed. 136 // 137 // These values are persisted to logs. Entries should not be renumbered and 138 // numeric values should never be reused. 139 // 140 // Needs to stay in sync with PasswordBubbleDismissalReason in enums.xml. 141 enum class BubbleDismissalReason { 142 kUnknown = 0, 143 kAccepted = 1, 144 kDeclined = 2, 145 kIgnored = 3 146 }; 147 148 // This enum is a designed to be able to collect all kinds of potentially 149 // interesting user interactions with sites and password manager UI in 150 // relation to a given form. In contrast to UserAction, it is intended to be 151 // extensible. 152 enum class DetailedUserAction { 153 // Interactions with password bubble. 154 kEditedUsernameInBubble = 100, 155 kSelectedDifferentPasswordInBubble = 101, 156 kTriggeredManualFallbackForSaving = 102, 157 kObsoleteTriggeredManualFallbackForUpdating = 103, // unused 158 159 // Interactions with form. 160 kCorrectedUsernameInForm = 200, 161 }; 162 163 // Indicator whether the user has seen a password generation popup and why. 164 // 165 // These values are persisted to logs. Entries should not be renumbered and 166 // numeric values should never be reused. 167 // 168 // Needs to stay in sync with PasswordGenerationPopupShown in enums.xml. 169 enum class PasswordGenerationPopupShown { 170 kNotShown = 0, 171 kShownAutomatically = 1, 172 kShownManually = 2, 173 kMaxValue = kShownManually, 174 }; 175 176 // Metric: PasswordGeneration.UserDecision 177 enum class GeneratedPasswordStatus { 178 // The generated password was accepted by the user. 179 kPasswordAccepted = 0, 180 // The generated password was edited by the user in the field in which 181 // it was filled after being accepted. 182 kPasswordEdited = 1, 183 // The generated password was deleted by the user from the field 184 // in which it was filled after being accepted. 185 kPasswordDeleted = 2, 186 kPasswordRejectedInDialogObsolete = 3, // obsolete 187 kMaxValue = kPasswordRejectedInDialogObsolete 188 }; 189 190 // Represents form differences. 191 // 1.This is a bit mask, so new values must be powers of 2. 192 // 2.This is used for UMA, so no deletion, only adding at the end. 193 enum FormDataDifferences { 194 // Different number of fields. 195 kFieldsNumber = 1 << 0, 196 kRendererFieldIDs = 1 << 1, 197 kAutocompleteAttributes = 1 << 2, 198 kFormControlTypes = 1 << 3, 199 kMaxFormDifferencesValue = 1 << 4, 200 }; 201 202 // Used in UMA histogram, please do NOT reorder. 203 // Metric: "PasswordManager.FirstWaitForUsernameReason" 204 // This metric records why the browser instructs the renderer not to fill the 205 // credentials on page load but to wait for the user to confirm the credential 206 // to be filled. This decision is only recorded for the first time, the 207 // browser informs the renderer about credentials for a given form. 208 // 209 // Needs to stay in sync with PasswordManagerFirstWaitForUsernameReason in 210 // enums.xml. 211 enum class WaitForUsernameReason { 212 // Credentials may be filled on page load. 213 kDontWait = 0, 214 // User is browsing in incognito mode. 215 kIncognitoMode = 1, 216 // A credential exists for a PSL matched site but not for the current 217 // security origin. 218 kPublicSuffixMatch = 2, 219 // Form is suspected to be a password change form. (Only recorded for old 220 // form parser) 221 kFormNotGoodForFilling = 3, 222 // User is on a site with an insecure main frame origin. 223 kInsecureOrigin = 4, 224 // The Touch To Fill feature is enabled. 225 kTouchToFill = 5, 226 // Show suggestion on account selection feature is enabled. 227 kFoasFeature = 6, 228 // Re-authenticaion for filling passwords is required. 229 kReauthRequired = 7, 230 // Password is already filled 231 kPasswordPrefilled = 8, 232 kMaxValue = kPasswordPrefilled, 233 }; 234 235 // This metric records the user experience with the passwords filling. The 236 // first 4 buckets are ranging from the best (automatic) to the worst (the 237 // user has to type already saved password). Next 2 buckets showed the cases 238 // when it was impossible to help because the unknown credentials were 239 // submitted. The last bucket are strange cases, that the submitted form has 240 // nor user input, nor autofilled data in password fields. 241 enum class FillingAssistance { 242 // Credential fields were filled automatically. 243 kAutomatic = 0, 244 // Credential fields were filled with involving manual filling (but none 245 // required typing). 246 kManual = 1, 247 // Password was filled (automatically or manually), known username was 248 // typed. 249 kUsernameTypedPasswordFilled = 2, 250 // Known password was typed. 251 kKnownPasswordTyped = 3, 252 // Unknown password was typed while some credentials were stored. 253 kNewPasswordTypedWhileCredentialsExisted = 4, 254 // No saved credentials. 255 kNoSavedCredentials = 5, 256 // Neither user input nor filling. 257 kNoUserInputNoFillingInPasswordFields = 6, 258 // Domain is blacklisted and no other credentials exist. 259 kNoSavedCredentialsAndBlacklisted = 7, 260 // No credentials exist and the user has ignored the save bubble too often, 261 // meaning that they won't be asked to save credentials anymore. 262 kNoSavedCredentialsAndBlacklistedBySmartBubble = 8, 263 kMaxValue = kNoSavedCredentialsAndBlacklistedBySmartBubble, 264 }; 265 266 // Records which store(s) a filled password came from. 267 // These values are persisted to logs. Entries should not be renumbered and 268 // numeric values should never be reused. 269 enum class FillingSource { 270 kNotFilled = 0, 271 kFilledFromProfileStore = 1, 272 kFilledFromAccountStore = 2, 273 kFilledFromBothStores = 3, 274 kMaxValue = kFilledFromBothStores, 275 }; 276 277 // Records whether a password hash was saved or not on Chrome sign-in page. 278 enum class ChromeSignInPageHashSaved { 279 kPasswordTypedHashNotSaved = 0, 280 kHashSaved = 1, 281 kMaxValue = kHashSaved, 282 }; 283 284 // Records user actions when Chrome suggests usernames on a page which are 285 // considered to be username first flow. 286 enum class SavingOnUsernameFirstFlow { 287 kSaved = 0, 288 kSavedWithEditedUsername = 1, 289 kNotSaved = 2, 290 kMaxValue = kNotSaved, 291 }; 292 293 // Used in UMA histogram, please do NOT reorder. 294 // Metric: "PasswordManager.JavaScriptOnlyValueInSubmittedForm" 295 enum class JsOnlyInput { 296 kOnlyJsInputNoFocus = 0, 297 kOnlyJsInputWithFocus = 1, 298 kAutofillOrUserInput = 2, 299 kMaxValue = kAutofillOrUserInput, 300 }; 301 302 // Called if the user could generate a password for this form. 303 void MarkGenerationAvailable(); 304 305 // Stores the user action associated with a generated password. 306 void SetGeneratedPasswordStatus(GeneratedPasswordStatus status); 307 308 // Stores the password manager action. During destruction the last 309 // set value will be logged. 310 void SetManagerAction(ManagerAction manager_action); 311 312 // Call these if/when we know the form submission worked or failed. 313 // These routines are used to update internal statistics ("ActionsTaken"). 314 void LogSubmitPassed(); 315 void LogSubmitFailed(); 316 317 // This can be called multiple times in which case the last value is reported. 318 void SetPasswordGenerationPopupShown(bool generation_popup_was_shown, 319 bool is_manual_generation); 320 321 // Call this once the submitted form type has been determined. 322 void SetSubmittedFormType(SubmittedFormType form_type); 323 324 // Call this when a password is saved to indicate which path led to 325 // submission. 326 void SetSubmissionIndicatorEvent( 327 autofill::mojom::SubmissionIndicatorEvent event); 328 329 // Records the event that a password bubble was shown. 330 void RecordPasswordBubbleShown( 331 metrics_util::CredentialSourceType credential_source_type, 332 metrics_util::UIDisplayDisposition display_disposition); 333 334 // Records the dismissal of a password bubble. 335 void RecordUIDismissalReason( 336 metrics_util::UIDismissalReason ui_dismissal_reason); 337 338 // Records that the password manager managed or failed to fill a form. 339 void RecordFillEvent(ManagerAutofillEvent event); 340 341 // Records a DetailedUserAction UKM metric. 342 void RecordDetailedUserAction(DetailedUserAction action); 343 344 // Hash algorithm for RecordFormSignature. Public for testing. 345 static int64_t HashFormSignature(autofill::FormSignature form_signature); 346 347 // Records a low entropy hash of the form signature in order to be able to 348 // distinguish two forms on the same site. 349 void RecordFormSignature(autofill::FormSignature form_signature); 350 351 // Records the readonly status encoded with parsing success after parsing for 352 // filling. The |value| is constructed as follows: The least significant bit 353 // says whether parsing succeeded (1) or not (0). The rest, shifted by one 354 // bit to the right is the FormDataParser::ReadonlyPasswordFields 355 // representation of the readonly status. 356 void RecordReadonlyWhenFilling(uint64_t value); 357 358 // Records the readonly status encoded with parsing success after parsing for 359 // creating pending credentials. See RecordReadonlyWhenFilling for the meaning 360 // of |value|. 361 void RecordReadonlyWhenSaving(uint64_t value); 362 363 // Records that Chrome noticed that it should show a manual fallback for 364 // saving. 365 void RecordShowManualFallbackForSaving(bool has_generated_password, 366 bool is_update); 367 368 void RecordFormChangeBitmask(uint32_t bitmask); 369 370 void RecordFirstFillingResult(int32_t result); 371 void RecordFirstWaitForUsernameReason(WaitForUsernameReason reason); 372 373 // Calculates FillingAssistance metric for |submitted_form|. The result is 374 // stored in |filling_assistance_| and recorded in the destructor in case when 375 // the successful submission is detected. 376 void CalculateFillingAssistanceMetric( 377 const autofill::FormData& submitted_form, 378 const std::set<std::pair<base::string16, PasswordForm::Store>>& 379 saved_usernames, 380 const std::set<std::pair<base::string16, PasswordForm::Store>>& 381 saved_passwords, 382 bool is_blacklisted, 383 const std::vector<InteractionsStats>& interactions_stats, 384 metrics_util::PasswordAccountStorageUsageLevel 385 account_storage_usage_level); 386 387 // Calculates whether all field values in |submitted_form| came from 388 // JavaScript. The result is stored in |js_only_input_|. 389 void CalculateJsOnlyInput(const autofill::FormData& submitted_form); 390 set_user_typed_password_on_chrome_sign_in_page()391 void set_user_typed_password_on_chrome_sign_in_page() { 392 user_typed_password_on_chrome_sign_in_page_ = true; 393 } 394 set_password_hash_saved_on_chrome_sing_in_page()395 void set_password_hash_saved_on_chrome_sing_in_page() { 396 password_hash_saved_on_chrome_sing_in_page_ = true; 397 } 398 set_possible_username_used(bool value)399 void set_possible_username_used(bool value) { 400 possible_username_used_ = value; 401 } 402 set_username_updated_in_bubble(bool value)403 void set_username_updated_in_bubble(bool value) { 404 username_updated_in_bubble_ = value; 405 } 406 set_clock_for_testing(base::Clock * clock)407 void set_clock_for_testing(base::Clock* clock) { clock_ = clock; } 408 409 private: 410 friend class base::RefCounted<PasswordFormMetricsRecorder>; 411 412 // Enum to track which password bubble is currently being displayed. 413 enum class CurrentBubbleOfInterest { 414 // This covers the cases that no password bubble is currently being 415 // displayed or the one displayed is none of the interesting cases. 416 kNone, 417 // The user is currently seeing a password save bubble. 418 kSaveBubble, 419 // The user is currently seeing a password update bubble. 420 kUpdateBubble, 421 }; 422 423 // Destructor reports a couple of UMA metrics as well as calls 424 // RecordUkmMetric. 425 ~PasswordFormMetricsRecorder(); 426 427 // Not owned. Points to base::DefaultClock::GetInstance() by default, but can 428 // be overridden for testing. 429 base::Clock* clock_; 430 431 // True if the main frame's committed URL, at the time PasswordFormManager 432 // was created, is secure. 433 const bool is_main_frame_secure_; 434 435 // Whether the user can choose to generate a password for this form. 436 bool generation_available_ = false; 437 438 // Contains the generated password's status, which resulted from a user 439 // action. 440 base::Optional<GeneratedPasswordStatus> generated_password_status_; 441 442 // Tracks which bubble is currently being displayed to the user. 443 CurrentBubbleOfInterest current_bubble_ = CurrentBubbleOfInterest::kNone; 444 445 // Whether the user was shown a prompt to update a password. 446 bool update_prompt_shown_ = false; 447 448 // Whether the user was shown a prompt to save a new credential. 449 bool save_prompt_shown_ = false; 450 451 // Whether the user was shown a password generation popup and why. 452 // Only reportet when a popup was shown. 453 PasswordGenerationPopupShown password_generation_popup_shown_ = 454 PasswordGenerationPopupShown::kNotShown; 455 456 // These three fields record the "ActionsTaken" by the browser and 457 // the user with this form, and the result. They are combined and 458 // recorded in UMA when the PasswordFormMetricsRecorder is destroyed. 459 ManagerAction manager_action_ = kManagerActionNone; 460 SubmitResult submit_result_ = SubmitResult::kNotSubmitted; 461 462 // Form type of the form that the PasswordFormManager is managing. Set after 463 // submission as the classification of the form can change depending on what 464 // data the user has entered. 465 SubmittedFormType submitted_form_type_ = SubmittedFormType::kUnspecified; 466 467 // The UKM SourceId of the document the form belongs to. 468 ukm::SourceId source_id_; 469 470 // Holds URL keyed metrics (UKMs) to be recorded on destruction. 471 ukm::builders::PasswordForm ukm_entry_builder_; 472 473 PrefService* const pref_service_; 474 475 // Counter for DetailedUserActions observed during the lifetime of a 476 // PasswordFormManager. Reported upon destruction. 477 std::map<DetailedUserAction, int64_t> detailed_user_actions_counts_; 478 479 // Bitmap of whether and why a manual fallback for saving was shown: 480 // 1 = the fallback was shown. 481 // 2 = the password was generated. 482 // 4 = this was an update prompt. 483 base::Optional<uint32_t> showed_manual_fallback_for_saving_; 484 485 base::Optional<uint32_t> form_changes_bitmask_; 486 487 bool recorded_first_filling_result_ = false; 488 489 bool recorded_wait_for_username_reason_ = false; 490 491 bool user_typed_password_on_chrome_sign_in_page_ = false; 492 bool password_hash_saved_on_chrome_sing_in_page_ = false; 493 494 base::Optional<FillingAssistance> filling_assistance_; 495 base::Optional<FillingSource> filling_source_; 496 base::Optional<metrics_util::PasswordAccountStorageUsageLevel> 497 account_storage_usage_level_; 498 499 bool possible_username_used_ = false; 500 bool username_updated_in_bubble_ = false; 501 502 base::Optional<JsOnlyInput> js_only_input_; 503 504 bool is_mixed_content_form_ = false; 505 506 DISALLOW_COPY_AND_ASSIGN(PasswordFormMetricsRecorder); 507 }; 508 509 } // namespace password_manager 510 511 #endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_METRICS_RECORDER_H_ 512