Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/autofill/core/browser/autofill_metrics.h" | 5 #include "components/autofill/core/browser/autofill_metrics.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 73 GROUP_CREDIT_CARD_DATE, | 73 GROUP_CREDIT_CARD_DATE, |
| 74 GROUP_CREDIT_CARD_TYPE, | 74 GROUP_CREDIT_CARD_TYPE, |
| 75 GROUP_PASSWORD, | 75 GROUP_PASSWORD, |
| 76 GROUP_ADDRESS_LINE_3, | 76 GROUP_ADDRESS_LINE_3, |
| 77 GROUP_USERNAME, | 77 GROUP_USERNAME, |
| 78 GROUP_STREET_ADDRESS, | 78 GROUP_STREET_ADDRESS, |
| 79 GROUP_CREDIT_CARD_VERIFICATION, | 79 GROUP_CREDIT_CARD_VERIFICATION, |
| 80 NUM_FIELD_TYPE_GROUPS_FOR_METRICS | 80 NUM_FIELD_TYPE_GROUPS_FOR_METRICS |
| 81 }; | 81 }; |
| 82 | 82 |
| 83 const int KMaxFieldTypeGroupMetric = | |
| 84 NUM_FIELD_TYPE_GROUPS_FOR_METRICS * | |
| 85 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS; | |
| 86 | |
| 83 std::string PreviousSaveCreditCardPromptUserDecisionToString( | 87 std::string PreviousSaveCreditCardPromptUserDecisionToString( |
| 84 int previous_save_credit_card_prompt_user_decision) { | 88 int previous_save_credit_card_prompt_user_decision) { |
| 85 DCHECK_LT(previous_save_credit_card_prompt_user_decision, | 89 DCHECK_LT(previous_save_credit_card_prompt_user_decision, |
| 86 prefs::NUM_PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISIONS); | 90 prefs::NUM_PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISIONS); |
| 87 std::string previous_response; | 91 std::string previous_response; |
| 88 if (previous_save_credit_card_prompt_user_decision == | 92 if (previous_save_credit_card_prompt_user_decision == |
| 89 prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED) | 93 prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED) |
| 90 previous_response = ".PreviouslyAccepted"; | 94 previous_response = ".PreviouslyAccepted"; |
| 91 else if (previous_save_credit_card_prompt_user_decision == | 95 else if (previous_save_credit_card_prompt_user_decision == |
| 92 prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED) | 96 prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED) |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 261 base::HistogramBase* histogram = | 265 base::HistogramBase* histogram = |
| 262 base::Histogram::FactoryTimeGet( | 266 base::Histogram::FactoryTimeGet( |
| 263 name, | 267 name, |
| 264 base::TimeDelta::FromMilliseconds(1), | 268 base::TimeDelta::FromMilliseconds(1), |
| 265 base::TimeDelta::FromHours(1), | 269 base::TimeDelta::FromHours(1), |
| 266 50, | 270 50, |
| 267 base::HistogramBase::kUmaTargetedHistogramFlag); | 271 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 268 histogram->AddTime(duration); | 272 histogram->AddTime(duration); |
| 269 } | 273 } |
| 270 | 274 |
| 275 const char* GetQualityMetricTypeSuffix( | |
| 276 AutofillMetrics::QualityMetricType metric_type) { | |
| 277 switch (metric_type) { | |
| 278 default: | |
| 279 NOTREACHED(); | |
| 280 // Fall through... | |
| 281 | |
| 282 case AutofillMetrics::TYPE_SUBMISSION: | |
| 283 return ""; | |
| 284 case AutofillMetrics::TYPE_NO_SUBMISSION: | |
| 285 return ".NoSubmission"; | |
| 286 case AutofillMetrics::TYPE_AUTOCOMPLETE_BASED: | |
| 287 return ".BasedOnAutocomplete"; | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 ServerFieldType GetFieldType(const ServerFieldTypeSet field_types, | |
|
Mathieu
2017/05/29 14:00:19
GetFieldType is a little vague, can we find a more
Roger McFarlane (Chromium)
2017/05/30 21:43:22
Done.
| |
| 292 ServerFieldType predicted_type) { | |
| 293 if (field_types.count(predicted_type)) | |
| 294 return predicted_type; | |
| 295 | |
| 296 if (field_types.count(EMPTY_TYPE)) | |
| 297 return EMPTY_TYPE; | |
| 298 | |
| 299 if (field_types.count(UNKNOWN_TYPE)) | |
| 300 return UNKNOWN_TYPE; | |
| 301 | |
| 302 // Collapse field types that Chrome treats as identical, e.g. home and | |
| 303 // billing address fields. | |
| 304 ServerFieldTypeSet collapsed_field_types; | |
| 305 for (const auto& type : field_types) { | |
| 306 // Since we currently only support US phone numbers, the (city code + main | |
| 307 // digits) number is almost always identical to the whole phone number. | |
| 308 // TODO(isherman): Improve this logic once we add support for | |
|
Mathieu
2017/05/29 14:00:19
hmm...
Roger McFarlane (Chromium)
2017/05/30 21:43:22
Indeed. It's not clear to me that we need to do th
| |
| 309 // international numbers. | |
| 310 if (type == PHONE_HOME_CITY_AND_NUMBER) | |
| 311 collapsed_field_types.insert(PHONE_HOME_WHOLE_NUMBER); | |
| 312 else | |
| 313 collapsed_field_types.insert(AutofillType(type).GetStorableType()); | |
| 314 } | |
| 315 | |
| 316 // Capture the field's type, if it is unambiguous. | |
| 317 ServerFieldType actual_type = UNKNOWN_TYPE; | |
| 318 if (collapsed_field_types.size() == 1) | |
| 319 actual_type = *collapsed_field_types.begin(); | |
| 320 | |
| 321 DVLOG(2) << "Inferred Type: " << AutofillType(actual_type).ToString(); | |
| 322 return actual_type; | |
| 323 } | |
| 324 | |
| 271 // Logs a type quality metric. The primary histogram name is constructed based | 325 // Logs a type quality metric. The primary histogram name is constructed based |
| 272 // on |base_name|. The field-specific histogram name also factors in the | 326 // on |base_name|. The field-specific histogram name also factors in the |
| 273 // |field_type|. Logs a sample of |metric|, which should be in the range | 327 // |field_type|. Logs a sample of |metric|, which should be in the range |
| 274 // [0, |num_possible_metrics|). May log a suffixed version of the metric | 328 // [0, |num_possible_metrics|). May log a suffixed version of the metric |
| 275 // depending on |metric_type|. | 329 // depending on |metric_type|. |
| 276 void LogTypeQualityMetric(const std::string& base_name, | 330 AutofillMetrics::FieldTypeQualityMetric LogTypeQualityMetric( |
| 277 AutofillMetrics::FieldTypeQualityMetric metric, | 331 const std::string& base_name, |
| 278 ServerFieldType field_type, | 332 ServerFieldTypeSet possible_types, |
| 279 AutofillMetrics::QualityMetricType metric_type) { | 333 ServerFieldType predicted_type, |
| 280 DCHECK_LT(metric, AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); | 334 AutofillMetrics::QualityMetricType metric_type) { |
| 335 // NO_SERVER_DATA is the equivalent of predicting UNKNOWN. | |
| 336 if (predicted_type == NO_SERVER_DATA) | |
| 337 predicted_type = UNKNOWN_TYPE; | |
| 281 | 338 |
| 282 std::string suffix; | 339 // Get the best type classification we can for the field. EMPTY is the same |
| 283 switch (metric_type) { | 340 // as UNKNOWN for our purposes, but remember whether or not it was empty for |
| 284 case AutofillMetrics::TYPE_SUBMISSION: | 341 // later. |
| 285 break; | 342 ServerFieldType actual_type = GetFieldType(possible_types, predicted_type); |
|
Mathieu
2017/05/29 14:00:19
GetActualFieldType perhaps?
Roger McFarlane (Chromium)
2017/05/30 21:43:22
Done.
| |
| 286 case AutofillMetrics::TYPE_NO_SUBMISSION: | 343 bool is_empty = (actual_type == EMPTY_TYPE); |
| 287 suffix = ".NoSubmission"; | 344 if (is_empty) |
| 288 break; | 345 actual_type = UNKNOWN_TYPE; |
| 289 case AutofillMetrics::TYPE_AUTOCOMPLETE_BASED: | 346 |
| 290 suffix = ".BasedOnAutocomplete"; | 347 // Capture the aggregate quality metric. |
| 291 break; | 348 const char* const suffix = GetQualityMetricTypeSuffix(metric_type); |
| 292 default: | 349 std::string aggregate_histogram = base_name + suffix; |
| 293 NOTREACHED(); | 350 std::string type_specific_histogram = base_name + ".ByFieldType" + suffix; |
| 351 | |
| 352 DVLOG(2) << "Predicted: " << AutofillType(predicted_type).ToString() << "; " | |
| 353 << "Actual: " << AutofillType(actual_type).ToString(); | |
| 354 | |
| 355 // If the predicted and actual types match then it's either a true positive | |
| 356 // or a true negative (if they are both unknown). Do not log type specific | |
| 357 // true negatives (instead log a true positive for the "Ambiguous" type). | |
| 358 if (predicted_type == actual_type) { | |
| 359 if (actual_type == UNKNOWN_TYPE) { | |
| 360 // Only log aggregate true negative; do not log type specific metrics | |
| 361 // for UNKNOWN/EMPTY. | |
| 362 DVLOG(2) << "TRUE NEGATIVE"; | |
| 363 auto empty_or_unknown = is_empty ? AutofillMetrics::TRUE_NEGATIVE_EMPTY | |
| 364 : AutofillMetrics::TRUE_NEGATIVE_UNKNOWN; | |
| 365 LogUMAHistogramEnumeration( | |
| 366 aggregate_histogram, empty_or_unknown, | |
| 367 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); | |
| 368 return empty_or_unknown; | |
| 369 } | |
| 370 | |
| 371 DVLOG(2) << "TRUE POSITIVE"; | |
| 372 // Log both aggregate and type specific true positive if we correctly | |
| 373 // predict that type with which the field was filled. | |
| 374 LogUMAHistogramEnumeration(aggregate_histogram, | |
| 375 AutofillMetrics::TRUE_POSITIVE, | |
| 376 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); | |
| 377 LogUMAHistogramEnumeration( | |
| 378 type_specific_histogram, | |
| 379 GetFieldTypeGroupMetric(actual_type, AutofillMetrics::TRUE_POSITIVE), | |
| 380 KMaxFieldTypeGroupMetric); | |
| 381 return AutofillMetrics::TRUE_POSITIVE; | |
| 294 } | 382 } |
| 295 LogUMAHistogramEnumeration(base_name + suffix, metric, | 383 |
| 384 // Note: At this point predicted_type != actual type | |
| 385 // If actual type is UNKNOWN_TYPE then the prediction is a false positive. | |
| 386 // Further specialize the type of false positive by whether the field was | |
| 387 // empty or contained an unknown value. | |
| 388 if (actual_type == UNKNOWN_TYPE) { | |
| 389 DVLOG(2) << "FALSE POSITIVE"; | |
| 390 auto empty_or_unknown = is_empty ? AutofillMetrics::FALSE_POSITIVE_EMPTY | |
| 391 : AutofillMetrics::FALSE_POSITIVE_UNKNOWN; | |
| 392 LogUMAHistogramEnumeration(aggregate_histogram, empty_or_unknown, | |
| 393 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); | |
| 394 LogUMAHistogramEnumeration( | |
| 395 type_specific_histogram, | |
| 396 GetFieldTypeGroupMetric(predicted_type, empty_or_unknown), | |
| 397 KMaxFieldTypeGroupMetric); | |
| 398 return empty_or_unknown; | |
| 399 } | |
| 400 | |
| 401 // Note: At this point predicted_type != actual type, actual_type != UNKNOWN. | |
| 402 // If predicted type is UNKNOWN_TYPE then the prediction is a false negative | |
| 403 // unknown. | |
| 404 if (predicted_type == UNKNOWN_TYPE) { | |
| 405 DVLOG(2) << "FALSE NEGATIVE"; | |
| 406 LogUMAHistogramEnumeration(aggregate_histogram, | |
| 407 AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, | |
| 408 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); | |
| 409 LogUMAHistogramEnumeration( | |
| 410 type_specific_histogram, | |
| 411 GetFieldTypeGroupMetric(actual_type, | |
| 412 AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), | |
| 413 KMaxFieldTypeGroupMetric); | |
| 414 return AutofillMetrics::FALSE_NEGATIVE_UNKNOWN; | |
| 415 } | |
| 416 | |
| 417 DVLOG(2) << "MISMATCH"; | |
| 418 | |
| 419 // Note: At this point predicted_type != actual type, actual_type != UNKNOWN, | |
| 420 // predicted_type != UNKNOWN. | |
| 421 // This is a mismatch. From the reference of the actual type, this is a false | |
| 422 // negative (it was T, but predicted U). From the reference of the prediction, | |
| 423 // this is a false positive (predicted it was T, but it was U). | |
| 424 LogUMAHistogramEnumeration(aggregate_histogram, | |
| 425 AutofillMetrics::FALSE_NEGATIVE_MISMATCH, | |
| 296 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); | 426 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); |
| 427 LogUMAHistogramEnumeration( | |
|
Mathieu
2017/05/29 14:00:19
Is it weird two log the same histograms for both r
Roger McFarlane (Chromium)
2017/05/30 21:43:22
It's impossible to do some analyses if you don't (
| |
| 428 type_specific_histogram, | |
| 429 GetFieldTypeGroupMetric(actual_type, | |
| 430 AutofillMetrics::FALSE_NEGATIVE_MISMATCH), | |
| 431 KMaxFieldTypeGroupMetric); | |
| 432 LogUMAHistogramEnumeration( | |
| 433 type_specific_histogram, | |
| 434 GetFieldTypeGroupMetric(predicted_type, | |
| 435 AutofillMetrics::FALSE_POSITIVE_MISMATCH), | |
| 436 KMaxFieldTypeGroupMetric); | |
| 297 | 437 |
| 298 int field_type_group_metric = GetFieldTypeGroupMetric(field_type, metric); | 438 // Return the aggregate finding. |
| 299 int num_field_type_group_metrics = | 439 return AutofillMetrics::FALSE_NEGATIVE_MISMATCH; |
| 300 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS * | |
| 301 NUM_FIELD_TYPE_GROUPS_FOR_METRICS; | |
| 302 LogUMAHistogramEnumeration(base_name + ".ByFieldType" + suffix, | |
| 303 field_type_group_metric, | |
| 304 num_field_type_group_metrics); | |
| 305 } | 440 } |
| 306 | 441 |
| 307 } // namespace | 442 } // namespace |
| 308 | 443 |
| 309 // static | 444 // static |
| 310 void AutofillMetrics::LogCardUploadDecisionMetrics( | 445 void AutofillMetrics::LogCardUploadDecisionMetrics( |
| 311 int upload_decision_metrics) { | 446 int upload_decision_metrics) { |
| 312 DCHECK(upload_decision_metrics); | 447 DCHECK(upload_decision_metrics); |
| 313 DCHECK_LT(upload_decision_metrics, 1 << kNumCardUploadDecisionMetrics); | 448 DCHECK_LT(upload_decision_metrics, 1 << kNumCardUploadDecisionMetrics); |
| 314 | 449 |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 495 // static | 630 // static |
| 496 void AutofillMetrics::LogDeveloperEngagementMetric( | 631 void AutofillMetrics::LogDeveloperEngagementMetric( |
| 497 DeveloperEngagementMetric metric) { | 632 DeveloperEngagementMetric metric) { |
| 498 DCHECK_LT(metric, NUM_DEVELOPER_ENGAGEMENT_METRICS); | 633 DCHECK_LT(metric, NUM_DEVELOPER_ENGAGEMENT_METRICS); |
| 499 UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric, | 634 UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric, |
| 500 NUM_DEVELOPER_ENGAGEMENT_METRICS); | 635 NUM_DEVELOPER_ENGAGEMENT_METRICS); |
| 501 } | 636 } |
| 502 | 637 |
| 503 // static | 638 // static |
| 504 void AutofillMetrics::LogHeuristicTypePrediction( | 639 void AutofillMetrics::LogHeuristicTypePrediction( |
| 505 FieldTypeQualityMetric metric, | 640 ServerFieldTypeSet possible_types, |
| 506 ServerFieldType field_type, | 641 ServerFieldType predicted_type, |
| 507 QualityMetricType metric_type) { | 642 QualityMetricType metric_type) { |
| 508 LogTypeQualityMetric("Autofill.Quality.HeuristicType", metric, field_type, | 643 LogTypeQualityMetric("Autofill.Quality.HeuristicType", possible_types, |
| 509 metric_type); | 644 predicted_type, metric_type); |
| 510 } | 645 } |
| 511 | 646 |
| 512 // static | 647 // static |
| 513 void AutofillMetrics::LogOverallTypePrediction(FieldTypeQualityMetric metric, | 648 void AutofillMetrics::LogOverallTypePrediction( |
| 514 ServerFieldType field_type, | 649 ServerFieldTypeSet possible_types, |
| 515 QualityMetricType metric_type) { | 650 ServerFieldType predicted_type, |
| 516 LogTypeQualityMetric("Autofill.Quality.PredictedType", metric, field_type, | 651 QualityMetricType metric_type) { |
| 517 metric_type); | 652 LogTypeQualityMetric("Autofill.Quality.PredictedType", possible_types, |
| 653 predicted_type, metric_type); | |
| 518 } | 654 } |
| 519 | 655 |
| 520 // static | 656 // static |
| 521 void AutofillMetrics::LogServerTypePrediction(FieldTypeQualityMetric metric, | 657 void AutofillMetrics::LogServerTypePrediction(ServerFieldTypeSet possible_types, |
| 522 ServerFieldType field_type, | 658 ServerFieldType predicted_type, |
| 523 QualityMetricType metric_type) { | 659 QualityMetricType metric_type) { |
| 524 LogTypeQualityMetric("Autofill.Quality.ServerType", metric, field_type, | 660 LogTypeQualityMetric("Autofill.Quality.ServerType", possible_types, |
| 525 metric_type); | 661 predicted_type, metric_type); |
| 526 } | 662 } |
| 527 | 663 |
| 528 // static | 664 // static |
| 529 void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) { | 665 void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) { |
| 530 DCHECK_LT(metric, NUM_SERVER_QUERY_METRICS); | 666 DCHECK_LT(metric, NUM_SERVER_QUERY_METRICS); |
| 531 UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric, | 667 UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric, |
| 532 NUM_SERVER_QUERY_METRICS); | 668 NUM_SERVER_QUERY_METRICS); |
| 533 } | 669 } |
| 534 | 670 |
| 535 // static | 671 // static |
| (...skipping 637 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1173 DCHECK(!form_parsed_timestamp_.is_null()); | 1309 DCHECK(!form_parsed_timestamp_.is_null()); |
| 1174 return (base::TimeTicks::Now() - form_parsed_timestamp_).InMilliseconds(); | 1310 return (base::TimeTicks::Now() - form_parsed_timestamp_).InMilliseconds(); |
| 1175 } | 1311 } |
| 1176 | 1312 |
| 1177 void AutofillMetrics::FormInteractionsUkmLogger::GetNewSourceID() { | 1313 void AutofillMetrics::FormInteractionsUkmLogger::GetNewSourceID() { |
| 1178 source_id_ = ukm_recorder_->GetNewSourceID(); | 1314 source_id_ = ukm_recorder_->GetNewSourceID(); |
| 1179 ukm_recorder_->UpdateSourceURL(source_id_, url_); | 1315 ukm_recorder_->UpdateSourceURL(source_id_, url_); |
| 1180 } | 1316 } |
| 1181 | 1317 |
| 1182 } // namespace autofill | 1318 } // namespace autofill |
| OLD | NEW |