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 152 // Interpolate the |metric| with the |group|, so that all metrics for a given 153 // |group| are adjacent. 154 return (group * num_possible_metrics) + metric; 155 } 156 157 std::string WalletApiMetricToString( 158 AutofillMetrics::WalletApiCallMetric metric) { 159 switch (metric) { 160 case AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS: 161 return "AcceptLegalDocuments"; 162 case AutofillMetrics::AUTHENTICATE_INSTRUMENT: 163 return "AuthenticateInstrument"; 164 case AutofillMetrics::GET_FULL_WALLET: 165 return "GetFullWallet"; 166 case AutofillMetrics::GET_WALLET_ITEMS: 167 return "GetWalletItems"; 168 case AutofillMetrics::SAVE_TO_WALLET: 169 return "SaveToWallet"; 170 case AutofillMetrics::UNKNOWN_API_CALL: 171 case AutofillMetrics::NUM_WALLET_API_CALLS: 172 NOTREACHED(); 173 return "UnknownApiCall"; 174 } 175 176 NOTREACHED(); 177 return "UnknownApiCall"; 178 } 179 180 // A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name| 181 // to vary over the program's runtime. 182 void LogUMAHistogramEnumeration(const std::string& name, 183 int sample, 184 int boundary_value) { 185 DCHECK_LT(sample, boundary_value); 186 187 // Note: This leaks memory, which is expected behavior. 188 base::HistogramBase* histogram = 189 base::LinearHistogram::FactoryGet( 190 name, 191 1, 192 boundary_value, 193 boundary_value + 1, 194 base::HistogramBase::kUmaTargetedHistogramFlag); 195 histogram->Add(sample); 196 } 197 198 // A version of the UMA_HISTOGRAM_TIMES macro that allows the |name| 199 // to vary over the program's runtime. 200 void LogUMAHistogramTimes(const std::string& name, 201 const base::TimeDelta& duration) { 202 // Note: This leaks memory, which is expected behavior. 203 base::HistogramBase* histogram = 204 base::Histogram::FactoryTimeGet( 205 name, 206 base::TimeDelta::FromMilliseconds(1), 207 base::TimeDelta::FromSeconds(10), 208 50, 209 base::HistogramBase::kUmaTargetedHistogramFlag); 210 histogram->AddTime(duration); 211 } 212 213 // A version of the UMA_HISTOGRAM_LONG_TIMES macro that allows the |name| 214 // to vary over the program's runtime. 215 void LogUMAHistogramLongTimes(const std::string& name, 216 const base::TimeDelta& duration) { 217 // Note: This leaks memory, which is expected behavior. 218 base::HistogramBase* histogram = 219 base::Histogram::FactoryTimeGet( 220 name, 221 base::TimeDelta::FromMilliseconds(1), 222 base::TimeDelta::FromHours(1), 223 50, 224 base::HistogramBase::kUmaTargetedHistogramFlag); 225 histogram->AddTime(duration); 226 } 227 228 // Logs a type quality metric. The primary histogram name is constructed based 229 // on |base_name|. The field-specific histogram name also factors in the 230 // |field_type|. Logs a sample of |metric|, which should be in the range 231 // [0, |num_possible_metrics|). 232 void LogTypeQualityMetric(const std::string& base_name, 233 const int metric, 234 const int num_possible_metrics, 235 const ServerFieldType field_type) { 236 DCHECK_LT(metric, num_possible_metrics); 237 238 std::string histogram_name = base_name; 239 LogUMAHistogramEnumeration(histogram_name, metric, num_possible_metrics); 240 241 std::string sub_histogram_name = base_name + ".ByFieldType"; 242 const int field_type_group_metric = 243 GetFieldTypeGroupMetric(field_type, metric, num_possible_metrics); 244 const int num_field_type_group_metrics = 245 num_possible_metrics * NUM_FIELD_TYPE_GROUPS_FOR_METRICS; 246 LogUMAHistogramEnumeration(sub_histogram_name, 247 field_type_group_metric, 248 num_field_type_group_metrics); 249 } 250 251 } // namespace 252 253 AutofillMetrics::AutofillMetrics() { 254 } 255 256 AutofillMetrics::~AutofillMetrics() { 257 } 258 259 void AutofillMetrics::LogCreditCardInfoBarMetric(InfoBarMetric metric) const { 260 DCHECK_LT(metric, NUM_INFO_BAR_METRICS); 261 262 UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric, 263 NUM_INFO_BAR_METRICS); 264 } 265 266 void AutofillMetrics::LogDialogDismissalState( 267 DialogDismissalState state) const { 268 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.DismissalState", 269 state, NUM_DIALOG_DISMISSAL_STATES); 270 } 271 272 void AutofillMetrics::LogDialogInitialUserState( 273 DialogInitialUserStateMetric user_type) const { 274 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.InitialUserState", 275 user_type, NUM_DIALOG_INITIAL_USER_STATE_METRICS); 276 } 277 278 void AutofillMetrics::LogDialogLatencyToShow( 279 const base::TimeDelta& duration) const { 280 LogUMAHistogramTimes("RequestAutocomplete.UiLatencyToShow", duration); 281 } 282 283 void AutofillMetrics::LogDialogPopupEvent(DialogPopupEvent event) const { 284 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.PopupInDialog", 285 event, NUM_DIALOG_POPUP_EVENTS); 286 } 287 288 void AutofillMetrics::LogDialogSecurityMetric( 289 DialogSecurityMetric metric) const { 290 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.Security", 291 metric, NUM_DIALOG_SECURITY_METRICS); 292 } 293 294 void AutofillMetrics::LogDialogUiDuration( 295 const base::TimeDelta& duration, 296 DialogDismissalAction dismissal_action) const { 297 std::string suffix; 298 switch (dismissal_action) { 299 case DIALOG_ACCEPTED: 300 suffix = "Submit"; 301 break; 302 303 case DIALOG_CANCELED: 304 suffix = "Cancel"; 305 break; 306 } 307 308 LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration", duration); 309 LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration." + suffix, 310 duration); 311 } 312 313 void AutofillMetrics::LogDialogUiEvent(DialogUiEvent event) const { 314 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.UiEvents", event, 315 NUM_DIALOG_UI_EVENTS); 316 } 317 318 void AutofillMetrics::LogWalletErrorMetric(WalletErrorMetric metric) const { 319 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletErrors", metric, 320 NUM_WALLET_ERROR_METRICS); 321 } 322 323 void AutofillMetrics::LogWalletApiCallDuration( 324 WalletApiCallMetric metric, 325 const base::TimeDelta& duration) const { 326 LogUMAHistogramTimes("Wallet.ApiCallDuration." + 327 WalletApiMetricToString(metric), duration); 328 } 329 330 void AutofillMetrics::LogWalletMalformedResponseMetric( 331 WalletApiCallMetric metric) const { 332 UMA_HISTOGRAM_ENUMERATION("Wallet.MalformedResponse", metric, 333 NUM_WALLET_API_CALLS); 334 } 335 336 void AutofillMetrics::LogWalletRequiredActionMetric( 337 WalletRequiredActionMetric required_action) const { 338 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletRequiredActions", 339 required_action, NUM_WALLET_REQUIRED_ACTIONS); 340 } 341 342 void AutofillMetrics::LogWalletResponseCode(int response_code) const { 343 UMA_HISTOGRAM_SPARSE_SLOWLY("Wallet.ResponseCode", response_code); 344 } 345 346 void AutofillMetrics::LogDeveloperEngagementMetric( 347 DeveloperEngagementMetric metric) const { 348 DCHECK_LT(metric, NUM_DEVELOPER_ENGAGEMENT_METRICS); 349 350 UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric, 351 NUM_DEVELOPER_ENGAGEMENT_METRICS); 352 } 353 354 void AutofillMetrics::LogHeuristicTypePrediction( 355 FieldTypeQualityMetric metric, 356 ServerFieldType field_type) const { 357 LogTypeQualityMetric("Autofill.Quality.HeuristicType", 358 metric, NUM_FIELD_TYPE_QUALITY_METRICS, field_type); 359 } 360 361 void AutofillMetrics::LogOverallTypePrediction( 362 FieldTypeQualityMetric metric, 363 ServerFieldType field_type) const { 364 LogTypeQualityMetric("Autofill.Quality.PredictedType", 365 metric, NUM_FIELD_TYPE_QUALITY_METRICS, field_type); 366 } 367 368 void AutofillMetrics::LogServerTypePrediction( 369 FieldTypeQualityMetric metric, 370 ServerFieldType field_type) const { 371 LogTypeQualityMetric("Autofill.Quality.ServerType", 372 metric, NUM_FIELD_TYPE_QUALITY_METRICS, field_type); 373 } 374 375 void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) const { 376 DCHECK_LT(metric, NUM_SERVER_QUERY_METRICS); 377 378 UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric, 379 NUM_SERVER_QUERY_METRICS); 380 } 381 382 void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) const { 383 DCHECK_LT(metric, NUM_USER_HAPPINESS_METRICS); 384 385 UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric, 386 NUM_USER_HAPPINESS_METRICS); 387 } 388 389 void AutofillMetrics::LogFormFillDurationFromLoadWithAutofill( 390 const base::TimeDelta& duration) const { 391 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithAutofill", 392 duration, 393 base::TimeDelta::FromMilliseconds(100), 394 base::TimeDelta::FromMinutes(10), 395 50); 396 } 397 398 void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill( 399 const base::TimeDelta& duration) const { 400 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithoutAutofill", 401 duration, 402 base::TimeDelta::FromMilliseconds(100), 403 base::TimeDelta::FromMinutes(10), 404 50); 405 } 406 407 void AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill( 408 const base::TimeDelta& duration) const { 409 UMA_HISTOGRAM_CUSTOM_TIMES( 410 "Autofill.FillDuration.FromInteraction.WithAutofill", 411 duration, 412 base::TimeDelta::FromMilliseconds(100), 413 base::TimeDelta::FromMinutes(10), 414 50); 415 } 416 417 void AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill( 418 const base::TimeDelta& duration) const { 419 UMA_HISTOGRAM_CUSTOM_TIMES( 420 "Autofill.FillDuration.FromInteraction.WithoutAutofill", 421 duration, 422 base::TimeDelta::FromMilliseconds(100), 423 base::TimeDelta::FromMinutes(10), 424 50); 425 } 426 427 void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const { 428 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled); 429 } 430 431 void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const { 432 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled); 433 } 434 435 void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const { 436 UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles); 437 } 438 439 void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const { 440 UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions); 441 } 442 443 } // namespace autofill 444