Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(105)

Side by Side Diff: chrome/browser/services/gcm/push_messaging_service_impl.cc

Issue 926583002: Push API: UMA logs of whether SWs show notifications when required (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@ifdef_brackets
Patch Set: Comment tweaks Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/services/gcm/push_messaging_service_impl.h" 5 #include "chrome/browser/services/gcm/push_messaging_service_impl.h"
6 6
7 #include <bitset> 7 #include <bitset>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/logging.h"
13 #include "base/metrics/histogram.h"
12 #include "base/prefs/pref_service.h" 14 #include "base/prefs/pref_service.h"
13 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h" 16 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/browser/browser_process.h" 17 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/notifications/notification_ui_manager.h" 18 #include "chrome/browser/notifications/notification_ui_manager.h"
17 #include "chrome/browser/notifications/platform_notification_service_impl.h" 19 #include "chrome/browser/notifications/platform_notification_service_impl.h"
18 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/services/gcm/gcm_profile_service.h" 21 #include "chrome/browser/services/gcm/gcm_profile_service.h"
20 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h" 22 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
21 #include "chrome/browser/services/gcm/push_messaging_application_id.h" 23 #include "chrome/browser/services/gcm/push_messaging_application_id.h"
22 #include "chrome/browser/services/gcm/push_messaging_constants.h" 24 #include "chrome/browser/services/gcm/push_messaging_constants.h"
23 #include "chrome/browser/services/gcm/push_messaging_permission_context.h" 25 #include "chrome/browser/services/gcm/push_messaging_permission_context.h"
24 #include "chrome/browser/services/gcm/push_messaging_permission_context_factory. h" 26 #include "chrome/browser/services/gcm/push_messaging_permission_context_factory. h"
25 #include "chrome/common/chrome_switches.h" 27 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/pref_names.h" 28 #include "chrome/common/pref_names.h"
27 #include "chrome/grit/generated_resources.h" 29 #include "chrome/grit/generated_resources.h"
28 #include "components/content_settings/core/common/permission_request_id.h" 30 #include "components/content_settings/core/common/permission_request_id.h"
29 #include "components/gcm_driver/gcm_driver.h" 31 #include "components/gcm_driver/gcm_driver.h"
30 #include "components/pref_registry/pref_registry_syncable.h" 32 #include "components/pref_registry/pref_registry_syncable.h"
31 #include "content/public/browser/browser_context.h" 33 #include "content/public/browser/browser_context.h"
32 #include "content/public/browser/render_frame_host.h" 34 #include "content/public/browser/render_frame_host.h"
33 #include "content/public/browser/service_worker_context.h" 35 #include "content/public/browser/service_worker_context.h"
34 #include "content/public/browser/storage_partition.h" 36 #include "content/public/browser/storage_partition.h"
35 #include "content/public/browser/web_contents.h" 37 #include "content/public/browser/web_contents.h"
36 #include "content/public/common/child_process_host.h" 38 #include "content/public/common/child_process_host.h"
37 #include "content/public/common/content_switches.h" 39 #include "content/public/common/content_switches.h"
38 #include "content/public/common/platform_notification_data.h" 40 #include "content/public/common/platform_notification_data.h"
41 #include "content/public/common/push_messaging_status.h"
39 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 42 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
40 #include "third_party/skia/include/core/SkBitmap.h" 43 #include "third_party/skia/include/core/SkBitmap.h"
41 #include "ui/base/l10n/l10n_util.h" 44 #include "ui/base/l10n/l10n_util.h"
42 45
43 #if defined(OS_ANDROID) 46 #if defined(OS_ANDROID)
44 #include "chrome/browser/ui/android/tab_model/tab_model.h" 47 #include "chrome/browser/ui/android/tab_model/tab_model.h"
45 #include "chrome/browser/ui/android/tab_model/tab_model_list.h" 48 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
46 #else 49 #else
47 #include "chrome/browser/ui/browser.h" 50 #include "chrome/browser/ui/browser.h"
48 #include "chrome/browser/ui/browser_iterator.h" 51 #include "chrome/browser/ui/browser_iterator.h"
49 #include "chrome/browser/ui/tabs/tab_strip_model.h" 52 #include "chrome/browser/ui/tabs/tab_strip_model.h"
50 #endif 53 #endif
51 54
52 namespace gcm { 55 namespace gcm {
53 56
54 namespace { 57 namespace {
55 const int kMaxRegistrations = 1000000; 58 const int kMaxRegistrations = 1000000;
56 59
60 void RecordUserVisibleStatus(content::PushUserVisibleStatus status) {
61 UMA_HISTOGRAM_ENUMERATION("PushMessaging.UserVisibleStatus",
62 status,
63 content::PUSH_USER_VISIBLE_STATUS_LAST + 1);
64 }
65
57 blink::WebPushPermissionStatus ToPushPermission(ContentSetting setting) { 66 blink::WebPushPermissionStatus ToPushPermission(ContentSetting setting) {
58 switch (setting) { 67 switch (setting) {
59 case CONTENT_SETTING_ALLOW: 68 case CONTENT_SETTING_ALLOW:
60 return blink::WebPushPermissionStatusGranted; 69 return blink::WebPushPermissionStatusGranted;
61 case CONTENT_SETTING_BLOCK: 70 case CONTENT_SETTING_BLOCK:
62 return blink::WebPushPermissionStatusDenied; 71 return blink::WebPushPermissionStatusDenied;
63 case CONTENT_SETTING_ASK: 72 case CONTENT_SETTING_ASK:
64 return blink::WebPushPermissionStatusDefault; 73 return blink::WebPushPermissionStatusDefault;
65 default: 74 default:
66 NOTREACHED(); 75 NOTREACHED();
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 // is supported. 274 // is supported.
266 int notification_count = notification_service->GetNotificationUIManager()-> 275 int notification_count = notification_service->GetNotificationUIManager()->
267 GetAllIdsByProfileAndSourceOrigin(profile_, application_id.origin).size(); 276 GetAllIdsByProfileAndSourceOrigin(profile_, application_id.origin).size();
268 // TODO(johnme): Hiding an existing notification should also count as a useful 277 // TODO(johnme): Hiding an existing notification should also count as a useful
269 // user-visible action done in response to a push message - but make sure that 278 // user-visible action done in response to a push message - but make sure that
270 // sending two messages in rapid succession which show then hide a 279 // sending two messages in rapid succession which show then hide a
271 // notification doesn't count. 280 // notification doesn't count.
272 bool notification_shown = notification_count > 0; 281 bool notification_shown = notification_count > 0;
273 282
274 bool notification_needed = true; 283 bool notification_needed = true;
275 if (!notification_shown) { 284 // Sites with a currently visible tab don't need to show notifications.
276 // Sites with a currently visible tab don't need to show notifications.
277 #if defined(OS_ANDROID) 285 #if defined(OS_ANDROID)
278 for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) { 286 for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) {
279 Profile* profile = (*it)->GetProfile(); 287 Profile* profile = (*it)->GetProfile();
280 content::WebContents* active_web_contents = 288 content::WebContents* active_web_contents =
281 (*it)->GetActiveWebContents(); 289 (*it)->GetActiveWebContents();
282 #else 290 #else
283 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 291 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
284 Profile* profile = it->profile(); 292 Profile* profile = it->profile();
285 content::WebContents* active_web_contents = 293 content::WebContents* active_web_contents =
286 it->tab_strip_model()->GetActiveWebContents(); 294 it->tab_strip_model()->GetActiveWebContents();
287 #endif 295 #endif
288 if (!active_web_contents) 296 if (!active_web_contents)
289 continue; 297 continue;
290 298
291 // Don't leak information from other profiles. 299 // Don't leak information from other profiles.
292 if (profile != profile_) 300 if (profile != profile_)
293 continue; 301 continue;
294 302
295 // Ignore minimized windows etc. 303 // Ignore minimized windows etc.
296 switch (active_web_contents->GetMainFrame()->GetVisibilityState()) { 304 switch (active_web_contents->GetMainFrame()->GetVisibilityState()) {
297 case blink::WebPageVisibilityStateHidden: 305 case blink::WebPageVisibilityStateHidden:
298 case blink::WebPageVisibilityStatePrerender: 306 case blink::WebPageVisibilityStatePrerender:
299 continue; 307 continue;
300 case blink::WebPageVisibilityStateVisible: 308 case blink::WebPageVisibilityStateVisible:
301 break; 309 break;
302 } 310 }
303 311
304 // Use the visible URL since that's the one the user is aware of (and it 312 // Use the visible URL since that's the one the user is aware of (and it
305 // doesn't matter whether the page loaded successfully). 313 // doesn't matter whether the page loaded successfully).
306 const GURL& active_url = active_web_contents->GetVisibleURL(); 314 const GURL& active_url = active_web_contents->GetVisibleURL();
307 315
308 // Allow https://foo.example.com Service Worker to not show notification 316 // Allow https://foo.example.com Service Worker to not show notification
309 // if an https://bar.example.com tab is visible (and hence might 317 // if an https://bar.example.com tab is visible (and hence might
310 // conceivably be showing UI in response to the push message); but http:// 318 // conceivably be showing UI in response to the push message); but http://
311 // doesn't count as the Service Worker can't talk to it, even with 319 // doesn't count as the Service Worker can't talk to it, even with
312 // navigator.connect. 320 // navigator.connect.
313 if (application_id.origin.scheme() != active_url.scheme()) 321 if (application_id.origin.scheme() != active_url.scheme())
314 continue; 322 continue;
315 if (net::registry_controlled_domains::SameDomainOrHost( 323 if (net::registry_controlled_domains::SameDomainOrHost(
316 application_id.origin, active_url, 324 application_id.origin, active_url,
317 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) { 325 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
318 notification_needed = false; 326 notification_needed = false;
319 break; 327 break;
320 } 328 }
321 #if defined(OS_ANDROID) 329 #if defined(OS_ANDROID)
322 } 330 }
323 #else 331 #else
324 } 332 }
325 #endif 333 #endif
326 }
327 334
328 // Don't track push messages that didn't show a notification but were exempt 335 // Don't track push messages that didn't show a notification but were exempt
329 // from needing to do so. 336 // from needing to do so.
330 if (notification_shown || notification_needed) { 337 if (notification_shown || notification_needed) {
331 content::ServiceWorkerContext* service_worker_context = 338 content::ServiceWorkerContext* service_worker_context =
332 content::BrowserContext::GetStoragePartitionForSite( 339 content::BrowserContext::GetStoragePartitionForSite(
333 profile_, application_id.origin)->GetServiceWorkerContext(); 340 profile_, application_id.origin)->GetServiceWorkerContext();
334 341
335 PushMessagingService::GetNotificationsShownByLastFewPushes( 342 PushMessagingService::GetNotificationsShownByLastFewPushes(
336 service_worker_context, application_id.service_worker_registration_id, 343 service_worker_context, application_id.service_worker_registration_id,
337 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown, 344 base::Bind(&PushMessagingServiceImpl::DidGetNotificationsShown,
338 weak_factory_.GetWeakPtr(), 345 weak_factory_.GetWeakPtr(),
339 application_id, notification_shown, notification_needed)); 346 application_id, notification_shown, notification_needed));
347 } else {
348 RecordUserVisibleStatus(
349 content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN);
340 } 350 }
341 #endif // defined(ENABLE_NOTIFICATIONS) 351 #endif // defined(ENABLE_NOTIFICATIONS)
342 } 352 }
343 353
344 static void IgnoreResult(bool unused) { 354 static void IgnoreResult(bool unused) {
345 } 355 }
346 356
347 void PushMessagingServiceImpl::DidGetNotificationsShown( 357 void PushMessagingServiceImpl::DidGetNotificationsShown(
348 const PushMessagingApplicationId& application_id, 358 const PushMessagingApplicationId& application_id,
349 bool notification_shown, bool notification_needed, 359 bool notification_shown, bool notification_needed,
(...skipping 14 matching lines...) Expand all
364 // the history length is exceeded. 374 // the history length is exceeded.
365 missed_notifications <<= 1; 375 missed_notifications <<= 1;
366 missed_notifications[0] = needed_but_not_shown; 376 missed_notifications[0] = needed_but_not_shown;
367 std::string updated_data(missed_notifications. 377 std::string updated_data(missed_notifications.
368 to_string<char, std::string::traits_type, std::string::allocator_type>()); 378 to_string<char, std::string::traits_type, std::string::allocator_type>());
369 PushMessagingService::SetNotificationsShownByLastFewPushes( 379 PushMessagingService::SetNotificationsShownByLastFewPushes(
370 service_worker_context, application_id.service_worker_registration_id, 380 service_worker_context, application_id.service_worker_registration_id,
371 application_id.origin, updated_data, 381 application_id.origin, updated_data,
372 base::Bind(&IgnoreResult)); // This is a heuristic; ignore failure. 382 base::Bind(&IgnoreResult)); // This is a heuristic; ignore failure.
373 383
374 if (needed_but_not_shown && missed_notifications.count() >= 2) { 384 if (notification_shown) {
385 RecordUserVisibleStatus(
386 notification_needed
387 ? content::PUSH_USER_VISIBLE_STATUS_REQUIRED_AND_SHOWN
388 : content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_BUT_SHOWN);
389 return;
390 }
391 if (needed_but_not_shown) {
392 if (missed_notifications.count() <= 1) {
393 RecordUserVisibleStatus(
394 content::PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_USED_GRACE);
395 return;
396 }
397 RecordUserVisibleStatus(
398 content::
399 PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED);
375 // The site failed to show a notification when one was needed, and they have 400 // The site failed to show a notification when one was needed, and they have
376 // already failed once in the previous 10 push messages, so we will show a 401 // already failed once in the previous 10 push messages, so we will show a
377 // generic notification. See https://crbug.com/437277. 402 // generic notification. See https://crbug.com/437277.
378 // TODO(johnme): The generic notification should probably automatically 403 // TODO(johnme): The generic notification should probably automatically
379 // close itself when the next push message arrives? 404 // close itself when the next push message arrives?
380 content::PlatformNotificationData notification_data; 405 content::PlatformNotificationData notification_data;
381 // TODO(johnme): Switch to FormatOriginForDisplay from crbug.com/402698 406 // TODO(johnme): Switch to FormatOriginForDisplay from crbug.com/402698
382 notification_data.title = l10n_util::GetStringFUTF16( 407 notification_data.title = l10n_util::GetStringFUTF16(
383 IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_TITLE, 408 IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_TITLE,
384 base::UTF8ToUTF16(application_id.origin.host())); 409 base::UTF8ToUTF16(application_id.origin.host()));
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 bool PushMessagingServiceImpl::HasPermission(const GURL& origin) { 664 bool PushMessagingServiceImpl::HasPermission(const GURL& origin) {
640 gcm::PushMessagingPermissionContext* permission_context = 665 gcm::PushMessagingPermissionContext* permission_context =
641 gcm::PushMessagingPermissionContextFactory::GetForProfile(profile_); 666 gcm::PushMessagingPermissionContextFactory::GetForProfile(profile_);
642 DCHECK(permission_context); 667 DCHECK(permission_context);
643 668
644 return permission_context->GetPermissionStatus(origin, origin) == 669 return permission_context->GetPermissionStatus(origin, origin) ==
645 CONTENT_SETTING_ALLOW; 670 CONTENT_SETTING_ALLOW;
646 } 671 }
647 672
648 } // namespace gcm 673 } // namespace gcm
OLDNEW
« no previous file with comments | « no previous file | content/public/common/push_messaging_status.h » ('j') | content/public/common/push_messaging_status.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698