| 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 3a74127c4b9607a52bc76da8848e2c372096ea24..2738c43dfe1dd161848d5b4f1670f4c2198839ad 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(
|
| bool use_mock_keychain,
|
| const base::FilePath& path,
|
| @@ -788,6 +881,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) {
|
|
|