summaryrefslogtreecommitdiff
path: root/chromium/chrome/browser/gcm
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/gcm')
-rw-r--r--chromium/chrome/browser/gcm/COMMON_METADATA4
-rw-r--r--chromium/chrome/browser/gcm/DIR_METADATA1
-rw-r--r--chromium/chrome/browser/gcm/OWNERS4
-rw-r--r--chromium/chrome/browser/gcm/gcm_product_util.cc57
-rw-r--r--chromium/chrome/browser/gcm/gcm_product_util.h30
-rw-r--r--chromium/chrome/browser/gcm/gcm_profile_service_factory.cc174
-rw-r--r--chromium/chrome/browser/gcm/gcm_profile_service_factory.h57
-rw-r--r--chromium/chrome/browser/gcm/gcm_profile_service_unittest.cc269
-rw-r--r--chromium/chrome/browser/gcm/instance_id/instance_id_profile_service_factory.cc60
-rw-r--r--chromium/chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h44
10 files changed, 700 insertions, 0 deletions
diff --git a/chromium/chrome/browser/gcm/COMMON_METADATA b/chromium/chrome/browser/gcm/COMMON_METADATA
new file mode 100644
index 00000000000..777cdb6a192
--- /dev/null
+++ b/chromium/chrome/browser/gcm/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+ component: "Services>CloudMessaging"
+}
+team_email: "platform-capabilities@chromium.org"
diff --git a/chromium/chrome/browser/gcm/DIR_METADATA b/chromium/chrome/browser/gcm/DIR_METADATA
new file mode 100644
index 00000000000..66fe8683773
--- /dev/null
+++ b/chromium/chrome/browser/gcm/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/gcm/COMMON_METADATA"
diff --git a/chromium/chrome/browser/gcm/OWNERS b/chromium/chrome/browser/gcm/OWNERS
new file mode 100644
index 00000000000..06f7d3cbe88
--- /dev/null
+++ b/chromium/chrome/browser/gcm/OWNERS
@@ -0,0 +1,4 @@
+dimich@chromium.org
+fgorski@chromium.org
+jianli@chromium.org
+peter@chromium.org
diff --git a/chromium/chrome/browser/gcm/gcm_product_util.cc b/chromium/chrome/browser/gcm/gcm_product_util.cc
new file mode 100644
index 00000000000..cb2fa486c11
--- /dev/null
+++ b/chromium/chrome/browser/gcm/gcm_product_util.cc
@@ -0,0 +1,57 @@
+// Copyright 2016 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/gcm/gcm_product_util.h"
+
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "chrome/common/chrome_version.h"
+#include "chrome/common/pref_names.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/version_info/version_info.h"
+
+namespace gcm {
+
+namespace {
+
+std::string ToLowerAlphaNum(base::StringPiece in) {
+ std::string out;
+ out.reserve(in.size());
+ for (char ch : in) {
+ if (base::IsAsciiAlpha(ch) || base::IsAsciiDigit(ch))
+ out.push_back(base::ToLowerASCII(ch));
+ }
+ return out;
+}
+
+} // namespace
+
+std::string GetProductCategoryForSubtypes(PrefService* prefs) {
+ std::string product_category_for_subtypes =
+ prefs->GetString(prefs::kGCMProductCategoryForSubtypes);
+ if (!product_category_for_subtypes.empty())
+ return product_category_for_subtypes;
+
+ std::string product = ToLowerAlphaNum(PRODUCT_SHORTNAME_STRING);
+ std::string ns = product == "chromium" ? "org" : "com";
+ std::string platform = ToLowerAlphaNum(version_info::GetOSType());
+ product_category_for_subtypes = ns + '.' + product + '.' + platform;
+
+ prefs->SetString(prefs::kGCMProductCategoryForSubtypes,
+ product_category_for_subtypes);
+ return product_category_for_subtypes;
+}
+
+void RegisterPrefs(PrefRegistrySimple* registry) {
+ registry->RegisterStringPref(prefs::kGCMProductCategoryForSubtypes,
+ std::string() /* default_value */);
+}
+
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
+ RegisterPrefs(registry);
+}
+
+} // namespace gcm
diff --git a/chromium/chrome/browser/gcm/gcm_product_util.h b/chromium/chrome/browser/gcm/gcm_product_util.h
new file mode 100644
index 00000000000..f91c869b310
--- /dev/null
+++ b/chromium/chrome/browser/gcm/gcm_product_util.h
@@ -0,0 +1,30 @@
+// Copyright 2016 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_GCM_GCM_PRODUCT_UTIL_H_
+#define CHROME_BROWSER_GCM_GCM_PRODUCT_UTIL_H_
+
+#include <string>
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+namespace gcm {
+
+// Returns a string like "com.chrome.macosx" that should be used as the GCM
+// category when an app_id is sent as a subtype instead of as a category. This
+// is generated once, then remains fixed forever (even if the product name
+// changes), since it must match existing Instance ID tokens.
+std::string GetProductCategoryForSubtypes(PrefService* prefs);
+
+void RegisterPrefs(PrefRegistrySimple* registry);
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+} // namespace gcm
+
+#endif // CHROME_BROWSER_GCM_GCM_PRODUCT_UTIL_H_
diff --git a/chromium/chrome/browser/gcm/gcm_profile_service_factory.cc b/chromium/chrome/browser/gcm/gcm_profile_service_factory.cc
new file mode 100644
index 00000000000..b3207963fdb
--- /dev/null
+++ b/chromium/chrome/browser/gcm/gcm_profile_service_factory.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2013 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/gcm/gcm_profile_service_factory.h"
+#include <memory>
+
+#include "base/bind.h"
+#include "base/no_destructor.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/thread_pool.h"
+#include "build/build_config.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_key.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "components/gcm_driver/gcm_profile_service.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/offline_pages/buildflags/buildflags.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/network_service_instance.h"
+#include "content/public/browser/storage_partition.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+
+#if !defined(OS_ANDROID)
+#include "chrome/browser/gcm/gcm_product_util.h"
+#include "chrome/common/channel_info.h"
+#include "components/gcm_driver/gcm_client_factory.h"
+#include "content/public/browser/browser_context.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#endif
+
+#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+#include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h"
+#include "components/gcm_driver/gcm_driver.h"
+#include "components/offline_pages/core/offline_page_feature.h"
+#include "components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h"
+#include "components/offline_pages/core/prefetch/prefetch_service.h"
+#endif
+
+namespace gcm {
+
+namespace {
+
+#if !defined(OS_ANDROID)
+// Requests a ProxyResolvingSocketFactory on the UI thread. Note that a WeakPtr
+// of GCMProfileService is needed to detect when the KeyedService shuts down,
+// and avoid calling into |profile| which might have also been destroyed.
+void RequestProxyResolvingSocketFactoryOnUIThread(
+ Profile* profile,
+ base::WeakPtr<GCMProfileService> service,
+ mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>
+ receiver) {
+ if (!service)
+ return;
+ network::mojom::NetworkContext* network_context =
+ profile->GetDefaultStoragePartition()->GetNetworkContext();
+ network_context->CreateProxyResolvingSocketFactory(std::move(receiver));
+}
+
+// A thread-safe wrapper to request a ProxyResolvingSocketFactory.
+void RequestProxyResolvingSocketFactory(
+ Profile* profile,
+ base::WeakPtr<GCMProfileService> service,
+ mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>
+ receiver) {
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&RequestProxyResolvingSocketFactoryOnUIThread, profile,
+ std::move(service), std::move(receiver)));
+}
+#endif
+
+BrowserContextKeyedServiceFactory::TestingFactory& GetTestingFactory() {
+ static base::NoDestructor<BrowserContextKeyedServiceFactory::TestingFactory>
+ testing_factory;
+ return *testing_factory;
+}
+
+} // namespace
+
+GCMProfileServiceFactory::ScopedTestingFactoryInstaller::
+ ScopedTestingFactoryInstaller(TestingFactory testing_factory) {
+ DCHECK(!GetTestingFactory());
+ GetTestingFactory() = std::move(testing_factory);
+}
+
+GCMProfileServiceFactory::ScopedTestingFactoryInstaller::
+ ~ScopedTestingFactoryInstaller() {
+ GetTestingFactory() = BrowserContextKeyedServiceFactory::TestingFactory();
+}
+
+// static
+GCMProfileService* GCMProfileServiceFactory::GetForProfile(
+ content::BrowserContext* profile) {
+ // GCM is not supported in incognito mode.
+ if (profile->IsOffTheRecord())
+ return NULL;
+
+ return static_cast<GCMProfileService*>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+GCMProfileServiceFactory* GCMProfileServiceFactory::GetInstance() {
+ static base::NoDestructor<GCMProfileServiceFactory> instance;
+ return instance.get();
+}
+
+GCMProfileServiceFactory::GCMProfileServiceFactory()
+ : BrowserContextKeyedServiceFactory(
+ "GCMProfileService",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(IdentityManagerFactory::GetInstance());
+#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+ DependsOn(offline_pages::PrefetchServiceFactory::GetInstance());
+#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES)
+}
+
+GCMProfileServiceFactory::~GCMProfileServiceFactory() {
+}
+
+KeyedService* GCMProfileServiceFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ Profile* profile = Profile::FromBrowserContext(context);
+ DCHECK(!profile->IsOffTheRecord());
+
+ TestingFactory& testing_factory = GetTestingFactory();
+ if (testing_factory)
+ return testing_factory.Run(context).release();
+
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner(
+ base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
+ std::unique_ptr<GCMProfileService> service;
+#if defined(OS_ANDROID)
+ service = std::make_unique<GCMProfileService>(profile->GetPath(),
+ blocking_task_runner);
+#else
+ service = std::make_unique<GCMProfileService>(
+ profile->GetPrefs(), profile->GetPath(),
+ base::BindRepeating(&RequestProxyResolvingSocketFactory, profile),
+ profile->GetDefaultStoragePartition()
+ ->GetURLLoaderFactoryForBrowserProcess(),
+ content::GetNetworkConnectionTracker(), chrome::GetChannel(),
+ gcm::GetProductCategoryForSubtypes(profile->GetPrefs()),
+ IdentityManagerFactory::GetForProfile(profile),
+ std::make_unique<GCMClientFactory>(), content::GetUIThreadTaskRunner({}),
+ content::GetIOThreadTaskRunner({}), blocking_task_runner);
+#endif
+#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+ offline_pages::PrefetchService* prefetch_service =
+ offline_pages::PrefetchServiceFactory::GetForKey(
+ profile->GetProfileKey());
+ if (prefetch_service != nullptr) {
+ offline_pages::PrefetchGCMHandler* prefetch_gcm_handler =
+ prefetch_service->GetPrefetchGCMHandler();
+ service->driver()->AddAppHandler(prefetch_gcm_handler->GetAppId(),
+ prefetch_gcm_handler->AsGCMAppHandler());
+ }
+#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES)
+
+ return service.release();
+}
+
+content::BrowserContext* GCMProfileServiceFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextOwnInstanceInIncognito(context);
+}
+
+} // namespace gcm
diff --git a/chromium/chrome/browser/gcm/gcm_profile_service_factory.h b/chromium/chrome/browser/gcm/gcm_profile_service_factory.h
new file mode 100644
index 00000000000..13511e84611
--- /dev/null
+++ b/chromium/chrome/browser/gcm/gcm_profile_service_factory.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2013 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_GCM_GCM_PROFILE_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_GCM_GCM_PROFILE_SERVICE_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/gcm_driver/system_encryptor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace gcm {
+
+class GCMProfileService;
+
+// Singleton that owns all GCMProfileService and associates them with
+// Profiles.
+class GCMProfileServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ static GCMProfileService* GetForProfile(content::BrowserContext* profile);
+ static GCMProfileServiceFactory* GetInstance();
+
+ // Helper registering a testing factory. Needs to be instantiated before the
+ // factory is accessed in your test, and deallocated after the last access.
+ // Usually this is achieved by putting this object as the first member in
+ // your test fixture.
+ class ScopedTestingFactoryInstaller {
+ public:
+ explicit ScopedTestingFactoryInstaller(TestingFactory testing_factory);
+
+ ScopedTestingFactoryInstaller(const ScopedTestingFactoryInstaller&) =
+ delete;
+ ScopedTestingFactoryInstaller& operator=(
+ const ScopedTestingFactoryInstaller&) = delete;
+
+ ~ScopedTestingFactoryInstaller();
+ };
+
+ GCMProfileServiceFactory(const GCMProfileServiceFactory&) = delete;
+ GCMProfileServiceFactory& operator=(const GCMProfileServiceFactory&) = delete;
+
+ private:
+ friend base::NoDestructor<GCMProfileServiceFactory>;
+
+ GCMProfileServiceFactory();
+ ~GCMProfileServiceFactory() override;
+
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* profile) const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace gcm
+
+#endif // CHROME_BROWSER_GCM_GCM_PROFILE_SERVICE_FACTORY_H_
diff --git a/chromium/chrome/browser/gcm/gcm_profile_service_unittest.cc b/chromium/chrome/browser/gcm/gcm_profile_service_unittest.cc
new file mode 100644
index 00000000000..2a13932a454
--- /dev/null
+++ b/chromium/chrome/browser/gcm/gcm_profile_service_unittest.cc
@@ -0,0 +1,269 @@
+// 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 <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/memory/raw_ptr.h"
+#include "base/run_loop.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/thread_pool.h"
+#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
+#include "chrome/browser/gcm/gcm_product_util.h"
+#include "chrome/browser/gcm/gcm_profile_service_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/common/channel_info.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/gcm_driver/fake_gcm_app_handler.h"
+#include "components/gcm_driver/fake_gcm_client.h"
+#include "components/gcm_driver/fake_gcm_client_factory.h"
+#include "components/gcm_driver/gcm_client.h"
+#include "components/gcm_driver/gcm_client_factory.h"
+#include "components/gcm_driver/gcm_driver.h"
+#include "components/gcm_driver/gcm_profile_service.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/test/browser_task_environment.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/test/test_network_connection_tracker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chromeos/dbus/concierge/concierge_client.h"
+#endif
+
+namespace gcm {
+
+namespace {
+
+const char kTestAppID[] = "TestApp";
+const char kUserID[] = "user";
+
+void RequestProxyResolvingSocketFactoryOnUIThread(
+ Profile* profile,
+ base::WeakPtr<gcm::GCMProfileService> service,
+ mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>
+ receiver) {
+ if (!service)
+ return;
+ return profile->GetDefaultStoragePartition()
+ ->GetNetworkContext()
+ ->CreateProxyResolvingSocketFactory(std::move(receiver));
+}
+
+void RequestProxyResolvingSocketFactory(
+ Profile* profile,
+ base::WeakPtr<gcm::GCMProfileService> service,
+ mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>
+ receiver) {
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(&RequestProxyResolvingSocketFactoryOnUIThread,
+ profile, service, std::move(receiver)));
+}
+
+std::unique_ptr<KeyedService> BuildGCMProfileService(
+ content::BrowserContext* context) {
+ Profile* profile = Profile::FromBrowserContext(context);
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner(
+ base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
+ return std::make_unique<gcm::GCMProfileService>(
+ profile->GetPrefs(), profile->GetPath(),
+ base::BindRepeating(&RequestProxyResolvingSocketFactory, profile),
+ profile->GetDefaultStoragePartition()
+ ->GetURLLoaderFactoryForBrowserProcess(),
+ network::TestNetworkConnectionTracker::GetInstance(),
+ chrome::GetChannel(),
+ gcm::GetProductCategoryForSubtypes(profile->GetPrefs()),
+ IdentityManagerFactory::GetForProfile(profile),
+ std::unique_ptr<gcm::GCMClientFactory>(
+ new gcm::FakeGCMClientFactory(content::GetUIThreadTaskRunner({}),
+ content::GetIOThreadTaskRunner({}))),
+ content::GetUIThreadTaskRunner({}), content::GetIOThreadTaskRunner({}),
+ blocking_task_runner);
+}
+
+} // namespace
+
+class GCMProfileServiceTest : public testing::Test {
+ public:
+ GCMProfileServiceTest(const GCMProfileServiceTest&) = delete;
+ GCMProfileServiceTest& operator=(const GCMProfileServiceTest&) = delete;
+
+ protected:
+ GCMProfileServiceTest();
+ ~GCMProfileServiceTest() override;
+
+ // testing::Test:
+ void SetUp() override;
+ void TearDown() override;
+
+ FakeGCMClient* GetGCMClient() const;
+
+ void CreateGCMProfileService();
+
+ void RegisterAndWaitForCompletion(const std::vector<std::string>& sender_ids);
+ void UnregisterAndWaitForCompletion();
+ void SendAndWaitForCompletion(const OutgoingMessage& message);
+
+ void RegisterCompleted(base::OnceClosure callback,
+ const std::string& registration_id,
+ GCMClient::Result result);
+ void UnregisterCompleted(base::OnceClosure callback,
+ GCMClient::Result result);
+ void SendCompleted(base::OnceClosure 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::BrowserTaskEnvironment task_environment_;
+ std::unique_ptr<TestingProfile> profile_;
+ raw_ptr<GCMProfileService> gcm_profile_service_;
+ std::unique_ptr<FakeGCMAppHandler> gcm_app_handler_;
+
+ std::string registration_id_;
+ GCMClient::Result registration_result_;
+ GCMClient::Result unregistration_result_;
+ std::string send_message_id_;
+ GCMClient::Result send_result_;
+};
+
+GCMProfileServiceTest::GCMProfileServiceTest()
+ : gcm_profile_service_(nullptr),
+ gcm_app_handler_(new FakeGCMAppHandler),
+ registration_result_(GCMClient::UNKNOWN_ERROR),
+ send_result_(GCMClient::UNKNOWN_ERROR) {}
+
+GCMProfileServiceTest::~GCMProfileServiceTest() {
+}
+
+FakeGCMClient* GCMProfileServiceTest::GetGCMClient() const {
+ return static_cast<FakeGCMClient*>(
+ gcm_profile_service_->driver()->GetGCMClientForTesting());
+}
+
+void GCMProfileServiceTest::SetUp() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ chromeos::ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr);
+#endif
+ TestingProfile::Builder builder;
+ profile_ = builder.Build();
+}
+
+void GCMProfileServiceTest::TearDown() {
+ gcm_profile_service_->driver()->RemoveAppHandler(kTestAppID);
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ profile_.reset();
+ chromeos::ConciergeClient::Shutdown();
+#endif
+}
+
+void GCMProfileServiceTest::CreateGCMProfileService() {
+ gcm_profile_service_ = static_cast<GCMProfileService*>(
+ GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+ profile_.get(), base::BindRepeating(&BuildGCMProfileService)));
+ gcm_profile_service_->driver()->AddAppHandler(
+ kTestAppID, gcm_app_handler_.get());
+}
+
+void GCMProfileServiceTest::RegisterAndWaitForCompletion(
+ const std::vector<std::string>& sender_ids) {
+ base::RunLoop run_loop;
+ gcm_profile_service_->driver()->Register(
+ kTestAppID, sender_ids,
+ base::BindOnce(&GCMProfileServiceTest::RegisterCompleted,
+ base::Unretained(this), run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+void GCMProfileServiceTest::UnregisterAndWaitForCompletion() {
+ base::RunLoop run_loop;
+ gcm_profile_service_->driver()->Unregister(
+ kTestAppID,
+ base::BindOnce(&GCMProfileServiceTest::UnregisterCompleted,
+ base::Unretained(this), run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+void GCMProfileServiceTest::SendAndWaitForCompletion(
+ const OutgoingMessage& message) {
+ base::RunLoop run_loop;
+ gcm_profile_service_->driver()->Send(
+ kTestAppID, kUserID, message,
+ base::BindOnce(&GCMProfileServiceTest::SendCompleted,
+ base::Unretained(this), run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+void GCMProfileServiceTest::RegisterCompleted(
+ base::OnceClosure callback,
+ const std::string& registration_id,
+ GCMClient::Result result) {
+ registration_id_ = registration_id;
+ registration_result_ = result;
+ std::move(callback).Run();
+}
+
+void GCMProfileServiceTest::UnregisterCompleted(base::OnceClosure callback,
+ GCMClient::Result result) {
+ unregistration_result_ = result;
+ std::move(callback).Run();
+}
+
+void GCMProfileServiceTest::SendCompleted(base::OnceClosure callback,
+ const std::string& message_id,
+ GCMClient::Result result) {
+ send_message_id_ = message_id;
+ send_result_ = result;
+ std::move(callback).Run();
+}
+
+TEST_F(GCMProfileServiceTest, RegisterAndUnregister) {
+ CreateGCMProfileService();
+
+ std::vector<std::string> sender_ids;
+ sender_ids.push_back("sender");
+ RegisterAndWaitForCompletion(sender_ids);
+
+ std::string expected_registration_id =
+ FakeGCMClient::GenerateGCMRegistrationID(sender_ids);
+ EXPECT_EQ(expected_registration_id, registration_id());
+ EXPECT_EQ(GCMClient::SUCCESS, registration_result());
+
+ UnregisterAndWaitForCompletion();
+ EXPECT_EQ(GCMClient::SUCCESS, unregistration_result());
+}
+
+TEST_F(GCMProfileServiceTest, Send) {
+ CreateGCMProfileService();
+
+ OutgoingMessage message;
+ message.id = "1";
+ message.data["key1"] = "value1";
+ SendAndWaitForCompletion(message);
+
+ EXPECT_EQ(message.id, send_message_id());
+ EXPECT_EQ(GCMClient::SUCCESS, send_result());
+}
+
+} // namespace gcm
diff --git a/chromium/chrome/browser/gcm/instance_id/instance_id_profile_service_factory.cc b/chromium/chrome/browser/gcm/instance_id/instance_id_profile_service_factory.cc
new file mode 100644
index 00000000000..8123d8f04c6
--- /dev/null
+++ b/chromium/chrome/browser/gcm/instance_id/instance_id_profile_service_factory.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2015 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/gcm/instance_id/instance_id_profile_service_factory.h"
+
+#include <memory>
+
+#include "chrome/browser/gcm/gcm_profile_service_factory.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/gcm_driver/gcm_profile_service.h"
+#include "components/gcm_driver/instance_id/instance_id_profile_service.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+namespace instance_id {
+
+// static
+InstanceIDProfileService* InstanceIDProfileServiceFactory::GetForProfile(
+ content::BrowserContext* profile) {
+ // Instance ID is not supported in incognito mode.
+ if (profile->IsOffTheRecord())
+ return NULL;
+
+ return static_cast<InstanceIDProfileService*>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+InstanceIDProfileServiceFactory*
+InstanceIDProfileServiceFactory::GetInstance() {
+ return base::Singleton<InstanceIDProfileServiceFactory>::get();
+}
+
+InstanceIDProfileServiceFactory::InstanceIDProfileServiceFactory()
+ : BrowserContextKeyedServiceFactory(
+ "InstanceIDProfileService",
+ BrowserContextDependencyManager::GetInstance()) {
+ // GCM is needed for device ID.
+ DependsOn(gcm::GCMProfileServiceFactory::GetInstance());
+}
+
+InstanceIDProfileServiceFactory::~InstanceIDProfileServiceFactory() {
+}
+
+KeyedService* InstanceIDProfileServiceFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ Profile* profile = Profile::FromBrowserContext(context);
+ return new InstanceIDProfileService(
+ gcm::GCMProfileServiceFactory::GetForProfile(profile)->driver(),
+ profile->IsOffTheRecord());
+}
+
+content::BrowserContext*
+InstanceIDProfileServiceFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextOwnInstanceInIncognito(context);
+}
+
+} // namespace instance_id
diff --git a/chromium/chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h b/chromium/chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h
new file mode 100644
index 00000000000..c4505760a3d
--- /dev/null
+++ b/chromium/chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2015 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_GCM_INSTANCE_ID_INSTANCE_ID_PROFILE_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_GCM_INSTANCE_ID_INSTANCE_ID_PROFILE_SERVICE_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace instance_id {
+
+class InstanceIDProfileService;
+
+// Singleton that owns all InstanceIDProfileService and associates them with
+// profiles.
+class InstanceIDProfileServiceFactory :
+ public BrowserContextKeyedServiceFactory {
+ public:
+ static InstanceIDProfileService* GetForProfile(
+ content::BrowserContext* profile);
+ static InstanceIDProfileServiceFactory* GetInstance();
+
+ InstanceIDProfileServiceFactory(const InstanceIDProfileServiceFactory&) =
+ delete;
+ InstanceIDProfileServiceFactory& operator=(
+ const InstanceIDProfileServiceFactory&) = delete;
+
+ private:
+ friend struct base::DefaultSingletonTraits<InstanceIDProfileServiceFactory>;
+
+ InstanceIDProfileServiceFactory();
+ ~InstanceIDProfileServiceFactory() override;
+
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* profile) const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace instance_id
+
+#endif // CHROME_BROWSER_GCM_INSTANCE_ID_INSTANCE_ID_PROFILE_SERVICE_FACTORY_H_