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
20 using base::ListValue;
21 using base::FundamentalValue;
22
23 namespace password_manager {
24
25 namespace metrics_util {
26
27 namespace {
28
29 // The number of domain groups.
30 const 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.
38 struct DomainGroupsPair {
39 const char* const domain_name;
40 const size_t group_ids[kGroupsPerDomain];
41 };
42 const 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 };
54 const 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.
GetGroupIndex(size_t domain_index,PrefService * pref_service)59 size_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
MonitoredDomainGroupId(const std::string & url_host,PrefService * pref_service)78 size_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
LogUMAHistogramEnumeration(const std::string & name,int sample,int boundary_value)88 void 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
LogUMAHistogramBoolean(const std::string & name,bool sample)104 void 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
GroupIdToString(size_t group_id)113 std::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
LogUIDismissalReason(ResponseType type)120 void 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
LogUIDismissalReason(UIDismissalReason reason)142 void LogUIDismissalReason(UIDismissalReason reason) {
143 UMA_HISTOGRAM_ENUMERATION("PasswordManager.UIDismissalReason",
144 reason,
145 NUM_UI_RESPONSES);
146 }
147
LogUIDisplayDisposition(UIDisplayDisposition disposition)148 void 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