Index: google_apis/gcm/engine/gcm_store_impl.cc |
diff --git a/google_apis/gcm/engine/gcm_store_impl.cc b/google_apis/gcm/engine/gcm_store_impl.cc |
index 9bd562d83eda2b0d15b8dbf2f4ded7a0708246c7..5393fd1a9fd2a0d20d5bec3437251c58b7bda86d 100644 |
--- a/google_apis/gcm/engine/gcm_store_impl.cc |
+++ b/google_apis/gcm/engine/gcm_store_impl.cc |
@@ -16,12 +16,14 @@ |
#include "base/stl_util.h" |
#include "base/strings/string_number_conversions.h" |
#include "base/strings/string_piece.h" |
+#include "base/time/time.h" |
#include "base/tracked_objects.h" |
#include "components/os_crypt/os_crypt.h" |
#include "google_apis/gcm/base/mcs_message.h" |
#include "google_apis/gcm/base/mcs_util.h" |
#include "google_apis/gcm/protocol/mcs.pb.h" |
#include "third_party/leveldatabase/src/include/leveldb/db.h" |
+#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
namespace gcm { |
@@ -53,6 +55,14 @@ const char kOutgoingMsgKeyStart[] = "outgoing1-"; |
// Key guaranteed to be higher than all outgoing message keys. |
// Used for limiting iteration. |
const char kOutgoingMsgKeyEnd[] = "outgoing2-"; |
+// Lowest lexicographically ordered G-service settings key. |
+// Used for prefixing G-services settings. |
+const char kGServiceSettingKeyStart[] = "gservice1-"; |
+// Key guaranteed to be higher than all G-services settings keys. |
+// Used for limiting iteration. |
+const char kGServiceSettingKeyEnd[] = "gservice2-"; |
+// Key for digest of the last G-services settings update. |
+const char kGServiceSettingsDigestKey[] = "gservices_digest"; |
// Key used to timestamp last checkin (marked with G services settings update). |
const char kLastCheckinTimeKey[] = "last_checkin_time"; |
@@ -76,6 +86,14 @@ std::string ParseOutgoingKey(const std::string& key) { |
return key.substr(arraysize(kOutgoingMsgKeyStart) - 1); |
} |
+std::string MakeGServiceSettingKey(const std::string& setting_name) { |
+ return kGServiceSettingKeyStart + setting_name; |
+} |
+ |
+std::string ParseGServiceSettingKey(const std::string& key) { |
+ return key.substr(arraysize(kGServiceSettingKeyStart) - 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. |
@@ -121,6 +139,10 @@ class GCMStoreImpl::Backend |
const UpdateCallback& callback); |
void SetLastCheckinTime(const base::Time& last_checkin_time, |
const UpdateCallback& callback); |
+ void SetGServicesSettings( |
+ const std::map<std::string, std::string>& settings, |
+ const std::string& digest, |
+ const UpdateCallback& callback); |
private: |
friend class base::RefCountedThreadSafe<Backend>; |
@@ -131,6 +153,8 @@ class GCMStoreImpl::Backend |
bool LoadIncomingMessages(std::vector<std::string>* incoming_messages); |
bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages); |
bool LoadLastCheckinTime(base::Time* last_checkin_time); |
+ bool LoadGServicesSettings(std::map<std::string, std::string>* settings, |
+ std::string* digest); |
const base::FilePath path_; |
scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_; |
@@ -176,12 +200,16 @@ void GCMStoreImpl::Backend::Load(const LoadCallback& callback) { |
!LoadRegistrations(&result->registrations) || |
!LoadIncomingMessages(&result->incoming_messages) || |
!LoadOutgoingMessages(&result->outgoing_messages) || |
- !LoadLastCheckinTime(&result->last_checkin_time)) { |
+ !LoadLastCheckinTime(&result->last_checkin_time) || |
+ !LoadGServicesSettings(&result->gservices_settings, |
+ &result->gservices_digest)) { |
result->device_android_id = 0; |
result->device_security_token = 0; |
result->registrations.clear(); |
result->incoming_messages.clear(); |
result->outgoing_messages.clear(); |
+ result->gservices_settings.clear(); |
+ result->gservices_digest.clear(); |
result->last_checkin_time = base::Time::FromInternalValue(0LL); |
foreground_task_runner_->PostTask(FROM_HERE, |
base::Bind(callback, |
@@ -465,7 +493,44 @@ void GCMStoreImpl::Backend::SetLastCheckinTime( |
if (!s.ok()) |
LOG(ERROR) << "LevelDB set last checkin time failed: " << s.ToString(); |
+ foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok())); |
+} |
+ |
+void GCMStoreImpl::Backend::SetGServicesSettings( |
+ const std::map<std::string, std::string>& settings, |
+ const std::string& settings_digest, |
+ const UpdateCallback& callback) { |
+ leveldb::WriteBatch write_batch; |
+ |
+ // Remove all existing settings. |
+ leveldb::ReadOptions read_options; |
+ read_options.verify_checksums = true; |
+ scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options)); |
+ for (iter->Seek(MakeSlice(kGServiceSettingKeyStart)); |
+ iter->Valid() && iter->key().ToString() < kGServiceSettingKeyEnd; |
+ iter->Next()) { |
+ write_batch.Delete(iter->key()); |
+ } |
+ |
+ // Add the new settings. |
+ for (std::map<std::string, std::string>::const_iterator iter = |
+ settings.begin(); |
+ iter != settings.end(); ++iter) { |
+ write_batch.Put(MakeSlice(MakeGServiceSettingKey(iter->first)), |
+ MakeSlice(iter->second)); |
+ } |
+ |
+ // Update the settings digest. |
+ write_batch.Put(MakeSlice(kGServiceSettingsDigestKey), |
+ MakeSlice(settings_digest)); |
+ |
+ // Write it all in a batch. |
+ leveldb::WriteOptions write_options; |
+ write_options.sync = true; |
+ leveldb::Status s = db_->Write(write_options, &write_batch); |
+ if (!s.ok()) |
+ LOG(ERROR) << "LevelDB GService Settings update failed: " << s.ToString(); |
foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok())); |
} |
@@ -604,6 +669,34 @@ bool GCMStoreImpl::Backend::LoadLastCheckinTime( |
return true; |
} |
+bool GCMStoreImpl::Backend::LoadGServicesSettings( |
+ std::map<std::string, std::string>* settings, |
+ std::string* digest) { |
+ leveldb::ReadOptions read_options; |
+ read_options.verify_checksums = true; |
+ |
+ // Load all of the GServices settings. |
+ scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options)); |
+ for (iter->Seek(MakeSlice(kGServiceSettingKeyStart)); |
+ iter->Valid() && iter->key().ToString() < kGServiceSettingKeyEnd; |
+ iter->Next()) { |
+ std::string value = iter->value().ToString(); |
+ if (value.empty()) { |
+ LOG(ERROR) << "Error reading GService Settings " << value; |
+ return false; |
+ } |
+ std::string id = ParseGServiceSettingKey(iter->key().ToString()); |
+ (*settings)[id] = value; |
+ DVLOG(1) << "Found G Service setting with key: " << id |
+ << ", and value: " << value; |
+ } |
+ |
+ // Load the settings digest. It's ok if it is empty. |
+ db_->Get(read_options, MakeSlice(kGServiceSettingsDigestKey), digest); |
+ |
+ return true; |
+} |
+ |
GCMStoreImpl::GCMStoreImpl( |
const base::FilePath& path, |
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) |
@@ -783,6 +876,19 @@ void GCMStoreImpl::SetLastCheckinTime(const base::Time& last_checkin_time, |
callback)); |
} |
+void GCMStoreImpl::SetGServicesSettings( |
+ const std::map<std::string, std::string>& settings, |
+ const std::string& digest, |
+ const UpdateCallback& callback) { |
+ blocking_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&GCMStoreImpl::Backend::SetGServicesSettings, |
+ backend_, |
+ settings, |
+ digest, |
+ callback)); |
+} |
+ |
void GCMStoreImpl::LoadContinuation(const LoadCallback& callback, |
scoped_ptr<LoadResult> result) { |
if (!result->success) { |