| Index: chrome/browser/push_messaging/push_messaging_service_impl.cc
|
| diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc
|
| index a3700e10c0426817cefec99eace20816c58e2dfa..f94fdb36d07bdbd2012c039ebd576380d817a9cb 100644
|
| --- a/chrome/browser/push_messaging/push_messaging_service_impl.cc
|
| +++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
|
| @@ -15,6 +15,7 @@
|
| #include "base/feature_list.h"
|
| #include "base/logging.h"
|
| #include "base/metrics/histogram_macros.h"
|
| +#include "base/strings/string_util.h"
|
| #include "build/build_config.h"
|
| #include "chrome/browser/browser_process.h"
|
| #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
| @@ -25,6 +26,8 @@
|
| #include "chrome/browser/push_messaging/push_messaging_service_factory.h"
|
| #include "chrome/browser/push_messaging/push_messaging_service_observer.h"
|
| #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
|
| +#include "chrome/browser/services/gcm/instance_id/instance_id_profile_service.h"
|
| +#include "chrome/browser/services/gcm/instance_id/instance_id_profile_service_factory.h"
|
| #include "chrome/browser/ui/chrome_pages.h"
|
| #include "chrome/common/chrome_features.h"
|
| #include "chrome/common/chrome_switches.h"
|
| @@ -34,6 +37,8 @@
|
| #include "components/content_settings/core/browser/host_content_settings_map.h"
|
| #include "components/gcm_driver/gcm_driver.h"
|
| #include "components/gcm_driver/gcm_profile_service.h"
|
| +#include "components/gcm_driver/instance_id/instance_id.h"
|
| +#include "components/gcm_driver/instance_id/instance_id_driver.h"
|
| #include "components/pref_registry/pref_registry_syncable.h"
|
| #include "components/prefs/pref_service.h"
|
| #include "components/rappor/rappor_utils.h"
|
| @@ -55,7 +60,14 @@
|
| #include "chrome/browser/lifetime/scoped_keep_alive.h"
|
| #endif
|
|
|
| +using instance_id::InstanceID;
|
| +
|
| namespace {
|
| +
|
| +// Scope passed to getToken to obtain GCM registration tokens.
|
| +// Must match Java GoogleCloudMessaging.INSTANCE_ID_SCOPE.
|
| +const char kGCMScope[] = "GCM";
|
| +
|
| const int kMaxRegistrations = 1000000;
|
|
|
| // Chrome does not yet support silent push messages, and requires websites to
|
| @@ -181,7 +193,8 @@ void PushMessagingServiceImpl::DecreasePushSubscriptionCount(int subtract,
|
| }
|
|
|
| bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const {
|
| - return !PushMessagingAppIdentifier::FindByAppId(profile_, app_id).is_null();
|
| + return base::StartsWith(app_id, kPushMessagingAppIdentifierPrefix,
|
| + base::CompareCase::INSENSITIVE_ASCII);
|
| }
|
|
|
| void PushMessagingServiceImpl::ShutdownHandler() {
|
| @@ -408,7 +421,7 @@ void PushMessagingServiceImpl::SubscribeFromDocument(
|
| profile_->GetPermissionManager()->RequestPermission(
|
| content::PermissionType::PUSH_MESSAGING, web_contents->GetMainFrame(),
|
| requesting_origin, true /* user_gesture */,
|
| - base::Bind(&PushMessagingServiceImpl::DidRequestPermission,
|
| + base::Bind(&PushMessagingServiceImpl::DoSubscribe,
|
| weak_factory_.GetWeakPtr(), app_identifier, options,
|
| callback));
|
| }
|
| @@ -430,8 +443,7 @@ void PushMessagingServiceImpl::SubscribeFromWorker(
|
| }
|
|
|
| blink::WebPushPermissionStatus permission_status =
|
| - PushMessagingServiceImpl::GetPermissionStatus(requesting_origin,
|
| - options.user_visible_only);
|
| + GetPermissionStatus(requesting_origin, options.user_visible_only);
|
|
|
| if (permission_status != blink::WebPushPermissionStatusGranted) {
|
| SubscribeEndWithError(register_callback,
|
| @@ -439,14 +451,8 @@ void PushMessagingServiceImpl::SubscribeFromWorker(
|
| return;
|
| }
|
|
|
| - IncreasePushSubscriptionCount(1, true /* is_pending */);
|
| - std::vector<std::string> sender_ids(1,
|
| - NormalizeSenderInfo(options.sender_info));
|
| -
|
| - GetGCMDriver()->Register(app_identifier.app_id(), sender_ids,
|
| - base::Bind(&PushMessagingServiceImpl::DidSubscribe,
|
| - weak_factory_.GetWeakPtr(),
|
| - app_identifier, register_callback));
|
| + DoSubscribe(app_identifier, options, register_callback,
|
| + blink::mojom::PermissionStatus::GRANTED);
|
| }
|
|
|
| blink::WebPushPermissionStatus PushMessagingServiceImpl::GetPermissionStatus(
|
| @@ -466,6 +472,28 @@ bool PushMessagingServiceImpl::SupportNonVisibleMessages() {
|
| return false;
|
| }
|
|
|
| +void PushMessagingServiceImpl::DoSubscribe(
|
| + const PushMessagingAppIdentifier& app_identifier,
|
| + const content::PushSubscriptionOptions& options,
|
| + const content::PushMessagingService::RegisterCallback& register_callback,
|
| + blink::mojom::PermissionStatus permission_status) {
|
| + if (permission_status != blink::mojom::PermissionStatus::GRANTED) {
|
| + SubscribeEndWithError(register_callback,
|
| + content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED);
|
| + return;
|
| + }
|
| +
|
| + IncreasePushSubscriptionCount(1, true /* is_pending */);
|
| +
|
| + GetInstanceIDDriver()
|
| + ->GetInstanceID(app_identifier.app_id())
|
| + ->GetToken(NormalizeSenderInfo(options.sender_info), kGCMScope,
|
| + std::map<std::string, std::string>() /* options */,
|
| + base::Bind(&PushMessagingServiceImpl::DidSubscribe,
|
| + weak_factory_.GetWeakPtr(), app_identifier,
|
| + options.sender_info, register_callback));
|
| +}
|
| +
|
| void PushMessagingServiceImpl::SubscribeEnd(
|
| const content::PushMessagingService::RegisterCallback& callback,
|
| const std::string& subscription_id,
|
| @@ -485,35 +513,36 @@ void PushMessagingServiceImpl::SubscribeEndWithError(
|
|
|
| void PushMessagingServiceImpl::DidSubscribe(
|
| const PushMessagingAppIdentifier& app_identifier,
|
| + const std::string& sender_id,
|
| const content::PushMessagingService::RegisterCallback& callback,
|
| const std::string& subscription_id,
|
| - gcm::GCMClient::Result result) {
|
| + InstanceID::Result result) {
|
| DecreasePushSubscriptionCount(1, true /* was_pending */);
|
|
|
| content::PushRegistrationStatus status =
|
| content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR;
|
|
|
| switch (result) {
|
| - case gcm::GCMClient::SUCCESS:
|
| + case InstanceID::SUCCESS:
|
| // Make sure that this subscription has associated encryption keys prior
|
| // to returning it to the developer - they'll need this information in
|
| // order to send payloads to the user.
|
| - GetGCMDriver()->GetEncryptionInfo(
|
| - app_identifier.app_id(),
|
| + GetEncryptionInfoForAppId(
|
| + app_identifier.app_id(), sender_id,
|
| base::Bind(&PushMessagingServiceImpl::DidSubscribeWithEncryptionInfo,
|
| weak_factory_.GetWeakPtr(), app_identifier, callback,
|
| subscription_id));
|
| -
|
| return;
|
| - case gcm::GCMClient::INVALID_PARAMETER:
|
| - case gcm::GCMClient::GCM_DISABLED:
|
| - case gcm::GCMClient::ASYNC_OPERATION_PENDING:
|
| - case gcm::GCMClient::SERVER_ERROR:
|
| - case gcm::GCMClient::UNKNOWN_ERROR:
|
| + case InstanceID::INVALID_PARAMETER:
|
| + case InstanceID::DISABLED:
|
| + case InstanceID::ASYNC_OPERATION_PENDING:
|
| + case InstanceID::SERVER_ERROR:
|
| + case InstanceID::UNKNOWN_ERROR:
|
| + DLOG(ERROR) << "Push messaging subscription failed; InstanceID::Result = "
|
| + << result;
|
| status = content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR;
|
| break;
|
| - case gcm::GCMClient::NETWORK_ERROR:
|
| - case gcm::GCMClient::TTL_EXCEEDED:
|
| + case InstanceID::NETWORK_ERROR:
|
| status = content::PUSH_REGISTRATION_STATUS_NETWORK_ERROR;
|
| break;
|
| }
|
| @@ -543,32 +572,12 @@ void PushMessagingServiceImpl::DidSubscribeWithEncryptionInfo(
|
| content::PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE);
|
| }
|
|
|
| -void PushMessagingServiceImpl::DidRequestPermission(
|
| - const PushMessagingAppIdentifier& app_identifier,
|
| - const content::PushSubscriptionOptions& options,
|
| - const content::PushMessagingService::RegisterCallback& register_callback,
|
| - blink::mojom::PermissionStatus permission_status) {
|
| - if (permission_status != blink::mojom::PermissionStatus::GRANTED) {
|
| - SubscribeEndWithError(register_callback,
|
| - content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED);
|
| - return;
|
| - }
|
| -
|
| - IncreasePushSubscriptionCount(1, true /* is_pending */);
|
| - std::vector<std::string> sender_ids(1,
|
| - NormalizeSenderInfo(options.sender_info));
|
| -
|
| - GetGCMDriver()->Register(app_identifier.app_id(), sender_ids,
|
| - base::Bind(&PushMessagingServiceImpl::DidSubscribe,
|
| - weak_factory_.GetWeakPtr(),
|
| - app_identifier, register_callback));
|
| -}
|
| -
|
| // GetEncryptionInfo methods ---------------------------------------------------
|
|
|
| void PushMessagingServiceImpl::GetEncryptionInfo(
|
| const GURL& origin,
|
| int64_t service_worker_registration_id,
|
| + const std::string& sender_id,
|
| const PushMessagingService::EncryptionInfoCallback& callback) {
|
| PushMessagingAppIdentifier app_identifier =
|
| PushMessagingAppIdentifier::FindByServiceWorker(
|
| @@ -576,8 +585,8 @@ void PushMessagingServiceImpl::GetEncryptionInfo(
|
|
|
| DCHECK(!app_identifier.is_null());
|
|
|
| - GetGCMDriver()->GetEncryptionInfo(
|
| - app_identifier.app_id(),
|
| + GetEncryptionInfoForAppId(
|
| + app_identifier.app_id(), sender_id,
|
| base::Bind(&PushMessagingServiceImpl::DidGetEncryptionInfo,
|
| weak_factory_.GetWeakPtr(), callback));
|
| }
|
| @@ -604,10 +613,8 @@ void PushMessagingServiceImpl::Unsubscribe(
|
| PushMessagingAppIdentifier::FindByServiceWorker(
|
| profile_, requesting_origin, service_worker_registration_id);
|
| if (app_identifier.is_null()) {
|
| - if (!callback.is_null()) {
|
| - callback.Run(
|
| - content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED);
|
| - }
|
| + callback.Run(
|
| + content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED);
|
| return;
|
| }
|
|
|
| @@ -624,37 +631,58 @@ void PushMessagingServiceImpl::Unsubscribe(
|
| // retry unregistration if it fails due to network errors (crbug.com/465399).
|
| PushMessagingAppIdentifier app_identifier =
|
| PushMessagingAppIdentifier::FindByAppId(profile_, app_id);
|
| - bool was_registered = !app_identifier.is_null();
|
| - if (was_registered)
|
| + bool was_subscribed = !app_identifier.is_null();
|
| + if (was_subscribed)
|
| app_identifier.DeleteFromPrefs(profile_);
|
|
|
| - const auto& unregister_callback =
|
| - base::Bind(&PushMessagingServiceImpl::DidUnsubscribe,
|
| - weak_factory_.GetWeakPtr(), was_registered, callback);
|
| -#if defined(OS_ANDROID)
|
| - // On Android the backend is different, and requires the original sender_id.
|
| - // UnsubscribeBecausePermissionRevoked sometimes calls us with an empty one.
|
| - if (sender_id.empty()) {
|
| - unregister_callback.Run(gcm::GCMClient::INVALID_PARAMETER);
|
| + if (PushMessagingAppIdentifier::UseInstanceID(app_id)) {
|
| + GetInstanceIDDriver()->GetInstanceID(app_id)->DeleteID(base::Bind(
|
| + &PushMessagingServiceImpl::DidDeleteID, weak_factory_.GetWeakPtr(),
|
| + app_id, was_subscribed, callback));
|
| } else {
|
| - GetGCMDriver()->UnregisterWithSenderId(
|
| - app_id, NormalizeSenderInfo(sender_id), unregister_callback);
|
| - }
|
| + auto unregister_callback =
|
| + base::Bind(&PushMessagingServiceImpl::DidUnsubscribe,
|
| + weak_factory_.GetWeakPtr(), was_subscribed, callback);
|
| +#if defined(OS_ANDROID)
|
| + // On Android the backend is different, and requires the original sender_id.
|
| + // UnsubscribeBecausePermissionRevoked sometimes calls us with an empty one.
|
| + if (sender_id.empty()) {
|
| + unregister_callback.Run(gcm::GCMClient::INVALID_PARAMETER);
|
| + } else {
|
| + GetGCMDriver()->UnregisterWithSenderId(
|
| + app_id, NormalizeSenderInfo(sender_id), unregister_callback);
|
| + }
|
| #else
|
| - GetGCMDriver()->Unregister(app_id, unregister_callback);
|
| + GetGCMDriver()->Unregister(app_id, unregister_callback);
|
| #endif
|
| + }
|
| }
|
|
|
| -void PushMessagingServiceImpl::DidUnsubscribe(
|
| +void PushMessagingServiceImpl::DidDeleteID(
|
| + const std::string& app_id,
|
| + bool was_subscribed,
|
| + const content::PushMessagingService::UnregisterCallback& callback,
|
| + InstanceID::Result result) {
|
| + // DidUnsubscribeInstanceID must be run asynchronously, since it calls
|
| + // InstanceIDDriver::RemoveInstanceID which deletes the InstanceID itself.
|
| + // Calling that immediately would cause a use-after-free in our caller.
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE, base::Bind(&PushMessagingServiceImpl::DidUnsubscribeInstanceID,
|
| + weak_factory_.GetWeakPtr(), app_id, was_subscribed,
|
| + callback, result));
|
| +}
|
| +
|
| +void PushMessagingServiceImpl::DidUnsubscribeInstanceID(
|
| + const std::string& app_id,
|
| bool was_subscribed,
|
| const content::PushMessagingService::UnregisterCallback& callback,
|
| - gcm::GCMClient::Result result) {
|
| + InstanceID::Result result) {
|
| + GetInstanceIDDriver()->RemoveInstanceID(app_id);
|
| +
|
| if (was_subscribed)
|
| DecreasePushSubscriptionCount(1, false /* was_pending */);
|
|
|
| - // Internal calls pass a null callback.
|
| - if (callback.is_null())
|
| - return;
|
| + DCHECK(!callback.is_null());
|
|
|
| if (!was_subscribed) {
|
| callback.Run(
|
| @@ -662,6 +690,37 @@ void PushMessagingServiceImpl::DidUnsubscribe(
|
| return;
|
| }
|
| switch (result) {
|
| + case InstanceID::SUCCESS:
|
| + callback.Run(content::PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED);
|
| + break;
|
| + case InstanceID::INVALID_PARAMETER:
|
| + case InstanceID::DISABLED:
|
| + case InstanceID::SERVER_ERROR:
|
| + case InstanceID::UNKNOWN_ERROR:
|
| + callback.Run(content::PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR);
|
| + break;
|
| + case InstanceID::ASYNC_OPERATION_PENDING:
|
| + case InstanceID::NETWORK_ERROR:
|
| + callback.Run(content::PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR);
|
| + break;
|
| + }
|
| +}
|
| +
|
| +void PushMessagingServiceImpl::DidUnsubscribe(
|
| + bool was_subscribed,
|
| + const content::PushMessagingService::UnregisterCallback& callback,
|
| + gcm::GCMClient::Result gcm_result) {
|
| + if (was_subscribed)
|
| + DecreasePushSubscriptionCount(1, false /* was_pending */);
|
| +
|
| + DCHECK(!callback.is_null());
|
| +
|
| + if (!was_subscribed) {
|
| + callback.Run(
|
| + content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED);
|
| + return;
|
| + }
|
| + switch (gcm_result) {
|
| case gcm::GCMClient::SUCCESS:
|
| callback.Run(content::PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED);
|
| break;
|
| @@ -715,12 +774,23 @@ void PushMessagingServiceImpl::OnContentSettingChanged(
|
| continue;
|
| }
|
|
|
| - GetSenderId(
|
| - profile_, app_identifier.origin(),
|
| - app_identifier.service_worker_registration_id(),
|
| - base::Bind(
|
| - &PushMessagingServiceImpl::UnsubscribeBecausePermissionRevoked,
|
| - weak_factory_.GetWeakPtr(), app_identifier, barrier_closure));
|
| + bool need_sender_id = false;
|
| +#if defined(OS_ANDROID)
|
| + need_sender_id =
|
| + !PushMessagingAppIdentifier::UseInstanceID(app_identifier.app_id());
|
| +#endif
|
| + if (need_sender_id) {
|
| + GetSenderId(
|
| + profile_, app_identifier.origin(),
|
| + app_identifier.service_worker_registration_id(),
|
| + base::Bind(
|
| + &PushMessagingServiceImpl::UnsubscribeBecausePermissionRevoked,
|
| + weak_factory_.GetWeakPtr(), app_identifier, barrier_closure));
|
| + } else {
|
| + UnsubscribeBecausePermissionRevoked(
|
| + app_identifier, barrier_closure, "" /* sender_id */,
|
| + true /* success */, true /* not_found */);
|
| + }
|
| }
|
| }
|
|
|
| @@ -735,8 +805,9 @@ void PushMessagingServiceImpl::UnsubscribeBecausePermissionRevoked(
|
| // Unsubscribe the PushMessagingAppIdentifier with the push service.
|
| // It's possible for GetSenderId to have failed and sender_id to be empty, if
|
| // cookies (and the SW database) for an origin got cleared before permissions
|
| - // are cleared for the origin. In that case Unsubscribe will just delete the
|
| - // app identifier to block future messages.
|
| + // are cleared for the origin. In that case for legacy GCM registrations on
|
| + // Android, Unsubscribe will just delete the app identifier to block future
|
| + // messages.
|
| // TODO(johnme): Auto-unregister before SW DB is cleared
|
| // (https://crbug.com/402458).
|
| Unsubscribe(app_identifier.app_id(), sender_id,
|
| @@ -799,6 +870,18 @@ bool PushMessagingServiceImpl::IsPermissionSet(const GURL& origin) {
|
| blink::WebPushPermissionStatusGranted;
|
| }
|
|
|
| +void PushMessagingServiceImpl::GetEncryptionInfoForAppId(
|
| + const std::string& app_id,
|
| + const std::string& sender_id,
|
| + gcm::GCMEncryptionProvider::EncryptionInfoCallback callback) {
|
| + if (PushMessagingAppIdentifier::UseInstanceID(app_id)) {
|
| + GetInstanceIDDriver()->GetInstanceID(app_id)->GetEncryptionInfo(
|
| + NormalizeSenderInfo(sender_id), callback);
|
| + } else {
|
| + GetGCMDriver()->GetEncryptionInfo(app_id, callback);
|
| + }
|
| +}
|
| +
|
| gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const {
|
| gcm::GCMProfileService* gcm_profile_service =
|
| gcm::GCMProfileServiceFactory::GetForProfile(profile_);
|
| @@ -806,3 +889,12 @@ gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const {
|
| CHECK(gcm_profile_service->driver());
|
| return gcm_profile_service->driver();
|
| }
|
| +
|
| +instance_id::InstanceIDDriver* PushMessagingServiceImpl::GetInstanceIDDriver()
|
| + const {
|
| + instance_id::InstanceIDProfileService* instance_id_profile_service =
|
| + instance_id::InstanceIDProfileServiceFactory::GetForProfile(profile_);
|
| + CHECK(instance_id_profile_service);
|
| + CHECK(instance_id_profile_service->driver());
|
| + return instance_id_profile_service->driver();
|
| +}
|
|
|