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 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
WalletApiMetricToString(AutofillMetrics::WalletApiCallMetric metric)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.
LogUMAHistogramEnumeration(const std::string & name,int sample,int boundary_value)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.
LogUMAHistogramTimes(const std::string & name,const base::TimeDelta & duration)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.
LogUMAHistogramLongTimes(const std::string & name,const base::TimeDelta & duration)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|).
LogTypeQualityMetric(const std::string & base_name,const int metric,const int num_possible_metrics,const ServerFieldType field_type)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
AutofillMetrics()257 AutofillMetrics::AutofillMetrics() {
258 }
259
~AutofillMetrics()260 AutofillMetrics::~AutofillMetrics() {
261 }
262
LogCreditCardInfoBarMetric(InfoBarMetric metric) const263 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
LogDialogDismissalState(DialogDismissalState state) const270 void AutofillMetrics::LogDialogDismissalState(
271 DialogDismissalState state) const {
272 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.DismissalState",
273 state, NUM_DIALOG_DISMISSAL_STATES);
274 }
275
LogDialogInitialUserState(DialogInitialUserStateMetric user_type) const276 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
LogDialogLatencyToShow(const base::TimeDelta & duration) const282 void AutofillMetrics::LogDialogLatencyToShow(
283 const base::TimeDelta& duration) const {
284 LogUMAHistogramTimes("RequestAutocomplete.UiLatencyToShow", duration);
285 }
286
LogDialogPopupEvent(DialogPopupEvent event) const287 void AutofillMetrics::LogDialogPopupEvent(DialogPopupEvent event) const {
288 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.PopupInDialog",
289 event, NUM_DIALOG_POPUP_EVENTS);
290 }
291
LogDialogSecurityMetric(DialogSecurityMetric metric) const292 void AutofillMetrics::LogDialogSecurityMetric(
293 DialogSecurityMetric metric) const {
294 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.Security",
295 metric, NUM_DIALOG_SECURITY_METRICS);
296 }
297
LogDialogUiDuration(const base::TimeDelta & duration,DialogDismissalAction dismissal_action) const298 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
LogDialogUiEvent(DialogUiEvent event) const317 void AutofillMetrics::LogDialogUiEvent(DialogUiEvent event) const {
318 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.UiEvents", event,
319 NUM_DIALOG_UI_EVENTS);
320 }
321
LogWalletErrorMetric(WalletErrorMetric metric) const322 void AutofillMetrics::LogWalletErrorMetric(WalletErrorMetric metric) const {
323 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletErrors", metric,
324 NUM_WALLET_ERROR_METRICS);
325 }
326
LogWalletApiCallDuration(WalletApiCallMetric metric,const base::TimeDelta & duration) const327 void AutofillMetrics::LogWalletApiCallDuration(
328 WalletApiCallMetric metric,
329 const base::TimeDelta& duration) const {
330 LogUMAHistogramTimes("Wallet.ApiCallDuration." +
331 WalletApiMetricToString(metric), duration);
332 }
333
LogWalletMalformedResponseMetric(WalletApiCallMetric metric) const334 void AutofillMetrics::LogWalletMalformedResponseMetric(
335 WalletApiCallMetric metric) const {
336 UMA_HISTOGRAM_ENUMERATION("Wallet.MalformedResponse", metric,
337 NUM_WALLET_API_CALLS);
338 }
339
LogWalletRequiredActionMetric(WalletRequiredActionMetric required_action) const340 void AutofillMetrics::LogWalletRequiredActionMetric(
341 WalletRequiredActionMetric required_action) const {
342 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletRequiredActions",
343 required_action, NUM_WALLET_REQUIRED_ACTIONS);
344 }
345
LogWalletResponseCode(int response_code) const346 void AutofillMetrics::LogWalletResponseCode(int response_code) const {
347 UMA_HISTOGRAM_SPARSE_SLOWLY("Wallet.ResponseCode", response_code);
348 }
349
LogDeveloperEngagementMetric(DeveloperEngagementMetric metric) const350 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
LogHeuristicTypePrediction(FieldTypeQualityMetric metric,ServerFieldType field_type) const358 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
LogOverallTypePrediction(FieldTypeQualityMetric metric,ServerFieldType field_type) const365 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
LogServerTypePrediction(FieldTypeQualityMetric metric,ServerFieldType field_type) const372 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
LogServerQueryMetric(ServerQueryMetric metric) const379 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
LogUserHappinessMetric(UserHappinessMetric metric) const386 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
LogFormFillDurationFromLoadWithAutofill(const base::TimeDelta & duration) const393 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
LogFormFillDurationFromLoadWithoutAutofill(const base::TimeDelta & duration) const402 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
LogFormFillDurationFromInteractionWithAutofill(const base::TimeDelta & duration) const411 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
LogFormFillDurationFromInteractionWithoutAutofill(const base::TimeDelta & duration) const421 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
LogIsAutofillEnabledAtStartup(bool enabled) const431 void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const {
432 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled);
433 }
434
LogIsAutofillEnabledAtPageLoad(bool enabled) const435 void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const {
436 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled);
437 }
438
LogStoredProfileCount(size_t num_profiles) const439 void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const {
440 UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles);
441 }
442
LogAddressSuggestionsCount(size_t num_suggestions) const443 void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const {
444 UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions);
445 }
446
447 } // namespace autofill
448