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
15namespace autofill {
16
17namespace {
18
19enum 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.
62int 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
161std::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.
186void 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.
204void 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.
219void 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|).
236void 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
257AutofillMetrics::AutofillMetrics() {
258}
259
260AutofillMetrics::~AutofillMetrics() {
261}
262
263void 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
270void AutofillMetrics::LogDialogDismissalState(
271    DialogDismissalState state) const {
272  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.DismissalState",
273                            state, NUM_DIALOG_DISMISSAL_STATES);
274}
275
276void AutofillMetrics::LogDialogInitialUserState(
277    DialogInitialUserStateMetric user_type) const {
278  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.InitialUserState",
279                            user_type, NUM_DIALOG_INITIAL_USER_STATE_METRICS);
280}
281
282void AutofillMetrics::LogDialogLatencyToShow(
283    const base::TimeDelta& duration) const {
284  LogUMAHistogramTimes("RequestAutocomplete.UiLatencyToShow", duration);
285}
286
287void AutofillMetrics::LogDialogPopupEvent(DialogPopupEvent event) const {
288  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.PopupInDialog",
289                            event, NUM_DIALOG_POPUP_EVENTS);
290}
291
292void AutofillMetrics::LogDialogSecurityMetric(
293    DialogSecurityMetric metric) const {
294  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.Security",
295                            metric, NUM_DIALOG_SECURITY_METRICS);
296}
297
298void 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
317void AutofillMetrics::LogDialogUiEvent(DialogUiEvent event) const {
318  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.UiEvents", event,
319                            NUM_DIALOG_UI_EVENTS);
320}
321
322void AutofillMetrics::LogWalletErrorMetric(WalletErrorMetric metric) const {
323  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletErrors", metric,
324                            NUM_WALLET_ERROR_METRICS);
325}
326
327void AutofillMetrics::LogWalletApiCallDuration(
328    WalletApiCallMetric metric,
329    const base::TimeDelta& duration) const {
330  LogUMAHistogramTimes("Wallet.ApiCallDuration." +
331                       WalletApiMetricToString(metric), duration);
332}
333
334void AutofillMetrics::LogWalletMalformedResponseMetric(
335    WalletApiCallMetric metric) const {
336  UMA_HISTOGRAM_ENUMERATION("Wallet.MalformedResponse", metric,
337                            NUM_WALLET_API_CALLS);
338}
339
340void AutofillMetrics::LogWalletRequiredActionMetric(
341      WalletRequiredActionMetric required_action) const {
342  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletRequiredActions",
343                            required_action, NUM_WALLET_REQUIRED_ACTIONS);
344}
345
346void AutofillMetrics::LogWalletResponseCode(int response_code) const {
347  UMA_HISTOGRAM_SPARSE_SLOWLY("Wallet.ResponseCode", response_code);
348}
349
350void 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
358void 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
365void 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
372void 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
379void 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
386void 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
393void 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
402void 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
411void 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
421void 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
431void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const {
432  UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled);
433}
434
435void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const {
436  UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled);
437}
438
439void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const {
440  UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles);
441}
442
443void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const {
444  UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions);
445}
446
447}  // namespace autofill
448