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/push_messaging/push_messaging_service_impl.h"
9 #include "base/barrier_closure.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/command_line.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/prefs/pref_service.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
18 #include "chrome/browser/permissions/permission_manager.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
21 #include "chrome/browser/push_messaging/push_messaging_constants.h"
22 #include "chrome/browser/push_messaging/push_messaging_service_factory.h"
23 #include "chrome/browser/services/gcm/gcm_profile_service.h"
24 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
25 #include "chrome/browser/ui/chrome_pages.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/pref_names.h"
28 #include "chrome/grit/generated_resources.h"
29 #include "components/content_settings/core/browser/host_content_settings_map.h"
30 #include "components/gcm_driver/gcm_driver.h"
31 #include "components/pref_registry/pref_registry_syncable.h"
32 #include "components/rappor/rappor_utils.h"
33 #include "content/public/browser/browser_context.h"
34 #include "content/public/browser/permission_type.h"
35 #include "content/public/browser/render_frame_host.h"
36 #include "content/public/browser/service_worker_context.h"
37 #include "content/public/browser/storage_partition.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/common/child_process_host.h"
40 #include "content/public/common/content_switches.h"
41 #include "content/public/common/push_messaging_status.h"
42 #include "ui/base/l10n/l10n_util.h"
44 #if defined(ENABLE_BACKGROUND)
45 #include "chrome/browser/background/background_mode_manager.h"
49 const int kMaxRegistrations
= 1000000;
51 // Chrome does not yet support silent push messages, and requires websites to
52 // indicate that they will only send user-visible messages.
53 const char kSilentPushUnsupportedMessage
[] =
54 "Chrome currently only supports the Push API for subscriptions that will "
55 "result in user-visible messages. You can indicate this by calling "
56 "pushManager.subscribe({userVisibleOnly: true}) instead. See "
57 "https://goo.gl/yqv4Q4 for more details.";
59 void RecordDeliveryStatus(content::PushDeliveryStatus status
) {
60 UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus",
62 content::PUSH_DELIVERY_STATUS_LAST
+ 1);
65 blink::WebPushPermissionStatus
ToPushPermission(
66 content::PermissionStatus permission_status
) {
67 switch (permission_status
) {
68 case content::PERMISSION_STATUS_GRANTED
:
69 return blink::WebPushPermissionStatusGranted
;
70 case content::PERMISSION_STATUS_DENIED
:
71 return blink::WebPushPermissionStatusDenied
;
72 case content::PERMISSION_STATUS_ASK
:
73 return blink::WebPushPermissionStatusPrompt
;
76 return blink::WebPushPermissionStatusDenied
;
80 void UnregisterCallbackToClosure(
81 const base::Closure
& closure
, content::PushUnregistrationStatus status
) {
85 #if defined(ENABLE_BACKGROUND)
86 bool UseBackgroundMode() {
87 // Note: if push is ever enabled in incognito, the background mode integration
88 // should not be enabled for it.
89 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
90 if (command_line
->HasSwitch(switches::kDisablePushApiBackgroundMode
))
92 return command_line
->HasSwitch(switches::kEnablePushApiBackgroundMode
);
94 #endif // defined(ENABLE_BACKGROUND)
99 void PushMessagingServiceImpl::RegisterProfilePrefs(
100 user_prefs::PrefRegistrySyncable
* registry
) {
101 registry
->RegisterIntegerPref(prefs::kPushMessagingRegistrationCount
, 0);
102 PushMessagingAppIdentifier::RegisterProfilePrefs(registry
);
106 void PushMessagingServiceImpl::InitializeForProfile(Profile
* profile
) {
107 // TODO(johnme): Consider whether push should be enabled in incognito.
108 if (!profile
|| profile
->IsOffTheRecord())
111 // TODO(johnme): If push becomes enabled in incognito (and this still uses a
112 // pref), be careful that this pref is read from the right profile, as prefs
113 // defined in a regular profile are visible in the corresponding incognito
114 // profile unless overridden.
115 // TODO(johnme): Make sure this pref doesn't get out of sync after crashes.
116 int count
= profile
->GetPrefs()->GetInteger(
117 prefs::kPushMessagingRegistrationCount
);
121 PushMessagingServiceImpl
* push_service
=
122 PushMessagingServiceFactory::GetForProfile(profile
);
123 push_service
->IncreasePushSubscriptionCount(count
, false /* is_pending */);
126 PushMessagingServiceImpl::PushMessagingServiceImpl(Profile
* profile
)
128 push_subscription_count_(0),
129 pending_push_subscription_count_(0),
130 #if defined(ENABLE_NOTIFICATIONS)
131 notification_manager_(profile
),
133 weak_factory_(this) {
135 HostContentSettingsMapFactory::GetForProfile(profile_
)->AddObserver(this);
138 PushMessagingServiceImpl::~PushMessagingServiceImpl() {
141 void PushMessagingServiceImpl::IncreasePushSubscriptionCount(int add
,
144 if (push_subscription_count_
+ pending_push_subscription_count_
== 0) {
145 GetGCMDriver()->AddAppHandler(kPushMessagingAppIdentifierPrefix
, this);
148 pending_push_subscription_count_
+= add
;
150 #if defined(ENABLE_BACKGROUND)
151 if (UseBackgroundMode() && g_browser_process
->background_mode_manager() &&
152 !push_subscription_count_
) {
153 g_browser_process
->background_mode_manager()->RegisterTrigger(
154 profile_
, this, false /* should_notify_user */);
156 #endif // defined(ENABLE_BACKGROUND)
157 push_subscription_count_
+= add
;
158 profile_
->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount
,
159 push_subscription_count_
);
163 void PushMessagingServiceImpl::DecreasePushSubscriptionCount(int subtract
,
165 DCHECK(subtract
> 0);
167 pending_push_subscription_count_
-= subtract
;
168 DCHECK(pending_push_subscription_count_
>= 0);
170 push_subscription_count_
-= subtract
;
171 DCHECK(push_subscription_count_
>= 0);
172 profile_
->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount
,
173 push_subscription_count_
);
175 if (push_subscription_count_
+ pending_push_subscription_count_
== 0) {
176 GetGCMDriver()->RemoveAppHandler(kPushMessagingAppIdentifierPrefix
);
178 #if defined(ENABLE_BACKGROUND)
179 if (UseBackgroundMode() && g_browser_process
->background_mode_manager()) {
180 g_browser_process
->background_mode_manager()->UnregisterTrigger(profile_
,
183 #endif // defined(ENABLE_BACKGROUND)
187 bool PushMessagingServiceImpl::CanHandle(const std::string
& app_id
) const {
188 return !PushMessagingAppIdentifier::FindByAppId(profile_
, app_id
).is_null();
191 void PushMessagingServiceImpl::ShutdownHandler() {
192 // Shutdown() should come before and it removes us from the list of app
193 // handlers of gcm::GCMDriver so this shouldn't ever been called.
197 // OnMessage methods -----------------------------------------------------------
199 void PushMessagingServiceImpl::OnMessage(const std::string
& app_id
,
200 const gcm::IncomingMessage
& message
) {
201 in_flight_message_deliveries_
.insert(app_id
);
203 base::Closure message_handled_closure
=
204 message_callback_for_testing_
.is_null() ? base::Bind(&base::DoNothing
)
205 : message_callback_for_testing_
;
206 PushMessagingAppIdentifier app_identifier
=
207 PushMessagingAppIdentifier::FindByAppId(profile_
, app_id
);
208 // Drop message and unregister if app_id was unknown (maybe recently deleted).
209 if (app_identifier
.is_null()) {
210 DeliverMessageCallback(app_id
, GURL::EmptyGURL(), -1, message
,
211 message_handled_closure
,
212 content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID
);
215 // Drop message and unregister if |origin| has lost push permission.
216 if (!IsPermissionSet(app_identifier
.origin())) {
217 DeliverMessageCallback(app_id
, app_identifier
.origin(),
218 app_identifier
.service_worker_registration_id(),
219 message
, message_handled_closure
,
220 content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED
);
224 rappor::SampleDomainAndRegistryFromGURL(
225 g_browser_process
->rappor_service(),
226 "PushMessaging.MessageReceived.Origin",
227 app_identifier
.origin());
229 // The Push API only exposes a single string of data in the push event fired
230 // on the Service Worker. When developers send messages using GCM to the Push
231 // API and want to include a message payload, they must pass a single key-
232 // value pair, where the key is "data" and the value is the string they want
233 // to be passed to their Service Worker. For example, they could send the
234 // following JSON using the HTTPS GCM API:
236 // "registration_ids": ["FOO", "BAR"],
240 // "delay_while_idle": true,
242 // TODO(johnme): Make sure this is clearly documented for developers.
244 // TODO(peter): Message payloads are disabled pending mandatory encryption.
245 // https://crbug.com/449184
246 if (AreMessagePayloadsEnabled()) {
247 gcm::MessageData::const_iterator it
= message
.data
.find("data");
248 if (it
!= message
.data
.end())
252 content::BrowserContext::DeliverPushMessage(
254 app_identifier
.origin(),
255 app_identifier
.service_worker_registration_id(),
257 base::Bind(&PushMessagingServiceImpl::DeliverMessageCallback
,
258 weak_factory_
.GetWeakPtr(),
259 app_identifier
.app_id(), app_identifier
.origin(),
260 app_identifier
.service_worker_registration_id(), message
,
261 message_handled_closure
));
264 void PushMessagingServiceImpl::DeliverMessageCallback(
265 const std::string
& app_id
,
266 const GURL
& requesting_origin
,
267 int64 service_worker_registration_id
,
268 const gcm::IncomingMessage
& message
,
269 const base::Closure
& message_handled_closure
,
270 content::PushDeliveryStatus status
) {
271 // Remove a single in-flight delivery for |app_id|. This has to be done using
272 // an iterator rather than by value, as the latter removes all entries.
273 DCHECK(in_flight_message_deliveries_
.find(app_id
) !=
274 in_flight_message_deliveries_
.end());
276 in_flight_message_deliveries_
.erase(
277 in_flight_message_deliveries_
.find(app_id
));
279 // TODO(mvanouwerkerk): Show a warning in the developer console of the
280 // Service Worker corresponding to app_id (and/or on an internals page).
281 // See https://crbug.com/508516 for options.
283 // Call EnforceUserVisibleOnlyRequirements if the message was delivered to
284 // the Service Worker JavaScript, even if the website's event handler failed
285 // (to prevent sites deliberately failing in order to avoid having to show
287 case content::PUSH_DELIVERY_STATUS_SUCCESS
:
288 case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED
:
289 #if defined(ENABLE_NOTIFICATIONS)
290 // Only enforce the user visible requirements after the entire queue of
291 // incoming messages for |app_id| has been flushed.
292 if (!in_flight_message_deliveries_
.count(app_id
)) {
293 notification_manager_
.EnforceUserVisibleOnlyRequirements(
294 requesting_origin
, service_worker_registration_id
,
295 message_handled_closure
);
297 message_handled_closure
.Run();
300 message_handled_closure
.Run();
303 case content::PUSH_DELIVERY_STATUS_INVALID_MESSAGE
:
304 case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR
:
305 message_handled_closure
.Run();
307 case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID
:
308 case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED
:
309 case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER
:
311 app_id
, message
.sender_id
,
312 base::Bind(&UnregisterCallbackToClosure
, message_handled_closure
));
316 RecordDeliveryStatus(status
);
319 void PushMessagingServiceImpl::SetMessageCallbackForTesting(
320 const base::Closure
& callback
) {
321 message_callback_for_testing_
= callback
;
324 // Other gcm::GCMAppHandler methods -------------------------------------------
326 void PushMessagingServiceImpl::OnMessagesDeleted(const std::string
& app_id
) {
327 // TODO(mvanouwerkerk): Fire push error event on the Service Worker
328 // corresponding to app_id.
331 void PushMessagingServiceImpl::OnSendError(
332 const std::string
& app_id
,
333 const gcm::GCMClient::SendErrorDetails
& send_error_details
) {
334 NOTREACHED() << "The Push API shouldn't have sent messages upstream";
337 void PushMessagingServiceImpl::OnSendAcknowledged(
338 const std::string
& app_id
,
339 const std::string
& message_id
) {
340 NOTREACHED() << "The Push API shouldn't have sent messages upstream";
343 // GetPushEndpoint method ------------------------------------------------------
345 GURL
PushMessagingServiceImpl::GetPushEndpoint() {
346 return GURL(std::string(kPushMessagingEndpoint
));
349 // Subscribe and GetPermissionStatus methods -----------------------------------
351 void PushMessagingServiceImpl::SubscribeFromDocument(
352 const GURL
& requesting_origin
,
353 int64 service_worker_registration_id
,
354 const std::string
& sender_id
,
358 const content::PushMessagingService::RegisterCallback
& callback
) {
359 PushMessagingAppIdentifier app_identifier
=
360 PushMessagingAppIdentifier::Generate(requesting_origin
,
361 service_worker_registration_id
);
363 if (push_subscription_count_
+ pending_push_subscription_count_
>=
365 SubscribeEndWithError(callback
,
366 content::PUSH_REGISTRATION_STATUS_LIMIT_REACHED
);
370 content::RenderFrameHost
* render_frame_host
=
371 content::RenderFrameHost::FromID(renderer_id
, render_frame_id
);
372 content::WebContents
* web_contents
=
373 content::WebContents::FromRenderFrameHost(render_frame_host
);
378 web_contents
->GetMainFrame()->AddMessageToConsole(
379 content::CONSOLE_MESSAGE_LEVEL_ERROR
,
380 kSilentPushUnsupportedMessage
);
382 SubscribeEndWithError(callback
,
383 content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED
);
387 // Push does not allow permission requests from iframes.
390 profile_
->GetPermissionManager()->RequestPermission(
391 content::PermissionType::PUSH_MESSAGING
, web_contents
->GetMainFrame(),
392 request_id
, requesting_origin
, true /* user_gesture */,
393 base::Bind(&PushMessagingServiceImpl::DidRequestPermission
,
394 weak_factory_
.GetWeakPtr(), app_identifier
, sender_id
,
398 void PushMessagingServiceImpl::SubscribeFromWorker(
399 const GURL
& requesting_origin
,
400 int64 service_worker_registration_id
,
401 const std::string
& sender_id
,
403 const content::PushMessagingService::RegisterCallback
& register_callback
) {
404 PushMessagingAppIdentifier app_identifier
=
405 PushMessagingAppIdentifier::Generate(requesting_origin
,
406 service_worker_registration_id
);
408 if (profile_
->GetPrefs()->GetInteger(
409 prefs::kPushMessagingRegistrationCount
) >= kMaxRegistrations
) {
410 SubscribeEndWithError(register_callback
,
411 content::PUSH_REGISTRATION_STATUS_LIMIT_REACHED
);
415 GURL embedding_origin
= requesting_origin
;
416 blink::WebPushPermissionStatus permission_status
=
417 PushMessagingServiceImpl::GetPermissionStatus(requesting_origin
,
420 if (permission_status
!= blink::WebPushPermissionStatusGranted
) {
421 SubscribeEndWithError(register_callback
,
422 content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED
);
426 IncreasePushSubscriptionCount(1, true /* is_pending */);
427 std::vector
<std::string
> sender_ids(1, sender_id
);
428 GetGCMDriver()->Register(app_identifier
.app_id(), sender_ids
,
429 base::Bind(&PushMessagingServiceImpl::DidSubscribe
,
430 weak_factory_
.GetWeakPtr(),
431 app_identifier
, register_callback
));
434 blink::WebPushPermissionStatus
PushMessagingServiceImpl::GetPermissionStatus(
435 const GURL
& requesting_origin
,
436 const GURL
& embedding_origin
,
439 return blink::WebPushPermissionStatusDenied
;
441 return ToPushPermission(profile_
->GetPermissionManager()->GetPermissionStatus(
442 content::PermissionType::PUSH_MESSAGING
, requesting_origin
,
446 bool PushMessagingServiceImpl::SupportNonVisibleMessages() {
450 void PushMessagingServiceImpl::SubscribeEnd(
451 const content::PushMessagingService::RegisterCallback
& callback
,
452 const std::string
& subscription_id
,
453 const std::vector
<uint8_t>& curve25519dh
,
454 content::PushRegistrationStatus status
) {
455 callback
.Run(subscription_id
, curve25519dh
, status
);
458 void PushMessagingServiceImpl::SubscribeEndWithError(
459 const content::PushMessagingService::RegisterCallback
& callback
,
460 content::PushRegistrationStatus status
) {
461 SubscribeEnd(callback
, std::string() /* subscription_id */,
462 std::vector
<uint8_t>() /* curve25519dh */, status
);
465 void PushMessagingServiceImpl::DidSubscribe(
466 const PushMessagingAppIdentifier
& app_identifier
,
467 const content::PushMessagingService::RegisterCallback
& callback
,
468 const std::string
& subscription_id
,
469 gcm::GCMClient::Result result
) {
470 DecreasePushSubscriptionCount(1, true /* was_pending */);
472 content::PushRegistrationStatus status
=
473 content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR
;
476 case gcm::GCMClient::SUCCESS
:
477 // Do not get a certificate if message payloads have not been enabled.
478 if (!AreMessagePayloadsEnabled()) {
479 DidSubscribeWithPublicKey(
480 app_identifier
, callback
, subscription_id
,
481 std::string() /* public_key */);
485 // Make sure that this subscription has associated encryption keys prior
486 // to returning it to the developer - they'll need this information in
487 // order to send payloads to the user.
488 GetGCMDriver()->GetPublicKey(
489 app_identifier
.app_id(),
491 &PushMessagingServiceImpl::DidSubscribeWithPublicKey
,
492 weak_factory_
.GetWeakPtr(), app_identifier
, callback
,
496 case gcm::GCMClient::INVALID_PARAMETER
:
497 case gcm::GCMClient::GCM_DISABLED
:
498 case gcm::GCMClient::ASYNC_OPERATION_PENDING
:
499 case gcm::GCMClient::SERVER_ERROR
:
500 case gcm::GCMClient::UNKNOWN_ERROR
:
501 status
= content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR
;
503 case gcm::GCMClient::NETWORK_ERROR
:
504 case gcm::GCMClient::TTL_EXCEEDED
:
505 status
= content::PUSH_REGISTRATION_STATUS_NETWORK_ERROR
;
509 SubscribeEndWithError(callback
, status
);
512 void PushMessagingServiceImpl::DidSubscribeWithPublicKey(
513 const PushMessagingAppIdentifier
& app_identifier
,
514 const content::PushMessagingService::RegisterCallback
& callback
,
515 const std::string
& subscription_id
,
516 const std::string
& public_key
) {
517 if (!public_key
.size() && AreMessagePayloadsEnabled()) {
518 SubscribeEndWithError(
519 callback
, content::PUSH_REGISTRATION_STATUS_PUBLIC_KEY_UNAVAILABLE
);
523 app_identifier
.PersistToPrefs(profile_
);
525 IncreasePushSubscriptionCount(1, false /* is_pending */);
527 SubscribeEnd(callback
, subscription_id
,
528 std::vector
<uint8_t>(public_key
.begin(), public_key
.end()),
529 content::PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE
);
532 void PushMessagingServiceImpl::DidRequestPermission(
533 const PushMessagingAppIdentifier
& app_identifier
,
534 const std::string
& sender_id
,
535 const content::PushMessagingService::RegisterCallback
& register_callback
,
536 content::PermissionStatus permission_status
) {
537 if (permission_status
!= content::PERMISSION_STATUS_GRANTED
) {
538 SubscribeEndWithError(register_callback
,
539 content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED
);
543 IncreasePushSubscriptionCount(1, true /* is_pending */);
544 std::vector
<std::string
> sender_ids(1, sender_id
);
545 GetGCMDriver()->Register(app_identifier
.app_id(), sender_ids
,
546 base::Bind(&PushMessagingServiceImpl::DidSubscribe
,
547 weak_factory_
.GetWeakPtr(),
548 app_identifier
, register_callback
));
551 // GetPublicEncryptionKey methods ----------------------------------------------
553 void PushMessagingServiceImpl::GetPublicEncryptionKey(
555 int64_t service_worker_registration_id
,
556 const PushMessagingService::PublicKeyCallback
& callback
) {
557 // An empty public key will be returned if payloads are not enabled.
558 if (!AreMessagePayloadsEnabled()) {
559 callback
.Run(true /* success */, std::vector
<uint8_t>());
563 PushMessagingAppIdentifier app_identifier
=
564 PushMessagingAppIdentifier::FindByServiceWorker(
565 profile_
, origin
, service_worker_registration_id
);
567 DCHECK(!app_identifier
.is_null());
569 GetGCMDriver()->GetPublicKey(
570 app_identifier
.app_id(),
571 base::Bind(&PushMessagingServiceImpl::DidGetPublicKey
,
572 weak_factory_
.GetWeakPtr(), callback
));
575 void PushMessagingServiceImpl::DidGetPublicKey(
576 const PushMessagingService::PublicKeyCallback
& callback
,
577 const std::string
& public_key
) const {
578 // I/O errors might prevent the GCM Driver from retrieving a key-pair.
579 const bool success
= !!public_key
.size();
581 callback
.Run(success
, std::vector
<uint8_t>(public_key
.begin(),
585 // Unsubscribe methods ---------------------------------------------------------
587 void PushMessagingServiceImpl::Unsubscribe(
588 const GURL
& requesting_origin
,
589 int64 service_worker_registration_id
,
590 const std::string
& sender_id
,
591 const content::PushMessagingService::UnregisterCallback
& callback
) {
592 PushMessagingAppIdentifier app_identifier
=
593 PushMessagingAppIdentifier::FindByServiceWorker(
594 profile_
, requesting_origin
, service_worker_registration_id
);
595 if (app_identifier
.is_null()) {
596 if (!callback
.is_null()) {
598 content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED
);
603 Unsubscribe(app_identifier
.app_id(), sender_id
, callback
);
606 void PushMessagingServiceImpl::Unsubscribe(
607 const std::string
& app_id
,
608 const std::string
& sender_id
,
609 const content::PushMessagingService::UnregisterCallback
& callback
) {
610 // Delete the mapping for this app_id, to guarantee that no messages get
611 // delivered in future (even if unregistration fails).
612 // TODO(johnme): Instead of deleting these app ids, store them elsewhere, and
613 // retry unregistration if it fails due to network errors (crbug.com/465399).
614 PushMessagingAppIdentifier app_identifier
=
615 PushMessagingAppIdentifier::FindByAppId(profile_
, app_id
);
616 bool was_registered
= !app_identifier
.is_null();
618 app_identifier
.DeleteFromPrefs(profile_
);
620 const auto& unregister_callback
=
621 base::Bind(&PushMessagingServiceImpl::DidUnsubscribe
,
622 weak_factory_
.GetWeakPtr(), was_registered
, callback
);
623 #if defined(OS_ANDROID)
624 // On Android the backend is different, and requires the original sender_id.
625 // UnsubscribeBecausePermissionRevoked sometimes calls us with an empty one.
626 if (sender_id
.empty())
627 unregister_callback
.Run(gcm::GCMClient::INVALID_PARAMETER
);
629 GetGCMDriver()->UnregisterWithSenderId(app_id
, sender_id
,
630 unregister_callback
);
632 GetGCMDriver()->Unregister(app_id
, unregister_callback
);
636 void PushMessagingServiceImpl::DidUnsubscribe(
638 const content::PushMessagingService::UnregisterCallback
& callback
,
639 gcm::GCMClient::Result result
) {
641 DecreasePushSubscriptionCount(1, false /* was_pending */);
643 // Internal calls pass a null callback.
644 if (callback
.is_null())
647 if (!was_subscribed
) {
649 content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED
);
653 case gcm::GCMClient::SUCCESS
:
654 callback
.Run(content::PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED
);
656 case gcm::GCMClient::INVALID_PARAMETER
:
657 case gcm::GCMClient::GCM_DISABLED
:
658 case gcm::GCMClient::SERVER_ERROR
:
659 case gcm::GCMClient::UNKNOWN_ERROR
:
660 callback
.Run(content::PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR
);
662 case gcm::GCMClient::ASYNC_OPERATION_PENDING
:
663 case gcm::GCMClient::NETWORK_ERROR
:
664 case gcm::GCMClient::TTL_EXCEEDED
:
665 callback
.Run(content::PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR
);
670 // OnContentSettingChanged methods ---------------------------------------------
672 void PushMessagingServiceImpl::OnContentSettingChanged(
673 const ContentSettingsPattern
& primary_pattern
,
674 const ContentSettingsPattern
& secondary_pattern
,
675 ContentSettingsType content_type
,
676 std::string resource_identifier
) {
677 if (content_type
!= CONTENT_SETTINGS_TYPE_PUSH_MESSAGING
&&
678 content_type
!= CONTENT_SETTINGS_TYPE_NOTIFICATIONS
) {
682 std::vector
<PushMessagingAppIdentifier
> all_app_identifiers
=
683 PushMessagingAppIdentifier::GetAll(profile_
);
685 base::Closure barrier_closure
= base::BarrierClosure(
686 all_app_identifiers
.size(),
687 content_setting_changed_callback_for_testing_
.is_null()
688 ? base::Bind(&base::DoNothing
)
689 : content_setting_changed_callback_for_testing_
);
691 for (const PushMessagingAppIdentifier
& app_identifier
: all_app_identifiers
) {
692 // If |primary_pattern| is not valid, we should always check for a
693 // permission change because it can happen for example when the entire
694 // Push or Notifications permissions are cleared.
695 // Otherwise, the permission should be checked if the pattern matches the
697 if (primary_pattern
.IsValid() &&
698 !primary_pattern
.Matches(app_identifier
.origin())) {
699 barrier_closure
.Run();
703 if (IsPermissionSet(app_identifier
.origin())) {
704 barrier_closure
.Run();
709 profile_
, app_identifier
.origin(),
710 app_identifier
.service_worker_registration_id(),
712 &PushMessagingServiceImpl::UnsubscribeBecausePermissionRevoked
,
713 weak_factory_
.GetWeakPtr(), app_identifier
, barrier_closure
));
717 void PushMessagingServiceImpl::UnsubscribeBecausePermissionRevoked(
718 const PushMessagingAppIdentifier
& app_identifier
,
719 const base::Closure
& closure
,
720 const std::string
& sender_id
,
723 base::Closure barrier_closure
= base::BarrierClosure(2, closure
);
725 // Unsubscribe the PushMessagingAppIdentifier with the push service.
726 // It's possible for GetSenderId to have failed and sender_id to be empty, if
727 // cookies (and the SW database) for an origin got cleared before permissions
728 // are cleared for the origin. In that case Unsubscribe will just delete the
729 // app identifier to block future messages.
730 // TODO(johnme): Auto-unregister before SW DB is cleared
731 // (https://crbug.com/402458).
732 Unsubscribe(app_identifier
.app_id(), sender_id
,
733 base::Bind(&UnregisterCallbackToClosure
, barrier_closure
));
735 // Clear the associated service worker push registration id.
736 ClearPushSubscriptionID(profile_
, app_identifier
.origin(),
737 app_identifier
.service_worker_registration_id(),
741 void PushMessagingServiceImpl::SetContentSettingChangedCallbackForTesting(
742 const base::Closure
& callback
) {
743 content_setting_changed_callback_for_testing_
= callback
;
746 // KeyedService methods -------------------------------------------------------
748 void PushMessagingServiceImpl::Shutdown() {
749 GetGCMDriver()->RemoveAppHandler(kPushMessagingAppIdentifierPrefix
);
752 // BackgroundTrigger methods ---------------------------------------------------
753 base::string16
PushMessagingServiceImpl::GetName() {
754 return l10n_util::GetStringUTF16(IDS_NOTIFICATIONS_BACKGROUND_SERVICE_NAME
);
757 gfx::ImageSkia
* PushMessagingServiceImpl::GetIcon() {
761 void PushMessagingServiceImpl::OnMenuClick() {
762 #if defined(ENABLE_BACKGROUND)
763 chrome::ShowContentSettings(
764 BackgroundModeManager::GetBrowserWindowForProfile(profile_
),
765 CONTENT_SETTINGS_TYPE_NOTIFICATIONS
);
766 #endif // defined(ENABLE_BACKGROUND)
769 // Helper methods --------------------------------------------------------------
771 // Assumes user_visible always since this is just meant to check
772 // if the permission was previously granted and not revoked.
773 bool PushMessagingServiceImpl::IsPermissionSet(const GURL
& origin
) {
774 return GetPermissionStatus(origin
, origin
, true /* user_visible */) ==
775 blink::WebPushPermissionStatusGranted
;
778 bool PushMessagingServiceImpl::AreMessagePayloadsEnabled() const {
779 return base::CommandLine::ForCurrentProcess()->HasSwitch(
780 switches::kEnablePushMessagePayload
);
783 gcm::GCMDriver
* PushMessagingServiceImpl::GetGCMDriver() const {
784 gcm::GCMProfileService
* gcm_profile_service
=
785 gcm::GCMProfileServiceFactory::GetForProfile(profile_
);
786 CHECK(gcm_profile_service
);
787 CHECK(gcm_profile_service
->driver());
788 return gcm_profile_service
->driver();