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.
GetFieldTypeGroupMetric(const ServerFieldType field_type,const int metric,const int num_possible_metrics)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
WalletApiMetricToString(AutofillMetrics::WalletApiCallMetric metric)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.
LogUMAHistogramEnumeration(const std::string & name,int sample,int boundary_value)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.
LogUMAHistogramTimes(const std::string & name,const base::TimeDelta & duration)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.
LogUMAHistogramLongTimes(const std::string & name,const base::TimeDelta & duration)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|).
LogTypeQualityMetric(const std::string & base_name,const int metric,const int num_possible_metrics,const ServerFieldType field_type)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
AutofillMetrics()253 AutofillMetrics::AutofillMetrics() {
254 }
255
~AutofillMetrics()256 AutofillMetrics::~AutofillMetrics() {
257 }
258
LogCreditCardInfoBarMetric(InfoBarMetric metric) const259 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
LogDialogDismissalState(DialogDismissalState state) const266 void AutofillMetrics::LogDialogDismissalState(
267 DialogDismissalState state) const {
268 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.DismissalState",
269 state, NUM_DIALOG_DISMISSAL_STATES);
270 }
271
LogDialogInitialUserState(DialogInitialUserStateMetric user_type) const272 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
LogDialogLatencyToShow(const base::TimeDelta & duration) const278 void AutofillMetrics::LogDialogLatencyToShow(
279 const base::TimeDelta& duration) const {
280 LogUMAHistogramTimes("RequestAutocomplete.UiLatencyToShow", duration);
281 }
282
LogDialogPopupEvent(DialogPopupEvent event) const283 void AutofillMetrics::LogDialogPopupEvent(DialogPopupEvent event) const {
284 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.PopupInDialog",
285 event, NUM_DIALOG_POPUP_EVENTS);
286 }
287
LogDialogSecurityMetric(DialogSecurityMetric metric) const288 void AutofillMetrics::LogDialogSecurityMetric(
289 DialogSecurityMetric metric) const {
290 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.Security",
291 metric, NUM_DIALOG_SECURITY_METRICS);
292 }
293
LogDialogUiDuration(const base::TimeDelta & duration,DialogDismissalAction dismissal_action) const294 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
LogDialogUiEvent(DialogUiEvent event) const313 void AutofillMetrics::LogDialogUiEvent(DialogUiEvent event) const {
314 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.UiEvents", event,
315 NUM_DIALOG_UI_EVENTS);
316 }
317
LogWalletErrorMetric(WalletErrorMetric metric) const318 void AutofillMetrics::LogWalletErrorMetric(WalletErrorMetric metric) const {
319 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletErrors", metric,
320 NUM_WALLET_ERROR_METRICS);
321 }
322
LogWalletApiCallDuration(WalletApiCallMetric metric,const base::TimeDelta & duration) const323 void AutofillMetrics::LogWalletApiCallDuration(
324 WalletApiCallMetric metric,
325 const base::TimeDelta& duration) const {
326 LogUMAHistogramTimes("Wallet.ApiCallDuration." +
327 WalletApiMetricToString(metric), duration);
328 }
329
LogWalletMalformedResponseMetric(WalletApiCallMetric metric) const330 void AutofillMetrics::LogWalletMalformedResponseMetric(
331 WalletApiCallMetric metric) const {
332 UMA_HISTOGRAM_ENUMERATION("Wallet.MalformedResponse", metric,
333 NUM_WALLET_API_CALLS);
334 }
335
LogWalletRequiredActionMetric(WalletRequiredActionMetric required_action) const336 void AutofillMetrics::LogWalletRequiredActionMetric(
337 WalletRequiredActionMetric required_action) const {
338 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletRequiredActions",
339 required_action, NUM_WALLET_REQUIRED_ACTIONS);
340 }
341
LogWalletResponseCode(int response_code) const342 void AutofillMetrics::LogWalletResponseCode(int response_code) const {
343 UMA_HISTOGRAM_SPARSE_SLOWLY("Wallet.ResponseCode", response_code);
344 }
345
LogDeveloperEngagementMetric(DeveloperEngagementMetric metric) const346 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
LogHeuristicTypePrediction(FieldTypeQualityMetric metric,ServerFieldType field_type) const354 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
LogOverallTypePrediction(FieldTypeQualityMetric metric,ServerFieldType field_type) const361 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
LogServerTypePrediction(FieldTypeQualityMetric metric,ServerFieldType field_type) const368 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
LogServerQueryMetric(ServerQueryMetric metric) const375 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
LogUserHappinessMetric(UserHappinessMetric metric) const382 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
LogFormFillDurationFromLoadWithAutofill(const base::TimeDelta & duration) const389 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
LogFormFillDurationFromLoadWithoutAutofill(const base::TimeDelta & duration) const398 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
LogFormFillDurationFromInteractionWithAutofill(const base::TimeDelta & duration) const407 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
LogFormFillDurationFromInteractionWithoutAutofill(const base::TimeDelta & duration) const417 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
LogIsAutofillEnabledAtStartup(bool enabled) const427 void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const {
428 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled);
429 }
430
LogIsAutofillEnabledAtPageLoad(bool enabled) const431 void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const {
432 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled);
433 }
434
LogStoredProfileCount(size_t num_profiles) const435 void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const {
436 UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles);
437 }
438
LogAddressSuggestionsCount(size_t num_suggestions) const439 void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const {
440 UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions);
441 }
442
443 } // namespace autofill
444