Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / permissions / permission_context_uma_util.cc
blob8a917559ffd9df6604b072a22a3ab4b61a434c2b
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.
5 #include "chrome/browser/permissions/permission_context_uma_util.h"
7 #include "base/metrics/histogram_macros.h"
8 #include "base/strings/stringprintf.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/permissions/permission_manager.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "components/rappor/rappor_service.h"
13 #include "components/rappor/rappor_utils.h"
14 #include "content/public/browser/permission_type.h"
15 #include "content/public/common/origin_util.h"
16 #include "url/gurl.h"
18 // UMA keys need to be statically initialized so plain function would not
19 // work. Use a Macro instead.
20 #define PERMISSION_ACTION_UMA(secure_origin, permission, permission_secure, \
21 permission_insecure, action) \
22 UMA_HISTOGRAM_ENUMERATION(permission, action, PERMISSION_ACTION_NUM); \
23 if (secure_origin) { \
24 UMA_HISTOGRAM_ENUMERATION(permission_secure, action, \
25 PERMISSION_ACTION_NUM); \
26 } else { \
27 UMA_HISTOGRAM_ENUMERATION(permission_insecure, action, \
28 PERMISSION_ACTION_NUM); \
31 using content::PermissionType;
33 namespace {
35 // Enum for UMA purposes, make sure you update histograms.xml if you add new
36 // permission actions. Never delete or reorder an entry; only add new entries
37 // immediately before PERMISSION_NUM
38 enum PermissionAction {
39 GRANTED = 0,
40 DENIED = 1,
41 DISMISSED = 2,
42 IGNORED = 3,
43 REVOKED = 4,
44 REENABLED = 5,
45 REQUESTED = 6,
47 // Always keep this at the end.
48 PERMISSION_ACTION_NUM,
51 // The returned strings must match the RAPPOR metrics in rappor.xml,
52 // e.g. Permissions.Action.Geolocation etc..
53 const std::string GetPermissionString(ContentSettingsType permission) {
54 switch (permission) {
55 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
56 return "Geolocation";
57 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
58 return "Notifications";
59 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
60 return "MidiSysEx";
61 case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
62 return "PushMessaging";
63 case CONTENT_SETTINGS_TYPE_DURABLE_STORAGE:
64 return "DurableStorage";
65 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
66 case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
67 return "ProtectedMediaIdentifier";
68 #endif
69 default:
70 NOTREACHED();
71 return "";
75 // Deprecated. This method is used for the single-dimensional RAPPOR metrics
76 // that are being replaced by the multi-dimensional ones.
77 const std::string GetRapporMetric(ContentSettingsType permission,
78 PermissionAction action) {
79 std::string action_str;
80 switch (action) {
81 case GRANTED:
82 action_str = "Granted";
83 break;
84 case DENIED:
85 action_str = "Denied";
86 break;
87 case DISMISSED:
88 action_str = "Dismissed";
89 break;
90 case IGNORED:
91 action_str = "Ignored";
92 break;
93 default:
94 NOTREACHED();
95 break;
98 std::string permission_str = GetPermissionString(permission);
99 if (permission_str.empty())
100 return "";
101 return base::StringPrintf("ContentSettings.PermissionActions_%s.%s.Url",
102 permission_str.c_str(), action_str.c_str());
105 void RecordPermissionAction(ContentSettingsType permission,
106 PermissionAction action,
107 const GURL& requesting_origin) {
108 bool secure_origin = content::IsOriginSecure(requesting_origin);
110 switch (permission) {
111 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
112 PERMISSION_ACTION_UMA(
113 secure_origin,
114 "ContentSettings.PermissionActions_Geolocation",
115 "ContentSettings.PermissionActionsSecureOrigin_Geolocation",
116 "ContentSettings.PermissionActionsInsecureOrigin_Geolocation",
117 action);
118 break;
119 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
120 PERMISSION_ACTION_UMA(
121 secure_origin,
122 "ContentSettings.PermissionActions_Notifications",
123 "ContentSettings.PermissionActionsSecureOrigin_Notifications",
124 "ContentSettings.PermissionActionsInsecureOrigin_Notifications",
125 action);
126 break;
127 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
128 PERMISSION_ACTION_UMA(
129 secure_origin,
130 "ContentSettings.PermissionActions_MidiSysEx",
131 "ContentSettings.PermissionActionsSecureOrigin_MidiSysEx",
132 "ContentSettings.PermissionActionsInsecureOrigin_MidiSysEx",
133 action);
134 break;
135 case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
136 PERMISSION_ACTION_UMA(
137 secure_origin,
138 "ContentSettings.PermissionActions_PushMessaging",
139 "ContentSettings.PermissionActionsSecureOrigin_PushMessaging",
140 "ContentSettings.PermissionActionsInsecureOrigin_PushMessaging",
141 action);
142 break;
143 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
144 case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
145 PERMISSION_ACTION_UMA(
146 secure_origin,
147 "ContentSettings.PermissionActions_ProtectedMedia",
148 "ContentSettings.PermissionActionsSecureOrigin_ProtectedMedia",
149 "ContentSettings.PermissionActionsInsecureOrigin_ProtectedMedia",
150 action);
151 break;
152 #endif
153 case CONTENT_SETTINGS_TYPE_DURABLE_STORAGE:
154 PERMISSION_ACTION_UMA(
155 secure_origin, "ContentSettings.PermissionActions_DurableStorage",
156 "ContentSettings.PermissionActionsSecureOrigin_DurableStorage",
157 "ContentSettings.PermissionActionsInsecureOrigin_DurableStorage",
158 action);
159 break;
160 default:
161 NOTREACHED() << "PERMISSION " << permission << " not accounted for";
164 // There are two sets of semi-redundant RAPPOR metrics being reported:
165 // The soon-to-be-deprecated single dimensional ones, and the new
166 // multi-dimensional ones.
167 rappor::RapporService* rappor_service = g_browser_process->rappor_service();
168 const std::string rappor_metric = GetRapporMetric(permission, action);
169 if (!rappor_metric.empty())
170 rappor::SampleDomainAndRegistryFromGURL(
171 rappor_service, rappor_metric, requesting_origin);
173 // Add multi-dimensional RAPPOR reporting for safe-browsing users.
174 std::string permission_str = GetPermissionString(permission);
175 if (!rappor_service || permission_str.empty())
176 return;
178 scoped_ptr<rappor::Sample> sample =
179 rappor_service->CreateSample(rappor::SAFEBROWSING_RAPPOR_TYPE);
180 sample->SetStringField("Scheme", requesting_origin.scheme());
181 sample->SetStringField("Host", requesting_origin.host());
182 sample->SetStringField("Port", requesting_origin.port());
183 sample->SetStringField("Domain",
184 rappor::GetDomainAndRegistrySampleFromGURL(requesting_origin));
185 sample->SetFlagsField("Actions",
186 1 << action,
187 PermissionAction::PERMISSION_ACTION_NUM);
188 rappor_service->RecordSampleObj("Permissions.Action." +
189 permission_str, sample.Pass());
192 std::string PermissionTypeToString(PermissionType permission_type) {
193 switch (permission_type) {
194 case PermissionType::MIDI_SYSEX:
195 return "MidiSysex";
196 case PermissionType::PUSH_MESSAGING:
197 return "PushMessaging";
198 case PermissionType::NOTIFICATIONS:
199 return "Notifications";
200 case PermissionType::GEOLOCATION:
201 return "Geolocation";
202 case PermissionType::PROTECTED_MEDIA_IDENTIFIER:
203 return "ProtectedMediaIdentifier";
204 case PermissionType::DURABLE_STORAGE:
205 return "DurableStorage";
206 case PermissionType::MIDI:
207 return "Midi";
208 case PermissionType::AUDIO_CAPTURE:
209 return "AudioRecording";
210 case PermissionType::VIDEO_CAPTURE:
211 return "VideoRecording";
212 case PermissionType::NUM:
213 break;
215 NOTREACHED();
216 return std::string();
219 void RecordPermissionRequest(ContentSettingsType permission,
220 const GURL& requesting_origin,
221 const GURL& embedding_origin,
222 Profile* profile) {
223 bool secure_origin = content::IsOriginSecure(requesting_origin);
224 PermissionType type;
225 switch (permission) {
226 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
227 type = PermissionType::GEOLOCATION;
228 rappor::SampleDomainAndRegistryFromGURL(
229 g_browser_process->rappor_service(),
230 "ContentSettings.PermissionRequested.Geolocation.Url",
231 requesting_origin);
232 break;
233 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
234 type = PermissionType::NOTIFICATIONS;
235 rappor::SampleDomainAndRegistryFromGURL(
236 g_browser_process->rappor_service(),
237 "ContentSettings.PermissionRequested.Notifications.Url",
238 requesting_origin);
239 break;
240 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
241 type = PermissionType::MIDI_SYSEX;
242 break;
243 case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
244 type = PermissionType::PUSH_MESSAGING;
245 break;
246 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
247 case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
248 type = PermissionType::PROTECTED_MEDIA_IDENTIFIER;
249 break;
250 #endif
251 case CONTENT_SETTINGS_TYPE_DURABLE_STORAGE:
252 type = content::PermissionType::DURABLE_STORAGE;
253 break;
254 default:
255 NOTREACHED() << "PERMISSION " << permission << " not accounted for";
256 return;
258 UMA_HISTOGRAM_ENUMERATION(
259 "ContentSettings.PermissionRequested",
260 static_cast<base::HistogramBase::Sample>(type),
261 static_cast<base::HistogramBase::Sample>(PermissionType::NUM));
262 if (secure_origin) {
263 UMA_HISTOGRAM_ENUMERATION(
264 "ContentSettings.PermissionRequested_SecureOrigin",
265 static_cast<base::HistogramBase::Sample>(type),
266 static_cast<base::HistogramBase::Sample>(PermissionType::NUM));
267 } else {
268 UMA_HISTOGRAM_ENUMERATION(
269 "ContentSettings.PermissionRequested_InsecureOrigin",
270 static_cast<base::HistogramBase::Sample>(type),
271 static_cast<base::HistogramBase::Sample>(PermissionType::NUM));
274 // In order to gauge the compatibility risk of implementing an improved
275 // iframe permissions security model, we would like to know the ratio of
276 // same-origin to cross-origin permission requests. Our estimate of this
277 // ratio could be somewhat biased by repeated requests coming from a
278 // single frame, but we expect this to be insignificant.
279 if (requesting_origin.GetOrigin() != embedding_origin.GetOrigin()) {
280 content::PermissionManager* manager = profile->GetPermissionManager();
281 if (!manager)
282 return;
283 content::PermissionStatus embedding_permission_status =
284 manager->GetPermissionStatus(type, embedding_origin, embedding_origin);
286 base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
287 "Permissions.Requested.CrossOrigin_" + PermissionTypeToString(type), 1,
288 content::PERMISSION_STATUS_LAST, content::PERMISSION_STATUS_LAST + 1,
289 base::HistogramBase::kUmaTargetedHistogramFlag);
290 histogram->Add(embedding_permission_status);
291 } else {
292 UMA_HISTOGRAM_ENUMERATION(
293 "Permissions.Requested.SameOrigin",
294 static_cast<base::HistogramBase::Sample>(type),
295 static_cast<base::HistogramBase::Sample>(PermissionType::NUM));
299 } // namespace
301 // Make sure you update histograms.xml permission histogram_suffix if you
302 // add new permission
303 void PermissionContextUmaUtil::PermissionRequested(
304 ContentSettingsType permission,
305 const GURL& requesting_origin,
306 const GURL& embedding_origin,
307 Profile* profile) {
308 RecordPermissionRequest(permission, requesting_origin, embedding_origin,
309 profile);
312 void PermissionContextUmaUtil::PermissionGranted(
313 ContentSettingsType permission, const GURL& requesting_origin) {
314 RecordPermissionAction(permission, GRANTED, requesting_origin);
317 void PermissionContextUmaUtil::PermissionDenied(
318 ContentSettingsType permission, const GURL& requesting_origin) {
319 RecordPermissionAction(permission, DENIED, requesting_origin);
322 void PermissionContextUmaUtil::PermissionDismissed(
323 ContentSettingsType permission, const GURL& requesting_origin) {
324 RecordPermissionAction(permission, DISMISSED, requesting_origin);
327 void PermissionContextUmaUtil::PermissionIgnored(
328 ContentSettingsType permission, const GURL& requesting_origin) {
329 RecordPermissionAction(permission, IGNORED, requesting_origin);