summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/api/instance_id/instance_id_api.cc21
-rw-r--r--chrome/browser/extensions/api/instance_id/instance_id_api.h4
-rw-r--r--chrome/browser/extensions/api/instance_id/instance_id_apitest.cc14
-rw-r--r--components/gcm_driver.gypi5
-rw-r--r--components/gcm_driver/fake_gcm_client.cc11
-rw-r--r--components/gcm_driver/fake_gcm_client.h4
-rw-r--r--components/gcm_driver/fake_gcm_driver.cc4
-rw-r--r--components/gcm_driver/fake_gcm_driver.h1
-rw-r--r--components/gcm_driver/gcm_client.h11
-rw-r--r--components/gcm_driver/gcm_client_impl.cc26
-rw-r--r--components/gcm_driver/gcm_client_impl.h7
-rw-r--r--components/gcm_driver/gcm_driver.cc6
-rw-r--r--components/gcm_driver/gcm_driver.h23
-rw-r--r--components/gcm_driver/gcm_driver_android.cc5
-rw-r--r--components/gcm_driver/gcm_driver_android.h1
-rw-r--r--components/gcm_driver/gcm_driver_desktop.cc82
-rw-r--r--components/gcm_driver/gcm_driver_desktop.h17
-rw-r--r--components/gcm_driver/instance_id/BUILD.gn5
-rw-r--r--components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc45
-rw-r--r--components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h42
-rw-r--r--components/gcm_driver/instance_id/fake_instance_id_driver.cc16
-rw-r--r--components/gcm_driver/instance_id/fake_instance_id_driver.h27
-rw-r--r--components/gcm_driver/instance_id/instance_id.h7
-rw-r--r--components/gcm_driver/instance_id/instance_id_android.cc7
-rw-r--r--components/gcm_driver/instance_id/instance_id_android.h6
-rw-r--r--components/gcm_driver/instance_id/instance_id_driver_unittest.cc143
-rw-r--r--components/gcm_driver/instance_id/instance_id_impl.cc82
-rw-r--r--components/gcm_driver/instance_id/instance_id_impl.h23
-rw-r--r--google_apis/gcm/engine/gcm_store.cc1
-rw-r--r--google_apis/gcm/engine/gcm_store.h8
-rw-r--r--google_apis/gcm/engine/gcm_store_impl.cc110
-rw-r--r--google_apis/gcm/engine/gcm_store_impl.h7
-rw-r--r--google_apis/gcm/engine/gcm_store_impl_unittest.cc51
-rw-r--r--tools/metrics/histograms/histograms.xml1
34 files changed, 724 insertions, 99 deletions
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_api.cc b/chrome/browser/extensions/api/instance_id/instance_id_api.cc
index 4c15782..c57b4ed 100644
--- a/chrome/browser/extensions/api/instance_id/instance_id_api.cc
+++ b/chrome/browser/extensions/api/instance_id/instance_id_api.cc
@@ -81,8 +81,13 @@ InstanceIDGetIDFunction::InstanceIDGetIDFunction() {}
InstanceIDGetIDFunction::~InstanceIDGetIDFunction() {}
ExtensionFunction::ResponseAction InstanceIDGetIDFunction::DoWork() {
- return RespondNow(
- OneArgument(new base::StringValue(GetInstanceID()->GetID())));
+ GetInstanceID()->GetID(
+ base::Bind(&InstanceIDGetIDFunction::GetIDCompleted, this));
+ return RespondLater();
+}
+
+void InstanceIDGetIDFunction::GetIDCompleted(const std::string& id) {
+ Respond(OneArgument(new base::StringValue(id)));
}
InstanceIDGetCreationTimeFunction::InstanceIDGetCreationTimeFunction() {}
@@ -90,9 +95,15 @@ InstanceIDGetCreationTimeFunction::InstanceIDGetCreationTimeFunction() {}
InstanceIDGetCreationTimeFunction::~InstanceIDGetCreationTimeFunction() {}
ExtensionFunction::ResponseAction InstanceIDGetCreationTimeFunction::DoWork() {
- return RespondNow(OneArgument(
- new base::FundamentalValue(
- GetInstanceID()->GetCreationTime().ToDoubleT())));
+ GetInstanceID()->GetCreationTime(
+ base::Bind(&InstanceIDGetCreationTimeFunction::GetCreationTimeCompleted,
+ this));
+ return RespondLater();
+}
+
+void InstanceIDGetCreationTimeFunction::GetCreationTimeCompleted(
+ const base::Time& creation_time) {
+ Respond(OneArgument(new base::FundamentalValue(creation_time.ToDoubleT())));
}
InstanceIDGetTokenFunction::InstanceIDGetTokenFunction() {}
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_api.h b/chrome/browser/extensions/api/instance_id/instance_id_api.h
index 9bb404a..6ae1f9d0 100644
--- a/chrome/browser/extensions/api/instance_id/instance_id_api.h
+++ b/chrome/browser/extensions/api/instance_id/instance_id_api.h
@@ -47,6 +47,8 @@ class InstanceIDGetIDFunction : public InstanceIDApiFunction {
ResponseAction DoWork() override;
private:
+ void GetIDCompleted(const std::string& id);
+
DISALLOW_COPY_AND_ASSIGN(InstanceIDGetIDFunction);
};
@@ -64,6 +66,8 @@ class InstanceIDGetCreationTimeFunction : public InstanceIDApiFunction {
ResponseAction DoWork() override;
private:
+ void GetCreationTimeCompleted(const base::Time& creation_time);
+
DISALLOW_COPY_AND_ASSIGN(InstanceIDGetCreationTimeFunction);
};
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
index 6a3c4ab..a8c00fb 100644
--- a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
+++ b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
@@ -12,12 +12,24 @@
#include "chrome/browser/services/gcm/instance_id/instance_id_profile_service_factory.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/ui_test_utils.h"
+#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
#include "extensions/test/result_catcher.h"
using extensions::ResultCatcher;
namespace extensions {
+namespace {
+
+KeyedService* BuildFakeGCMProfileService(content::BrowserContext* context) {
+ gcm::FakeGCMProfileService* service =
+ new gcm::FakeGCMProfileService(Profile::FromBrowserContext(context));
+ service->SetDriverForTesting(new instance_id::FakeGCMDriverForInstanceID());
+ return service;
+}
+
+} // namespace
+
class InstanceIDApiTest : public ExtensionApiTest {
public:
InstanceIDApiTest() {}
@@ -32,7 +44,7 @@ class InstanceIDApiTest : public ExtensionApiTest {
void InstanceIDApiTest::SetUpOnMainThread() {
gcm::GCMProfileServiceFactory::GetInstance()->SetTestingFactory(
- browser()->profile(), &gcm::FakeGCMProfileService::Build);
+ browser()->profile(), &BuildFakeGCMProfileService);
ExtensionApiTest::SetUpOnMainThread();
}
diff --git a/components/gcm_driver.gypi b/components/gcm_driver.gypi
index 4b5e011..b0c90b7 100644
--- a/components/gcm_driver.gypi
+++ b/components/gcm_driver.gypi
@@ -167,6 +167,7 @@
'target_name': 'instance_id_test_support',
'type': 'static_library',
'dependencies': [
+ 'gcm_driver_test_support',
'instance_id',
'../testing/gtest.gyp:gtest',
],
@@ -175,8 +176,8 @@
],
'sources': [
# Note: file list duplicated in GN build.
- 'gcm_driver/instance_id/fake_instance_id_driver.cc',
- 'gcm_driver/instance_id/fake_instance_id_driver.h',
+ 'gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc',
+ 'gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h',
],
},
],
diff --git a/components/gcm_driver/fake_gcm_client.cc b/components/gcm_driver/fake_gcm_client.cc
index 1795288..ffa77d1 100644
--- a/components/gcm_driver/fake_gcm_client.cc
+++ b/components/gcm_driver/fake_gcm_client.cc
@@ -137,6 +137,17 @@ void FakeGCMClient::SetLastTokenFetchTime(const base::Time& time) {
void FakeGCMClient::UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) {
}
+void FakeGCMClient::AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data) {
+}
+
+void FakeGCMClient::RemoveInstanceIDData(const std::string& app_id) {
+}
+
+std::string FakeGCMClient::GetInstanceIDData(const std::string& app_id) {
+ return std::string();
+}
+
void FakeGCMClient::PerformDelayedStart() {
DCHECK(ui_thread_->RunsTasksOnCurrentThread());
diff --git a/components/gcm_driver/fake_gcm_client.h b/components/gcm_driver/fake_gcm_client.h
index 21d696d..c0b03da 100644
--- a/components/gcm_driver/fake_gcm_client.h
+++ b/components/gcm_driver/fake_gcm_client.h
@@ -56,6 +56,10 @@ class FakeGCMClient : public GCMClient {
void RemoveAccountMapping(const std::string& account_id) override;
void SetLastTokenFetchTime(const base::Time& time) override;
void UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) override;
+ void AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data) override;
+ void RemoveInstanceIDData(const std::string& app_id) override;
+ std::string GetInstanceIDData(const std::string& app_id) override;
// Initiate the start that has been delayed.
// Called on UI thread.
diff --git a/components/gcm_driver/fake_gcm_driver.cc b/components/gcm_driver/fake_gcm_driver.cc
index 45791f6..c6f7d9e 100644
--- a/components/gcm_driver/fake_gcm_driver.cc
+++ b/components/gcm_driver/fake_gcm_driver.cc
@@ -98,4 +98,8 @@ void FakeGCMDriver::SetLastTokenFetchTime(const base::Time& time) {
void FakeGCMDriver::WakeFromSuspendForHeartbeat(bool wake) {
}
+InstanceIDStore* FakeGCMDriver::GetInstanceIDStore() {
+ return NULL;
+}
+
} // namespace gcm
diff --git a/components/gcm_driver/fake_gcm_driver.h b/components/gcm_driver/fake_gcm_driver.h
index 9b57af2e..5e334c6 100644
--- a/components/gcm_driver/fake_gcm_driver.h
+++ b/components/gcm_driver/fake_gcm_driver.h
@@ -41,6 +41,7 @@ class FakeGCMDriver : public GCMDriver {
base::Time GetLastTokenFetchTime() override;
void SetLastTokenFetchTime(const base::Time& time) override;
void WakeFromSuspendForHeartbeat(bool wake) override;
+ InstanceIDStore* GetInstanceIDStore() override;
protected:
// GCMDriver implementation:
diff --git a/components/gcm_driver/gcm_client.h b/components/gcm_driver/gcm_client.h
index 2aa224a..cd804b2 100644
--- a/components/gcm_driver/gcm_client.h
+++ b/components/gcm_driver/gcm_client.h
@@ -309,6 +309,17 @@ class GCMClient {
// Updates the timer used by the HeartbeatManager for sending heartbeats.
virtual void UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) = 0;
+
+ // Adds the Instance ID data for a specific app to the persistent store.
+ virtual void AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data) = 0;
+
+ // Removes the Instance ID data for a specific app from the persistent store.
+ virtual void RemoveInstanceIDData(const std::string& app_id) = 0;
+
+ // Retrieves the Instance ID data for a specific app from the persistent
+ // store.
+ virtual std::string GetInstanceIDData(const std::string& app_id) = 0;
};
} // namespace gcm
diff --git a/components/gcm_driver/gcm_client_impl.cc b/components/gcm_driver/gcm_client_impl.cc
index 1c9f64f..8fb162d 100644
--- a/components/gcm_driver/gcm_client_impl.cc
+++ b/components/gcm_driver/gcm_client_impl.cc
@@ -348,6 +348,7 @@ void GCMClientImpl::OnLoadCompleted(scoped_ptr<GCMStore::LoadResult> result) {
device_checkin_info_.accounts_set = true;
last_checkin_time_ = result->last_checkin_time;
gservices_settings_.UpdateFromLoadResult(*result);
+ instance_id_data_ = result->instance_id_data;
load_result_ = result.Pass();
state_ = LOADED;
@@ -530,6 +531,31 @@ void GCMClientImpl::UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) {
mcs_client_->UpdateHeartbeatTimer(timer.Pass());
}
+void GCMClientImpl::AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data) {
+ instance_id_data_[app_id] = instance_id_data;
+ gcm_store_->AddInstanceIDData(
+ app_id,
+ instance_id_data,
+ base::Bind(&GCMClientImpl::IgnoreWriteResultCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void GCMClientImpl::RemoveInstanceIDData(const std::string& app_id) {
+ instance_id_data_.erase(app_id);
+ gcm_store_->RemoveInstanceIDData(
+ app_id,
+ base::Bind(&GCMClientImpl::IgnoreWriteResultCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+std::string GCMClientImpl::GetInstanceIDData(const std::string& app_id) {
+ auto iter = instance_id_data_.find(app_id);
+ if (iter == instance_id_data_.end())
+ return std::string();
+ return iter->second;
+}
+
void GCMClientImpl::StartCheckin() {
// Make sure no checkin is in progress.
if (checkin_request_.get())
diff --git a/components/gcm_driver/gcm_client_impl.h b/components/gcm_driver/gcm_client_impl.h
index 65b04a6..2db1805 100644
--- a/components/gcm_driver/gcm_client_impl.h
+++ b/components/gcm_driver/gcm_client_impl.h
@@ -126,6 +126,10 @@ class GCMClientImpl
void RemoveAccountMapping(const std::string& account_id) override;
void SetLastTokenFetchTime(const base::Time& time) override;
void UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) override;
+ void AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data) override;
+ void RemoveInstanceIDData(const std::string& app_id) override;
+ std::string GetInstanceIDData(const std::string& app_id) override;
// GCMStatsRecorder::Delegate implemenation.
void OnActivityRecorded() override;
@@ -341,6 +345,9 @@ class GCMClientImpl
// Time of the last successful checkin.
base::Time last_checkin_time_;
+ // Cached instance ID data, key is app id.
+ std::map<std::string, std::string> instance_id_data_;
+
// Factory for creating references when scheduling periodic checkin.
base::WeakPtrFactory<GCMClientImpl> periodic_checkin_ptr_factory_;
diff --git a/components/gcm_driver/gcm_driver.cc b/components/gcm_driver/gcm_driver.cc
index 080ba52..1b115c0 100644
--- a/components/gcm_driver/gcm_driver.cc
+++ b/components/gcm_driver/gcm_driver.cc
@@ -12,6 +12,12 @@
namespace gcm {
+InstanceIDStore::InstanceIDStore() {
+}
+
+InstanceIDStore::~InstanceIDStore() {
+}
+
GCMDriver::GCMDriver() : weak_ptr_factory_(this) {
}
diff --git a/components/gcm_driver/gcm_driver.h b/components/gcm_driver/gcm_driver.h
index fb20f3a..aac0975 100644
--- a/components/gcm_driver/gcm_driver.h
+++ b/components/gcm_driver/gcm_driver.h
@@ -22,6 +22,26 @@ class GCMAppHandler;
class GCMConnectionObserver;
struct AccountMapping;
+// Provides the capability to set/get InstanceID data in the GCM store.
+class InstanceIDStore {
+ public:
+ typedef base::Callback<void(const std::string& instance_id_data)>
+ GetInstanceIDDataCallback;
+
+ InstanceIDStore();
+ virtual ~InstanceIDStore();
+
+ virtual void AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data) = 0;
+ virtual void RemoveInstanceIDData(const std::string& app_id) = 0;
+ virtual void GetInstanceIDData(
+ const std::string& app_id,
+ const GetInstanceIDDataCallback& callback) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InstanceIDStore);
+};
+
// Bridge between GCM users in Chrome and the platform-specific implementation.
class GCMDriver {
public:
@@ -146,6 +166,9 @@ class GCMDriver {
// to send a heartbeat message.
virtual void WakeFromSuspendForHeartbeat(bool wake) = 0;
+ // Supports saving the Instance ID data in the GCM store.
+ virtual InstanceIDStore* GetInstanceIDStore() = 0;
+
protected:
// Ensures that the GCM service starts (if necessary conditions are met).
virtual GCMClient::Result EnsureStarted(GCMClient::StartMode start_mode) = 0;
diff --git a/components/gcm_driver/gcm_driver_android.cc b/components/gcm_driver/gcm_driver_android.cc
index 2f82fbe..ec69952 100644
--- a/components/gcm_driver/gcm_driver_android.cc
+++ b/components/gcm_driver/gcm_driver_android.cc
@@ -162,6 +162,11 @@ void GCMDriverAndroid::SetLastTokenFetchTime(const base::Time& time) {
void GCMDriverAndroid::WakeFromSuspendForHeartbeat(bool wake) {
}
+InstanceIDStore* GCMDriverAndroid::GetInstanceIDStore() {
+ // Not supported for Android.
+ return NULL;
+}
+
GCMClient::Result GCMDriverAndroid::EnsureStarted(
GCMClient::StartMode start_mode) {
// TODO(johnme): Maybe we should check if GMS is available?
diff --git a/components/gcm_driver/gcm_driver_android.h b/components/gcm_driver/gcm_driver_android.h
index 41c47b5..3c5d357 100644
--- a/components/gcm_driver/gcm_driver_android.h
+++ b/components/gcm_driver/gcm_driver_android.h
@@ -64,6 +64,7 @@ class GCMDriverAndroid : public GCMDriver {
base::Time GetLastTokenFetchTime() override;
void SetLastTokenFetchTime(const base::Time& time) override;
void WakeFromSuspendForHeartbeat(bool wake) override;
+ InstanceIDStore* GetInstanceIDStore() override;
protected:
// GCMDriver implementation:
diff --git a/components/gcm_driver/gcm_driver_desktop.cc b/components/gcm_driver/gcm_driver_desktop.cc
index 7db396d..a711999 100644
--- a/components/gcm_driver/gcm_driver_desktop.cc
+++ b/components/gcm_driver/gcm_driver_desktop.cc
@@ -87,6 +87,10 @@ class GCMDriverDesktop::IOWorker : public GCMClient::Delegate {
void RemoveAccountMapping(const std::string& account_id);
void SetLastTokenFetchTime(const base::Time& time);
void WakeFromSuspendForHeartbeat(bool wake);
+ void AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data);
+ void RemoveInstanceIDData(const std::string& app_id);
+ void GetInstanceIDData(const std::string& app_id);
// For testing purpose. Can be called from UI thread. Use with care.
GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); }
@@ -343,6 +347,37 @@ void GCMDriverDesktop::IOWorker::SetLastTokenFetchTime(const base::Time& time) {
gcm_client_->SetLastTokenFetchTime(time);
}
+void GCMDriverDesktop::IOWorker::AddInstanceIDData(
+ const std::string& app_id,
+ const std::string& instance_id_data) {
+ DCHECK(io_thread_->RunsTasksOnCurrentThread());
+
+ if (gcm_client_.get())
+ gcm_client_->AddInstanceIDData(app_id, instance_id_data);
+}
+
+void GCMDriverDesktop::IOWorker::RemoveInstanceIDData(
+ const std::string& app_id) {
+ DCHECK(io_thread_->RunsTasksOnCurrentThread());
+
+ if (gcm_client_.get())
+ gcm_client_->RemoveInstanceIDData(app_id);
+}
+
+void GCMDriverDesktop::IOWorker::GetInstanceIDData(
+ const std::string& app_id) {
+ DCHECK(io_thread_->RunsTasksOnCurrentThread());
+
+ std::string instance_id_data;
+ if (gcm_client_.get())
+ instance_id_data = gcm_client_->GetInstanceIDData(app_id);
+
+ ui_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&GCMDriverDesktop::GetInstanceIDDataFinished,
+ service_, app_id, instance_id_data));
+}
+
void GCMDriverDesktop::IOWorker::WakeFromSuspendForHeartbeat(bool wake) {
#if defined(OS_CHROMEOS)
DCHECK(io_thread_->RunsTasksOnCurrentThread());
@@ -659,6 +694,53 @@ void GCMDriverDesktop::SetLastTokenFetchTime(const base::Time& time) {
time));
}
+InstanceIDStore* GCMDriverDesktop::GetInstanceIDStore() {
+ return this;
+}
+
+void GCMDriverDesktop::AddInstanceIDData(
+ const std::string& app_id,
+ const std::string& instance_id_data) {
+ DCHECK(ui_thread_->RunsTasksOnCurrentThread());
+
+ io_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&GCMDriverDesktop::IOWorker::AddInstanceIDData,
+ base::Unretained(io_worker_.get()),
+ app_id,
+ instance_id_data));
+}
+
+void GCMDriverDesktop::RemoveInstanceIDData(const std::string& app_id) {
+ DCHECK(ui_thread_->RunsTasksOnCurrentThread());
+
+ io_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&GCMDriverDesktop::IOWorker::RemoveInstanceIDData,
+ base::Unretained(io_worker_.get()),
+ app_id));
+}
+
+void GCMDriverDesktop::GetInstanceIDData(
+ const std::string& app_id,
+ const GetInstanceIDDataCallback& callback) {
+ DCHECK(!get_instance_id_data_callbacks_.count(app_id));
+ get_instance_id_data_callbacks_[app_id] = callback;
+ io_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&GCMDriverDesktop::IOWorker::GetInstanceIDData,
+ base::Unretained(io_worker_.get()),
+ app_id));
+}
+
+void GCMDriverDesktop::GetInstanceIDDataFinished(
+ const std::string& app_id,
+ const std::string& instance_id_data) {
+ DCHECK(get_instance_id_data_callbacks_.count(app_id));
+ get_instance_id_data_callbacks_[app_id].Run(instance_id_data);
+ get_instance_id_data_callbacks_.erase(app_id);
+}
+
void GCMDriverDesktop::WakeFromSuspendForHeartbeat(bool wake) {
DCHECK(ui_thread_->RunsTasksOnCurrentThread());
diff --git a/components/gcm_driver/gcm_driver_desktop.h b/components/gcm_driver/gcm_driver_desktop.h
index 422f0f5..f52dd6bb 100644
--- a/components/gcm_driver/gcm_driver_desktop.h
+++ b/components/gcm_driver/gcm_driver_desktop.h
@@ -43,7 +43,8 @@ class GCMClientFactory;
class GCMDelayedTaskController;
// GCMDriver implementation for desktop and Chrome OS, using GCMClient.
-class GCMDriverDesktop : public GCMDriver {
+class GCMDriverDesktop : public GCMDriver,
+ public InstanceIDStore {
public:
GCMDriverDesktop(
scoped_ptr<GCMClientFactory> gcm_client_factory,
@@ -83,6 +84,14 @@ class GCMDriverDesktop : public GCMDriver {
base::Time GetLastTokenFetchTime() override;
void SetLastTokenFetchTime(const base::Time& time) override;
void WakeFromSuspendForHeartbeat(bool wake) override;
+ InstanceIDStore* GetInstanceIDStore() override;
+
+ // InstanceIDStore overrides:
+ void AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data) override;
+ void RemoveInstanceIDData(const std::string& app_id) override;
+ void GetInstanceIDData(const std::string& app_id,
+ const GetInstanceIDDataCallback& callback) override;
// Exposed for testing purpose.
bool gcm_enabled() const { return gcm_enabled_; }
@@ -130,6 +139,8 @@ class GCMDriverDesktop : public GCMDriver {
void OnDisconnected();
void GetGCMStatisticsFinished(const GCMClient::GCMStatistics& stats);
+ void GetInstanceIDDataFinished(const std::string& app_id,
+ const std::string& instance_id_data);
scoped_ptr<GCMChannelStatusSyncer> gcm_channel_status_syncer_;
@@ -172,6 +183,10 @@ class GCMDriverDesktop : public GCMDriver {
// Callback for GetGCMStatistics.
GetGCMStatisticsCallback request_gcm_statistics_callback_;
+ // Callbacks for GetInstanceIDData.
+ std::map<std::string, GetInstanceIDDataCallback>
+ get_instance_id_data_callbacks_;
+
// Used to pass a weak pointer to the IO worker.
base::WeakPtrFactory<GCMDriverDesktop> weak_ptr_factory_;
diff --git a/components/gcm_driver/instance_id/BUILD.gn b/components/gcm_driver/instance_id/BUILD.gn
index 430de17..179828f 100644
--- a/components/gcm_driver/instance_id/BUILD.gn
+++ b/components/gcm_driver/instance_id/BUILD.gn
@@ -34,12 +34,13 @@ source_set("instance_id") {
source_set("test_support") {
testonly = true
sources = [
- "fake_instance_id_driver.cc",
- "fake_instance_id_driver.h",
+ "fake_gcm_driver_for_instance_id.cc",
+ "fake_gcm_driver_for_instance_id.h",
]
deps = [
":instance_id",
+ "//components/gcm_driver:test_support",
"//testing/gtest",
]
}
diff --git a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc
new file mode 100644
index 0000000..2a50a03
--- /dev/null
+++ b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc
@@ -0,0 +1,45 @@
+// Copyright 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 "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+
+namespace instance_id {
+
+FakeGCMDriverForInstanceID::FakeGCMDriverForInstanceID() {
+}
+
+FakeGCMDriverForInstanceID::~FakeGCMDriverForInstanceID() {
+}
+
+gcm::InstanceIDStore* FakeGCMDriverForInstanceID::GetInstanceIDStore() {
+ return this;
+}
+
+void FakeGCMDriverForInstanceID::AddInstanceIDData(
+ const std::string& app_id,
+ const std::string& instance_id_data) {
+ instance_id_data_[app_id] = instance_id_data;
+}
+
+void FakeGCMDriverForInstanceID::RemoveInstanceIDData(
+ const std::string& app_id) {
+ instance_id_data_.erase(app_id);
+}
+
+void FakeGCMDriverForInstanceID::GetInstanceIDData(
+ const std::string& app_id,
+ const gcm::InstanceIDStore::GetInstanceIDDataCallback& callback) {
+ std::string data;
+ auto iter = instance_id_data_.find(app_id);
+ if (iter != instance_id_data_.end())
+ data = iter->second;
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, data));
+}
+
+} // namespace instance_id
diff --git a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h
new file mode 100644
index 0000000..d5f9dd1
--- /dev/null
+++ b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h
@@ -0,0 +1,42 @@
+// Copyright 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 COMPONENTS_GCM_DRIVER_INSTANCE_ID_FAKE_GCM_DRIVER__FOR_INSTANCE_ID_H_
+#define COMPONENTS_GCM_DRIVER_INSTANCE_ID_FAKE_GCM_DRIVER__FOR_INSTANCE_ID_H_
+
+#include <map>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "components/gcm_driver/fake_gcm_driver.h"
+
+namespace instance_id {
+
+class FakeGCMDriverForInstanceID : public gcm::FakeGCMDriver,
+ public gcm::InstanceIDStore {
+ public:
+ FakeGCMDriverForInstanceID();
+ ~FakeGCMDriverForInstanceID() override;
+
+ // FakeGCMDriver overrides:
+ gcm::InstanceIDStore* GetInstanceIDStore() override;
+
+ // InstanceIDStore overrides:
+ void AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data) override;
+ void RemoveInstanceIDData(const std::string& app_id) override;
+ void GetInstanceIDData(
+ const std::string& app_id,
+ const gcm::InstanceIDStore::GetInstanceIDDataCallback& callback) override;
+
+ private:
+ std::map<std::string, std::string> instance_id_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeGCMDriverForInstanceID);
+};
+
+} // namespace instance_id
+
+#endif // COMPONENTS_GCM_DRIVER_INSTANCE_ID_FAKE_GCM_DRIVER__FOR_INSTANCE_ID_H_
diff --git a/components/gcm_driver/instance_id/fake_instance_id_driver.cc b/components/gcm_driver/instance_id/fake_instance_id_driver.cc
deleted file mode 100644
index 6b88f22..0000000
--- a/components/gcm_driver/instance_id/fake_instance_id_driver.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 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 "components/gcm_driver/instance_id/fake_instance_id_driver.h"
-
-namespace instance_id {
-
-FakeInstanceIDDriver::FakeInstanceIDDriver()
- : InstanceIDDriver(NULL) {
-}
-
-FakeInstanceIDDriver::~FakeInstanceIDDriver() {
-}
-
-} // namespace instance_id
diff --git a/components/gcm_driver/instance_id/fake_instance_id_driver.h b/components/gcm_driver/instance_id/fake_instance_id_driver.h
deleted file mode 100644
index 60fc0b2..0000000
--- a/components/gcm_driver/instance_id/fake_instance_id_driver.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 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 COMPONENTS_GCM_DRIVER_INSTANCE_ID_FAKE_INSTANCE_ID_DRIVER_H_
-#define COMPONENTS_GCM_DRIVER_INSTANCE_ID_FAKE_INSTANCE_ID_DRIVER_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "components/gcm_driver/instance_id/instance_id_driver.h"
-
-namespace instance_id {
-
-class InstanceID;
-
-class FakeInstanceIDDriver : public InstanceIDDriver {
- public:
- FakeInstanceIDDriver();
- ~FakeInstanceIDDriver() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FakeInstanceIDDriver);
-};
-
-} // namespace instance_id
-
-#endif // COMPONENTS_GCM_DRIVER_INSTANCE_ID_FAKE_INSTANCE_ID_DRIVER_H_
diff --git a/components/gcm_driver/instance_id/instance_id.h b/components/gcm_driver/instance_id/instance_id.h
index 731d274..8141a3a 100644
--- a/components/gcm_driver/instance_id/instance_id.h
+++ b/components/gcm_driver/instance_id/instance_id.h
@@ -41,6 +41,9 @@ class InstanceID {
// Asynchronous callbacks.
typedef base::Callback<void(const std::string& app_id,
bool update_id)> TokenRefreshCallback;
+ typedef base::Callback<void(const std::string& id)> GetIDCallback;
+ typedef base::Callback<void(const base::Time& creation_time)>
+ GetCreationTimeCallback;
typedef base::Callback<void(const std::string& token,
Result result)> GetTokenCallback;
typedef base::Callback<void(Result result)> DeleteTokenCallback;
@@ -62,10 +65,10 @@ class InstanceID {
void SetTokenRefreshCallback(const TokenRefreshCallback& callback);
// Returns the Instance ID.
- virtual std::string GetID() = 0;
+ virtual void GetID(const GetIDCallback& callback) = 0;
// Returns the time when the InstanceID has been generated.
- virtual base::Time GetCreationTime() = 0;
+ virtual void GetCreationTime(const GetCreationTimeCallback& callback) = 0;
// Retrieves a token that allows the authorized entity to access the service
// defined as "scope".
diff --git a/components/gcm_driver/instance_id/instance_id_android.cc b/components/gcm_driver/instance_id/instance_id_android.cc
index 2057a814..9e7a164 100644
--- a/components/gcm_driver/instance_id/instance_id_android.cc
+++ b/components/gcm_driver/instance_id/instance_id_android.cc
@@ -21,14 +21,13 @@ InstanceIDAndroid::InstanceIDAndroid(const std::string& app_id)
InstanceIDAndroid::~InstanceIDAndroid() {
}
-std::string InstanceIDAndroid::GetID() {
+void InstanceIDAndroid::GetID(const GetIDCallback& callback) {
NOTIMPLEMENTED();
- return std::string();
}
-base::Time InstanceIDAndroid::GetCreationTime() {
+void InstanceIDAndroid::GetCreationTime(
+ const GetCreationTimeCallback& callback) {
NOTIMPLEMENTED();
- return base::Time();
}
void InstanceIDAndroid::GetToken(
diff --git a/components/gcm_driver/instance_id/instance_id_android.h b/components/gcm_driver/instance_id/instance_id_android.h
index b09901a..7a6babf 100644
--- a/components/gcm_driver/instance_id/instance_id_android.h
+++ b/components/gcm_driver/instance_id/instance_id_android.h
@@ -19,12 +19,12 @@ namespace instance_id {
// InstanceID implementation for Android.
class InstanceIDAndroid : public InstanceID {
public:
- explicit InstanceIDAndroid(const std::string& app_id);
+ InstanceIDAndroid(const std::string& app_id);
~InstanceIDAndroid() override;
// InstanceID:
- std::string GetID() override;
- base::Time GetCreationTime() override;
+ void GetID(const GetIDCallback& callback) override;
+ void GetCreationTime(const GetCreationTimeCallback& callback) override;
void GetToken(const std::string& audience,
const std::string& scope,
const std::map<std::string, std::string>& options,
diff --git a/components/gcm_driver/instance_id/instance_id_driver_unittest.cc b/components/gcm_driver/instance_id/instance_id_driver_unittest.cc
index 37a1040..41305b5 100644
--- a/components/gcm_driver/instance_id/instance_id_driver_unittest.cc
+++ b/components/gcm_driver/instance_id/instance_id_driver_unittest.cc
@@ -9,7 +9,7 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
-#include "components/gcm_driver/fake_gcm_driver.h"
+#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
#include "components/gcm_driver/instance_id/instance_id.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -46,41 +46,107 @@ class InstanceIDDriverTest : public testing::Test {
void WaitForAsyncOperation();
- void DeleteIDCompleted(InstanceID::Result result);
+ // Recreates InstanceIDDriver to simulate restart.
+ void RecreateInstanceIDDriver();
+
+ // Sync wrappers for async version.
+ std::string GetID(InstanceID* instance_id);
+ base::Time GetCreationTime(InstanceID* instance_id);
+ InstanceID::Result DeleteID(InstanceID* instance_id);
InstanceIDDriver* driver() const { return driver_.get(); }
- InstanceID::Result delete_id_result() const { return delete_id_result_; }
private:
+ void GetIDCompleted(const std::string& id);
+ void GetCreationTimeCompleted(const base::Time& creation_time);
+ void DeleteIDCompleted(InstanceID::Result result);
+
base::MessageLoopForUI message_loop_;
- scoped_ptr<gcm::FakeGCMDriver> gcm_driver_;
+ scoped_ptr<FakeGCMDriverForInstanceID> gcm_driver_;
scoped_ptr<InstanceIDDriver> driver_;
- InstanceID::Result delete_id_result_;
+
+ std::string id_;
+ base::Time creation_time_;
+ InstanceID::Result result_;
+
+ bool async_operation_completed_;
base::Closure async_operation_completed_callback_;
DISALLOW_COPY_AND_ASSIGN(InstanceIDDriverTest);
};
InstanceIDDriverTest::InstanceIDDriverTest()
- : delete_id_result_(InstanceID::UNKNOWN_ERROR) {
+ : result_(InstanceID::UNKNOWN_ERROR),
+ async_operation_completed_(false) {
}
InstanceIDDriverTest::~InstanceIDDriverTest() {
}
void InstanceIDDriverTest::SetUp() {
- gcm_driver_.reset(new gcm::FakeGCMDriver);
+ gcm_driver_.reset(new FakeGCMDriverForInstanceID);
+ RecreateInstanceIDDriver();
+}
+
+void InstanceIDDriverTest::RecreateInstanceIDDriver() {
driver_.reset(new InstanceIDDriver(gcm_driver_.get()));
}
void InstanceIDDriverTest::WaitForAsyncOperation() {
+ // No need to wait if async operation is not needed.
+ if (async_operation_completed_)
+ return;
base::RunLoop run_loop;
async_operation_completed_callback_ = run_loop.QuitClosure();
run_loop.Run();
}
+std::string InstanceIDDriverTest::GetID(InstanceID* instance_id) {
+ async_operation_completed_ = false;
+ id_.clear();
+ instance_id->GetID(base::Bind(&InstanceIDDriverTest::GetIDCompleted,
+ base::Unretained(this)));
+ WaitForAsyncOperation();
+ return id_;
+}
+
+base::Time InstanceIDDriverTest::GetCreationTime(InstanceID* instance_id) {
+ async_operation_completed_ = false;
+ creation_time_ = base::Time();
+ instance_id->GetCreationTime(
+ base::Bind(&InstanceIDDriverTest::GetCreationTimeCompleted,
+ base::Unretained(this)));
+ WaitForAsyncOperation();
+ return creation_time_;
+}
+
+InstanceID::Result InstanceIDDriverTest::DeleteID(InstanceID* instance_id) {
+ async_operation_completed_ = false;
+ result_ = InstanceID::UNKNOWN_ERROR;;
+ instance_id->DeleteID(base::Bind(&InstanceIDDriverTest::DeleteIDCompleted,
+ base::Unretained(this)));
+ WaitForAsyncOperation();
+ return result_;
+}
+
+void InstanceIDDriverTest::GetIDCompleted(const std::string& id) {
+ async_operation_completed_ = true;
+ id_ = id;
+ if (!async_operation_completed_callback_.is_null())
+ async_operation_completed_callback_.Run();
+}
+
+void InstanceIDDriverTest::GetCreationTimeCompleted(
+ const base::Time& creation_time) {
+ async_operation_completed_ = true;
+ creation_time_ = creation_time;
+ if (!async_operation_completed_callback_.is_null())
+ async_operation_completed_callback_.Run();
+}
+
void InstanceIDDriverTest::DeleteIDCompleted(InstanceID::Result result) {
- delete_id_result_ = result;
+ async_operation_completed_ = true;
+ result_ = result;
if (!async_operation_completed_callback_.is_null())
async_operation_completed_callback_.Run();
}
@@ -88,45 +154,70 @@ void InstanceIDDriverTest::DeleteIDCompleted(InstanceID::Result result) {
TEST_F(InstanceIDDriverTest, NewID) {
// Creation time should not be set when the ID is not created.
InstanceID* instance_id1 = driver()->GetInstanceID(kTestAppID1);
- EXPECT_TRUE(instance_id1->GetCreationTime().is_null());
+ EXPECT_TRUE(GetCreationTime(instance_id1).is_null());
// New ID is generated for the first time.
- std::string id1 = instance_id1->GetID();
- EXPECT_FALSE(id1.empty());
+ std::string id1 = GetID(instance_id1);
EXPECT_TRUE(VerifyInstanceID(id1));
- base::Time creation_time = instance_id1->GetCreationTime();
+ base::Time creation_time = GetCreationTime(instance_id1);
EXPECT_FALSE(creation_time.is_null());
// Same ID is returned for the same app.
- EXPECT_EQ(id1, instance_id1->GetID());
- EXPECT_EQ(creation_time, instance_id1->GetCreationTime());
+ EXPECT_EQ(id1, GetID(instance_id1));
+ EXPECT_EQ(creation_time, GetCreationTime(instance_id1));
// New ID is generated for another app.
InstanceID* instance_id2 = driver()->GetInstanceID(kTestAppID2);
- std::string id2 = instance_id2->GetID();
- EXPECT_FALSE(id2.empty());
+ std::string id2 = GetID(instance_id2);
EXPECT_TRUE(VerifyInstanceID(id2));
EXPECT_NE(id1, id2);
- EXPECT_FALSE(instance_id2->GetCreationTime().is_null());
+ EXPECT_FALSE(GetCreationTime(instance_id2).is_null());
+}
+
+TEST_F(InstanceIDDriverTest, PersistID) {
+ InstanceID* instance_id = driver()->GetInstanceID(kTestAppID1);
+
+ // Create the ID for the first time. The ID and creation time should be saved
+ // to the store.
+ std::string id = GetID(instance_id);
+ EXPECT_FALSE(id.empty());
+ base::Time creation_time = GetCreationTime(instance_id);
+ EXPECT_FALSE(creation_time.is_null());
+
+ // Simulate restart by recreating InstanceIDDriver. Same ID and creation time
+ // should be expected.
+ RecreateInstanceIDDriver();
+ instance_id = driver()->GetInstanceID(kTestAppID1);
+ EXPECT_EQ(creation_time, GetCreationTime(instance_id));
+ EXPECT_EQ(id, GetID(instance_id));
+
+ // Delete the ID. The ID and creation time should be removed from the store.
+ EXPECT_EQ(InstanceID::SUCCESS, DeleteID(instance_id));
+ EXPECT_TRUE(GetCreationTime(instance_id).is_null());
+
+ // Simulate restart by recreating InstanceIDDriver. Different ID should be
+ // expected.
+ // Note that we do not check for different creation time since the test might
+ // be run at a very fast server.
+ RecreateInstanceIDDriver();
+ instance_id = driver()->GetInstanceID(kTestAppID1);
+ EXPECT_NE(id, GetID(instance_id));
}
TEST_F(InstanceIDDriverTest, DeleteID) {
InstanceID* instance_id = driver()->GetInstanceID(kTestAppID1);
- std::string id1 = instance_id->GetID();
+ std::string id1 = GetID(instance_id);
EXPECT_FALSE(id1.empty());
- EXPECT_FALSE(instance_id->GetCreationTime().is_null());
+ EXPECT_FALSE(GetCreationTime(instance_id).is_null());
// New ID will be generated from GetID after calling DeleteID.
- instance_id->DeleteID(base::Bind(&InstanceIDDriverTest::DeleteIDCompleted,
- base::Unretained(this)));
- WaitForAsyncOperation();
- EXPECT_EQ(InstanceID::SUCCESS, delete_id_result());
- EXPECT_TRUE(instance_id->GetCreationTime().is_null());
+ EXPECT_EQ(InstanceID::SUCCESS, DeleteID(instance_id));
+ EXPECT_TRUE(GetCreationTime(instance_id).is_null());
- std::string id2 = instance_id->GetID();
+ std::string id2 = GetID(instance_id);
EXPECT_FALSE(id2.empty());
EXPECT_NE(id1, id2);
- EXPECT_FALSE(instance_id->GetCreationTime().is_null());
+ EXPECT_FALSE(GetCreationTime(instance_id).is_null());
}
} // instance_id
diff --git a/components/gcm_driver/instance_id/instance_id_impl.cc b/components/gcm_driver/instance_id/instance_id_impl.cc
index 0ebcdf8..b77cf3f 100644
--- a/components/gcm_driver/instance_id/instance_id_impl.cc
+++ b/components/gcm_driver/instance_id/instance_id_impl.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "components/gcm_driver/gcm_driver_desktop.h"
#include "crypto/random.h"
@@ -23,19 +24,50 @@ InstanceID* InstanceID::Create(const std::string& app_id,
InstanceIDImpl::InstanceIDImpl(const std::string& app_id,
gcm::GCMDriver* gcm_driver)
: InstanceID(app_id),
- gcm_driver_(gcm_driver) {
+ gcm_driver_(gcm_driver),
+ load_from_store_(false),
+ weak_ptr_factory_(this) {
+ gcm_driver_->GetInstanceIDStore()->GetInstanceIDData(
+ app_id,
+ base::Bind(&InstanceIDImpl::GetInstanceIDDataCompleted,
+ weak_ptr_factory_.GetWeakPtr()));
}
InstanceIDImpl::~InstanceIDImpl() {
}
-std::string InstanceIDImpl::GetID() {
+void InstanceIDImpl::GetID(const GetIDCallback& callback) {
+ if (!delayed_task_controller_.CanRunTaskWithoutDelay()) {
+ delayed_task_controller_.AddTask(
+ base::Bind(&InstanceIDImpl::DoGetID,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+ return;
+ }
+
+ DoGetID(callback);
+}
+
+void InstanceIDImpl::DoGetID(const GetIDCallback& callback) {
EnsureIDGenerated();
- return id_;
+ callback.Run(id_);
+}
+
+void InstanceIDImpl::GetCreationTime(const GetCreationTimeCallback& callback) {
+ if (!delayed_task_controller_.CanRunTaskWithoutDelay()) {
+ delayed_task_controller_.AddTask(
+ base::Bind(&InstanceIDImpl::DoGetCreationTime,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+ return;
+ }
+
+ DoGetCreationTime(callback);
}
-base::Time InstanceIDImpl::GetCreationTime() {
- return creation_time_;
+void InstanceIDImpl::DoGetCreationTime(
+ const GetCreationTimeCallback& callback) {
+ callback.Run(creation_time_);
}
void InstanceIDImpl::GetToken(
@@ -53,7 +85,8 @@ void InstanceIDImpl::DeleteToken(const std::string& authorized_entity,
}
void InstanceIDImpl::DeleteID(const DeleteIDCallback& callback) {
- // TODO(jianli): Delete the ID from the store.
+ gcm_driver_->GetInstanceIDStore()->RemoveInstanceIDData(app_id());
+
id_.clear();
creation_time_ = base::Time();
@@ -62,6 +95,12 @@ void InstanceIDImpl::DeleteID(const DeleteIDCallback& callback) {
base::Bind(callback, InstanceID::SUCCESS));
}
+void InstanceIDImpl::GetInstanceIDDataCompleted(
+ const std::string& instance_id_data) {
+ Deserialize(instance_id_data);
+ delayed_task_controller_.SetReady();
+}
+
void InstanceIDImpl::EnsureIDGenerated() {
if (!id_.empty())
return;
@@ -91,7 +130,36 @@ void InstanceIDImpl::EnsureIDGenerated() {
creation_time_ = base::Time::Now();
- // TODO(jianli): Save the ID to the store.
+ // Save to the persistent store.
+ gcm_driver_->GetInstanceIDStore()->AddInstanceIDData(
+ app_id(), SerializeAsString());
+}
+
+std::string InstanceIDImpl::SerializeAsString() const {
+ std::string serialized_data;
+ serialized_data += id_;
+ serialized_data += ",";
+ serialized_data += base::Int64ToString(creation_time_.ToInternalValue());
+ return serialized_data;
+}
+
+void InstanceIDImpl::Deserialize(const std::string& serialized_data) {
+ if (serialized_data.empty())
+ return;
+ std::size_t pos = serialized_data.find(',');
+ if (pos == std::string::npos) {
+ DVLOG(1) << "Failed to deserialize the InstanceID data: " + serialized_data;
+ return;
+ }
+
+ id_ = serialized_data.substr(0, pos);
+
+ int64 time_internal = 0LL;
+ if (!base::StringToInt64(serialized_data.substr(pos + 1), &time_internal)) {
+ DVLOG(1) << "Failed to deserialize the InstanceID data: " + serialized_data;
+ return;
+ }
+ creation_time_ = base::Time::FromInternalValue(time_internal);
}
} // namespace instance_id
diff --git a/components/gcm_driver/instance_id/instance_id_impl.h b/components/gcm_driver/instance_id/instance_id_impl.h
index dd7b775..a5124c1 100644
--- a/components/gcm_driver/instance_id/instance_id_impl.h
+++ b/components/gcm_driver/instance_id/instance_id_impl.h
@@ -11,7 +11,9 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
+#include "components/gcm_driver/gcm_delayed_task_controller.h"
#include "components/gcm_driver/instance_id/instance_id.h"
namespace gcm {
@@ -27,8 +29,8 @@ class InstanceIDImpl : public InstanceID {
~InstanceIDImpl() override;
// InstanceID:
- std::string GetID() override;
- base::Time GetCreationTime() override;
+ void GetID(const GetIDCallback& callback) override;
+ void GetCreationTime(const GetCreationTimeCallback& callback) override;
void GetToken(const std::string& authorized_entity,
const std::string& scope,
const std::map<std::string, std::string>& options,
@@ -39,9 +41,22 @@ class InstanceIDImpl : public InstanceID {
void DeleteID(const DeleteIDCallback& callback) override;
private:
+ void EnsureIDGenerated();
+ void GetInstanceIDDataCompleted(const std::string& instance_id_data);
+
+ void DoGetID(const GetIDCallback& callback);
+ void DoGetCreationTime(const GetCreationTimeCallback& callback);
+
+ // Encodes/decodes the InstanceID data to work with the persistent store.
+ std::string SerializeAsString() const;
+ void Deserialize(const std::string& serialized_data);
+
gcm::GCMDriver* gcm_driver_; // Not owned.
- void EnsureIDGenerated();
+ gcm::GCMDelayedTaskController delayed_task_controller_;
+
+ // Flag to indicate that we have tries to load the data from the store.
+ bool load_from_store_;
// The generated Instance ID.
std::string id_;
@@ -49,6 +64,8 @@ class InstanceIDImpl : public InstanceID {
// The time when the Instance ID has been generated.
base::Time creation_time_;
+ base::WeakPtrFactory<InstanceIDImpl> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(InstanceIDImpl);
};
diff --git a/google_apis/gcm/engine/gcm_store.cc b/google_apis/gcm/engine/gcm_store.cc
index 31f2992..6f5ab0e 100644
--- a/google_apis/gcm/engine/gcm_store.cc
+++ b/google_apis/gcm/engine/gcm_store.cc
@@ -27,6 +27,7 @@ void GCMStore::LoadResult::Reset() {
last_checkin_accounts.clear();
account_mappings.clear();
success = false;
+ instance_id_data.clear();
}
GCMStore::GCMStore() {}
diff --git a/google_apis/gcm/engine/gcm_store.h b/google_apis/gcm/engine/gcm_store.h
index 0cbb085..cfefe91 100644
--- a/google_apis/gcm/engine/gcm_store.h
+++ b/google_apis/gcm/engine/gcm_store.h
@@ -57,6 +57,7 @@ class GCM_EXPORT GCMStore {
AccountMappings account_mappings;
base::Time last_token_fetch_time;
std::map<std::string, int> heartbeat_intervals;
+ std::map<std::string, std::string> instance_id_data;
};
typedef std::vector<std::string> PersistentIdList;
@@ -141,6 +142,13 @@ class GCM_EXPORT GCMStore {
virtual void RemoveHeartbeatInterval(const std::string& scope,
const UpdateCallback& callback) = 0;
+ // Instance ID data.
+ virtual void AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data,
+ const UpdateCallback& callback) = 0;
+ virtual void RemoveInstanceIDData(const std::string& app_id,
+ const UpdateCallback& callback) = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(GCMStore);
};
diff --git a/google_apis/gcm/engine/gcm_store_impl.cc b/google_apis/gcm/engine/gcm_store_impl.cc
index 72220dc..09bfb83 100644
--- a/google_apis/gcm/engine/gcm_store_impl.cc
+++ b/google_apis/gcm/engine/gcm_store_impl.cc
@@ -48,6 +48,7 @@ enum LoadStatus {
LOADING_ACCOUNT_MAPPING_FAILED,
LOADING_LAST_TOKEN_TIME_FAILED,
LOADING_HEARTBEAT_INTERVALS_FAILED,
+ LOADING_INSTANCE_ID_DATA_FAILED,
// NOTE: always keep this entry at the end. Add new status types only
// immediately above this line. Make sure to update the corresponding
@@ -107,6 +108,12 @@ const char kHeartbeatKeyStart[] = "heartbeat1-";
const char kHeartbeatKeyEnd[] = "heartbeat2-";
// Key used for last token fetch time.
const char kLastTokenFetchTimeKey[] = "last_token_fetch_time";
+// Lowest lexicographically ordered app ids.
+// Used for prefixing app id.
+const char kInstanceIDKeyStart[] = "iid1-";
+// Key guaranteed to be higher than all app ids.
+// Used for limiting iteration.
+const char kInstanceIDKeyEnd[] = "iid2-";
std::string MakeRegistrationKey(const std::string& app_id) {
return kRegistrationKeyStart + app_id;
@@ -152,6 +159,14 @@ std::string ParseHeartbeatKey(const std::string& key) {
return key.substr(arraysize(kHeartbeatKeyStart) - 1);
}
+std::string MakeInstanceIDKey(const std::string& app_id) {
+ return kInstanceIDKeyStart + app_id;
+}
+
+std::string ParseInstanceIDKey(const std::string& key) {
+ return key.substr(arraysize(kInstanceIDKeyStart) - 1);
+}
+
// Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore
// outlive the slice.
// For example: MakeSlice(MakeOutgoingKey(x)) is invalid.
@@ -214,6 +229,11 @@ class GCMStoreImpl::Backend
const UpdateCallback& callback);
void RemoveHeartbeatInterval(const std::string& scope,
const UpdateCallback& callback);
+ void AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data,
+ const UpdateCallback& callback);
+ void RemoveInstanceIDData(const std::string& app_id,
+ const UpdateCallback& callback);
void SetValue(const std::string& key,
const std::string& value,
const UpdateCallback& callback);
@@ -234,6 +254,7 @@ class GCMStoreImpl::Backend
bool LoadAccountMappingInfo(AccountMappings* account_mappings);
bool LoadLastTokenFetchTime(base::Time* last_token_fetch_time);
bool LoadHeartbeatIntervals(std::map<std::string, int>* heartbeat_intervals);
+ bool LoadInstanceIDData(std::map<std::string, std::string>* instance_id_data);
const base::FilePath path_;
scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
@@ -297,6 +318,8 @@ LoadStatus GCMStoreImpl::Backend::OpenStoreAndLoadData(LoadResult* result) {
return LOADING_LAST_TOKEN_TIME_FAILED;
if (!LoadHeartbeatIntervals(&result->heartbeat_intervals))
return LOADING_HEARTBEAT_INTERVALS_FAILED;
+ if (!LoadInstanceIDData(&result->instance_id_data))
+ return LOADING_INSTANCE_ID_DATA_FAILED;
return LOADING_SUCCEEDED;
}
@@ -607,6 +630,28 @@ void GCMStoreImpl::Backend::SetLastCheckinInfo(
foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
}
+void GCMStoreImpl::AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data,
+ const UpdateCallback& callback) {
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&GCMStoreImpl::Backend::AddInstanceIDData,
+ backend_,
+ app_id,
+ instance_id_data,
+ callback));
+}
+
+void GCMStoreImpl::RemoveInstanceIDData(const std::string& app_id,
+ const UpdateCallback& callback) {
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&GCMStoreImpl::Backend::RemoveInstanceIDData,
+ backend_,
+ app_id,
+ callback));
+}
+
void GCMStoreImpl::Backend::SetGServicesSettings(
const std::map<std::string, std::string>& settings,
const std::string& settings_digest,
@@ -757,6 +802,49 @@ void GCMStoreImpl::Backend::RemoveHeartbeatInterval(
foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
}
+void GCMStoreImpl::Backend::AddInstanceIDData(
+ const std::string& app_id,
+ const std::string& instance_id_data,
+ const UpdateCallback& callback) {
+ DVLOG(1) << "Adding Instance ID data.";
+ if (!db_.get()) {
+ LOG(ERROR) << "GCMStore db doesn't exist.";
+ foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
+ return;
+ }
+
+ leveldb::WriteOptions write_options;
+ write_options.sync = true;
+
+ std::string key = MakeInstanceIDKey(app_id);
+ const leveldb::Status status = db_->Put(write_options,
+ MakeSlice(key),
+ MakeSlice(instance_id_data));
+ if (!status.ok())
+ LOG(ERROR) << "LevelDB put failed: " << status.ToString();
+ foreground_task_runner_->PostTask(
+ FROM_HERE, base::Bind(callback, status.ok()));
+}
+
+void GCMStoreImpl::Backend::RemoveInstanceIDData(
+ const std::string& app_id,
+ const UpdateCallback& callback) {
+ if (!db_.get()) {
+ LOG(ERROR) << "GCMStore db doesn't exist.";
+ foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
+ return;
+ }
+ leveldb::WriteOptions write_options;
+ write_options.sync = true;
+
+ leveldb::Status status =
+ db_->Delete(write_options, MakeSlice(MakeInstanceIDKey(app_id)));
+ if (!status.ok())
+ LOG(ERROR) << "LevelDB remove failed: " << status.ToString();
+ foreground_task_runner_->PostTask(
+ FROM_HERE, base::Bind(callback, status.ok()));
+}
+
void GCMStoreImpl::Backend::SetValue(const std::string& key,
const std::string& value,
const UpdateCallback& callback) {
@@ -1022,6 +1110,28 @@ bool GCMStoreImpl::Backend::LoadHeartbeatIntervals(
return true;
}
+bool GCMStoreImpl::Backend::LoadInstanceIDData(
+ std::map<std::string, std::string>* instance_id_data) {
+ leveldb::ReadOptions read_options;
+ read_options.verify_checksums = true;
+
+ scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
+ for (iter->Seek(MakeSlice(kInstanceIDKeyStart));
+ iter->Valid() && iter->key().ToString() < kInstanceIDKeyEnd;
+ iter->Next()) {
+ leveldb::Slice s = iter->value();
+ if (s.size() <= 1) {
+ LOG(ERROR) << "Error reading IID data with key " << s.ToString();
+ return false;
+ }
+ std::string app_id = ParseInstanceIDKey(iter->key().ToString());
+ DVLOG(1) << "Found IID data with app id " << app_id;
+ (*instance_id_data)[app_id] = s.ToString();
+ }
+
+ return true;
+}
+
GCMStoreImpl::GCMStoreImpl(
const base::FilePath& path,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
diff --git a/google_apis/gcm/engine/gcm_store_impl.h b/google_apis/gcm/engine/gcm_store_impl.h
index 6ee8e88..4815b20 100644
--- a/google_apis/gcm/engine/gcm_store_impl.h
+++ b/google_apis/gcm/engine/gcm_store_impl.h
@@ -102,6 +102,13 @@ class GCM_EXPORT GCMStoreImpl : public GCMStore {
void RemoveHeartbeatInterval(const std::string& scope,
const UpdateCallback& callback) override;
+ // Instance ID data.
+ void AddInstanceIDData(const std::string& app_id,
+ const std::string& instance_id_data,
+ const UpdateCallback& callback) override;
+ void RemoveInstanceIDData(const std::string& app_id,
+ const UpdateCallback& callback) override;
+
// Injects a value to database. Only to be used for testing.
void SetValueForTesting(const std::string& key,
const std::string& value,
diff --git a/google_apis/gcm/engine/gcm_store_impl_unittest.cc b/google_apis/gcm/engine/gcm_store_impl_unittest.cc
index 1a6c4bb..b7bf75d 100644
--- a/google_apis/gcm/engine/gcm_store_impl_unittest.cc
+++ b/google_apis/gcm/engine/gcm_store_impl_unittest.cc
@@ -33,6 +33,7 @@ const int kNumMessagesPerApp = 20;
// App name for testing.
const char kAppName[] = "my_app";
+const char kAppName2[] = "my_app_2";
// Category name for testing.
const char kCategoryName[] = "my_category";
@@ -741,6 +742,56 @@ TEST_F(GCMStoreImplTest, LastTokenFetchTime) {
EXPECT_EQ(base::Time(), load_result->last_token_fetch_time);
}
+TEST_F(GCMStoreImplTest, InstanceIDData) {
+ scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
+ scoped_ptr<GCMStore::LoadResult> load_result;
+ gcm_store->Load(base::Bind(
+ &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
+ PumpLoop();
+
+ std::string instance_id_data("Foo");
+ gcm_store->AddInstanceIDData(
+ kAppName,
+ instance_id_data,
+ base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
+ PumpLoop();
+
+ std::string instance_id_data2("Hello Instance ID");
+ gcm_store->AddInstanceIDData(
+ kAppName2,
+ instance_id_data2,
+ base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
+ PumpLoop();
+
+ gcm_store = BuildGCMStore().Pass();
+ gcm_store->Load(base::Bind(
+ &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
+ PumpLoop();
+
+ ASSERT_EQ(2u, load_result->instance_id_data.size());
+ ASSERT_TRUE(load_result->instance_id_data.find(kAppName) !=
+ load_result->instance_id_data.end());
+ ASSERT_TRUE(load_result->instance_id_data.find(kAppName2) !=
+ load_result->instance_id_data.end());
+ EXPECT_EQ(instance_id_data, load_result->instance_id_data[kAppName]);
+ EXPECT_EQ(instance_id_data2, load_result->instance_id_data[kAppName2]);
+
+ gcm_store->RemoveInstanceIDData(
+ kAppName,
+ base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
+ PumpLoop();
+
+ gcm_store = BuildGCMStore().Pass();
+ gcm_store->Load(base::Bind(
+ &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
+ PumpLoop();
+
+ ASSERT_EQ(1u, load_result->instance_id_data.size());
+ ASSERT_TRUE(load_result->instance_id_data.find(kAppName2) !=
+ load_result->instance_id_data.end());
+ EXPECT_EQ(instance_id_data2, load_result->instance_id_data[kAppName2]);
+}
+
} // namespace
} // namespace gcm
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 76146ce..ef1870e 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -53963,6 +53963,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="9" label="Loading account mapping failed"/>
<int value="10" label="Loading last token time failed"/>
<int value="11" label="Loading heartbeat intervals failed"/>
+ <int value="12" label="Loading Instance ID data failed"/>
</enum>
<enum name="GCMOutgoingMessageTTLCategory" type="int">