[GCM] Move extension specific logic out of GCMProfileService
A new interface GCMAppHandler is introduce for app specific logic.
For extensions, ExtensionGCMAppHandler is created for both event
dispatching and extension notification handling.
BUG=343268
[email protected]
Review URL: https://codereview.chromium.org/196143003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@258235 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/api/gcm/gcm_api.h b/chrome/browser/extensions/api/gcm/gcm_api.h
index 78bdad3..07009a16 100644
--- a/chrome/browser/extensions/api/gcm/gcm_api.h
+++ b/chrome/browser/extensions/api/gcm/gcm_api.h
@@ -5,7 +5,6 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_GCM_GCM_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_GCM_GCM_API_H_
-#include "chrome/browser/services/gcm/gcm_event_router.h"
#include "chrome/common/extensions/api/gcm.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_function.h"
@@ -92,21 +91,17 @@
bool ValidateMessageData(const gcm::GCMClient::MessageData& data) const;
};
-class GcmJsEventRouter : public gcm::GCMEventRouter,
- public EventRouter::Observer {
+class GcmJsEventRouter : public EventRouter::Observer {
public:
explicit GcmJsEventRouter(Profile* profile);
virtual ~GcmJsEventRouter();
- // GCMEventRouter:
- virtual void OnMessage(
- const std::string& app_id,
- const gcm::GCMClient::IncomingMessage& message) OVERRIDE;
- virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
- virtual void OnSendError(
- const std::string& app_id,
- const gcm::GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
+ void OnMessage(const std::string& app_id,
+ const gcm::GCMClient::IncomingMessage& message);
+ void OnMessagesDeleted(const std::string& app_id);
+ void OnSendError(const std::string& app_id,
+ const gcm::GCMClient::SendErrorDetails& send_error_details);
// EventRouter::Observer:
virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE;
diff --git a/chrome/browser/extensions/api/gcm/gcm_apitest.cc b/chrome/browser/extensions/api/gcm/gcm_apitest.cc
index faf4f98f..879c1c9 100644
--- a/chrome/browser/extensions/api/gcm/gcm_apitest.cc
+++ b/chrome/browser/extensions/api/gcm/gcm_apitest.cc
@@ -5,6 +5,7 @@
#include "base/run_loop.h"
#include "chrome/browser/extensions/api/gcm/gcm_api.h"
#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_gcm_app_handler.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/services/gcm/fake_gcm_profile_service.h"
#include "chrome/browser/services/gcm/gcm_client_factory.h"
@@ -186,8 +187,8 @@
LoadTestExtension(kEventsExtension, "on_messages_deleted.html");
ASSERT_TRUE(extension);
- GcmJsEventRouter router(profile());
- router.OnMessagesDeleted(extension->id());
+ extensions::ExtensionGCMAppHandler app_handler(profile());
+ app_handler.OnMessagesDeleted(extension->id());
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
@@ -199,17 +200,17 @@
LoadTestExtension(kEventsExtension, "on_message.html");
ASSERT_TRUE(extension);
- GcmJsEventRouter router(profile());
+ extensions::ExtensionGCMAppHandler app_handler(profile());
gcm::GCMClient::IncomingMessage message;
message.data["property1"] = "value1";
message.data["property2"] = "value2";
// First message is sent without a collapse key.
- router.OnMessage(extension->id(), message);
+ app_handler.OnMessage(extension->id(), message);
// Second message carries the same data and a collapse key.
message.collapse_key = "collapseKeyValue";
- router.OnMessage(extension->id(), message);
+ app_handler.OnMessage(extension->id(), message);
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
@@ -223,27 +224,32 @@
ASSERT_TRUE(extension);
std::string total_expected_messages = "5";
- GcmJsEventRouter router(profile());
- router.OnSendError(extension->id(),
- CreateErrorDetails("error_message_1",
- gcm::GCMClient::ASYNC_OPERATION_PENDING,
- total_expected_messages));
- router.OnSendError(extension->id(),
- CreateErrorDetails("error_message_2",
- gcm::GCMClient::SERVER_ERROR,
- total_expected_messages));
- router.OnSendError(extension->id(),
- CreateErrorDetails("error_message_3",
- gcm::GCMClient::NETWORK_ERROR,
- total_expected_messages));
- router.OnSendError(extension->id(),
- CreateErrorDetails("error_message_4",
- gcm::GCMClient::UNKNOWN_ERROR,
- total_expected_messages));
- router.OnSendError(extension->id(),
- CreateErrorDetails("error_message_5",
- gcm::GCMClient::TTL_EXCEEDED,
- total_expected_messages));
+ extensions::ExtensionGCMAppHandler app_handler(profile());
+ app_handler.OnSendError(
+ extension->id(),
+ CreateErrorDetails("error_message_1",
+ gcm::GCMClient::ASYNC_OPERATION_PENDING,
+ total_expected_messages));
+ app_handler.OnSendError(
+ extension->id(),
+ CreateErrorDetails("error_message_2",
+ gcm::GCMClient::SERVER_ERROR,
+ total_expected_messages));
+ app_handler.OnSendError(
+ extension->id(),
+ CreateErrorDetails("error_message_3",
+ gcm::GCMClient::NETWORK_ERROR,
+ total_expected_messages));
+ app_handler.OnSendError(
+ extension->id(),
+ CreateErrorDetails("error_message_4",
+ gcm::GCMClient::UNKNOWN_ERROR,
+ total_expected_messages));
+ app_handler.OnSendError(
+ extension->id(),
+ CreateErrorDetails("error_message_5",
+ gcm::GCMClient::TTL_EXCEEDED,
+ total_expected_messages));
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
diff --git a/chrome/browser/extensions/extension_gcm_app_handler.cc b/chrome/browser/extensions/extension_gcm_app_handler.cc
new file mode 100644
index 0000000..3ed99a0
--- /dev/null
+++ b/chrome/browser/extensions/extension_gcm_app_handler.cc
@@ -0,0 +1,156 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_gcm_app_handler.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/services/gcm/gcm_profile_service.h"
+#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/one_shot_event.h"
+#include "extensions/common/permissions/permissions_data.h"
+
+#if !defined(OS_ANDROID)
+#include "chrome/browser/extensions/api/gcm/gcm_api.h"
+#endif
+
+namespace extensions {
+
+namespace {
+
+bool IsGCMPermissionEnabled(const Extension* extension) {
+ return PermissionsData::HasAPIPermission(extension, APIPermission::kGcm);
+}
+
+} // namespace
+
+ExtensionGCMAppHandler::ExtensionGCMAppHandler(Profile* profile)
+ : profile_(profile),
+ weak_factory_(this) {
+ // Listen to various extension related notifications.
+ registrar_.Add(this,
+ chrome::NOTIFICATION_EXTENSION_LOADED,
+ content::Source<Profile>(profile_));
+ registrar_.Add(this,
+ chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
+ content::Source<Profile>(profile_));
+ registrar_.Add(this,
+ chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
+ content::Source<Profile>(profile_));
+
+ // Register app handlers when the extension system is ready. It might be ready
+ // now.
+ ExtensionSystem::Get(profile_)->ready().Post(
+ FROM_HERE,
+ base::Bind(&ExtensionGCMAppHandler::OnExtensionsReady,
+ weak_factory_.GetWeakPtr()));
+
+#if !defined(OS_ANDROID)
+ js_event_router_.reset(new extensions::GcmJsEventRouter(profile_));
+#endif
+}
+
+ExtensionGCMAppHandler::~ExtensionGCMAppHandler() {
+ const ExtensionSet& enabled_extensions =
+ ExtensionRegistry::Get(profile_)->enabled_extensions();
+ for (ExtensionSet::const_iterator extension = enabled_extensions.begin();
+ extension != enabled_extensions.end();
+ ++extension) {
+ if (IsGCMPermissionEnabled(extension->get()))
+ GetGCMProfileService()->RemoveAppHandler((*extension)->id());
+ }
+}
+
+void ExtensionGCMAppHandler::ShutdownHandler() {
+#if !defined(OS_ANDROID)
+ js_event_router_.reset();
+#endif
+}
+
+void ExtensionGCMAppHandler::OnMessage(
+ const std::string& app_id,
+ const gcm::GCMClient::IncomingMessage& message) {
+#if !defined(OS_ANDROID)
+ js_event_router_->OnMessage(app_id, message);
+#endif
+}
+
+void ExtensionGCMAppHandler::OnMessagesDeleted(const std::string& app_id) {
+#if !defined(OS_ANDROID)
+ js_event_router_->OnMessagesDeleted(app_id);
+#endif
+}
+
+void ExtensionGCMAppHandler::OnSendError(
+ const std::string& app_id,
+ const gcm::GCMClient::SendErrorDetails& send_error_details) {
+#if !defined(OS_ANDROID)
+ js_event_router_->OnSendError(app_id, send_error_details);
+#endif
+}
+
+void ExtensionGCMAppHandler::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ switch (type) {
+ case chrome:: NOTIFICATION_EXTENSION_LOADED: {
+ const Extension* extension = content::Details<Extension>(details).ptr();
+ if (IsGCMPermissionEnabled(extension))
+ GetGCMProfileService()->AddAppHandler(extension->id(), this);
+ break;
+ }
+ case chrome:: NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
+ const Extension* extension =
+ content::Details<UnloadedExtensionInfo>(details)->extension;
+ if (IsGCMPermissionEnabled(extension))
+ GetGCMProfileService()->RemoveAppHandler(extension->id());
+ break;
+ }
+ case chrome:: NOTIFICATION_EXTENSION_UNINSTALLED: {
+ const Extension* extension = content::Details<Extension>(details).ptr();
+ if (IsGCMPermissionEnabled(extension)) {
+ GetGCMProfileService()->Unregister(
+ extension->id(),
+ base::Bind(&ExtensionGCMAppHandler::OnUnregisterCompleted,
+ weak_factory_.GetWeakPtr(),
+ extension->id()));
+ GetGCMProfileService()->RemoveAppHandler(extension->id());
+ }
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+}
+
+gcm::GCMProfileService* ExtensionGCMAppHandler::GetGCMProfileService() const {
+ return gcm::GCMProfileServiceFactory::GetForProfile(profile_);
+}
+
+void ExtensionGCMAppHandler::OnExtensionsReady() {
+ // Register app handler for those loaded extensions that use GCM.
+ const ExtensionSet& enabled_extensions =
+ ExtensionRegistry::Get(profile_)->enabled_extensions();
+ for (ExtensionSet::const_iterator extension = enabled_extensions.begin();
+ extension != enabled_extensions.end();
+ ++extension) {
+ if (IsGCMPermissionEnabled(extension->get()))
+ GetGCMProfileService()->AddAppHandler((*extension)->id(), this);
+ }
+}
+
+void ExtensionGCMAppHandler::OnUnregisterCompleted(
+ const std::string& app_id, gcm::GCMClient::Result result) {
+ // Nothing to do.
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/extension_gcm_app_handler.h b/chrome/browser/extensions/extension_gcm_app_handler.h
new file mode 100644
index 0000000..5edf0a9f
--- /dev/null
+++ b/chrome/browser/extensions/extension_gcm_app_handler.h
@@ -0,0 +1,67 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_GCM_APP_HANDLER_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_GCM_APP_HANDLER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/services/gcm/gcm_app_handler.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "extensions/browser/event_router.h"
+#include "google_apis/gcm/gcm_client.h"
+
+class Profile;
+namespace gcm {
+class GCMProfileService;
+}
+
+namespace extensions {
+
+class GcmJsEventRouter;
+
+// Defines the interface to provide handling logic for a given app.
+class ExtensionGCMAppHandler : public gcm::GCMAppHandler,
+ public content::NotificationObserver {
+ public:
+ explicit ExtensionGCMAppHandler(Profile* profile);
+ virtual ~ExtensionGCMAppHandler();
+
+ // Overridden from gcm::GCMAppHandler:
+ virtual void ShutdownHandler() OVERRIDE;
+ virtual void OnMessage(
+ const std::string& app_id,
+ const gcm::GCMClient::IncomingMessage& message) OVERRIDE;
+ virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
+ virtual void OnSendError(
+ const std::string& app_id,
+ const gcm::GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
+
+ private:
+ // Overridden from content::NotificationObserver:
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ gcm::GCMProfileService* GetGCMProfileService() const;
+ void OnExtensionsReady();
+ void OnUnregisterCompleted(const std::string& app_id,
+ gcm::GCMClient::Result result);
+
+ Profile* profile_;
+ content::NotificationRegistrar registrar_;
+
+#if !defined(OS_ANDROID)
+ scoped_ptr<extensions::GcmJsEventRouter> js_event_router_;
+#endif
+
+ base::WeakPtrFactory<ExtensionGCMAppHandler> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionGCMAppHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_GCM_APP_HANDLER_H_
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc
index 833a1ce..87b6623 100644
--- a/chrome/browser/extensions/extension_sync_service.cc
+++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -11,6 +11,7 @@
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/extensions/app_sync_data.h"
#include "chrome/browser/extensions/extension_error_ui.h"
+#include "chrome/browser/extensions/extension_gcm_app_handler.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_sync_data.h"
#include "chrome/browser/extensions/extension_sync_service_factory.h"
@@ -33,6 +34,7 @@
using extensions::ExtensionPrefs;
using extensions::ExtensionRegistry;
using extensions::FeatureSwitch;
+using extensions::ExtensionGCMAppHandler;
ExtensionSyncService::ExtensionSyncService(Profile* profile,
ExtensionPrefs* extension_prefs,
@@ -51,7 +53,8 @@
make_scoped_ptr(new browser_sync::SyncPrefs(
extension_prefs_->pref_service())),
&extension_sync_bundle_,
- syncer::EXTENSIONS) {
+ syncer::EXTENSIONS),
+ extesnion_gcm_app_handler_(new ExtensionGCMAppHandler(profile)) {
SetSyncStartFlare(sync_start_util::GetFlareForSyncableService(
profile_->GetPath()));
diff --git a/chrome/browser/extensions/extension_sync_service.h b/chrome/browser/extensions/extension_sync_service.h
index e5e3af7..e8a8fe5 100644
--- a/chrome/browser/extensions/extension_sync_service.h
+++ b/chrome/browser/extensions/extension_sync_service.h
@@ -29,6 +29,7 @@
namespace extensions {
class AppSyncData;
+class ExtensionGCMAppHandler;
class ExtensionPrefs;
class ExtensionSyncData;
} // namespace extensions
@@ -151,6 +152,9 @@
// asynchronously via MergeDataAndStartSyncing as soon as possible.
syncer::SyncableService::StartSyncFlare flare_;
+ // Used to provide the extension specific logic for GCMProfileService.
+ scoped_ptr<extensions::ExtensionGCMAppHandler> extesnion_gcm_app_handler_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionSyncService);
};