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

Unified Diff: chrome/browser/push_messaging/push_messaging_service_impl.cc

Issue 2387483002: Push API: Refactor and fix unsubscribe API (Closed)
Patch Set: Created 4 years, 3 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 side-by-side diff with in-line comments
Download patch
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 1cc200aaa054c6c024e07709450e1b4831dab4c3..fbe657c04e8b434d1f0b076f65d9b8e5d6d5cd69 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -83,6 +83,11 @@ void RecordDeliveryStatus(content::PushDeliveryStatus status) {
content::PUSH_DELIVERY_STATUS_LAST + 1);
}
+void RecordUnsubscribeReason(content::PushUnregistrationReason reason) {
+ UMA_HISTOGRAM_ENUMERATION("PushMessaging.UnregistrationReason", reason,
+ content::PUSH_UNREGISTRATION_REASON_LAST + 1);
+}
+
blink::WebPushPermissionStatus ToPushPermission(
blink::mojom::PermissionStatus permission_status) {
switch (permission_status) {
@@ -98,8 +103,49 @@ blink::WebPushPermissionStatus ToPushPermission(
}
}
+content::PushUnregistrationStatus ToUnregisterStatus(
+ InstanceID::Result result) {
+ switch (result) {
+ case InstanceID::SUCCESS:
+ return content::PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED;
+ case InstanceID::INVALID_PARAMETER:
+ case InstanceID::DISABLED:
+ case InstanceID::SERVER_ERROR:
+ case InstanceID::UNKNOWN_ERROR:
+ return content::PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR;
+ case InstanceID::ASYNC_OPERATION_PENDING:
+ case InstanceID::NETWORK_ERROR:
+ return content::PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR;
+ }
Peter Beverloo 2016/09/30 14:26:06 Most compilers will want you to return a default v
johnme 2016/09/30 17:02:09 No, default is evil! It prevents compilers from wa
+}
+
+content::PushUnregistrationStatus ToUnregisterStatus(
+ gcm::GCMClient::Result gcm_result) {
+ switch (gcm_result) {
+ case gcm::GCMClient::SUCCESS:
+ return content::PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED;
+ case gcm::GCMClient::INVALID_PARAMETER:
+ case gcm::GCMClient::GCM_DISABLED:
+ case gcm::GCMClient::SERVER_ERROR:
+ case gcm::GCMClient::UNKNOWN_ERROR:
+ return content::PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR;
+ case gcm::GCMClient::ASYNC_OPERATION_PENDING:
+ case gcm::GCMClient::NETWORK_ERROR:
+ case gcm::GCMClient::TTL_EXCEEDED:
+ return content::PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR;
+ }
+}
+
+void GCMCallbackToUnregisterCallback(
+ const content::PushMessagingService::UnregisterCallback& callback,
+ gcm::GCMClient::Result result) {
+ DCHECK(!callback.is_null());
+ callback.Run(ToUnregisterStatus(result));
+}
+
void UnregisterCallbackToClosure(const base::Closure& closure,
content::PushUnregistrationStatus status) {
+ DCHECK(!closure.is_null());
closure.Run();
}
@@ -236,8 +282,9 @@ void PushMessagingServiceImpl::OnMessage(const std::string& app_id,
PushMessagingAppIdentifier::FindByAppId(profile_, app_id);
// Drop message and unregister if app_id was unknown (maybe recently deleted).
if (app_identifier.is_null()) {
- DeliverMessageCallback(app_id, GURL::EmptyGURL(), -1, message,
- message_handled_closure,
+ DeliverMessageCallback(app_id, GURL::EmptyGURL(),
+ -1 /* kInvalidServiceWorkerRegistrationId */,
+ message, message_handled_closure,
content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID);
return;
}
@@ -287,6 +334,8 @@ void PushMessagingServiceImpl::DeliverMessageCallback(
content::PushDeliveryStatus status) {
DCHECK_GE(in_flight_message_deliveries_.count(app_id), 1u);
+ RecordDeliveryStatus(status);
+
base::Closure completion_closure =
base::Bind(&PushMessagingServiceImpl::DidHandleMessage,
weak_factory_.GetWeakPtr(), app_id, message_handled_closure);
@@ -294,6 +343,13 @@ void PushMessagingServiceImpl::DeliverMessageCallback(
// unless it is explicitly passed to another function.
base::ScopedClosureRunner completion_closure_runner(completion_closure);
+ // Dummy reason meaning this function should not automatically unsubscribe.
+ const content::PushUnregistrationReason DO_NOT_UNSUBSCRIBE =
+ content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API;
Peter Beverloo 2016/09/30 14:26:06 What about defining a PUSH_UNREGISTRATION_REASON_U
johnme 2016/09/30 17:02:10 Done.
+
+ // Whether and why automatic unsubscription is necessary.
+ content::PushUnregistrationReason unsubscribe_reason = DO_NOT_UNSUBSCRIBE;
+
// TODO(mvanouwerkerk): Show a warning in the developer console of the
// Service Worker corresponding to app_id (and/or on an internals page).
// See https://crbug.com/508516 for options.
@@ -318,17 +374,35 @@ void PushMessagingServiceImpl::DeliverMessageCallback(
#endif
break;
case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR:
+ // Do nothing, and hope the error is transient.
break;
case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID:
+ unsubscribe_reason =
+ content::PUSH_UNREGISTRATION_REASON_DELIVERY_UNKNOWN_APP_ID;
+ break;
case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED:
+ unsubscribe_reason =
+ content::PUSH_UNREGISTRATION_REASON_DELIVERY_PERMISSION_DENIED;
+ break;
case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER:
- Unsubscribe(app_id, message.sender_id,
- base::Bind(&UnregisterCallbackToClosure,
- completion_closure_runner.Release()));
+ unsubscribe_reason =
+ content::PUSH_UNREGISTRATION_REASON_DELIVERY_NO_SERVICE_WORKER;
break;
}
- RecordDeliveryStatus(status);
+ if (unsubscribe_reason != DO_NOT_UNSUBSCRIBE) {
+ PushMessagingAppIdentifier app_identifier =
+ PushMessagingAppIdentifier::FindByAppId(profile_, app_id);
+ UnsubscribeInternal(
+ unsubscribe_reason,
+ app_identifier.is_null() ? GURL::EmptyGURL() : app_identifier.origin(),
+ app_identifier.is_null()
+ ? -1 /* kInvalidServiceWorkerRegistrationId */
+ : app_identifier.service_worker_registration_id(),
+ app_id, message.sender_id,
+ base::Bind(&UnregisterCallbackToClosure,
+ completion_closure_runner.Release()));
+ }
}
void PushMessagingServiceImpl::DidHandleMessage(
@@ -614,19 +688,54 @@ void PushMessagingServiceImpl::Unsubscribe(
PushMessagingAppIdentifier app_identifier =
PushMessagingAppIdentifier::FindByServiceWorker(
profile_, requesting_origin, service_worker_registration_id);
- if (app_identifier.is_null()) {
- callback.Run(
- content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED);
+
+ UnsubscribeInternal(
+ content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, requesting_origin,
+ service_worker_registration_id,
+ app_identifier.is_null() ? std::string() : app_identifier.app_id(),
+ sender_id, callback);
+}
+
+void PushMessagingServiceImpl::UnsubscribeInternal(
+ content::PushUnregistrationReason reason,
+ const GURL& origin,
+ int64_t service_worker_registration_id,
+ const std::string& app_id,
+ const std::string& sender_id,
+ const content::PushMessagingService::UnregisterCallback& callback) {
+ DCHECK(!app_id.empty() || (!origin.is_empty() &&
+ service_worker_registration_id !=
+ -1 /* kInvalidServiceWorkerRegistrationId */))
+ << "Need an app_id and/or origin+service_worker_registration_id";
+
+ RecordUnsubscribeReason(reason);
+
+ if (origin.is_empty() ||
+ service_worker_registration_id ==
+ -1 /* kInvalidServiceWorkerRegistrationId */) {
+ // Can't clear Service Worker database.
+ DidClearPushSubscriptionId(reason, app_id, sender_id, callback);
return;
}
-
- Unsubscribe(app_identifier.app_id(), sender_id, callback);
+ ClearPushSubscriptionId(
+ profile_, origin, service_worker_registration_id,
+ base::Bind(&PushMessagingServiceImpl::DidClearPushSubscriptionId,
+ weak_factory_.GetWeakPtr(), reason, app_id, sender_id,
+ callback));
}
-void PushMessagingServiceImpl::Unsubscribe(
+void PushMessagingServiceImpl::DidClearPushSubscriptionId(
+ content::PushUnregistrationReason reason,
const std::string& app_id,
const std::string& sender_id,
const content::PushMessagingService::UnregisterCallback& callback) {
Peter Beverloo 2016/09/30 14:26:06 Specific to UnregisterCallback, since this is the
Peter Beverloo 2016/09/30 14:26:06 We probably want to have a `using` statement in th
johnme 2016/09/30 17:02:10 I just removed all occurrences of (content::)?Push
johnme 2016/09/30 17:02:10 I just removed all occurrences of (content::)?Push
+ if (app_id.empty()) {
+ // There's nothing more we can do.
Peter Beverloo 2016/09/30 14:26:06 // We cannot unsubscribe with the GCM Driver witho
johnme 2016/09/30 17:02:10 Done (expanded to cover PushMessagingAppIdentifier
+ callback.Run(
+ content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED);
+ return;
+ }
+
// Delete the mapping for this app_id, to guarantee that no messages get
// delivered in future (even if unregistration fails).
// TODO(johnme): Instead of deleting these app ids, store them elsewhere, and
@@ -641,10 +750,14 @@ void PushMessagingServiceImpl::Unsubscribe(
GetInstanceIDDriver()->GetInstanceID(app_id)->DeleteID(base::Bind(
&PushMessagingServiceImpl::DidDeleteID, weak_factory_.GetWeakPtr(),
app_id, was_subscribed, callback));
+
} else {
auto unregister_callback =
- base::Bind(&PushMessagingServiceImpl::DidUnsubscribe,
- weak_factory_.GetWeakPtr(), was_subscribed, callback);
+ base::Bind(&GCMCallbackToUnregisterCallback,
+ base::Bind(&PushMessagingServiceImpl::DidUnsubscribe,
+ weak_factory_.GetWeakPtr(),
+ std::string() /* app_id_if_was_instance_id */,
+ 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.
@@ -665,78 +778,33 @@ void PushMessagingServiceImpl::DidDeleteID(
bool was_subscribed,
const content::PushMessagingService::UnregisterCallback& callback,
InstanceID::Result result) {
- // DidUnsubscribeInstanceID must be run asynchronously, since it calls
+ // DidUnsubscribe must be run asynchronously when passing a non-empty
+ // |app_id_if_was_instance_id|, 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,
+ FROM_HERE, base::Bind(&PushMessagingServiceImpl::DidUnsubscribe,
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,
- InstanceID::Result result) {
- GetInstanceIDDriver()->RemoveInstanceID(app_id);
-
- 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 (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;
- }
+ callback, ToUnregisterStatus(result)));
}
void PushMessagingServiceImpl::DidUnsubscribe(
+ const std::string& app_id_if_was_instance_id,
bool was_subscribed,
const content::PushMessagingService::UnregisterCallback& callback,
- gcm::GCMClient::Result gcm_result) {
- if (was_subscribed)
- DecreasePushSubscriptionCount(1, false /* was_pending */);
+ content::PushUnregistrationStatus status) {
+ if (!app_id_if_was_instance_id.empty())
+ GetInstanceIDDriver()->RemoveInstanceID(app_id_if_was_instance_id);
DCHECK(!callback.is_null());
- if (!was_subscribed) {
+ if (was_subscribed) {
+ DecreasePushSubscriptionCount(1, false /* was_pending */);
+ callback.Run(status);
+ } else {
+ // Override status since there was no record of an existing subscription.
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;
- case gcm::GCMClient::INVALID_PARAMETER:
- case gcm::GCMClient::GCM_DISABLED:
- case gcm::GCMClient::SERVER_ERROR:
- case gcm::GCMClient::UNKNOWN_ERROR:
- callback.Run(content::PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR);
- break;
- case gcm::GCMClient::ASYNC_OPERATION_PENDING:
- case gcm::GCMClient::NETWORK_ERROR:
- case gcm::GCMClient::TTL_EXCEEDED:
- callback.Run(content::PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR);
- break;
}
}
@@ -787,38 +855,36 @@ void PushMessagingServiceImpl::OnContentSettingChanged(
app_identifier.service_worker_registration_id(),
base::Bind(
&PushMessagingServiceImpl::UnsubscribeBecausePermissionRevoked,
- weak_factory_.GetWeakPtr(), app_identifier, barrier_closure));
+ weak_factory_.GetWeakPtr(), app_identifier,
+ base::Bind(&UnregisterCallbackToClosure, barrier_closure)));
} else {
- UnsubscribeBecausePermissionRevoked(
- app_identifier, barrier_closure, "" /* sender_id */,
- true /* success */, true /* not_found */);
+ UnsubscribeInternal(
+ content::PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED,
+ app_identifier.origin(),
+ app_identifier.service_worker_registration_id(),
+ app_identifier.app_id(), std::string() /* sender_id */,
+ base::Bind(&UnregisterCallbackToClosure, barrier_closure));
}
}
}
void PushMessagingServiceImpl::UnsubscribeBecausePermissionRevoked(
const PushMessagingAppIdentifier& app_identifier,
- const base::Closure& closure,
+ const content::PushMessagingService::UnregisterCallback& callback,
const std::string& sender_id,
bool success,
bool not_found) {
- base::Closure barrier_closure = base::BarrierClosure(2, closure);
-
// 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 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,
- base::Bind(&UnregisterCallbackToClosure, barrier_closure));
-
- // Clear the associated service worker push registration id.
- ClearPushSubscriptionID(profile_, app_identifier.origin(),
- app_identifier.service_worker_registration_id(),
- barrier_closure);
+ // TODO(johnme): Auto-unregister before SW DB is cleared (crbug.com/402458).
+ UnsubscribeInternal(content::PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED,
+ app_identifier.origin(),
+ app_identifier.service_worker_registration_id(),
+ app_identifier.app_id(), sender_id, callback);
}
void PushMessagingServiceImpl::SetContentSettingChangedCallbackForTesting(

Powered by Google App Engine
This is Rietveld 408576698