1// Copyright 2014 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/password_manager/core/browser/password_manager_metrics_util.h"
6
7#include "base/basictypes.h"
8#include "base/metrics/histogram.h"
9#include "base/numerics/safe_conversions.h"
10#include "base/prefs/pref_service.h"
11#include "base/prefs/scoped_user_pref_update.h"
12#include "base/rand_util.h"
13#include "base/strings/string_number_conversions.h"
14#include "base/strings/string_util.h"
15#include "base/time/time.h"
16#include "base/values.h"
17#include "components/password_manager/core/common/password_manager_pref_names.h"
18#include "url/gurl.h"
19
20using base::ListValue;
21using base::FundamentalValue;
22
23namespace password_manager {
24
25namespace metrics_util {
26
27namespace {
28
29// The number of domain groups.
30const size_t kNumGroups = 2u * kGroupsPerDomain;
31
32// |kDomainMapping| contains each monitored website together with all ids of
33// groups which contain the website. Each website appears in
34// |kGroupsPerDomain| groups, and each group includes an equal number of
35// websites, so that no two websites have the same set of groups that they
36// belong to. All ids are in the range [1, |kNumGroups|].
37// For more information about the algorithm used see http://goo.gl/vUuFd5.
38struct DomainGroupsPair {
39  const char* const domain_name;
40  const size_t group_ids[kGroupsPerDomain];
41};
42const DomainGroupsPair kDomainMapping[] = {
43    {"google.com", {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
44    {"yahoo.com", {1, 2, 3, 4, 5, 11, 12, 13, 14, 15}},
45    {"baidu.com", {1, 2, 3, 4, 6, 7, 11, 12, 16, 17}},
46    {"wikipedia.org", {1, 2, 3, 4, 5, 6, 11, 12, 16, 18}},
47    {"linkedin.com", {1, 6, 8, 11, 13, 14, 15, 16, 17, 19}},
48    {"twitter.com", {5, 6, 7, 8, 9, 11, 13, 17, 19, 20}},
49    {"facebook.com", {7, 8, 9, 10, 13, 14, 16, 17, 18, 20}},
50    {"amazon.com", {2, 5, 9, 10, 12, 14, 15, 18, 19, 20}},
51    {"ebay.com", {3, 7, 9, 10, 14, 15, 17, 18, 19, 20}},
52    {"tumblr.com", {4, 8, 10, 12, 13, 15, 16, 18, 19, 20}},
53};
54const size_t kNumDomains = arraysize(kDomainMapping);
55
56// For every monitored domain, this function chooses which of the groups
57// containing that domain should be used for reporting. That number is chosen
58// randomly and stored in the user's preferences.
59size_t GetGroupIndex(size_t domain_index, PrefService* pref_service) {
60  DCHECK_LT(domain_index, kNumDomains);
61
62  const base::ListValue* group_indices =
63      pref_service->GetList(prefs::kPasswordManagerGroupsForDomains);
64  int result = 0;
65  if (!group_indices->GetInteger(domain_index, &result)) {
66    ListPrefUpdate group_indices_updater(
67        pref_service, prefs::kPasswordManagerGroupsForDomains);
68    // This value has not been generated yet.
69    result =
70        base::checked_cast<int>(base::RandGenerator(kGroupsPerDomain));
71    group_indices_updater->Set(domain_index, new FundamentalValue(result));
72  }
73  return base::checked_cast<size_t>(result);
74}
75
76}  // namespace
77
78size_t MonitoredDomainGroupId(const std::string& url_host,
79                              PrefService* pref_service) {
80  GURL url(url_host);
81  for (size_t i = 0; i < kNumDomains; ++i) {
82    if (url.DomainIs(kDomainMapping[i].domain_name))
83      return kDomainMapping[i].group_ids[GetGroupIndex(i, pref_service)];
84  }
85  return 0;
86}
87
88void LogUMAHistogramEnumeration(const std::string& name,
89                                int sample,
90                                int boundary_value) {
91  DCHECK_LT(sample, boundary_value);
92
93  // Note: This leaks memory, which is expected behavior.
94  base::HistogramBase* histogram =
95      base::LinearHistogram::FactoryGet(
96          name,
97          1,
98          boundary_value,
99          boundary_value + 1,
100          base::HistogramBase::kUmaTargetedHistogramFlag);
101  histogram->Add(sample);
102}
103
104void LogUMAHistogramBoolean(const std::string& name, bool sample) {
105  // Note: This leaks memory, which is expected behavior.
106  base::HistogramBase* histogram =
107      base::BooleanHistogram::FactoryGet(
108          name,
109          base::Histogram::kNoFlags);
110          histogram->AddBoolean(sample);
111}
112
113std::string GroupIdToString(size_t group_id) {
114  DCHECK_LE(group_id, kNumGroups);
115  if (group_id > 0)
116    return "group_" + base::IntToString(group_id);
117  return std::string();
118}
119
120void LogUIDismissalReason(ResponseType type) {
121  UIDismissalReason reason = NO_DIRECT_INTERACTION;
122  switch (type) {
123    case NO_RESPONSE:
124      reason = NO_DIRECT_INTERACTION;
125      break;
126    case REMEMBER_PASSWORD:
127      reason = CLICKED_SAVE;
128      break;
129    case NEVER_REMEMBER_PASSWORD:
130      reason = CLICKED_NEVER;
131      break;
132    case INFOBAR_DISMISSED:
133      reason = CLICKED_NOPE;
134      break;
135    case NUM_RESPONSE_TYPES:
136      NOTREACHED();
137      break;
138  }
139  LogUIDismissalReason(reason);
140}
141
142void LogUIDismissalReason(UIDismissalReason reason) {
143  UMA_HISTOGRAM_ENUMERATION("PasswordManager.UIDismissalReason",
144                            reason,
145                            NUM_UI_RESPONSES);
146}
147
148void LogUIDisplayDisposition(UIDisplayDisposition disposition) {
149  UMA_HISTOGRAM_ENUMERATION("PasswordBubble.DisplayDisposition",
150                            disposition,
151                            NUM_DISPLAY_DISPOSITIONS);
152}
153
154}  // namespace metrics_util
155
156}  // namespace password_manager
157