1 // Copyright 2013 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 #include "components/autofill/core/browser/autofill_metrics.h" 6 7 #include "base/logging.h" 8 #include "base/metrics/histogram.h" 9 #include "base/metrics/sparse_histogram.h" 10 #include "base/time/time.h" 11 #include "components/autofill/core/browser/autofill_type.h" 12 #include "components/autofill/core/browser/form_structure.h" 13 #include "components/autofill/core/common/form_data.h" 14 15 namespace autofill { 16 17 namespace { 18 19 // Server experiments we support. 20 enum ServerExperiment { 21 NO_EXPERIMENT = 0, 22 UNKNOWN_EXPERIMENT, 23 ACCEPTANCE_RATIO_06, 24 ACCEPTANCE_RATIO_1, 25 ACCEPTANCE_RATIO_2, 26 ACCEPTANCE_RATIO_4, 27 ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15, 28 ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_25, 29 ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15_MIN_FORM_SCORE_5, 30 TOOLBAR_DATA_ONLY, 31 ACCEPTANCE_RATIO_04_WINNER_LEAD_RATIO_3_MIN_FORM_SCORE_4, 32 NO_SERVER_RESPONSE, 33 PROBABILITY_PICKER_05, 34 PROBABILITY_PICKER_025, 35 PROBABILITY_PICKER_025_CC_THRESHOLD_03, 36 PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03, 37 PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03_WITH_FALLBACK, 38 PROBABILITY_PICKER_05_CC_NAME_THRESHOLD_03_EXPERIMENT_1, 39 NUM_SERVER_EXPERIMENTS 40 }; 41 42 enum FieldTypeGroupForMetrics { 43 AMBIGUOUS = 0, 44 NAME, 45 COMPANY, 46 ADDRESS_LINE_1, 47 ADDRESS_LINE_2, 48 ADDRESS_CITY, 49 ADDRESS_STATE, 50 ADDRESS_ZIP, 51 ADDRESS_COUNTRY, 52 PHONE, 53 FAX, // Deprecated. 54 EMAIL, 55 CREDIT_CARD_NAME, 56 CREDIT_CARD_NUMBER, 57 CREDIT_CARD_DATE, 58 CREDIT_CARD_TYPE, 59 PASSWORD, 60 NUM_FIELD_TYPE_GROUPS_FOR_METRICS 61 }; 62 63 // First, translates |field_type| to the corresponding logical |group| from 64 // |FieldTypeGroupForMetrics|. Then, interpolates this with the given |metric|, 65 // which should be in the range [0, |num_possible_metrics|). 66 // Returns the interpolated index. 67 // 68 // The interpolation maps the pair (|group|, |metric|) to a single index, so 69 // that all the indicies for a given group are adjacent. In particular, with 70 // the groups {AMBIGUOUS, NAME, ...} combining with the metrics {UNKNOWN, MATCH, 71 // MISMATCH}, we create this set of mapped indices: 72 // { 73 // AMBIGUOUS+UNKNOWN, 74 // AMBIGUOUS+MATCH, 75 // AMBIGUOUS+MISMATCH, 76 // NAME+UNKNOWN, 77 // NAME+MATCH, 78 // NAME+MISMATCH, 79 // ... 80 // }. 81 // 82 // Clients must ensure that |field_type| is one of the types Chrome supports 83 // natively, e.g. |field_type| must not be a billng address. 84 int GetFieldTypeGroupMetric(const ServerFieldType field_type, 85 const int metric, 86 const int num_possible_metrics) { 87 DCHECK_LT(metric, num_possible_metrics); 88 89 FieldTypeGroupForMetrics group = AMBIGUOUS; 90 switch (AutofillType(field_type).group()) { 91 case ::autofill::NO_GROUP: 92 group = AMBIGUOUS; 93 break; 94 95 case ::autofill::NAME: 96 case ::autofill::NAME_BILLING: 97 group = NAME; 98 break; 99 100 case ::autofill::COMPANY: 101 group = COMPANY; 102 break; 103 104 case ::autofill::ADDRESS_HOME: 105 case ::autofill::ADDRESS_BILLING: 106 switch (AutofillType(field_type).GetStorableType()) { 107 case ADDRESS_HOME_LINE1: 108 group = ADDRESS_LINE_1; 109 break; 110 case ADDRESS_HOME_LINE2: 111 group = ADDRESS_LINE_2; 112 break; 113 case ADDRESS_HOME_CITY: 114 group = ADDRESS_CITY; 115 break; 116 case ADDRESS_HOME_STATE: 117 group = ADDRESS_STATE; 118 break; 119 case ADDRESS_HOME_ZIP: 120 group = ADDRESS_ZIP; 121 break; 122 case ADDRESS_HOME_COUNTRY: 123 group = ADDRESS_COUNTRY; 124 break; 125 default: 126 NOTREACHED(); 127 group = AMBIGUOUS; 128 break; 129 } 130 break; 131 132 case ::autofill::EMAIL: 133 group = EMAIL; 134 break; 135 136 case ::autofill::PHONE_HOME: 137 case ::autofill::PHONE_BILLING: 138 group = PHONE; 139 break; 140 141 case ::autofill::CREDIT_CARD: 142 switch (field_type) { 143 case ::autofill::CREDIT_CARD_NAME: 144 group = CREDIT_CARD_NAME; 145 break; 146 case ::autofill::CREDIT_CARD_NUMBER: 147 group = CREDIT_CARD_NUMBER; 148 break; 149 case ::autofill::CREDIT_CARD_TYPE: 150 group = CREDIT_CARD_TYPE; 151 break; 152 case ::autofill::CREDIT_CARD_EXP_MONTH: 153 case ::autofill::CREDIT_CARD_EXP_2_DIGIT_YEAR: 154 case ::autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR: 155 case ::autofill::CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: 156 case ::autofill::CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: 157 group = CREDIT_CARD_DATE; 158 break; 159 default: 160 NOTREACHED(); 161 group = AMBIGUOUS; 162 break; 163 } 164 break; 165 166 case ::autofill::PASSWORD_FIELD: 167 group = PASSWORD; 168 break; 169 } 170 171 // Interpolate the |metric| with the |group|, so that all metrics for a given 172 // |group| are adjacent. 173 return (group * num_possible_metrics) + metric; 174 } 175 176 std::string WalletApiMetricToString( 177 AutofillMetrics::WalletApiCallMetric metric) { 178 switch (metric) { 179 case AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS: 180 return "AcceptLegalDocuments"; 181 case AutofillMetrics::AUTHENTICATE_INSTRUMENT: 182 return "AuthenticateInstrument"; 183 case AutofillMetrics::GET_FULL_WALLET: 184 return "GetFullWallet"; 185 case AutofillMetrics::GET_WALLET_ITEMS: 186 return "GetWalletItems"; 187 case AutofillMetrics::SAVE_TO_WALLET: 188 return "SaveToWallet"; 189 case AutofillMetrics::UNKNOWN_API_CALL: 190 case AutofillMetrics::NUM_WALLET_API_CALLS: 191 NOTREACHED(); 192 return "UnknownApiCall"; 193 } 194 195 NOTREACHED(); 196 return "UnknownApiCall"; 197 } 198 199 // A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name| 200 // to vary over the program's runtime. 201 void LogUMAHistogramEnumeration(const std::string& name, 202 int sample, 203 int boundary_value) { 204 DCHECK_LT(sample, boundary_value); 205 206 // Note: This leaks memory, which is expected behavior. 207 base::HistogramBase* histogram = 208 base::LinearHistogram::FactoryGet( 209 name, 210 1, 211 boundary_value, 212 boundary_value + 1, 213 base::HistogramBase::kUmaTargetedHistogramFlag); 214 histogram->Add(sample); 215 } 216 217 // A version of the UMA_HISTOGRAM_TIMES macro that allows the |name| 218 // to vary over the program's runtime. 219 void LogUMAHistogramTimes(const std::string& name, 220 const base::TimeDelta& duration) { 221 // Note: This leaks memory, which is expected behavior. 222 base::HistogramBase* histogram = 223 base::Histogram::FactoryTimeGet( 224 name, 225 base::TimeDelta::FromMilliseconds(1), 226 base::TimeDelta::FromSeconds(10), 227 50, 228 base::HistogramBase::kUmaTargetedHistogramFlag); 229 histogram->AddTime(duration); 230 } 231 232 // A version of the UMA_HISTOGRAM_LONG_TIMES macro that allows the |name| 233 // to vary over the program's runtime. 234 void LogUMAHistogramLongTimes(const std::string& name, 235 const base::TimeDelta& duration) { 236 // Note: This leaks memory, which is expected behavior. 237 base::HistogramBase* histogram = 238 base::Histogram::FactoryTimeGet( 239 name, 240 base::TimeDelta::FromMilliseconds(1), 241 base::TimeDelta::FromHours(1), 242 50, 243 base::HistogramBase::kUmaTargetedHistogramFlag); 244 histogram->AddTime(duration); 245 } 246 247 // Logs a type quality metric. The primary histogram name is constructed based 248 // on |base_name| and |experiment_id|. The field-specific histogram name also 249 // factors in the |field_type|. Logs a sample of |metric|, which should be in 250 // the range [0, |num_possible_metrics|). 251 void LogTypeQualityMetric(const std::string& base_name, 252 const int metric, 253 const int num_possible_metrics, 254 const ServerFieldType field_type, 255 const std::string& experiment_id) { 256 DCHECK_LT(metric, num_possible_metrics); 257 258 std::string histogram_name = base_name; 259 if (!experiment_id.empty()) 260 histogram_name += "_" + experiment_id; 261 LogUMAHistogramEnumeration(histogram_name, metric, num_possible_metrics); 262 263 std::string sub_histogram_name = base_name + ".ByFieldType"; 264 if (!experiment_id.empty()) 265 sub_histogram_name += "_" + experiment_id; 266 const int field_type_group_metric = 267 GetFieldTypeGroupMetric(field_type, metric, num_possible_metrics); 268 const int num_field_type_group_metrics = 269 num_possible_metrics * NUM_FIELD_TYPE_GROUPS_FOR_METRICS; 270 LogUMAHistogramEnumeration(sub_histogram_name, 271 field_type_group_metric, 272 num_field_type_group_metrics); 273 } 274 275 void LogServerExperimentId(const std::string& histogram_name, 276 const std::string& experiment_id) { 277 ServerExperiment metric = UNKNOWN_EXPERIMENT; 278 279 const std::string default_experiment_name = 280 FormStructure(FormData()).server_experiment_id(); 281 if (experiment_id.empty()) 282 metric = NO_EXPERIMENT; 283 else if (experiment_id == "ar06") 284 metric = ACCEPTANCE_RATIO_06; 285 else if (experiment_id == "ar1") 286 metric = ACCEPTANCE_RATIO_1; 287 else if (experiment_id == "ar2") 288 metric = ACCEPTANCE_RATIO_2; 289 else if (experiment_id == "ar4") 290 metric = ACCEPTANCE_RATIO_4; 291 else if (experiment_id == "ar05wlr15") 292 metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15; 293 else if (experiment_id == "ar05wlr25") 294 metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_25; 295 else if (experiment_id == "ar05wr15fs5") 296 metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15_MIN_FORM_SCORE_5; 297 else if (experiment_id == "tbar1") 298 metric = TOOLBAR_DATA_ONLY; 299 else if (experiment_id == "ar04wr3fs4") 300 metric = ACCEPTANCE_RATIO_04_WINNER_LEAD_RATIO_3_MIN_FORM_SCORE_4; 301 else if (experiment_id == default_experiment_name) 302 metric = NO_SERVER_RESPONSE; 303 else if (experiment_id == "fp05") 304 metric = PROBABILITY_PICKER_05; 305 else if (experiment_id == "fp025") 306 metric = PROBABILITY_PICKER_025; 307 else if (experiment_id == "fp05cc03") 308 metric = PROBABILITY_PICKER_025_CC_THRESHOLD_03; 309 else if (experiment_id == "fp05cco03") 310 metric = PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03; 311 else if (experiment_id == "fp05cco03cstd") 312 metric = PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03_WITH_FALLBACK; 313 else if (experiment_id == "fp05cc03e1") 314 metric = PROBABILITY_PICKER_05_CC_NAME_THRESHOLD_03_EXPERIMENT_1; 315 316 DCHECK_LT(metric, NUM_SERVER_EXPERIMENTS); 317 LogUMAHistogramEnumeration(histogram_name, metric, NUM_SERVER_EXPERIMENTS); 318 } 319 320 } // namespace 321 322 AutofillMetrics::AutofillMetrics() { 323 } 324 325 AutofillMetrics::~AutofillMetrics() { 326 } 327 328 void AutofillMetrics::LogCreditCardInfoBarMetric(InfoBarMetric metric) const { 329 DCHECK_LT(metric, NUM_INFO_BAR_METRICS); 330 331 UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric, 332 NUM_INFO_BAR_METRICS); 333 } 334 335 void AutofillMetrics::LogDialogDismissalState( 336 DialogDismissalState state) const { 337 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.DismissalState", 338 state, NUM_DIALOG_DISMISSAL_STATES); 339 } 340 341 void AutofillMetrics::LogDialogInitialUserState( 342 DialogInitialUserStateMetric user_type) const { 343 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.InitialUserState", 344 user_type, NUM_DIALOG_INITIAL_USER_STATE_METRICS); 345 } 346 347 void AutofillMetrics::LogDialogLatencyToShow( 348 const base::TimeDelta& duration) const { 349 LogUMAHistogramTimes("RequestAutocomplete.UiLatencyToShow", duration); 350 } 351 352 void AutofillMetrics::LogDialogPopupEvent(DialogPopupEvent event) const { 353 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.PopupInDialog", 354 event, NUM_DIALOG_POPUP_EVENTS); 355 } 356 357 void AutofillMetrics::LogDialogSecurityMetric( 358 DialogSecurityMetric metric) const { 359 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.Security", 360 metric, NUM_DIALOG_SECURITY_METRICS); 361 } 362 363 void AutofillMetrics::LogDialogUiDuration( 364 const base::TimeDelta& duration, 365 DialogDismissalAction dismissal_action) const { 366 std::string suffix; 367 switch (dismissal_action) { 368 case DIALOG_ACCEPTED: 369 suffix = "Submit"; 370 break; 371 372 case DIALOG_CANCELED: 373 suffix = "Cancel"; 374 break; 375 } 376 377 LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration", duration); 378 LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration." + suffix, 379 duration); 380 } 381 382 void AutofillMetrics::LogDialogUiEvent(DialogUiEvent event) const { 383 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.UiEvents", event, 384 NUM_DIALOG_UI_EVENTS); 385 } 386 387 void AutofillMetrics::LogWalletErrorMetric(WalletErrorMetric metric) const { 388 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletErrors", metric, 389 NUM_WALLET_ERROR_METRICS); 390 } 391 392 void AutofillMetrics::LogWalletApiCallDuration( 393 WalletApiCallMetric metric, 394 const base::TimeDelta& duration) const { 395 LogUMAHistogramTimes("Wallet.ApiCallDuration." + 396 WalletApiMetricToString(metric), duration); 397 } 398 399 void AutofillMetrics::LogWalletMalformedResponseMetric( 400 WalletApiCallMetric metric) const { 401 UMA_HISTOGRAM_ENUMERATION("Wallet.MalformedResponse", metric, 402 NUM_WALLET_API_CALLS); 403 } 404 405 void AutofillMetrics::LogWalletRequiredActionMetric( 406 WalletRequiredActionMetric required_action) const { 407 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletRequiredActions", 408 required_action, NUM_WALLET_REQUIRED_ACTIONS); 409 } 410 411 void AutofillMetrics::LogWalletResponseCode(int response_code) const { 412 UMA_HISTOGRAM_SPARSE_SLOWLY("Wallet.ResponseCode", response_code); 413 } 414 415 void AutofillMetrics::LogDeveloperEngagementMetric( 416 DeveloperEngagementMetric metric) const { 417 DCHECK_LT(metric, NUM_DEVELOPER_ENGAGEMENT_METRICS); 418 419 UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric, 420 NUM_DEVELOPER_ENGAGEMENT_METRICS); 421 } 422 423 void AutofillMetrics::LogHeuristicTypePrediction( 424 FieldTypeQualityMetric metric, 425 ServerFieldType field_type, 426 const std::string& experiment_id) const { 427 LogTypeQualityMetric("Autofill.Quality.HeuristicType", 428 metric, NUM_FIELD_TYPE_QUALITY_METRICS, 429 field_type, experiment_id); 430 } 431 432 void AutofillMetrics::LogOverallTypePrediction( 433 FieldTypeQualityMetric metric, 434 ServerFieldType field_type, 435 const std::string& experiment_id) const { 436 LogTypeQualityMetric("Autofill.Quality.PredictedType", 437 metric, NUM_FIELD_TYPE_QUALITY_METRICS, 438 field_type, experiment_id); 439 } 440 441 void AutofillMetrics::LogServerTypePrediction( 442 FieldTypeQualityMetric metric, 443 ServerFieldType field_type, 444 const std::string& experiment_id) const { 445 LogTypeQualityMetric("Autofill.Quality.ServerType", 446 metric, NUM_FIELD_TYPE_QUALITY_METRICS, 447 field_type, experiment_id); 448 } 449 450 void AutofillMetrics::LogQualityMetric(QualityMetric metric, 451 const std::string& experiment_id) const { 452 DCHECK_LT(metric, NUM_QUALITY_METRICS); 453 454 std::string histogram_name = "Autofill.Quality"; 455 if (!experiment_id.empty()) 456 histogram_name += "_" + experiment_id; 457 458 LogUMAHistogramEnumeration(histogram_name, metric, NUM_QUALITY_METRICS); 459 } 460 461 void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) const { 462 DCHECK_LT(metric, NUM_SERVER_QUERY_METRICS); 463 464 UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric, 465 NUM_SERVER_QUERY_METRICS); 466 } 467 468 void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) const { 469 DCHECK_LT(metric, NUM_USER_HAPPINESS_METRICS); 470 471 UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric, 472 NUM_USER_HAPPINESS_METRICS); 473 } 474 475 void AutofillMetrics::LogFormFillDurationFromLoadWithAutofill( 476 const base::TimeDelta& duration) const { 477 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithAutofill", 478 duration, 479 base::TimeDelta::FromMilliseconds(100), 480 base::TimeDelta::FromMinutes(10), 481 50); 482 } 483 484 void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill( 485 const base::TimeDelta& duration) const { 486 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithoutAutofill", 487 duration, 488 base::TimeDelta::FromMilliseconds(100), 489 base::TimeDelta::FromMinutes(10), 490 50); 491 } 492 493 void AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill( 494 const base::TimeDelta& duration) const { 495 UMA_HISTOGRAM_CUSTOM_TIMES( 496 "Autofill.FillDuration.FromInteraction.WithAutofill", 497 duration, 498 base::TimeDelta::FromMilliseconds(100), 499 base::TimeDelta::FromMinutes(10), 500 50); 501 } 502 503 void AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill( 504 const base::TimeDelta& duration) const { 505 UMA_HISTOGRAM_CUSTOM_TIMES( 506 "Autofill.FillDuration.FromInteraction.WithoutAutofill", 507 duration, 508 base::TimeDelta::FromMilliseconds(100), 509 base::TimeDelta::FromMinutes(10), 510 50); 511 } 512 513 void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const { 514 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled); 515 } 516 517 void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const { 518 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled); 519 } 520 521 void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const { 522 UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles); 523 } 524 525 void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const { 526 UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions); 527 } 528 529 void AutofillMetrics::LogServerExperimentIdForQuery( 530 const std::string& experiment_id) const { 531 LogServerExperimentId("Autofill.ServerExperimentId.Query", experiment_id); 532 } 533 534 void AutofillMetrics::LogServerExperimentIdForUpload( 535 const std::string& experiment_id) const { 536 LogServerExperimentId("Autofill.ServerExperimentId.Upload", experiment_id); 537 } 538 539 } // namespace autofill 540