Make GCMProfileService own GCMDriver, instead of deriving from it

Also remove several tests related to testing on neutral channel signals.
Replacement tests will be added when we switch to starting and stopping
GCM on demand in the future patch.

BUG=356716
TEST=tests updated
[email protected],[email protected],[email protected]

Review URL: https://codereview.chromium.org/286213003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271832 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/api/gcm/gcm_api.cc b/chrome/browser/extensions/api/gcm/gcm_api.cc
index 9134c5e..6fd12ec 100644
--- a/chrome/browser/extensions/api/gcm/gcm_api.cc
+++ b/chrome/browser/extensions/api/gcm/gcm_api.cc
@@ -13,9 +13,11 @@
 #include "base/strings/string_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/services/gcm/gcm_driver.h"
 #include "chrome/browser/services/gcm/gcm_profile_service.h"
 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
 #include "chrome/common/extensions/api/gcm.h"
+#include "extensions/browser/event_router.h"
 #include "extensions/common/extension.h"
 
 namespace {
@@ -28,6 +30,7 @@
 // Error messages.
 const char kInvalidParameter[] =
     "Function was called with invalid parameters.";
+const char kGCMDisabled[] = "GCM is currently disabled.";
 const char kNotSignedIn[] = "Profile was not signed in.";
 const char kAsyncOperationPending[] =
     "Asynchronous operation is pending.";
@@ -42,6 +45,8 @@
       return "";
     case gcm::GCMClient::INVALID_PARAMETER:
       return kInvalidParameter;
+    case gcm::GCMClient::GCM_DISABLED:
+      return kGCMDisabled;
     case gcm::GCMClient::NOT_SIGNED_IN:
       return kNotSignedIn;
     case gcm::GCMClient::ASYNC_OPERATION_PENDING:
@@ -97,9 +102,9 @@
       gcm::GCMProfileService::ALWAYS_DISABLED;
 }
 
-gcm::GCMProfileService* GcmApiFunction::GCMProfileService() const {
+gcm::GCMDriver* GcmApiFunction::GetGCMDriver() const {
   return gcm::GCMProfileServiceFactory::GetForProfile(
-      Profile::FromBrowserContext(browser_context()));
+      Profile::FromBrowserContext(browser_context()))->driver();
 }
 
 GcmRegisterFunction::GcmRegisterFunction() {}
@@ -111,7 +116,7 @@
       api::gcm::Register::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  GCMProfileService()->Register(
+  GetGCMDriver()->Register(
       GetExtension()->id(),
       params->sender_ids,
       base::Bind(&GcmRegisterFunction::CompleteFunctionWithResult, this));
@@ -134,7 +139,7 @@
 bool GcmUnregisterFunction::DoWork() {
   UMA_HISTOGRAM_BOOLEAN("GCM.APICallUnregister", true);
 
-  GCMProfileService()->Unregister(
+  GetGCMDriver()->Unregister(
       GetExtension()->id(),
       base::Bind(&GcmUnregisterFunction::CompleteFunctionWithResult, this));
 
@@ -164,7 +169,7 @@
   if (params->message.time_to_live.get())
     outgoing_message.time_to_live = *params->message.time_to_live;
 
-  GCMProfileService()->Send(
+  GetGCMDriver()->Send(
       GetExtension()->id(),
       params->message.destination_id,
       outgoing_message,
@@ -199,19 +204,9 @@
 }
 
 GcmJsEventRouter::GcmJsEventRouter(Profile* profile) : profile_(profile) {
-  EventRouter* event_router = EventRouter::Get(profile_);
-  if (!event_router)
-    return;
-
-  event_router->RegisterObserver(this, api::gcm::OnMessage::kEventName);
-  event_router->RegisterObserver(this, api::gcm::OnMessagesDeleted::kEventName);
-  event_router->RegisterObserver(this, api::gcm::OnSendError::kEventName);
 }
 
 GcmJsEventRouter::~GcmJsEventRouter() {
-  EventRouter* event_router = EventRouter::Get(profile_);
-  if (event_router)
-    event_router->UnregisterObserver(this);
 }
 
 void GcmJsEventRouter::OnMessage(
@@ -252,12 +247,4 @@
   EventRouter::Get(profile_)->DispatchEventToExtension(app_id, event.Pass());
 }
 
-void GcmJsEventRouter::OnListenerAdded(const EventListenerInfo& details) {
-  if (gcm::GCMProfileService::GetGCMEnabledState(profile_) ==
-      gcm::GCMProfileService::ALWAYS_DISABLED) {
-    return;
-  }
-  gcm::GCMProfileServiceFactory::GetForProfile(profile_)->Start();
-}
-
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/gcm/gcm_api.h b/chrome/browser/extensions/api/gcm/gcm_api.h
index e5447c0..4a13a2fd 100644
--- a/chrome/browser/extensions/api/gcm/gcm_api.h
+++ b/chrome/browser/extensions/api/gcm/gcm_api.h
@@ -6,11 +6,11 @@
 #define CHROME_BROWSER_EXTENSIONS_API_GCM_GCM_API_H_
 
 #include "chrome/common/extensions/api/gcm.h"
-#include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_function.h"
 #include "google_apis/gcm/gcm_client.h"
 
 namespace gcm {
+class GCMDriver;
 class GCMProfileService;
 }  // namespace gcm
 
@@ -34,7 +34,7 @@
   // Checks that the GCM API is enabled.
   bool IsGcmApiEnabled() const;
 
-  gcm::GCMProfileService* GCMProfileService() const;
+  gcm::GCMDriver* GetGCMDriver() const;
 };
 
 class GcmRegisterFunction : public GcmApiFunction {
@@ -91,7 +91,7 @@
   bool ValidateMessageData(const gcm::GCMClient::MessageData& data) const;
 };
 
-class GcmJsEventRouter : public EventRouter::Observer {
+class GcmJsEventRouter {
  public:
   explicit GcmJsEventRouter(Profile* profile);
 
@@ -103,9 +103,6 @@
   void OnSendError(const std::string& app_id,
                    const gcm::GCMClient::SendErrorDetails& send_error_details);
 
-  // EventRouter::Observer:
-  virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE;
-
  private:
   // The application we route the event to is running in context of the
   // |profile_| and the latter outlives the event router.
diff --git a/chrome/browser/extensions/api/gcm/gcm_apitest.cc b/chrome/browser/extensions/api/gcm/gcm_apitest.cc
index 70212ab4..46b02ff 100644
--- a/chrome/browser/extensions/api/gcm/gcm_apitest.cc
+++ b/chrome/browser/extensions/api/gcm/gcm_apitest.cc
@@ -13,7 +13,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/gcm_driver/gcm_client_factory.h"
 
 namespace {
 
diff --git a/chrome/browser/extensions/extension_gcm_app_handler.cc b/chrome/browser/extensions/extension_gcm_app_handler.cc
index 879a351..505271ae 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler.cc
+++ b/chrome/browser/extensions/extension_gcm_app_handler.cc
@@ -9,6 +9,7 @@
 #include "base/location.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/services/gcm/gcm_driver.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"
@@ -63,7 +64,7 @@
        extension != enabled_extensions.end();
        ++extension) {
     if (IsGCMPermissionEnabled(extension->get()))
-      GetGCMProfileService()->RemoveAppHandler((*extension)->id());
+      GetGCMDriver()->RemoveAppHandler((*extension)->id());
   }
 }
 
@@ -99,7 +100,7 @@
     content::BrowserContext* browser_context,
     const Extension* extension) {
   if (IsGCMPermissionEnabled(extension))
-    GetGCMProfileService()->AddAppHandler(extension->id(), this);
+    GetGCMDriver()->AddAppHandler(extension->id(), this);
 }
 
 void ExtensionGCMAppHandler::OnExtensionUnloaded(
@@ -107,7 +108,7 @@
     const Extension* extension,
     UnloadedExtensionInfo::Reason reason) {
   if (IsGCMPermissionEnabled(extension))
-    GetGCMProfileService()->RemoveAppHandler(extension->id());
+    GetGCMDriver()->RemoveAppHandler(extension->id());
 }
 
 void ExtensionGCMAppHandler::Observe(
@@ -117,17 +118,17 @@
   DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UNINSTALLED, type);
   const Extension* extension = content::Details<Extension>(details).ptr();
   if (IsGCMPermissionEnabled(extension)) {
-    GetGCMProfileService()->Unregister(
+    GetGCMDriver()->Unregister(
         extension->id(),
         base::Bind(&ExtensionGCMAppHandler::OnUnregisterCompleted,
                    weak_factory_.GetWeakPtr(),
                    extension->id()));
-    GetGCMProfileService()->RemoveAppHandler(extension->id());
+    GetGCMDriver()->RemoveAppHandler(extension->id());
   }
 }
 
-gcm::GCMProfileService* ExtensionGCMAppHandler::GetGCMProfileService() const {
-  return gcm::GCMProfileServiceFactory::GetForProfile(profile_);
+gcm::GCMDriver* ExtensionGCMAppHandler::GetGCMDriver() const {
+  return gcm::GCMProfileServiceFactory::GetForProfile(profile_)->driver();
 }
 
 void ExtensionGCMAppHandler::OnUnregisterCompleted(
diff --git a/chrome/browser/extensions/extension_gcm_app_handler.h b/chrome/browser/extensions/extension_gcm_app_handler.h
index 7b1f0da4..5da91b7 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler.h
+++ b/chrome/browser/extensions/extension_gcm_app_handler.h
@@ -26,6 +26,7 @@
 }
 
 namespace gcm {
+class GCMDriver;
 class GCMProfileService;
 }
 
@@ -77,7 +78,7 @@
       const Extension* extension,
       UnloadedExtensionInfo::Reason reason) OVERRIDE;
 
-  gcm::GCMProfileService* GetGCMProfileService() const;
+  gcm::GCMDriver* GetGCMDriver() const;
 
   // BrowserContextKeyedAPI implementation.
   static const char* service_name() { return "ExtensionGCMAppHandler"; }
diff --git a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
index 786f1d9..81e9c7c 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
+++ b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/services/gcm/fake_gcm_client.h"
 #include "chrome/browser/services/gcm/fake_gcm_client_factory.h"
 #include "chrome/browser/services/gcm/fake_signin_manager.h"
+#include "chrome/browser/services/gcm/gcm_driver.h"
 #include "chrome/browser/services/gcm/gcm_profile_service.h"
 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
@@ -167,7 +168,10 @@
  public:
   static KeyedService* BuildGCMProfileService(
       content::BrowserContext* context) {
-    return new gcm::GCMProfileService(static_cast<Profile*>(context));
+    return new gcm::GCMProfileService(
+        Profile::FromBrowserContext(context),
+        scoped_ptr<gcm::GCMClientFactory>(
+            new gcm::FakeGCMClientFactory(gcm::FakeGCMClient::NO_DELAY_START)));
   }
 
   ExtensionGCMAppHandlerTest()
@@ -209,15 +213,8 @@
     profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled, true);
 
     // Create GCMProfileService that talks with fake GCMClient.
-    gcm::GCMProfileService* gcm_profile_service =
-        static_cast<gcm::GCMProfileService*>(
-            gcm::GCMProfileServiceFactory::GetInstance()->
-                SetTestingFactoryAndUse(
-                    profile(),
-                    &ExtensionGCMAppHandlerTest::BuildGCMProfileService));
-    scoped_ptr<gcm::GCMClientFactory> gcm_client_factory(
-        new gcm::FakeGCMClientFactory(gcm::FakeGCMClient::NO_DELAY_START));
-    gcm_profile_service->Initialize(gcm_client_factory.Pass());
+    gcm::GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+        profile(), &ExtensionGCMAppHandlerTest::BuildGCMProfileService);
 
     // Create a fake version of ExtensionGCMAppHandler.
     gcm_app_handler_.reset(new FakeExtensionGCMAppHandler(profile(), &waiter_));
@@ -288,7 +285,7 @@
 
   void Register(const std::string& app_id,
                 const std::vector<std::string>& sender_ids) {
-    GetGCMProfileService()->Register(
+    GetGCMDriver()->Register(
         app_id,
         sender_ids,
         base::Bind(&ExtensionGCMAppHandlerTest::RegisterCompleted,
@@ -301,12 +298,12 @@
     waiter_.SignalCompleted();
   }
 
-  gcm::GCMProfileService* GetGCMProfileService() const {
-    return gcm::GCMProfileServiceFactory::GetForProfile(profile());
+  gcm::GCMDriver* GetGCMDriver() const {
+    return gcm::GCMProfileServiceFactory::GetForProfile(profile())->driver();
   }
 
   bool HasAppHandlers(const std::string& app_id) const {
-    return GetGCMProfileService()->app_handlers().count(app_id);
+    return GetGCMDriver()->app_handlers().count(app_id);
   }
 
   Profile* profile() const { return profile_.get(); }
diff --git a/chrome/browser/invalidation/gcm_invalidation_bridge.h b/chrome/browser/invalidation/gcm_invalidation_bridge.h
index f020470..e8ad7efd 100644
--- a/chrome/browser/invalidation/gcm_invalidation_bridge.h
+++ b/chrome/browser/invalidation/gcm_invalidation_bridge.h
@@ -37,7 +37,7 @@
  public:
   class Core;
 
-  GCMInvalidationBridge(gcm::GCMDriver* gcm_service,
+  GCMInvalidationBridge(gcm::GCMDriver* gcm_driver,
                         IdentityProvider* identity_provider);
   virtual ~GCMInvalidationBridge();
 
diff --git a/chrome/browser/invalidation/gcm_invalidation_bridge_unittest.cc b/chrome/browser/invalidation/gcm_invalidation_bridge_unittest.cc
index 9b4b6b1..a16ddee4 100644
--- a/chrome/browser/invalidation/gcm_invalidation_bridge_unittest.cc
+++ b/chrome/browser/invalidation/gcm_invalidation_bridge_unittest.cc
@@ -4,8 +4,7 @@
 
 #include "base/run_loop.h"
 #include "chrome/browser/invalidation/gcm_invalidation_bridge.h"
-#include "chrome/browser/services/gcm/gcm_profile_service.h"
-#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
+#include "chrome/browser/services/gcm/gcm_driver.h"
 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
@@ -18,17 +17,12 @@
 namespace invalidation {
 namespace {
 
-// Implementation of GCMProfileService::Register that always succeeds with the
-// same registrationId.
-class FakeGCMProfileService : public gcm::GCMProfileService {
+// Implementation of GCMDriver::Register that always succeeds with the same
+// registrationId.
+class FakeGCMDriver : public gcm::GCMDriver {
  public:
-  static KeyedService* Build(content::BrowserContext* context) {
-    Profile* profile = static_cast<Profile*>(context);
-    return new FakeGCMProfileService(profile);
-  }
-
-  explicit FakeGCMProfileService(Profile* profile)
-      : gcm::GCMProfileService(profile) {}
+  FakeGCMDriver() {}
+  virtual ~FakeGCMDriver() {}
 
   virtual void Register(const std::string& app_id,
                         const std::vector<std::string>& sender_ids,
@@ -40,7 +34,7 @@
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(FakeGCMProfileService);
+  DISALLOW_COPY_AND_ASSIGN(FakeGCMDriver);
 };
 
 class GCMInvalidationBridgeTest : public ::testing::Test {
@@ -53,20 +47,16 @@
     TestingProfile::Builder builder;
     builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
                               &BuildAutoIssuingFakeProfileOAuth2TokenService);
-    builder.AddTestingFactory(gcm::GCMProfileServiceFactory::GetInstance(),
-                              &FakeGCMProfileService::Build);
     profile_ = builder.Build();
 
     FakeProfileOAuth2TokenService* token_service =
         (FakeProfileOAuth2TokenService*)
         ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
     token_service->IssueRefreshTokenForUser("", "fake_refresh_token");
-    gcm_profile_service_ =
-        (FakeGCMProfileService*)gcm::GCMProfileServiceFactory::GetForProfile(
-            profile_.get());
+    gcm_driver_.reset(new FakeGCMDriver());
 
     identity_provider_.reset(new FakeIdentityProvider(token_service));
-    bridge_.reset(new GCMInvalidationBridge(gcm_profile_service_,
+    bridge_.reset(new GCMInvalidationBridge(gcm_driver_.get(),
                                             identity_provider_.get()));
 
     delegate_ = bridge_->CreateDelegate();
@@ -89,7 +79,7 @@
 
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<Profile> profile_;
-  FakeGCMProfileService* gcm_profile_service_;
+  scoped_ptr<gcm::GCMDriver> gcm_driver_;
   scoped_ptr<FakeIdentityProvider> identity_provider_;
 
   std::vector<std::string> issued_tokens_;
diff --git a/chrome/browser/invalidation/invalidation_service_factory.cc b/chrome/browser/invalidation/invalidation_service_factory.cc
index a780143..76797b2f 100644
--- a/chrome/browser/invalidation/invalidation_service_factory.cc
+++ b/chrome/browser/invalidation/invalidation_service_factory.cc
@@ -125,7 +125,7 @@
       identity_provider.Pass(),
       scoped_ptr<TiclSettingsProvider>(
           new TiclProfileSettingsProvider(profile)),
-      gcm::GCMProfileServiceFactory::GetForProfile(profile),
+      gcm::GCMProfileServiceFactory::GetForProfile(profile)->driver(),
       profile->GetRequestContext());
   service->Init(scoped_ptr<syncer::InvalidationStateTracker>(
       new InvalidatorStorage(profile->GetPrefs())));
diff --git a/chrome/browser/invalidation/ticl_invalidation_service.h b/chrome/browser/invalidation/ticl_invalidation_service.h
index 07b8e6f1..ebb63a2 100644
--- a/chrome/browser/invalidation/ticl_invalidation_service.h
+++ b/chrome/browser/invalidation/ticl_invalidation_service.h
@@ -62,7 +62,7 @@
   TiclInvalidationService(
       scoped_ptr<IdentityProvider> identity_provider,
       scoped_ptr<TiclSettingsProvider> settings_provider,
-      gcm::GCMDriver* gcm_service,
+      gcm::GCMDriver* gcm_driver,
       const scoped_refptr<net::URLRequestContextGetter>& request_context);
   virtual ~TiclInvalidationService();
 
diff --git a/chrome/browser/invalidation/ticl_invalidation_service_unittest.cc b/chrome/browser/invalidation/ticl_invalidation_service_unittest.cc
index bd838c5b..9259199 100644
--- a/chrome/browser/invalidation/ticl_invalidation_service_unittest.cc
+++ b/chrome/browser/invalidation/ticl_invalidation_service_unittest.cc
@@ -37,16 +37,9 @@
 
 class FakeGCMDriver : public gcm::GCMDriver {
  public:
-  explicit FakeGCMDriver(OAuth2TokenService* token_service);
+  FakeGCMDriver();
   virtual ~FakeGCMDriver();
 
- protected:
-  // gcm::GCMDriver:
-  virtual bool ShouldStartAutomatically() const OVERRIDE;
-  virtual base::FilePath GetStorePath() const OVERRIDE;
-  virtual scoped_refptr<net::URLRequestContextGetter>
-      GetURLRequestContextGetter() const OVERRIDE;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(FakeGCMDriver);
 };
@@ -61,27 +54,12 @@
   return false;
 }
 
-FakeGCMDriver::FakeGCMDriver(OAuth2TokenService* token_service)
-    : GCMDriver(scoped_ptr<IdentityProvider>(
-          new FakeIdentityProvider(token_service))) {
+FakeGCMDriver::FakeGCMDriver() {
 }
 
 FakeGCMDriver::~FakeGCMDriver() {
 }
 
-bool FakeGCMDriver::ShouldStartAutomatically() const {
-  return false;
-}
-
-base::FilePath FakeGCMDriver::GetStorePath() const {
-  return base::FilePath();
-}
-
-scoped_refptr<net::URLRequestContextGetter>
-FakeGCMDriver::GetURLRequestContextGetter() const {
-  return NULL;
-}
-
 }  // namespace
 
 class TiclInvalidationServiceTestDelegate {
@@ -98,11 +76,11 @@
   }
 
   void CreateUninitializedInvalidationService() {
-    gcm_service_.reset(new FakeGCMDriver(&token_service_));
+    gcm_driver_.reset(new FakeGCMDriver());
     invalidation_service_.reset(new TiclInvalidationService(
         scoped_ptr<IdentityProvider>(new FakeIdentityProvider(&token_service_)),
         scoped_ptr<TiclSettingsProvider>(new FakeTiclSettingsProvider),
-        gcm_service_.get(),
+        gcm_driver_.get(),
         NULL));
   }
 
@@ -132,7 +110,7 @@
   }
 
   FakeOAuth2TokenService token_service_;
-  scoped_ptr<gcm::GCMDriver> gcm_service_;
+  scoped_ptr<gcm::GCMDriver> gcm_driver_;
   syncer::FakeInvalidator* fake_invalidator_;  // Owned by the service.
 
   scoped_ptr<TiclInvalidationService> invalidation_service_;
diff --git a/chrome/browser/invalidation/ticl_profile_settings_provider_unittest.cc b/chrome/browser/invalidation/ticl_profile_settings_provider_unittest.cc
index 179760b8..d7fb24b 100644
--- a/chrome/browser/invalidation/ticl_profile_settings_provider_unittest.cc
+++ b/chrome/browser/invalidation/ticl_profile_settings_provider_unittest.cc
@@ -56,7 +56,7 @@
       scoped_ptr<IdentityProvider>(new FakeIdentityProvider(&token_service_)),
       scoped_ptr<TiclSettingsProvider>(
           new TiclProfileSettingsProvider(&profile_)),
-      gcm::GCMProfileServiceFactory::GetForProfile(&profile_),
+      gcm::GCMProfileServiceFactory::GetForProfile(&profile_)->driver(),
       profile_.GetRequestContext()));
   invalidation_service_->Init(scoped_ptr<syncer::InvalidationStateTracker>(
       new syncer::FakeInvalidationStateTracker));
diff --git a/chrome/browser/services/gcm/fake_gcm_profile_service.cc b/chrome/browser/services/gcm/fake_gcm_profile_service.cc
index e2b32e63..b4c7eee 100644
--- a/chrome/browser/services/gcm/fake_gcm_profile_service.cc
+++ b/chrome/browser/services/gcm/fake_gcm_profile_service.cc
@@ -8,38 +8,111 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/services/gcm/fake_gcm_client_factory.h"
 #include "content/public/browser/browser_context.h"
 
 namespace gcm {
 
-// static
-KeyedService* FakeGCMProfileService::Build(content::BrowserContext* context) {
-  Profile* profile = static_cast<Profile*>(context);
-  return new FakeGCMProfileService(profile);
+namespace {
+
+class FakeGCMDriver : public GCMDriver {
+ public:
+  explicit FakeGCMDriver(FakeGCMProfileService* service);
+  virtual ~FakeGCMDriver();
+
+  // GCMDriver overrides.
+  virtual void Shutdown() OVERRIDE;
+  virtual void AddAppHandler(const std::string& app_id,
+                             GCMAppHandler* handler) OVERRIDE;
+  virtual void RemoveAppHandler(const std::string& app_id) OVERRIDE;
+  virtual void Register(const std::string& app_id,
+                        const std::vector<std::string>& sender_ids,
+                        const RegisterCallback& callback) OVERRIDE;
+  virtual void Unregister(const std::string& app_id,
+                          const UnregisterCallback& callback) OVERRIDE;
+  virtual void Send(const std::string& app_id,
+                    const std::string& receiver_id,
+                    const GCMClient::OutgoingMessage& message,
+                    const SendCallback& callback) OVERRIDE;
+
+ private:
+  FakeGCMProfileService* service_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeGCMDriver);
+};
+
+FakeGCMDriver::FakeGCMDriver(FakeGCMProfileService* service)
+    : service_(service) {
 }
 
-FakeGCMProfileService::FakeGCMProfileService(Profile* profile)
-    : GCMProfileService(profile),
-      collect_(false) {}
+FakeGCMDriver::~FakeGCMDriver() {
+}
 
-FakeGCMProfileService::~FakeGCMProfileService() {}
+void FakeGCMDriver::Shutdown() {
+}
 
-void FakeGCMProfileService::Register(const std::string& app_id,
-                                     const std::vector<std::string>& sender_ids,
-                                     const RegisterCallback& callback) {
+void FakeGCMDriver::AddAppHandler(const std::string& app_id,
+                                  GCMAppHandler* handler) {
+}
+
+void FakeGCMDriver::RemoveAppHandler(const std::string& app_id) {
+}
+
+void FakeGCMDriver::Register(const std::string& app_id,
+                             const std::vector<std::string>& sender_ids,
+                             const RegisterCallback& callback) {
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
       base::Bind(&FakeGCMProfileService::RegisterFinished,
-                 base::Unretained(this),
+                 base::Unretained(service_),
                  app_id,
                  sender_ids,
                  callback));
 }
 
+void FakeGCMDriver::Unregister(const std::string& app_id,
+                               const UnregisterCallback& callback) {
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(
+          &FakeGCMProfileService::UnregisterFinished,
+          base::Unretained(service_),
+          app_id,
+          callback));
+}
+
+void FakeGCMDriver::Send(const std::string& app_id,
+                         const std::string& receiver_id,
+                         const GCMClient::OutgoingMessage& message,
+                         const SendCallback& callback) {
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&FakeGCMProfileService::SendFinished,
+                 base::Unretained(service_),
+                 app_id,
+                 receiver_id,
+                 message,
+                 callback));
+}
+
+}  // namespace
+
+// static
+KeyedService* FakeGCMProfileService::Build(content::BrowserContext* context) {
+  Profile* profile = static_cast<Profile*>(context);
+  FakeGCMProfileService* service = new FakeGCMProfileService(profile);
+  service->SetDriverForTesting(new FakeGCMDriver(service));
+  return service;
+}
+
+FakeGCMProfileService::FakeGCMProfileService(Profile* profile)
+    : collect_(false) {}
+
+FakeGCMProfileService::~FakeGCMProfileService() {}
+
 void FakeGCMProfileService::RegisterFinished(
     const std::string& app_id,
     const std::vector<std::string>& sender_ids,
-    const RegisterCallback& callback) {
+    const GCMDriver::RegisterCallback& callback) {
   if (collect_) {
     last_registered_app_id_ = app_id;
     last_registered_sender_ids_ = sender_ids;
@@ -48,31 +121,23 @@
   callback.Run(base::UintToString(sender_ids.size()), GCMClient::SUCCESS);
 }
 
-void FakeGCMProfileService::Unregister(const std::string& app_id,
-                                       const UnregisterCallback& callback) {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(callback, GetNextExpectedUnregisterResponse()));
-}
+void FakeGCMProfileService::UnregisterFinished(
+    const std::string& app_id,
+    const GCMDriver::UnregisterCallback& callback) {
+  GCMClient::Result result = GCMClient::SUCCESS;
+  if (!unregister_responses_.empty()) {
+    result = unregister_responses_.front();
+    unregister_responses_.pop_front();
+  }
 
-void FakeGCMProfileService::Send(const std::string& app_id,
-                                 const std::string& receiver_id,
-                                 const GCMClient::OutgoingMessage& message,
-                                 const SendCallback& callback) {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&FakeGCMProfileService::SendFinished,
-                 base::Unretained(this),
-                 app_id,
-                 receiver_id,
-                 message,
-                 callback));
+  callback.Run(result);
 }
 
 void FakeGCMProfileService::SendFinished(
     const std::string& app_id,
     const std::string& receiver_id,
     const GCMClient::OutgoingMessage& message,
-    const SendCallback& callback) {
+    const GCMDriver::SendCallback& callback) {
   if (collect_) {
     last_sent_message_ = message;
     last_receiver_id_ = receiver_id;
@@ -86,12 +151,4 @@
   unregister_responses_.push_back(result);
 }
 
-GCMClient::Result FakeGCMProfileService::GetNextExpectedUnregisterResponse() {
-  if (unregister_responses_.empty())
-    return GCMClient::SUCCESS;
-  GCMClient::Result response = *unregister_responses_.begin();
-  unregister_responses_.erase(unregister_responses_.begin());
-  return response;
-}
-
 }  // namespace gcm
diff --git a/chrome/browser/services/gcm/fake_gcm_profile_service.h b/chrome/browser/services/gcm/fake_gcm_profile_service.h
index 119a91e..ee1fe13 100644
--- a/chrome/browser/services/gcm/fake_gcm_profile_service.h
+++ b/chrome/browser/services/gcm/fake_gcm_profile_service.h
@@ -5,6 +5,10 @@
 #ifndef CHROME_BROWSER_SERVICES_GCM_FAKE_GCM_PROFILE_SERVICE_H_
 #define CHROME_BROWSER_SERVICES_GCM_FAKE_GCM_PROFILE_SERVICE_H_
 
+#include <list>
+#include <vector>
+
+#include "chrome/browser/services/gcm/gcm_driver.h"
 #include "chrome/browser/services/gcm/gcm_profile_service.h"
 
 namespace content {
@@ -23,28 +27,17 @@
   explicit FakeGCMProfileService(Profile* profile);
   virtual ~FakeGCMProfileService();
 
-  // GCMProfileService overrides.
-  virtual void Register(const std::string& app_id,
-                        const std::vector<std::string>& sender_ids,
-                        const RegisterCallback& callback) OVERRIDE;
-  virtual void Unregister(const std::string& app_id,
-                          const UnregisterCallback& callback) OVERRIDE;
-  virtual void Send(const std::string& app_id,
-                    const std::string& receiver_id,
-                    const GCMClient::OutgoingMessage& message,
-                    const SendCallback& callback) OVERRIDE;
-
   void RegisterFinished(const std::string& app_id,
                         const std::vector<std::string>& sender_ids,
-                        const RegisterCallback& callback);
-
+                        const GCMDriver::RegisterCallback& callback);
+  void UnregisterFinished(const std::string& app_id,
+                          const GCMDriver::UnregisterCallback& callback);
   void SendFinished(const std::string& app_id,
                     const std::string& receiver_id,
                     const GCMClient::OutgoingMessage& message,
-                    const SendCallback& callback);
+                    const GCMDriver::SendCallback& callback);
 
   void AddExpectedUnregisterResponse(GCMClient::Result result);
-  GCMClient::Result GetNextExpectedUnregisterResponse();
 
   const GCMClient::OutgoingMessage& last_sent_message() const {
     return last_sent_message_;
@@ -72,7 +65,7 @@
   bool collect_;
   std::string last_registered_app_id_;
   std::vector<std::string> last_registered_sender_ids_;
-  std::vector<GCMClient::Result> unregister_responses_;
+  std::list<GCMClient::Result> unregister_responses_;
   GCMClient::OutgoingMessage last_sent_message_;
   std::string last_receiver_id_;
 
diff --git a/chrome/browser/services/gcm/gcm_driver.cc b/chrome/browser/services/gcm/gcm_driver.cc
index f8bcf72..a855a18 100644
--- a/chrome/browser/services/gcm/gcm_driver.cc
+++ b/chrome/browser/services/gcm/gcm_driver.cc
@@ -382,16 +382,15 @@
       base::Bind(&GCMDriver::GetGCMStatisticsFinished, service_, stats));
 }
 
-GCMDriver::GCMDriver(scoped_ptr<IdentityProvider> identity_provider)
-    : identity_provider_(identity_provider.Pass()),
+GCMDriver::GCMDriver(
+    scoped_ptr<GCMClientFactory> gcm_client_factory,
+    scoped_ptr<IdentityProvider> identity_provider,
+    const base::FilePath& store_path,
+    const scoped_refptr<net::URLRequestContextGetter>& request_context)
+    : gcm_enabled_(true),
       gcm_client_ready_(false),
+      identity_provider_(identity_provider.Pass()),
       weak_ptr_factory_(this) {
-}
-
-GCMDriver::~GCMDriver() {
-}
-
-void GCMDriver::Initialize(scoped_ptr<GCMClientFactory> gcm_client_factory) {
   // Get the list of available accounts.
   std::vector<std::string> account_ids;
 #if !defined(OS_ANDROID)
@@ -400,7 +399,6 @@
 
   // Create and initialize the GCMClient. Note that this does not initiate the
   // GCM check-in.
-  DCHECK(!io_worker_);
   io_worker_.reset(new IOWorker());
   content::BrowserThread::PostTask(
       content::BrowserThread::IO,
@@ -408,23 +406,42 @@
       base::Bind(&GCMDriver::IOWorker::Initialize,
                  base::Unretained(io_worker_.get()),
                  base::Passed(&gcm_client_factory),
-                 GetStorePath(),
+                 store_path,
                  account_ids,
-                 GetURLRequestContextGetter()));
-
-  // Start the GCM service if the rollout signal indicates yes.
-  if (ShouldStartAutomatically())
-    EnsureStarted();
+                 request_context));
 
   identity_provider_->AddObserver(this);
 }
 
-void GCMDriver::Start() {
+GCMDriver::GCMDriver()
+    : gcm_enabled_(true),
+      gcm_client_ready_(false),
+      weak_ptr_factory_(this) {
+}
+
+GCMDriver::~GCMDriver() {
+}
+
+void GCMDriver::Enable() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
+  if (gcm_enabled_)
+    return;
+  gcm_enabled_ = true;
+
   EnsureStarted();
 }
 
+void GCMDriver::Disable() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  if (!gcm_enabled_)
+    return;
+  gcm_enabled_ = false;
+
+  Stop();
+}
+
 void GCMDriver::Stop() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
@@ -441,7 +458,7 @@
                  base::Unretained(io_worker_.get())));
 }
 
-void GCMDriver::ShutdownService() {
+void GCMDriver::Shutdown() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   identity_provider_->RemoveObserver(this);
   for (GCMAppHandlerMap::const_iterator iter = app_handlers_.begin();
@@ -462,6 +479,9 @@
   DCHECK(app_handlers_.find(app_id) == app_handlers_.end());
 
   app_handlers_[app_id] = handler;
+
+   // Ensures that the GCM service is started when there is an interest.
+  EnsureStarted();
 }
 
 void GCMDriver::RemoveAppHandler(const std::string& app_id) {
@@ -479,7 +499,7 @@
   DCHECK(!sender_ids.empty());
   DCHECK(!callback.is_null());
 
-  GCMClient::Result result = EnsureAppReady(app_id);
+  GCMClient::Result result = EnsureStarted();
   if (result != GCMClient::SUCCESS) {
     callback.Run(std::string(), result);
     return;
@@ -534,7 +554,7 @@
   DCHECK(!app_id.empty());
   DCHECK(!callback.is_null());
 
-  GCMClient::Result result = EnsureAppReady(app_id);
+  GCMClient::Result result = EnsureStarted();
   if (result != GCMClient::SUCCESS) {
     callback.Run(result);
     return;
@@ -582,7 +602,7 @@
   DCHECK(!receiver_id.empty());
   DCHECK(!callback.is_null());
 
-  GCMClient::Result result = EnsureAppReady(app_id);
+  GCMClient::Result result = EnsureStarted();
   if (result != GCMClient::SUCCESS) {
     callback.Run(std::string(), result);
     return;
@@ -667,25 +687,29 @@
 }
 
 void GCMDriver::OnActiveAccountLogin() {
-  if (ShouldStartAutomatically())
-    EnsureStarted();
+  EnsureStarted();
 }
 
 void GCMDriver::OnActiveAccountLogout() {
   CheckOut();
 }
 
-void GCMDriver::EnsureStarted() {
+GCMClient::Result GCMDriver::EnsureStarted() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  if (!gcm_enabled_)
+    return GCMClient::GCM_DISABLED;
+
+  // Is the user signed in?
   const std::string account_id = identity_provider_->GetActiveAccountId();
   if (account_id.empty())
-    return;
+    return GCMClient::NOT_SIGNED_IN;
 
   // CheckIn could be called more than once when:
   // 1) The password changes.
   // 2) Register/send function calls it to ensure CheckIn is done.
   if (account_id_ == account_id)
-    return;
+    return GCMClient::SUCCESS;
   account_id_ = account_id;
 
   DCHECK(!delayed_task_controller_);
@@ -699,6 +723,8 @@
       base::Bind(&GCMDriver::IOWorker::Start,
                  base::Unretained(io_worker_.get()),
                  weak_ptr_factory_.GetWeakPtr()));
+
+  return GCMClient::SUCCESS;
 }
 
 void GCMDriver::RemoveCachedData() {
@@ -730,19 +756,6 @@
                  base::Unretained(io_worker_.get())));
 }
 
-GCMClient::Result GCMDriver::EnsureAppReady(const std::string& app_id) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-
-  // Starts the service if not yet.
-  EnsureStarted();
-
-  // If the service cannot be started, bail out.
-  if (account_id_.empty())
-    return GCMClient::NOT_SIGNED_IN;
-
-  return GCMClient::SUCCESS;
-}
-
 bool GCMDriver::IsAsyncOperationPending(const std::string& app_id) const {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   return register_callbacks_.find(app_id) != register_callbacks_.end() ||
@@ -859,4 +872,10 @@
     LOG(WARNING) << "request_gcm_statistics_callback_ is NULL.";
 }
 
+std::string GCMDriver::SignedInUserName() const {
+  if (IsStarted())
+    return identity_provider_->GetActiveUsername();
+  return std::string();
+}
+
 }  // namespace gcm
diff --git a/chrome/browser/services/gcm/gcm_driver.h b/chrome/browser/services/gcm/gcm_driver.h
index f0ff169..9db2d66 100644
--- a/chrome/browser/services/gcm/gcm_driver.h
+++ b/chrome/browser/services/gcm/gcm_driver.h
@@ -12,14 +12,16 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "components/gcm_driver/default_gcm_app_handler.h"
 #include "google_apis/gaia/identity_provider.h"
 #include "google_apis/gcm/gcm_client.h"
 
+namespace base {
+class FilePath;
+}
+
 namespace extensions {
 class ExtensionGCMAppHandlerTest;
 }
@@ -45,24 +47,25 @@
   typedef base::Callback<void(const GCMClient::GCMStatistics& stats)>
       GetGCMStatisticsCallback;
 
-  explicit GCMDriver(scoped_ptr<IdentityProvider> identity_provider);
+  GCMDriver(scoped_ptr<GCMClientFactory> gcm_client_factory,
+            scoped_ptr<IdentityProvider> identity_provider,
+            const base::FilePath& store_path,
+            const scoped_refptr<net::URLRequestContextGetter>& request_context);
   virtual ~GCMDriver();
 
-  void Initialize(scoped_ptr<GCMClientFactory> gcm_client_factory);
-
-  void Start();
-
-  void Stop();
+  // Enables/disables GCM service.
+  void Enable();
+  void Disable();
 
   // This method must be called before destroying the GCMDriver. Once it has
   // been called, no other GCMDriver methods may be used.
-  void ShutdownService();
+  virtual void Shutdown();
 
   // Adds a handler for a given app.
-  void AddAppHandler(const std::string& app_id, GCMAppHandler* handler);
+  virtual void AddAppHandler(const std::string& app_id, GCMAppHandler* handler);
 
   // Remove the handler for a given app.
-  void RemoveAppHandler(const std::string& app_id);
+  virtual void RemoveAppHandler(const std::string& app_id);
 
   // Registers |sender_id| for an app. A registration ID will be returned by
   // the GCM server.
@@ -110,6 +113,9 @@
   void SetGCMRecording(const GetGCMStatisticsCallback& callback,
                        bool recording);
 
+  // Returns the user name if the profile is signed in. Empty string otherwise.
+  std::string SignedInUserName() const;
+
   // IdentityProvider::Observer:
   virtual void OnActiveAccountLogin() OVERRIDE;
   virtual void OnActiveAccountLogout() OVERRIDE;
@@ -117,22 +123,21 @@
   const GCMAppHandlerMap& app_handlers() const { return app_handlers_; }
 
  protected:
-  virtual bool ShouldStartAutomatically() const = 0;
-
-  virtual base::FilePath GetStorePath() const = 0;
-
-  virtual scoped_refptr<net::URLRequestContextGetter>
-      GetURLRequestContextGetter() const = 0;
-
-  scoped_ptr<IdentityProvider> identity_provider_;
+  // Used for constructing fake GCMDriver for testing purpose.
+  GCMDriver();
 
  private:
   class DelayedTaskController;
   class IOWorker;
 
-  // Ensures that the GCMClient is started and the GCM check-in is done if the
-  // |identity_provider_| is able to supply an account ID.
-  void EnsureStarted();
+  // Ensures that the GCM service starts when all of the following conditions
+  // satisfy:
+  // 1) GCM is enabled.
+  // 2) The identity provider is able to supply an account ID.
+  GCMClient::Result EnsureStarted();
+
+  //  Stops the GCM service. It can be restarted by calling EnsureStarted again.
+  void Stop();
 
   // Remove cached data when GCM service is stopped.
   void RemoveCachedData();
@@ -140,9 +145,6 @@
   // Checks out of GCM and erases any cached and persisted data.
   void CheckOut();
 
-  // Ensures that the app is ready for GCM functions and events.
-  GCMClient::Result EnsureAppReady(const std::string& app_id);
-
   // Should be called when an app with |app_id| is trying to un/register.
   // Checks whether another un/registration is in progress.
   bool IsAsyncOperationPending(const std::string& app_id) const;
@@ -174,6 +176,9 @@
 
   void GetGCMStatisticsFinished(GCMClient::GCMStatistics stats);
 
+  // Flag to indicate if GCM is enabled.
+  bool gcm_enabled_;
+
   // Flag to indicate if GCMClient is ready.
   bool gcm_client_ready_;
 
@@ -181,6 +186,8 @@
   // is not running.
   std::string account_id_;
 
+  scoped_ptr<IdentityProvider> identity_provider_;
+
   scoped_ptr<DelayedTaskController> delayed_task_controller_;
 
   // For all the work occurring on the IO thread. Must be destroyed on the IO
diff --git a/chrome/browser/services/gcm/gcm_driver_unittest.cc b/chrome/browser/services/gcm/gcm_driver_unittest.cc
index 3d22079..1170513 100644
--- a/chrome/browser/services/gcm/gcm_driver_unittest.cc
+++ b/chrome/browser/services/gcm/gcm_driver_unittest.cc
@@ -101,29 +101,6 @@
   DISALLOW_COPY_AND_ASSIGN(FakeGCMAppHandler);
 };
 
-class TestGCMDriver : public GCMDriver {
- public:
-  TestGCMDriver(
-      bool start_automatically,
-      scoped_ptr<IdentityProvider> identity_provider,
-      const scoped_refptr<net::URLRequestContextGetter>& request_context);
-  virtual ~TestGCMDriver();
-
- protected:
-  // GCMDriver:
-  virtual bool ShouldStartAutomatically() const OVERRIDE;
-  virtual base::FilePath GetStorePath() const OVERRIDE;
-  virtual scoped_refptr<net::URLRequestContextGetter>
-      GetURLRequestContextGetter() const OVERRIDE;
-
- private:
-  base::ScopedTempDir temp_dir_;
-  scoped_refptr<net::URLRequestContextGetter> request_context_;
-  const bool start_automatically_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestGCMDriver);
-};
-
 FakeGCMAppHandler::FakeGCMAppHandler() : received_event_(NO_EVENT) {
 }
 
@@ -175,33 +152,6 @@
   send_error_details_ = GCMClient::SendErrorDetails();
 }
 
-TestGCMDriver::TestGCMDriver(
-    bool start_automatically,
-    scoped_ptr<IdentityProvider> identity_provider,
-    const scoped_refptr<net::URLRequestContextGetter>& request_context)
-    : GCMDriver(identity_provider.Pass()),
-      request_context_(request_context),
-      start_automatically_(start_automatically) {
-  if (!temp_dir_.CreateUniqueTempDir())
-    ADD_FAILURE();
-}
-
-TestGCMDriver::~TestGCMDriver() {
-}
-
-bool TestGCMDriver::ShouldStartAutomatically() const {
-  return start_automatically_;
-}
-
-base::FilePath TestGCMDriver::GetStorePath() const {
-  return temp_dir_.path();
-}
-
-scoped_refptr<net::URLRequestContextGetter>
-TestGCMDriver::GetURLRequestContextGetter() const {
-  return request_context_;
-}
-
 }  // namespace
 
 class GCMDriverTest : public testing::Test {
@@ -218,7 +168,7 @@
   virtual void SetUp() OVERRIDE;
   virtual void TearDown() OVERRIDE;
 
-  TestGCMDriver* driver() { return driver_.get(); }
+  GCMDriver* driver() { return driver_.get(); }
   FakeGCMAppHandler* gcm_app_handler() { return gcm_app_handler_.get(); }
   const std::string& registration_id() const { return registration_id_; }
   GCMClient::Result registration_result() const { return registration_result_; }
@@ -228,14 +178,12 @@
     return unregistration_result_;
   }
 
-  void ClearRegistrationResult();
-  void ClearUnregistrationResult();
+  void ClearResults();
 
   bool HasAppHandlers() const;
   FakeGCMClient* GetGCMClient();
 
-  void CreateDriver(bool start_automatically,
-                    FakeGCMClient::StartMode gcm_client_start_mode);
+  void CreateDriver(FakeGCMClient::StartMode gcm_client_start_mode);
 
   void SignIn(const std::string& account_id);
   void SignOut();
@@ -258,10 +206,11 @@
   void UnregisterCompleted(GCMClient::Result result);
 
   scoped_ptr<content::TestBrowserThreadBundle> thread_bundle_;
+  base::ScopedTempDir temp_dir_;
   FakeOAuth2TokenService token_service_;
   scoped_ptr<FakeIdentityProvider> identity_provider_owner_;
   FakeIdentityProvider* identity_provider_;
-  scoped_ptr<TestGCMDriver> driver_;
+  scoped_ptr<GCMDriver> driver_;
   scoped_ptr<FakeGCMAppHandler> gcm_app_handler_;
 
   base::Closure async_operation_completed_callback_;
@@ -290,23 +239,25 @@
 void GCMDriverTest::SetUp() {
   thread_bundle_.reset(new content::TestBrowserThreadBundle(
       content::TestBrowserThreadBundle::REAL_IO_THREAD));
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
 }
 
 void GCMDriverTest::TearDown() {
   if (!driver_)
     return;
 
-  driver_->ShutdownService();
+  driver_->Shutdown();
   driver_.reset();
   PumpIOLoop();
 }
 
-void GCMDriverTest::ClearRegistrationResult() {
+void GCMDriverTest::ClearResults() {
   registration_id_.clear();
   registration_result_ = GCMClient::UNKNOWN_ERROR;
-}
 
-void GCMDriverTest::ClearUnregistrationResult() {
+  send_message_id_.clear();
+  send_result_ = GCMClient::UNKNOWN_ERROR;
+
   unregistration_result_ = GCMClient::UNKNOWN_ERROR;
 }
 
@@ -319,18 +270,17 @@
 }
 
 void GCMDriverTest::CreateDriver(
-    bool start_automatically,
     FakeGCMClient::StartMode gcm_client_start_mode) {
   scoped_refptr<net::URLRequestContextGetter> request_context =
       new net::TestURLRequestContextGetter(
           content::BrowserThread::GetMessageLoopProxyForThread(
               content::BrowserThread::IO));
-  driver_.reset(new TestGCMDriver(
-      start_automatically,
+  driver_.reset(new GCMDriver(
+      scoped_ptr<GCMClientFactory>(new FakeGCMClientFactory(
+          gcm_client_start_mode)).Pass(),
       identity_provider_owner_.PassAs<IdentityProvider>(),
+      temp_dir_.path(),
       request_context));
-  driver_->Initialize(scoped_ptr<GCMClientFactory>(
-      new FakeGCMClientFactory(gcm_client_start_mode)));
 
   gcm_app_handler_.reset(new FakeGCMAppHandler);
   driver_->AddAppHandler(kTestAppID1, gcm_app_handler_.get());
@@ -419,7 +369,7 @@
 
 TEST_F(GCMDriverTest, CreateGCMDriverBeforeSignIn) {
   // Create CreateGMCService first.
-  CreateDriver(true, FakeGCMClient::NO_DELAY_START);
+  CreateDriver(FakeGCMClient::NO_DELAY_START);
   EXPECT_FALSE(driver()->IsStarted());
 
   // Sign in. This will kick off the check-in.
@@ -432,20 +382,20 @@
   SignIn(kTestAccountID1);
 
   // Create GCMeService after sign-in.
-  CreateDriver(true, FakeGCMClient::NO_DELAY_START);
+  CreateDriver(FakeGCMClient::NO_DELAY_START);
   EXPECT_TRUE(driver()->IsStarted());
 }
 
 TEST_F(GCMDriverTest, Shutdown) {
-  CreateDriver(true, FakeGCMClient::NO_DELAY_START);
+  CreateDriver(FakeGCMClient::NO_DELAY_START);
   EXPECT_TRUE(HasAppHandlers());
 
-  driver()->ShutdownService();
+  driver()->Shutdown();
   EXPECT_FALSE(HasAppHandlers());
 }
 
 TEST_F(GCMDriverTest, SignInAndSignOutUnderPositiveChannelSignal) {
-  CreateDriver(true, FakeGCMClient::NO_DELAY_START);
+  CreateDriver(FakeGCMClient::NO_DELAY_START);
   SignIn(kTestAccountID1);
 
   // GCMClient should be loaded.
@@ -459,25 +409,8 @@
   EXPECT_EQ(FakeGCMClient::CHECKED_OUT, GetGCMClient()->status());
 }
 
-TEST_F(GCMDriverTest, SignInAndSignOutUnderNonPositiveChannelSignal) {
-  // Non-positive channel signal will prevent GCMClient from checking in during
-  // sign-in.
-  CreateDriver(false, FakeGCMClient::NO_DELAY_START);
-  SignIn(kTestAccountID1);
-
-  // GCMClient should not be loaded.
-  EXPECT_FALSE(driver()->IsGCMClientReady());
-  EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status());
-
-  SignOut();
-
-  // Check-out should still be performed.
-  EXPECT_FALSE(driver()->IsGCMClientReady());
-  EXPECT_EQ(FakeGCMClient::CHECKED_OUT, GetGCMClient()->status());
-}
-
 TEST_F(GCMDriverTest, SignOutAndThenSignIn) {
-  CreateDriver(true, FakeGCMClient::NO_DELAY_START);
+  CreateDriver(FakeGCMClient::NO_DELAY_START);
   SignIn(kTestAccountID1);
 
   // GCMClient should be loaded.
@@ -498,16 +431,16 @@
   EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status());
 }
 
-TEST_F(GCMDriverTest, StopAndRestartGCM) {
-  CreateDriver(true, FakeGCMClient::NO_DELAY_START);
+TEST_F(GCMDriverTest, DisableAndReenableGCM) {
+  CreateDriver(FakeGCMClient::NO_DELAY_START);
   SignIn(kTestAccountID1);
 
-  // GCMClient should be loaded.
+  // GCMClient should be started.
   EXPECT_TRUE(driver()->IsGCMClientReady());
   EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status());
 
-  // Stops the GCM.
-  driver()->Stop();
+  // Disables the GCM.
+  driver()->Disable();
   PumpIOLoop();
   PumpUILoop();
 
@@ -515,17 +448,17 @@
   EXPECT_FALSE(driver()->IsGCMClientReady());
   EXPECT_EQ(FakeGCMClient::STOPPED, GetGCMClient()->status());
 
-  // Restarts the GCM.
-  driver()->Start();
+  // Enables the GCM.
+  driver()->Enable();
   PumpIOLoop();
   PumpUILoop();
 
-  // GCMClient should be loaded.
+  // GCMClient should be started.
   EXPECT_TRUE(driver()->IsGCMClientReady());
   EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status());
 
-  // Stops the GCM.
-  driver()->Stop();
+  // Disables the GCM.
+  driver()->Disable();
   PumpIOLoop();
   PumpUILoop();
 
@@ -541,83 +474,68 @@
   EXPECT_EQ(FakeGCMClient::CHECKED_OUT, GetGCMClient()->status());
 }
 
-TEST_F(GCMDriverTest, RegisterWhenNotSignedIn) {
-  CreateDriver(true, FakeGCMClient::NO_DELAY_START);
-
+TEST_F(GCMDriverTest, RegisterFailed) {
   std::vector<std::string> sender_ids;
   sender_ids.push_back("sender1");
-  Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
 
+  CreateDriver(FakeGCMClient::NO_DELAY_START);
+
+  // Registration fails when GCM is disabled.
+  driver()->Disable();
+  Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
+  EXPECT_TRUE(registration_id().empty());
+  EXPECT_EQ(GCMClient::GCM_DISABLED, registration_result());
+
+  ClearResults();
+
+  // Registration fails when the sign-in does not occur.
+  driver()->Enable();
+  Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
   EXPECT_TRUE(registration_id().empty());
   EXPECT_EQ(GCMClient::NOT_SIGNED_IN, registration_result());
 }
 
-TEST_F(GCMDriverTest, RegisterUnderNonPositiveChannelSignal) {
-  // Non-positive channel signal will prevent GCMClient from checking in during
-  // sign-in.
-  CreateDriver(false, FakeGCMClient::NO_DELAY_START);
-  SignIn(kTestAccountID1);
+TEST_F(GCMDriverTest, UnregisterFailed) {
+  CreateDriver(FakeGCMClient::NO_DELAY_START);
 
-  // GCMClient should not be checked in.
-  EXPECT_FALSE(driver()->IsGCMClientReady());
-  EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status());
+  // Unregistration fails when GCM is disabled.
+  driver()->Disable();
+  Unregister(kTestAppID1, GCMDriverTest::WAIT);
+  EXPECT_EQ(GCMClient::GCM_DISABLED, unregistration_result());
 
-  // Invoking register will make GCMClient checked in.
-  std::vector<std::string> sender_ids;
-  sender_ids.push_back("sender1");
-  Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
+  ClearResults();
 
-  // GCMClient should be checked in.
-  EXPECT_TRUE(driver()->IsGCMClientReady());
-  EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status());
-
-  // Registration should succeed.
-  const std::string expected_registration_id =
-      FakeGCMClient::GetRegistrationIdFromSenderIds(sender_ids);
-  EXPECT_EQ(expected_registration_id, registration_id());
-  EXPECT_EQ(GCMClient::SUCCESS, registration_result());
+  // Unregistration fails when the sign-in does not occur.
+  driver()->Enable();
+  Unregister(kTestAppID1, GCMDriverTest::WAIT);
+  EXPECT_EQ(GCMClient::NOT_SIGNED_IN, unregistration_result());
 }
 
-TEST_F(GCMDriverTest, SendWhenNotSignedIn) {
-  CreateDriver(true, FakeGCMClient::NO_DELAY_START);
-
+TEST_F(GCMDriverTest, SendFailed) {
   GCMClient::OutgoingMessage message;
   message.id = "1";
   message.data["key1"] = "value1";
-  Send(kTestAppID1, kUserID1, message, GCMDriverTest::WAIT);
 
+  CreateDriver(FakeGCMClient::NO_DELAY_START);
+
+  // Sending fails when GCM is disabled.
+  driver()->Disable();
+  Send(kTestAppID1, kUserID1, message, GCMDriverTest::WAIT);
+  EXPECT_TRUE(send_message_id().empty());
+  EXPECT_EQ(GCMClient::GCM_DISABLED, send_result());
+
+  ClearResults();
+
+  // Registration fails when the sign-in does not occur.
+  driver()->Enable();
+  Send(kTestAppID1, kUserID1, message, GCMDriverTest::WAIT);
   EXPECT_TRUE(send_message_id().empty());
   EXPECT_EQ(GCMClient::NOT_SIGNED_IN, send_result());
 }
 
-TEST_F(GCMDriverTest, SendUnderNonPositiveChannelSignal) {
-  // Non-positive channel signal will prevent GCMClient from checking in during
-  // sign-in.
-  CreateDriver(false, FakeGCMClient::NO_DELAY_START);
-  SignIn(kTestAccountID1);
-
-  // GCMClient should not be checked in.
-  EXPECT_FALSE(driver()->IsGCMClientReady());
-  EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status());
-
-  // Invoking send will make GCMClient checked in.
-  GCMClient::OutgoingMessage message;
-  message.id = "1";
-  message.data["key1"] = "value1";
-  Send(kTestAppID1, kUserID1, message, GCMDriverTest::WAIT);
-
-  // GCMClient should be checked in.
-  EXPECT_TRUE(driver()->IsGCMClientReady());
-  EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status());
-
-  // Sending should succeed.
-  EXPECT_EQ(message.id, send_message_id());
-  EXPECT_EQ(GCMClient::SUCCESS, send_result());
-}
-
 TEST_F(GCMDriverTest, GCMClientNotReadyBeforeRegistration) {
   // Make GCMClient not ready initially.
-  CreateDriver(true, FakeGCMClient::DELAY_START);
+  CreateDriver(FakeGCMClient::DELAY_START);
   SignIn(kTestAccountID1);
 
   // The registration is on hold until GCMClient is ready.
@@ -640,7 +558,7 @@
 
 TEST_F(GCMDriverTest, GCMClientNotReadyBeforeSending) {
   // Make GCMClient not ready initially.
-  CreateDriver(true, FakeGCMClient::DELAY_START);
+  CreateDriver(FakeGCMClient::DELAY_START);
   SignIn(kTestAccountID1);
 
   // The sending is on hold until GCMClient is ready.
@@ -684,7 +602,7 @@
 void GCMDriverFunctionalTest::SetUp() {
   GCMDriverTest::SetUp();
 
-  CreateDriver(true, FakeGCMClient::NO_DELAY_START);
+  CreateDriver(FakeGCMClient::NO_DELAY_START);
   SignIn(kTestAccountID1);
 }
 
@@ -721,7 +639,7 @@
 
   // Clears the results the would be set by the Register callback in preparation
   // to call register 2nd time.
-  ClearRegistrationResult();
+  ClearResults();
 
   // Calling register 2nd time with the same set of sender IDs but different
   // ordering will get back the same registration ID.
@@ -808,7 +726,7 @@
   Unregister(kTestAppID1, GCMDriverTest::WAIT);
   EXPECT_EQ(GCMClient::ASYNC_OPERATION_PENDING,
             unregistration_result());
-  ClearUnregistrationResult();
+  ClearResults();
 
   // Complete unregistration.
   WaitForAsyncOperation();
@@ -828,7 +746,7 @@
   Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
   EXPECT_EQ(GCMClient::ASYNC_OPERATION_PENDING,
             registration_result());
-  ClearRegistrationResult();
+  ClearResults();
 
   // Complete the registration.
   WaitForAsyncOperation();
diff --git a/chrome/browser/services/gcm/gcm_profile_service.cc b/chrome/browser/services/gcm/gcm_profile_service.cc
index a14ae00d..39283d9 100644
--- a/chrome/browser/services/gcm/gcm_profile_service.cc
+++ b/chrome/browser/services/gcm/gcm_profile_service.cc
@@ -9,12 +9,14 @@
 #include "base/prefs/pref_service.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/services/gcm/gcm_driver.h"
 #include "chrome/browser/signin/profile_identity_provider.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/pref_names.h"
+#include "components/gcm_driver/gcm_client_factory.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "google_apis/gaia/identity_provider.h"
@@ -73,43 +75,61 @@
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
-GCMProfileService::GCMProfileService(Profile* profile)
-    : GCMDriver(scoped_ptr<IdentityProvider>(new ProfileIdentityProvider(
-          SigninManagerFactory::GetForProfile(profile),
-          ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
-#if defined(OS_ANDROID)
-          NULL))),
-#else
-          LoginUIServiceFactory::GetForProfile(profile)))),
-#endif
-      profile_(profile) {
+GCMProfileService::GCMProfileService(
+    Profile* profile,
+    scoped_ptr<GCMClientFactory> gcm_client_factory)
+    : profile_(profile) {
   DCHECK(!profile->IsOffTheRecord());
+
+#if defined(OS_ANDROID)
+  LoginUIService* login_ui_service = NULL;
+#else
+  LoginUIService* login_ui_service =
+      LoginUIServiceFactory::GetForProfile(profile_);
+#endif
+  driver_.reset(new GCMDriver(
+      gcm_client_factory.Pass(),
+      scoped_ptr<IdentityProvider>(new ProfileIdentityProvider(
+          SigninManagerFactory::GetForProfile(profile_),
+          ProfileOAuth2TokenServiceFactory::GetForProfile(profile_),
+          login_ui_service)),
+      profile_->GetPath().Append(chrome::kGCMStoreDirname),
+      profile_->GetRequestContext()));
+}
+
+GCMProfileService::GCMProfileService() : profile_(NULL) {
 }
 
 GCMProfileService::~GCMProfileService() {
 }
 
+void GCMProfileService::AddAppHandler(const std::string& app_id,
+                                      GCMAppHandler* handler) {
+  if (driver_)
+    driver_->AddAppHandler(app_id, handler);
+}
+
+void GCMProfileService::RemoveAppHandler(const std::string& app_id) {
+  if (driver_)
+    driver_->RemoveAppHandler(app_id);
+}
+
+void GCMProfileService::Register(const std::string& app_id,
+                                 const std::vector<std::string>& sender_ids,
+                                 const GCMDriver::RegisterCallback& callback) {
+  if (driver_)
+    driver_->Register(app_id, sender_ids, callback);
+}
+
 void GCMProfileService::Shutdown() {
-  ShutdownService();
+  if (driver_) {
+    driver_->Shutdown();
+    driver_.reset();
+  }
 }
 
-std::string GCMProfileService::SignedInUserName() const {
-  if (IsStarted())
-    return identity_provider_->GetActiveUsername();
-  return std::string();
-}
-
-bool GCMProfileService::ShouldStartAutomatically() const {
-  return GetGCMEnabledState(profile_) == ALWAYS_ENABLED;
-}
-
-base::FilePath GCMProfileService::GetStorePath() const {
-  return profile_->GetPath().Append(chrome::kGCMStoreDirname);
-}
-
-scoped_refptr<net::URLRequestContextGetter>
-GCMProfileService::GetURLRequestContextGetter() const {
-  return profile_->GetRequestContext();
+void GCMProfileService::SetDriverForTesting(GCMDriver* driver) {
+  driver_.reset(driver);
 }
 
 }  // namespace gcm
diff --git a/chrome/browser/services/gcm/gcm_profile_service.h b/chrome/browser/services/gcm/gcm_profile_service.h
index 69f346f..d68c65d 100644
--- a/chrome/browser/services/gcm/gcm_profile_service.h
+++ b/chrome/browser/services/gcm/gcm_profile_service.h
@@ -10,6 +10,8 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+// TODO(jianli): include needed for obsolete methods that are going to be
+// removed soon.
 #include "chrome/browser/services/gcm/gcm_driver.h"
 #include "components/keyed_service/core/keyed_service.h"
 
@@ -21,8 +23,11 @@
 
 namespace gcm {
 
-// A specialization of GCMDriver that is tied to a Profile.
-class GCMProfileService : public GCMDriver, public KeyedService {
+class GCMClientFactory;
+class GCMDriver;
+
+// Providing GCM service, via GCMDriver, to a profile.
+class GCMProfileService : public KeyedService {
  public:
   // Any change made to this enum should have corresponding change in the
   // GetGCMEnabledStateString(...) function.
@@ -45,26 +50,35 @@
   // Register profile-specific prefs for GCM.
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
-  explicit GCMProfileService(Profile* profile);
+  GCMProfileService(Profile* profile,
+                    scoped_ptr<GCMClientFactory> gcm_client_factory);
   virtual ~GCMProfileService();
 
+  // TODO(jianli): obsolete methods that are going to be removed soon.
+  void AddAppHandler(const std::string& app_id, GCMAppHandler* handler);
+  void RemoveAppHandler(const std::string& app_id);
+  void Register(const std::string& app_id,
+                const std::vector<std::string>& sender_ids,
+                const GCMDriver::RegisterCallback& callback);
+
   // KeyedService:
   virtual void Shutdown() OVERRIDE;
 
-  // Returns the user name if the profile is signed in.
-  std::string SignedInUserName() const;
+  // For testing purpose.
+  void SetDriverForTesting(GCMDriver* driver);
+
+  GCMDriver* driver() const { return driver_.get(); }
 
  protected:
-  // Overridden from GCMDriver:
-  virtual bool ShouldStartAutomatically() const OVERRIDE;
-  virtual base::FilePath GetStorePath() const OVERRIDE;
-  virtual scoped_refptr<net::URLRequestContextGetter>
-      GetURLRequestContextGetter() const OVERRIDE;
+  // Used for constructing fake GCMProfileService for testing purpose.
+  GCMProfileService();
 
  private:
   // The profile which owns this object.
   Profile* profile_;
 
+  scoped_ptr<GCMDriver> driver_;
+
   DISALLOW_COPY_AND_ASSIGN(GCMProfileService);
 };
 
diff --git a/chrome/browser/services/gcm/gcm_profile_service_factory.cc b/chrome/browser/services/gcm/gcm_profile_service_factory.cc
index 2e380b1..2cd5bd72 100644
--- a/chrome/browser/services/gcm/gcm_profile_service_factory.cc
+++ b/chrome/browser/services/gcm/gcm_profile_service_factory.cc
@@ -50,11 +50,9 @@
 
 KeyedService* GCMProfileServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  Profile* profile = static_cast<Profile*>(context);
-  GCMProfileService* service = new GCMProfileService(profile);
-  scoped_ptr<GCMClientFactory> gcm_client_factory(new GCMClientFactory);
-  service->Initialize(gcm_client_factory.Pass());
-  return service;
+  return new GCMProfileService(
+      Profile::FromBrowserContext(context),
+      scoped_ptr<GCMClientFactory>(new GCMClientFactory));
 }
 
 content::BrowserContext* GCMProfileServiceFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
index 1fe24c32..ff6ce35 100644
--- a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
+++ b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/services/gcm/fake_gcm_client.h"
 #include "chrome/browser/services/gcm/fake_gcm_client_factory.h"
 #include "chrome/browser/services/gcm/fake_signin_manager.h"
+#include "chrome/browser/services/gcm/gcm_driver.h"
 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/test/base/testing_profile.h"
@@ -33,7 +34,10 @@
 const char kUserID[] = "user";
 
 KeyedService* BuildGCMProfileService(content::BrowserContext* context) {
-  return new GCMProfileService(Profile::FromBrowserContext(context));
+  return new GCMProfileService(
+      Profile::FromBrowserContext(context),
+      scoped_ptr<GCMClientFactory>(
+          new FakeGCMClientFactory(FakeGCMClient::NO_DELAY_START)));
 }
 
 }  // namespace
@@ -49,25 +53,38 @@
   FakeGCMClient* GetGCMClient() const;
 
   void RegisterAndWaitForCompletion(const std::vector<std::string>& sender_ids);
+  void UnregisterAndWaitForCompletion();
   void SendAndWaitForCompletion(const GCMClient::OutgoingMessage& message);
 
   void RegisterCompleted(const base::Closure& callback,
                          const std::string& registration_id,
                          GCMClient::Result result);
+  void UnregisterCompleted(const base::Closure& callback,
+                           GCMClient::Result result);
   void SendCompleted(const base::Closure& callback,
                      const std::string& message_id,
                      GCMClient::Result result);
 
+  GCMDriver* driver() const { return gcm_profile_service_->driver(); }
+  std::string registration_id() const { return registration_id_; }
+  GCMClient::Result registration_result() const { return registration_result_; }
+  GCMClient::Result unregistration_result() const {
+    return unregistration_result_;
+  }
+  std::string send_message_id() const { return send_message_id_; }
+  GCMClient::Result send_result() const { return send_result_; }
+
+ private:
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfile> profile_;
   GCMProfileService* gcm_profile_service_;
 
   std::string registration_id_;
   GCMClient::Result registration_result_;
+  GCMClient::Result unregistration_result_;
   std::string send_message_id_;
   GCMClient::Result send_result_;
 
- private:
   DISALLOW_COPY_AND_ASSIGN(GCMProfileServiceTest);
 };
 
@@ -82,7 +99,7 @@
 
 FakeGCMClient* GCMProfileServiceTest::GetGCMClient() const {
   return static_cast<FakeGCMClient*>(
-      gcm_profile_service_->GetGCMClientForTesting());
+      gcm_profile_service_->driver()->GetGCMClientForTesting());
 }
 
 void GCMProfileServiceTest::SetUp() {
@@ -95,8 +112,6 @@
       GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse(
           profile_.get(),
           &BuildGCMProfileService));
-  gcm_profile_service_->Initialize(scoped_ptr<GCMClientFactory>(
-      new FakeGCMClientFactory(FakeGCMClient::NO_DELAY_START)));
 
   FakeSigninManager* signin_manager = static_cast<FakeSigninManager*>(
       SigninManagerFactory::GetInstance()->GetForProfile(profile_.get()));
@@ -107,7 +122,7 @@
 void GCMProfileServiceTest::RegisterAndWaitForCompletion(
     const std::vector<std::string>& sender_ids) {
   base::RunLoop run_loop;
-  gcm_profile_service_->Register(
+  gcm_profile_service_->driver()->Register(
       kTestAppID,
       sender_ids,
       base::Bind(&GCMProfileServiceTest::RegisterCompleted,
@@ -116,15 +131,26 @@
   run_loop.Run();
 }
 
+void GCMProfileServiceTest::UnregisterAndWaitForCompletion() {
+  base::RunLoop run_loop;
+  gcm_profile_service_->driver()->Unregister(
+      kTestAppID,
+      base::Bind(&GCMProfileServiceTest::UnregisterCompleted,
+                 base::Unretained(this),
+                 run_loop.QuitClosure()));
+  run_loop.Run();
+}
+
 void GCMProfileServiceTest::SendAndWaitForCompletion(
     const GCMClient::OutgoingMessage& message) {
   base::RunLoop run_loop;
-  gcm_profile_service_->Send(kTestAppID,
-                             kUserID,
-                             message,
-                             base::Bind(&GCMProfileServiceTest::SendCompleted,
-                                        base::Unretained(this),
-                                        run_loop.QuitClosure()));
+  gcm_profile_service_->driver()->Send(
+      kTestAppID,
+      kUserID,
+      message,
+      base::Bind(&GCMProfileServiceTest::SendCompleted,
+                 base::Unretained(this),
+                 run_loop.QuitClosure()));
   run_loop.Run();
 }
 
@@ -137,6 +163,13 @@
   callback.Run();
 }
 
+void GCMProfileServiceTest::UnregisterCompleted(
+    const base::Closure& callback,
+    GCMClient::Result result) {
+  unregistration_result_ = result;
+  callback.Run();
+}
+
 void GCMProfileServiceTest::SendCompleted(
     const base::Closure& callback,
     const std::string& message_id,
@@ -146,45 +179,28 @@
   callback.Run();
 }
 
-TEST_F(GCMProfileServiceTest, RegisterUnderNeutralChannelSignal) {
-  // GCMClient should not be checked in.
-  EXPECT_FALSE(gcm_profile_service_->IsGCMClientReady());
-  EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status());
-
-  // Invoking register will make GCMClient checked in.
+TEST_F(GCMProfileServiceTest, RegisterAndUnregister) {
   std::vector<std::string> sender_ids;
   sender_ids.push_back("sender");
   RegisterAndWaitForCompletion(sender_ids);
 
-  // GCMClient should be checked in.
-  EXPECT_TRUE(gcm_profile_service_->IsGCMClientReady());
-  EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status());
-
-  // Registration should succeed.
   std::string expected_registration_id =
       FakeGCMClient::GetRegistrationIdFromSenderIds(sender_ids);
-  EXPECT_EQ(expected_registration_id, registration_id_);
-  EXPECT_EQ(GCMClient::SUCCESS, registration_result_);
+  EXPECT_EQ(expected_registration_id, registration_id());
+  EXPECT_EQ(GCMClient::SUCCESS, registration_result());
+
+  UnregisterAndWaitForCompletion();
+  EXPECT_EQ(GCMClient::SUCCESS, unregistration_result());
 }
 
-TEST_F(GCMProfileServiceTest, SendUnderNeutralChannelSignal) {
-  // GCMClient should not be checked in.
-  EXPECT_FALSE(gcm_profile_service_->IsGCMClientReady());
-  EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status());
-
-  // Invoking send will make GCMClient checked in.
+TEST_F(GCMProfileServiceTest, Send) {
   GCMClient::OutgoingMessage message;
   message.id = "1";
   message.data["key1"] = "value1";
   SendAndWaitForCompletion( message);
 
-  // GCMClient should be checked in.
-  EXPECT_TRUE(gcm_profile_service_->IsGCMClientReady());
-  EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status());
-
-  // Sending should succeed.
-  EXPECT_EQ(message.id, send_message_id_);
-  EXPECT_EQ(GCMClient::SUCCESS, send_result_);
+  EXPECT_EQ(message.id, send_message_id());
+  EXPECT_EQ(GCMClient::SUCCESS, send_result());
 }
 
 }  // namespace gcm
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index 627a732b..58e87f3d 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/net/chrome_cookie_notification_details.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/services/gcm/gcm_driver.h"
 #include "chrome/browser/services/gcm/gcm_profile_service.h"
 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/signin/about_signin_internals_factory.h"
@@ -1023,11 +1024,11 @@
                                           syncer::Experiments::ENABLED);
     gcm::GCMProfileService* gcm_profile_service =
         gcm::GCMProfileServiceFactory::GetForProfile(profile());
-    if (gcm_profile_service) {
+    if (gcm_profile_service && gcm_profile_service->driver()) {
       if (experiments.gcm_channel_state == syncer::Experiments::SUPPRESSED)
-        gcm_profile_service->Stop();
+        gcm_profile_service->driver()->Disable();
       else
-        gcm_profile_service->Start();
+        gcm_profile_service->driver()->Enable();
     }
   } else {
     profile()->GetPrefs()->ClearPref(prefs::kGCMChannelEnabled);
diff --git a/chrome/browser/ui/webui/gcm_internals_ui.cc b/chrome/browser/ui/webui/gcm_internals_ui.cc
index bc560a8a..7f63acc 100644
--- a/chrome/browser/ui/webui/gcm_internals_ui.cc
+++ b/chrome/browser/ui/webui/gcm_internals_ui.cc
@@ -14,6 +14,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/services/gcm/gcm_driver.h"
 #include "chrome/browser/services/gcm/gcm_profile_service.h"
 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
 #include "chrome/common/url_constants.h"
@@ -161,9 +162,9 @@
           gcm::GCMProfileService::GetGCMEnabledState(profile)));
   if (profile_service) {
     device_info->SetString("signedInUserName",
-                           profile_service->SignedInUserName());
+                           profile_service->driver()->SignedInUserName());
     device_info->SetBoolean("gcmClientReady",
-                            profile_service->IsGCMClientReady());
+                            profile_service->driver()->IsGCMClientReady());
   }
   if (stats) {
     results.SetBoolean("isRecording", stats->is_recording);
@@ -234,10 +235,10 @@
 
   if (!profile_service) {
     ReturnResults(profile, NULL, NULL);
-  } else if (profile_service->SignedInUserName().empty()) {
+  } else if (profile_service->driver()->SignedInUserName().empty()) {
     ReturnResults(profile, profile_service, NULL);
   } else {
-    profile_service->GetGCMStatistics(
+    profile_service->driver()->GetGCMStatistics(
         base::Bind(&GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished,
                    weak_ptr_factory_.GetWeakPtr()),
         clear_logs);
@@ -263,12 +264,12 @@
     ReturnResults(profile, NULL, NULL);
     return;
   }
-  if (profile_service->SignedInUserName().empty()) {
+  if (profile_service->driver()->SignedInUserName().empty()) {
     ReturnResults(profile, profile_service, NULL);
     return;
   }
   // Get fresh stats after changing recording setting.
-  profile_service->SetGCMRecording(
+  profile_service->driver()->SetGCMRecording(
       base::Bind(
           &GcmInternalsUIMessageHandler::RequestGCMStatisticsFinished,
           weak_ptr_factory_.GetWeakPtr()),