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