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

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

Issue 914693002: Push API: Fix unsubscribing from GCM on Android (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove obsolete PushEventNoPermission test 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"
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 } 173 }
174 174
175 bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const { 175 bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const {
176 return PushMessagingApplicationId::Get(profile_, app_id).IsValid(); 176 return PushMessagingApplicationId::Get(profile_, app_id).IsValid();
177 } 177 }
178 178
179 void PushMessagingServiceImpl::ShutdownHandler() { 179 void PushMessagingServiceImpl::ShutdownHandler() {
180 // TODO(johnme): Do any necessary cleanup. 180 // TODO(johnme): Do any necessary cleanup.
181 } 181 }
182 182
183 // OnMessage methods -----------------------------------------------------------
184
183 void PushMessagingServiceImpl::OnMessage( 185 void PushMessagingServiceImpl::OnMessage(
184 const std::string& app_id, 186 const std::string& app_id,
185 const GCMClient::IncomingMessage& message) { 187 const GCMClient::IncomingMessage& message) {
186 PushMessagingApplicationId application_id = 188 PushMessagingApplicationId application_id =
187 PushMessagingApplicationId::Get(profile_, app_id); 189 PushMessagingApplicationId::Get(profile_, app_id);
188 // Drop message and unregister if app id was unknown (maybe recently deleted). 190 // Drop message and unregister if app id was unknown (maybe recently deleted).
189 if (!application_id.IsValid()) { 191 if (!application_id.IsValid()) {
190 DeliverMessageCallback(app_id, GURL::EmptyGURL(), -1, message, 192 DeliverMessageCallback(app_id, GURL::EmptyGURL(), -1, message,
191 content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID); 193 content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID);
192 return; 194 return;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 profile_, 230 profile_,
229 application_id.origin(), 231 application_id.origin(),
230 application_id.service_worker_registration_id(), 232 application_id.service_worker_registration_id(),
231 data, 233 data,
232 base::Bind(&PushMessagingServiceImpl::DeliverMessageCallback, 234 base::Bind(&PushMessagingServiceImpl::DeliverMessageCallback,
233 weak_factory_.GetWeakPtr(), 235 weak_factory_.GetWeakPtr(),
234 application_id.app_id_guid(), application_id.origin(), 236 application_id.app_id_guid(), application_id.origin(),
235 application_id.service_worker_registration_id(), message)); 237 application_id.service_worker_registration_id(), message));
236 } 238 }
237 239
238 void PushMessagingServiceImpl::OnContentSettingChanged(
239 const ContentSettingsPattern& primary_pattern,
240 const ContentSettingsPattern& secondary_pattern,
241 ContentSettingsType content_type,
242 std::string resource_identifier) {
243 if (content_type != CONTENT_SETTINGS_TYPE_PUSH_MESSAGING &&
244 content_type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
245 return;
246 }
247
248 for (const auto& id : PushMessagingApplicationId::GetAll(profile_)) {
249 // If |primary_pattern| is not valid, we should always check for a
250 // permission change because it can happen for example when the entire
251 // Push or Notifications permissions are cleared.
252 // Otherwise, the permission should be checked if the pattern matches the
253 // origin.
254 if (primary_pattern.IsValid() && !primary_pattern.Matches(id.origin()))
255 continue;
256
257 if (HasPermission(id.origin()))
258 continue;
259
260 // Unregister the PushMessagingApplicationId with the push service.
261 Unregister(id.app_id_guid(), true /* retry */, UnregisterCallback());
262
263 // Clear the associated service worker push registration id.
264 PushMessagingService::ClearPushRegistrationID(
265 profile_, id.origin(), id.service_worker_registration_id());
266 }
267 }
268
269 void PushMessagingServiceImpl::SetProfileForTesting(Profile* profile) {
270 profile_ = profile;
271 profile_->GetHostContentSettingsMap()->AddObserver(this);
272 }
273
274 void PushMessagingServiceImpl::DeliverMessageCallback( 240 void PushMessagingServiceImpl::DeliverMessageCallback(
275 const std::string& app_id_guid, 241 const std::string& app_id_guid,
276 const GURL& requesting_origin, 242 const GURL& requesting_origin,
277 int64 service_worker_registration_id, 243 int64 service_worker_registration_id,
278 const GCMClient::IncomingMessage& message, 244 const GCMClient::IncomingMessage& message,
279 content::PushDeliveryStatus status) { 245 content::PushDeliveryStatus status) {
280 // TODO(mvanouwerkerk): UMA logging. 246 // TODO(mvanouwerkerk): UMA logging.
281 // TODO(mvanouwerkerk): Show a warning in the developer console of the 247 // TODO(mvanouwerkerk): Show a warning in the developer console of the
282 // Service Worker corresponding to app_id (and/or on an internals page). 248 // Service Worker corresponding to app_id (and/or on an internals page).
283 // TODO(mvanouwerkerk): Is there a way to recover from failure? 249 // TODO(mvanouwerkerk): Is there a way to recover from failure?
284 switch (status) { 250 switch (status) {
285 // Call RequireUserVisibleUX if the message was delivered to the Service 251 // Call RequireUserVisibleUX if the message was delivered to the Service
286 // Worker JS, even if the website's event handler failed (to prevent sites 252 // Worker JS, even if the website's event handler failed (to prevent sites
287 // deliberately failing in order to avoid having to show notifications). 253 // deliberately failing in order to avoid having to show notifications).
288 case content::PUSH_DELIVERY_STATUS_SUCCESS: 254 case content::PUSH_DELIVERY_STATUS_SUCCESS:
289 case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED: 255 case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED:
290 RequireUserVisibleUX(requesting_origin, service_worker_registration_id); 256 RequireUserVisibleUX(requesting_origin, service_worker_registration_id);
291 break; 257 break;
292 case content::PUSH_DELIVERY_STATUS_INVALID_MESSAGE: 258 case content::PUSH_DELIVERY_STATUS_INVALID_MESSAGE:
293 case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR: 259 case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR:
294 break; 260 break;
295 case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID: 261 case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID:
296 case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED: 262 case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED:
297 case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: 263 case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER:
298 Unregister(app_id_guid, true /*retry_on_failure*/, UnregisterCallback()); 264 Unregister(app_id_guid, message.sender_id, true /* retry_on_failure */,
265 UnregisterCallback());
299 break; 266 break;
300 } 267 }
301 } 268 }
302 269
303 void PushMessagingServiceImpl::RequireUserVisibleUX( 270 void PushMessagingServiceImpl::RequireUserVisibleUX(
304 const GURL& requesting_origin, int64 service_worker_registration_id) { 271 const GURL& requesting_origin, int64 service_worker_registration_id) {
305 #if defined(ENABLE_NOTIFICATIONS) 272 #if defined(ENABLE_NOTIFICATIONS)
306 // TODO(johnme): Relax this heuristic slightly. 273 // TODO(johnme): Relax this heuristic slightly.
307 PlatformNotificationServiceImpl* notification_service = 274 PlatformNotificationServiceImpl* notification_service =
308 PlatformNotificationServiceImpl::GetInstance(); 275 PlatformNotificationServiceImpl::GetInstance();
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 PlatformNotificationServiceImpl::GetInstance(); 422 PlatformNotificationServiceImpl::GetInstance();
456 notification_service->DisplayPersistentNotification( 423 notification_service->DisplayPersistentNotification(
457 profile_, 424 profile_,
458 service_worker_registration_id, 425 service_worker_registration_id,
459 requesting_origin, 426 requesting_origin,
460 SkBitmap() /* icon */, 427 SkBitmap() /* icon */,
461 notification_data); 428 notification_data);
462 } 429 }
463 } 430 }
464 431
432 // Other GCMAppHandler methods -------------------------------------------------
433
465 void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) { 434 void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) {
466 // TODO(mvanouwerkerk): Fire push error event on the Service Worker 435 // TODO(mvanouwerkerk): Fire push error event on the Service Worker
467 // corresponding to app_id. 436 // corresponding to app_id.
468 } 437 }
469 438
470 void PushMessagingServiceImpl::OnSendError( 439 void PushMessagingServiceImpl::OnSendError(
471 const std::string& app_id, 440 const std::string& app_id,
472 const GCMClient::SendErrorDetails& send_error_details) { 441 const GCMClient::SendErrorDetails& send_error_details) {
473 NOTREACHED() << "The Push API shouldn't have sent messages upstream"; 442 NOTREACHED() << "The Push API shouldn't have sent messages upstream";
474 } 443 }
475 444
476 void PushMessagingServiceImpl::OnSendAcknowledged( 445 void PushMessagingServiceImpl::OnSendAcknowledged(
477 const std::string& app_id, 446 const std::string& app_id,
478 const std::string& message_id) { 447 const std::string& message_id) {
479 NOTREACHED() << "The Push API shouldn't have sent messages upstream"; 448 NOTREACHED() << "The Push API shouldn't have sent messages upstream";
480 } 449 }
481 450
451 // GetPushEndpoint method ------------------------------------------------------
452
482 GURL PushMessagingServiceImpl::GetPushEndpoint() { 453 GURL PushMessagingServiceImpl::GetPushEndpoint() {
483 return GURL(std::string(kPushMessagingEndpoint)); 454 return GURL(std::string(kPushMessagingEndpoint));
484 } 455 }
485 456
457 // Register and GetPermissionStatus methods ------------------------------------
458
486 void PushMessagingServiceImpl::RegisterFromDocument( 459 void PushMessagingServiceImpl::RegisterFromDocument(
487 const GURL& requesting_origin, 460 const GURL& requesting_origin,
488 int64 service_worker_registration_id, 461 int64 service_worker_registration_id,
489 const std::string& sender_id, 462 const std::string& sender_id,
490 int renderer_id, 463 int renderer_id,
491 int render_frame_id, 464 int render_frame_id,
492 bool user_visible_only, 465 bool user_visible_only,
493 const content::PushMessagingService::RegisterCallback& callback) { 466 const content::PushMessagingService::RegisterCallback& callback) {
494 if (!gcm_profile_service_->driver()) { 467 if (!gcm_profile_service_->driver()) {
495 NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?"; 468 NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?";
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 IncreasePushRegistrationCount(1, true /* is_pending */); 613 IncreasePushRegistrationCount(1, true /* is_pending */);
641 std::vector<std::string> sender_ids(1, sender_id); 614 std::vector<std::string> sender_ids(1, sender_id);
642 gcm_profile_service_->driver()->Register( 615 gcm_profile_service_->driver()->Register(
643 application_id.app_id_guid(), 616 application_id.app_id_guid(),
644 sender_ids, 617 sender_ids,
645 base::Bind(&PushMessagingServiceImpl::DidRegister, 618 base::Bind(&PushMessagingServiceImpl::DidRegister,
646 weak_factory_.GetWeakPtr(), 619 weak_factory_.GetWeakPtr(),
647 application_id, register_callback)); 620 application_id, register_callback));
648 } 621 }
649 622
623 // Unregister methods ----------------------------------------------------------
624
650 void PushMessagingServiceImpl::Unregister( 625 void PushMessagingServiceImpl::Unregister(
651 const GURL& requesting_origin, 626 const GURL& requesting_origin,
652 int64 service_worker_registration_id, 627 int64 service_worker_registration_id,
628 const std::string& sender_id,
653 bool retry_on_failure, 629 bool retry_on_failure,
654 const content::PushMessagingService::UnregisterCallback& callback) { 630 const content::PushMessagingService::UnregisterCallback& callback) {
655 DCHECK(gcm_profile_service_->driver()); 631 DCHECK(gcm_profile_service_->driver());
656 632
657 PushMessagingApplicationId application_id = PushMessagingApplicationId::Get( 633 PushMessagingApplicationId application_id = PushMessagingApplicationId::Get(
658 profile_, requesting_origin, service_worker_registration_id); 634 profile_, requesting_origin, service_worker_registration_id);
659 if (!application_id.IsValid()) { 635 if (!application_id.IsValid()) {
660 if (!callback.is_null()) { 636 if (!callback.is_null()) {
661 callback.Run( 637 callback.Run(
662 content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED); 638 content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED);
663 } 639 }
664 return; 640 return;
665 } 641 }
666 642
667 Unregister(application_id.app_id_guid(), retry_on_failure, callback); 643 Unregister(application_id.app_id_guid(), sender_id, retry_on_failure,
644 callback);
668 } 645 }
669 646
670 void PushMessagingServiceImpl::Unregister( 647 void PushMessagingServiceImpl::Unregister(
671 const std::string& app_id_guid, 648 const std::string& app_id_guid,
649 const std::string& sender_id,
672 bool retry_on_failure, 650 bool retry_on_failure,
673 const content::PushMessagingService::UnregisterCallback& callback) { 651 const content::PushMessagingService::UnregisterCallback& callback) {
674 DCHECK(gcm_profile_service_->driver()); 652 DCHECK(gcm_profile_service_->driver());
675 653
676 if (retry_on_failure) { 654 if (retry_on_failure) {
677 // Delete the mapping for this app id, to guarantee that no messages get 655 // Delete the mapping for this app id, to guarantee that no messages get
678 // delivered in future (even if unregistration fails). 656 // delivered in future (even if unregistration fails).
679 // TODO(johnme): Instead of deleting these app ids, store them elsewhere, 657 // TODO(johnme): Instead of deleting these app ids, store them elsewhere,
680 // and retry unregistration if it fails due to network errors. 658 // and retry unregistration if it fails due to network errors.
681 PushMessagingApplicationId application_id = 659 PushMessagingApplicationId application_id =
682 PushMessagingApplicationId::Get(profile_, app_id_guid); 660 PushMessagingApplicationId::Get(profile_, app_id_guid);
683 if (application_id.IsValid()) 661 if (application_id.IsValid())
684 application_id.DeleteFromDisk(profile_); 662 application_id.DeleteFromDisk(profile_);
685 } 663 }
686 664
687 gcm_profile_service_->driver()->Unregister( 665 const auto& unregister_callback =
688 app_id_guid,
689 base::Bind(&PushMessagingServiceImpl::DidUnregister, 666 base::Bind(&PushMessagingServiceImpl::DidUnregister,
690 weak_factory_.GetWeakPtr(), 667 weak_factory_.GetWeakPtr(),
691 app_id_guid, retry_on_failure, callback)); 668 app_id_guid, retry_on_failure, callback);
669 #if defined(OS_ANDROID)
670 // On Android the backend is different, and requires the original sender_id.
671 gcm_profile_service_->driver()->UnregisterWithSenderId(app_id_guid, sender_id,
672 unregister_callback);
673 #else
674 gcm_profile_service_->driver()->Unregister(app_id_guid, unregister_callback);
675 #endif
692 } 676 }
693 677
694 void PushMessagingServiceImpl::DidUnregister( 678 void PushMessagingServiceImpl::DidUnregister(
695 const std::string& app_id_guid, 679 const std::string& app_id_guid,
696 bool retry_on_failure, 680 bool retry_on_failure,
697 const content::PushMessagingService::UnregisterCallback& callback, 681 const content::PushMessagingService::UnregisterCallback& callback,
698 GCMClient::Result result) { 682 GCMClient::Result result) {
699 if (result == GCMClient::SUCCESS) { 683 if (result == GCMClient::SUCCESS) {
700 PushMessagingApplicationId application_id = 684 PushMessagingApplicationId application_id =
701 PushMessagingApplicationId::Get(profile_, app_id_guid); 685 PushMessagingApplicationId::Get(profile_, app_id_guid);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
733 callback.Run(content::PUSH_UNREGISTRATION_STATUS_UNKNOWN_ERROR); 717 callback.Run(content::PUSH_UNREGISTRATION_STATUS_UNKNOWN_ERROR);
734 break; 718 break;
735 default: 719 default:
736 NOTREACHED() << "Unexpected GCMClient::Result value."; 720 NOTREACHED() << "Unexpected GCMClient::Result value.";
737 callback.Run(content::PUSH_UNREGISTRATION_STATUS_UNKNOWN_ERROR); 721 callback.Run(content::PUSH_UNREGISTRATION_STATUS_UNKNOWN_ERROR);
738 break; 722 break;
739 } 723 }
740 } 724 }
741 } 725 }
742 726
727 // OnContentSettingChanged methods ---------------------------------------------
728
729 void PushMessagingServiceImpl::OnContentSettingChanged(
730 const ContentSettingsPattern& primary_pattern,
731 const ContentSettingsPattern& secondary_pattern,
732 ContentSettingsType content_type,
733 std::string resource_identifier) {
734 if (content_type != CONTENT_SETTINGS_TYPE_PUSH_MESSAGING &&
735 content_type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
736 return;
737 }
738
739 for (const auto& id : PushMessagingApplicationId::GetAll(profile_)) {
740 // If |primary_pattern| is not valid, we should always check for a
741 // permission change because it can happen for example when the entire
742 // Push or Notifications permissions are cleared.
743 // Otherwise, the permission should be checked if the pattern matches the
744 // origin.
745 if (primary_pattern.IsValid() && !primary_pattern.Matches(id.origin()))
746 continue;
747
748 if (HasPermission(id.origin()))
749 continue;
750
751 PushMessagingService::GetSenderId(
752 profile_, id.origin(), id.service_worker_registration_id(),
753 base::Bind(
754 &PushMessagingServiceImpl::UnregisterBecausePermissionRevoked,
755 weak_factory_.GetWeakPtr(), id));
756 }
757 }
758
759 void PushMessagingServiceImpl::UnregisterBecausePermissionRevoked(
760 const PushMessagingApplicationId& id,
761 const std::string& sender_id, bool success, bool not_found) {
762 // Unregister the PushMessagingApplicationId with the push service.
763 Unregister(id.app_id_guid(), sender_id, true /* retry_on_failure */,
764 UnregisterCallback());
765
766 // Clear the associated service worker push registration id.
767 PushMessagingService::ClearPushRegistrationID(
768 profile_, id.origin(), id.service_worker_registration_id());
769 }
770
771 // Helper methods --------------------------------------------------------------
772
743 bool PushMessagingServiceImpl::HasPermission(const GURL& origin) { 773 bool PushMessagingServiceImpl::HasPermission(const GURL& origin) {
744 gcm::PushMessagingPermissionContext* permission_context = 774 gcm::PushMessagingPermissionContext* permission_context =
745 gcm::PushMessagingPermissionContextFactory::GetForProfile(profile_); 775 gcm::PushMessagingPermissionContextFactory::GetForProfile(profile_);
746 DCHECK(permission_context); 776 DCHECK(permission_context);
747 777
748 return permission_context->GetPermissionStatus(origin, origin) == 778 return permission_context->GetPermissionStatus(origin, origin) ==
749 CONTENT_SETTING_ALLOW; 779 CONTENT_SETTING_ALLOW;
750 } 780 }
751 781
782 void PushMessagingServiceImpl::SetProfileForTesting(Profile* profile) {
783 profile_ = profile;
784 profile_->GetHostContentSettingsMap()->AddObserver(this);
785 }
786
752 } // namespace gcm 787 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698