diff options
author | jianli <jianli@chromium.org> | 2015-05-11 14:14:13 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-11 21:14:58 +0000 |
commit | 10018b2d2d5954cb697ccad19eef63919aef0786 (patch) | |
tree | 7f5f4fa86eacf75884463c87438ddfe84b1fd4f1 /components/gcm_driver | |
parent | e8624082aaf1743e46f2868f807ac164c587d77b (diff) | |
download | chromium_src-10018b2d2d5954cb697ccad19eef63919aef0786.zip chromium_src-10018b2d2d5954cb697ccad19eef63919aef0786.tar.gz chromium_src-10018b2d2d5954cb697ccad19eef63919aef0786.tar.bz2 |
Persist Instance ID data to GCM store.
BUG=477084
TEST=new tests
TBR=asvitkine@chromium.org
Review URL: https://codereview.chromium.org/1126233004
Cr-Commit-Position: refs/heads/master@{#329233}
Diffstat (limited to 'components/gcm_driver')
24 files changed, 510 insertions, 91 deletions
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); }; |