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