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/permissions/permission_manager.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
20 #include "chrome/browser/push_messaging/push_messaging_constants.h"
21 #include "chrome/browser/push_messaging/push_messaging_service_factory.h"
22 #include "chrome/browser/services/gcm/gcm_profile_service.h"
23 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/pref_names.h"
26 #include "components/content_settings/core/browser/host_content_settings_map.h"
27 #include "components/gcm_driver/gcm_driver.h"
28 #include "components/pref_registry/pref_registry_syncable.h"
29 #include "components/rappor/rappor_utils.h"
30 #include "content/public/browser/browser_context.h"
31 #include "content/public/browser/permission_type.h"
32 #include "content/public/browser/render_frame_host.h"
33 #include "content/public/browser/service_worker_context.h"
34 #include "content/public/browser/storage_partition.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/common/child_process_host.h"
37 #include "content/public/common/content_switches.h"
38 #include "content/public/common/push_messaging_status.h"
41 const int kMaxRegistrations
= 1000000;
43 // Chrome does not yet support silent push messages, and requires websites to
44 // indicate that they will only send user-visible messages.
45 const char kSilentPushUnsupportedMessage
[] =
46 "Chrome currently only supports the Push API for subscriptions that will "
47 "result in user-visible messages. You can indicate this by calling "
48 "pushManager.subscribe({userVisibleOnly: true}) instead. See "
49 "https://goo.gl/yqv4Q4 for more details.";
51 void RecordDeliveryStatus(content::PushDeliveryStatus status
) {
52 UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus",
54 content::PUSH_DELIVERY_STATUS_LAST
+ 1);
57 blink::WebPushPermissionStatus
ToPushPermission(
58 content::PermissionStatus permission_status
) {
59 switch (permission_status
) {
60 case content::PERMISSION_STATUS_GRANTED
:
61 return blink::WebPushPermissionStatusGranted
;
62 case content::PERMISSION_STATUS_DENIED
:
63 return blink::WebPushPermissionStatusDenied
;
64 case content::PERMISSION_STATUS_ASK
:
65 return blink::WebPushPermissionStatusPrompt
;
68 return blink::WebPushPermissionStatusDenied
;
72 void UnregisterCallbackToClosure(
73 const base::Closure
& closure
, content::PushUnregistrationStatus status
) {
80 void PushMessagingServiceImpl::RegisterProfilePrefs(
81 user_prefs::PrefRegistrySyncable
* registry
) {
82 registry
->RegisterIntegerPref(prefs::kPushMessagingRegistrationCount
, 0);
83 PushMessagingAppIdentifier::RegisterProfilePrefs(registry
);
87 void PushMessagingServiceImpl::InitializeForProfile(Profile
* profile
) {
88 // TODO(johnme): Consider whether push should be enabled in incognito.
89 if (!profile
|| profile
->IsOffTheRecord())
92 // TODO(johnme): If push becomes enabled in incognito (and this still uses a
93 // pref), be careful that this pref is read from the right profile, as prefs
94 // defined in a regular profile are visible in the corresponding incognito
95 // profile unless overridden.
96 // TODO(johnme): Make sure this pref doesn't get out of sync after crashes.
97 int count
= profile
->GetPrefs()->GetInteger(
98 prefs::kPushMessagingRegistrationCount
);
102 PushMessagingServiceImpl
* push_service
=
103 PushMessagingServiceFactory::GetForProfile(profile
);
104 push_service
->IncreasePushSubscriptionCount(count
, false /* is_pending */);
107 PushMessagingServiceImpl::PushMessagingServiceImpl(Profile
* profile
)
109 push_subscription_count_(0),
110 pending_push_subscription_count_(0),
111 #if defined(ENABLE_NOTIFICATIONS)
112 notification_manager_(profile
),
114 weak_factory_(this) {
116 profile_
->GetHostContentSettingsMap()->AddObserver(this);
119 PushMessagingServiceImpl::~PushMessagingServiceImpl() {
120 profile_
->GetHostContentSettingsMap()->RemoveObserver(this);
123 void PushMessagingServiceImpl::IncreasePushSubscriptionCount(int add
,
126 if (push_subscription_count_
+ pending_push_subscription_count_
== 0) {
127 GetGCMDriver()->AddAppHandler(kPushMessagingAppIdentifierPrefix
, this);
130 pending_push_subscription_count_
+= add
;
132 push_subscription_count_
+= add
;
133 profile_
->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount
,
134 push_subscription_count_
);
138 void PushMessagingServiceImpl::DecreasePushSubscriptionCount(int subtract
,
140 DCHECK(subtract
> 0);
142 pending_push_subscription_count_
-= subtract
;
143 DCHECK(pending_push_subscription_count_
>= 0);
145 push_subscription_count_
-= subtract
;
146 DCHECK(push_subscription_count_
>= 0);
147 profile_
->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount
,
148 push_subscription_count_
);
150 if (push_subscription_count_
+ pending_push_subscription_count_
== 0) {
151 GetGCMDriver()->RemoveAppHandler(kPushMessagingAppIdentifierPrefix
);
155 bool PushMessagingServiceImpl::CanHandle(const std::string
& app_id
) const {
156 return !PushMessagingAppIdentifier::FindByAppId(profile_
, app_id
).is_null();
159 void PushMessagingServiceImpl::ShutdownHandler() {
160 // Shutdown() should come before and it removes us from the list of app
161 // handlers of gcm::GCMDriver so this shouldn't ever been called.
165 // OnMessage methods -----------------------------------------------------------
167 void PushMessagingServiceImpl::OnMessage(const std::string
& app_id
,
168 const gcm::IncomingMessage
& message
) {
169 in_flight_message_deliveries_
.insert(app_id
);
171 base::Closure message_handled_closure
=
172 message_callback_for_testing_
.is_null() ? base::Bind(&base::DoNothing
)
173 : message_callback_for_testing_
;
174 PushMessagingAppIdentifier app_identifier
=
175 PushMessagingAppIdentifier::FindByAppId(profile_
, app_id
);
176 // Drop message and unregister if app_id was unknown (maybe recently deleted).
177 if (app_identifier
.is_null()) {
178 DeliverMessageCallback(app_id
, GURL::EmptyGURL(), -1, message
,
179 message_handled_closure
,
180 content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID
);
183 // Drop message and unregister if |origin| has lost push permission.
184 if (!IsPermissionSet(app_identifier
.origin())) {
185 DeliverMessageCallback(app_id
, app_identifier
.origin(),
186 app_identifier
.service_worker_registration_id(),
187 message
, message_handled_closure
,
188 content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED
);
192 rappor::SampleDomainAndRegistryFromGURL(
193 g_browser_process
->rappor_service(),
194 "PushMessaging.MessageReceived.Origin",
195 app_identifier
.origin());
197 // The Push API only exposes a single string of data in the push event fired
198 // on the Service Worker. When developers send messages using GCM to the Push
199 // API and want to include a message payload, they must pass a single key-
200 // value pair, where the key is "data" and the value is the string they want
201 // to be passed to their Service Worker. For example, they could send the
202 // following JSON using the HTTPS GCM API:
204 // "registration_ids": ["FOO", "BAR"],
208 // "delay_while_idle": true,
210 // TODO(johnme): Make sure this is clearly documented for developers.
212 // TODO(peter): Message payloads are disabled pending mandatory encryption.
213 // https://crbug.com/449184
214 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
215 switches::kEnablePushMessagePayload
)) {
216 gcm::MessageData::const_iterator it
= message
.data
.find("data");
217 if (it
!= message
.data
.end())
221 content::BrowserContext::DeliverPushMessage(
223 app_identifier
.origin(),
224 app_identifier
.service_worker_registration_id(),
226 base::Bind(&PushMessagingServiceImpl::DeliverMessageCallback
,
227 weak_factory_
.GetWeakPtr(),
228 app_identifier
.app_id(), app_identifier
.origin(),
229 app_identifier
.service_worker_registration_id(), message
,
230 message_handled_closure
));
233 void PushMessagingServiceImpl::DeliverMessageCallback(
234 const std::string
& app_id
,
235 const GURL
& requesting_origin
,
236 int64 service_worker_registration_id
,
237 const gcm::IncomingMessage
& message
,
238 const base::Closure
& message_handled_closure
,
239 content::PushDeliveryStatus status
) {
240 // Remove a single in-flight delivery for |app_id|. This has to be done using
241 // an iterator rather than by value, as the latter removes all entries.
242 DCHECK(in_flight_message_deliveries_
.find(app_id
) !=
243 in_flight_message_deliveries_
.end());
245 in_flight_message_deliveries_
.erase(
246 in_flight_message_deliveries_
.find(app_id
));
248 // TODO(mvanouwerkerk): Show a warning in the developer console of the
249 // Service Worker corresponding to app_id (and/or on an internals page).
250 // See https://crbug.com/508516 for options.
252 // Call EnforceUserVisibleOnlyRequirements if the message was delivered to
253 // the Service Worker JavaScript, even if the website's event handler failed
254 // (to prevent sites deliberately failing in order to avoid having to show
256 case content::PUSH_DELIVERY_STATUS_SUCCESS
:
257 case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED
:
258 #if defined(ENABLE_NOTIFICATIONS)
259 // Only enforce the user visible requirements after the entire queue of
260 // incoming messages for |app_id| has been flushed.
261 if (!in_flight_message_deliveries_
.count(app_id
)) {
262 notification_manager_
.EnforceUserVisibleOnlyRequirements(
263 requesting_origin
, service_worker_registration_id
,
264 message_handled_closure
);
266 message_handled_closure
.Run();
269 message_handled_closure
.Run();
272 case content::PUSH_DELIVERY_STATUS_INVALID_MESSAGE
:
273 case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR
:
274 message_handled_closure
.Run();
276 case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID
:
277 case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED
:
278 case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER
:
280 app_id
, message
.sender_id
,
281 base::Bind(&UnregisterCallbackToClosure
, message_handled_closure
));
285 RecordDeliveryStatus(status
);
288 void PushMessagingServiceImpl::SetMessageCallbackForTesting(
289 const base::Closure
& callback
) {
290 message_callback_for_testing_
= callback
;
293 // Other gcm::GCMAppHandler methods -------------------------------------------
295 void PushMessagingServiceImpl::OnMessagesDeleted(const std::string
& app_id
) {
296 // TODO(mvanouwerkerk): Fire push error event on the Service Worker
297 // corresponding to app_id.
300 void PushMessagingServiceImpl::OnSendError(
301 const std::string
& app_id
,
302 const gcm::GCMClient::SendErrorDetails
& send_error_details
) {
303 NOTREACHED() << "The Push API shouldn't have sent messages upstream";
306 void PushMessagingServiceImpl::OnSendAcknowledged(
307 const std::string
& app_id
,
308 const std::string
& message_id
) {
309 NOTREACHED() << "The Push API shouldn't have sent messages upstream";
312 // GetPushEndpoint method ------------------------------------------------------
314 GURL
PushMessagingServiceImpl::GetPushEndpoint() {
315 return GURL(std::string(kPushMessagingEndpoint
));
318 // GetPublicEncryptionKey method -----------------------------------------------
320 void PushMessagingServiceImpl::GetPublicEncryptionKey(
322 int64_t service_worker_registration_id
,
323 const PushMessagingService::PublicKeyCallback
& callback
) {
324 // TODO(peter): Get the public key from the GCM Driver. Right now we have to
325 // return success=true here, otherwise subscriptions would fail.
326 callback
.Run(true /* success */, std::vector
<uint8_t>());
329 // Subscribe and GetPermissionStatus methods -----------------------------------
331 void PushMessagingServiceImpl::SubscribeFromDocument(
332 const GURL
& requesting_origin
,
333 int64 service_worker_registration_id
,
334 const std::string
& sender_id
,
338 const content::PushMessagingService::RegisterCallback
& callback
) {
339 PushMessagingAppIdentifier app_identifier
=
340 PushMessagingAppIdentifier::Generate(requesting_origin
,
341 service_worker_registration_id
);
343 if (push_subscription_count_
+ pending_push_subscription_count_
>=
345 SubscribeEndWithError(callback
,
346 content::PUSH_REGISTRATION_STATUS_LIMIT_REACHED
);
350 content::RenderFrameHost
* render_frame_host
=
351 content::RenderFrameHost::FromID(renderer_id
, render_frame_id
);
352 content::WebContents
* web_contents
=
353 content::WebContents::FromRenderFrameHost(render_frame_host
);
358 web_contents
->GetMainFrame()->AddMessageToConsole(
359 content::CONSOLE_MESSAGE_LEVEL_ERROR
,
360 kSilentPushUnsupportedMessage
);
362 SubscribeEndWithError(callback
,
363 content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED
);
367 // Push does not allow permission requests from iframes.
370 profile_
->GetPermissionManager()->RequestPermission(
371 content::PermissionType::PUSH_MESSAGING
, web_contents
->GetMainFrame(),
372 request_id
, requesting_origin
, true /* user_gesture */,
373 base::Bind(&PushMessagingServiceImpl::DidRequestPermission
,
374 weak_factory_
.GetWeakPtr(), app_identifier
, sender_id
,
378 void PushMessagingServiceImpl::SubscribeFromWorker(
379 const GURL
& requesting_origin
,
380 int64 service_worker_registration_id
,
381 const std::string
& sender_id
,
383 const content::PushMessagingService::RegisterCallback
& register_callback
) {
384 PushMessagingAppIdentifier app_identifier
=
385 PushMessagingAppIdentifier::Generate(requesting_origin
,
386 service_worker_registration_id
);
388 if (profile_
->GetPrefs()->GetInteger(
389 prefs::kPushMessagingRegistrationCount
) >= kMaxRegistrations
) {
390 SubscribeEndWithError(register_callback
,
391 content::PUSH_REGISTRATION_STATUS_LIMIT_REACHED
);
395 GURL embedding_origin
= requesting_origin
;
396 blink::WebPushPermissionStatus permission_status
=
397 PushMessagingServiceImpl::GetPermissionStatus(requesting_origin
,
400 if (permission_status
!= blink::WebPushPermissionStatusGranted
) {
401 SubscribeEndWithError(register_callback
,
402 content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED
);
406 IncreasePushSubscriptionCount(1, true /* is_pending */);
407 std::vector
<std::string
> sender_ids(1, sender_id
);
408 GetGCMDriver()->Register(app_identifier
.app_id(), sender_ids
,
409 base::Bind(&PushMessagingServiceImpl::DidSubscribe
,
410 weak_factory_
.GetWeakPtr(),
411 app_identifier
, register_callback
));
414 blink::WebPushPermissionStatus
PushMessagingServiceImpl::GetPermissionStatus(
415 const GURL
& requesting_origin
,
416 const GURL
& embedding_origin
,
419 return blink::WebPushPermissionStatusDenied
;
421 return ToPushPermission(profile_
->GetPermissionManager()->GetPermissionStatus(
422 content::PermissionType::PUSH_MESSAGING
, requesting_origin
,
426 bool PushMessagingServiceImpl::SupportNonVisibleMessages() {
430 void PushMessagingServiceImpl::SubscribeEnd(
431 const content::PushMessagingService::RegisterCallback
& callback
,
432 const std::string
& subscription_id
,
433 const std::vector
<uint8_t>& curve25519dh
,
434 content::PushRegistrationStatus status
) {
435 callback
.Run(subscription_id
, curve25519dh
, status
);
438 void PushMessagingServiceImpl::SubscribeEndWithError(
439 const content::PushMessagingService::RegisterCallback
& callback
,
440 content::PushRegistrationStatus status
) {
441 SubscribeEnd(callback
, std::string() /* subscription_id */,
442 std::vector
<uint8_t>() /* curve25519dh */, status
);
445 void PushMessagingServiceImpl::DidSubscribe(
446 const PushMessagingAppIdentifier
& app_identifier
,
447 const content::PushMessagingService::RegisterCallback
& callback
,
448 const std::string
& subscription_id
,
449 gcm::GCMClient::Result result
) {
450 content::PushRegistrationStatus status
=
451 content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR
;
452 std::vector
<uint8_t> curve25519dh
;
455 case gcm::GCMClient::SUCCESS
:
456 status
= content::PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE
;
457 app_identifier
.PersistToPrefs(profile_
);
459 // TODO(peter): Hook up getting the keys from the GCM Driver.
461 IncreasePushSubscriptionCount(1, false /* is_pending */);
463 case gcm::GCMClient::INVALID_PARAMETER
:
464 case gcm::GCMClient::GCM_DISABLED
:
465 case gcm::GCMClient::ASYNC_OPERATION_PENDING
:
466 case gcm::GCMClient::SERVER_ERROR
:
467 case gcm::GCMClient::UNKNOWN_ERROR
:
468 status
= content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR
;
470 case gcm::GCMClient::NETWORK_ERROR
:
471 case gcm::GCMClient::TTL_EXCEEDED
:
472 status
= content::PUSH_REGISTRATION_STATUS_NETWORK_ERROR
;
476 SubscribeEnd(callback
, subscription_id
, curve25519dh
, status
);
477 DecreasePushSubscriptionCount(1, true /* was_pending */);
480 void PushMessagingServiceImpl::DidRequestPermission(
481 const PushMessagingAppIdentifier
& app_identifier
,
482 const std::string
& sender_id
,
483 const content::PushMessagingService::RegisterCallback
& register_callback
,
484 content::PermissionStatus permission_status
) {
485 if (permission_status
!= content::PERMISSION_STATUS_GRANTED
) {
486 SubscribeEndWithError(register_callback
,
487 content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED
);
491 IncreasePushSubscriptionCount(1, true /* is_pending */);
492 std::vector
<std::string
> sender_ids(1, sender_id
);
493 GetGCMDriver()->Register(app_identifier
.app_id(), sender_ids
,
494 base::Bind(&PushMessagingServiceImpl::DidSubscribe
,
495 weak_factory_
.GetWeakPtr(),
496 app_identifier
, register_callback
));
499 // Unsubscribe methods ---------------------------------------------------------
501 void PushMessagingServiceImpl::Unsubscribe(
502 const GURL
& requesting_origin
,
503 int64 service_worker_registration_id
,
504 const std::string
& sender_id
,
505 const content::PushMessagingService::UnregisterCallback
& callback
) {
506 PushMessagingAppIdentifier app_identifier
=
507 PushMessagingAppIdentifier::FindByServiceWorker(
508 profile_
, requesting_origin
, service_worker_registration_id
);
509 if (app_identifier
.is_null()) {
510 if (!callback
.is_null()) {
512 content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED
);
517 Unsubscribe(app_identifier
.app_id(), sender_id
, callback
);
520 void PushMessagingServiceImpl::Unsubscribe(
521 const std::string
& app_id
,
522 const std::string
& sender_id
,
523 const content::PushMessagingService::UnregisterCallback
& callback
) {
524 // Delete the mapping for this app_id, to guarantee that no messages get
525 // delivered in future (even if unregistration fails).
526 // TODO(johnme): Instead of deleting these app ids, store them elsewhere, and
527 // retry unregistration if it fails due to network errors (crbug.com/465399).
528 PushMessagingAppIdentifier app_identifier
=
529 PushMessagingAppIdentifier::FindByAppId(profile_
, app_id
);
530 bool was_registered
= !app_identifier
.is_null();
532 app_identifier
.DeleteFromPrefs(profile_
);
534 const auto& unregister_callback
=
535 base::Bind(&PushMessagingServiceImpl::DidUnsubscribe
,
536 weak_factory_
.GetWeakPtr(), was_registered
, callback
);
537 #if defined(OS_ANDROID)
538 // On Android the backend is different, and requires the original sender_id.
539 // UnsubscribeBecausePermissionRevoked sometimes calls us with an empty one.
540 if (sender_id
.empty())
541 unregister_callback
.Run(gcm::GCMClient::INVALID_PARAMETER
);
543 GetGCMDriver()->UnregisterWithSenderId(app_id
, sender_id
,
544 unregister_callback
);
546 GetGCMDriver()->Unregister(app_id
, unregister_callback
);
550 void PushMessagingServiceImpl::DidUnsubscribe(
552 const content::PushMessagingService::UnregisterCallback
& callback
,
553 gcm::GCMClient::Result result
) {
555 DecreasePushSubscriptionCount(1, false /* was_pending */);
557 // Internal calls pass a null callback.
558 if (callback
.is_null())
561 if (!was_subscribed
) {
563 content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED
);
567 case gcm::GCMClient::SUCCESS
:
568 callback
.Run(content::PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED
);
570 case gcm::GCMClient::INVALID_PARAMETER
:
571 case gcm::GCMClient::GCM_DISABLED
:
572 case gcm::GCMClient::SERVER_ERROR
:
573 case gcm::GCMClient::UNKNOWN_ERROR
:
574 callback
.Run(content::PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR
);
576 case gcm::GCMClient::ASYNC_OPERATION_PENDING
:
577 case gcm::GCMClient::NETWORK_ERROR
:
578 case gcm::GCMClient::TTL_EXCEEDED
:
579 callback
.Run(content::PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR
);
584 // OnContentSettingChanged methods ---------------------------------------------
586 void PushMessagingServiceImpl::OnContentSettingChanged(
587 const ContentSettingsPattern
& primary_pattern
,
588 const ContentSettingsPattern
& secondary_pattern
,
589 ContentSettingsType content_type
,
590 std::string resource_identifier
) {
591 if (content_type
!= CONTENT_SETTINGS_TYPE_PUSH_MESSAGING
&&
592 content_type
!= CONTENT_SETTINGS_TYPE_NOTIFICATIONS
) {
596 std::vector
<PushMessagingAppIdentifier
> all_app_identifiers
=
597 PushMessagingAppIdentifier::GetAll(profile_
);
599 base::Closure barrier_closure
= base::BarrierClosure(
600 all_app_identifiers
.size(),
601 content_setting_changed_callback_for_testing_
.is_null()
602 ? base::Bind(&base::DoNothing
)
603 : content_setting_changed_callback_for_testing_
);
605 for (const PushMessagingAppIdentifier
& app_identifier
: all_app_identifiers
) {
606 // If |primary_pattern| is not valid, we should always check for a
607 // permission change because it can happen for example when the entire
608 // Push or Notifications permissions are cleared.
609 // Otherwise, the permission should be checked if the pattern matches the
611 if (primary_pattern
.IsValid() &&
612 !primary_pattern
.Matches(app_identifier
.origin())) {
613 barrier_closure
.Run();
617 if (IsPermissionSet(app_identifier
.origin())) {
618 barrier_closure
.Run();
623 profile_
, app_identifier
.origin(),
624 app_identifier
.service_worker_registration_id(),
626 &PushMessagingServiceImpl::UnsubscribeBecausePermissionRevoked
,
627 weak_factory_
.GetWeakPtr(), app_identifier
, barrier_closure
));
631 void PushMessagingServiceImpl::UnsubscribeBecausePermissionRevoked(
632 const PushMessagingAppIdentifier
& app_identifier
,
633 const base::Closure
& closure
,
634 const std::string
& sender_id
,
637 base::Closure barrier_closure
= base::BarrierClosure(2, closure
);
639 // Unsubscribe the PushMessagingAppIdentifier with the push service.
640 // It's possible for GetSenderId to have failed and sender_id to be empty, if
641 // cookies (and the SW database) for an origin got cleared before permissions
642 // are cleared for the origin. In that case Unsubscribe will just delete the
643 // app identifier to block future messages.
644 // TODO(johnme): Auto-unregister before SW DB is cleared
645 // (https://crbug.com/402458).
646 Unsubscribe(app_identifier
.app_id(), sender_id
,
647 base::Bind(&UnregisterCallbackToClosure
, barrier_closure
));
649 // Clear the associated service worker push registration id.
650 ClearPushSubscriptionID(profile_
, app_identifier
.origin(),
651 app_identifier
.service_worker_registration_id(),
655 void PushMessagingServiceImpl::SetContentSettingChangedCallbackForTesting(
656 const base::Closure
& callback
) {
657 content_setting_changed_callback_for_testing_
= callback
;
660 // KeyedService methods -------------------------------------------------------
662 void PushMessagingServiceImpl::Shutdown() {
663 GetGCMDriver()->RemoveAppHandler(kPushMessagingAppIdentifierPrefix
);
666 // Helper methods --------------------------------------------------------------
668 // Assumes user_visible always since this is just meant to check
669 // if the permission was previously granted and not revoked.
670 bool PushMessagingServiceImpl::IsPermissionSet(const GURL
& origin
) {
671 return GetPermissionStatus(origin
, origin
, true /* user_visible */) ==
672 blink::WebPushPermissionStatusGranted
;
675 gcm::GCMDriver
* PushMessagingServiceImpl::GetGCMDriver() const {
676 gcm::GCMProfileService
* gcm_profile_service
=
677 gcm::GCMProfileServiceFactory::GetForProfile(profile_
);
678 CHECK(gcm_profile_service
);
679 CHECK(gcm_profile_service
->driver());
680 return gcm_profile_service
->driver();