Chromium Code Reviews| 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 7f272870d808cffb0c2134867fa4b9be205b6bef..6af3a5bc7c8060a928a036f5c4c422b8a52918ec 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 used to timestamp last checkin (marked with G services settings update). |
| +const char kLastCheckinTimeKey[] = "last_checkin_time"; |
| std::string MakeRegistrationKey(const std::string& app_id) { |
| return kRegistrationKeyStart + app_id; |
| @@ -74,6 +84,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. |
| @@ -118,6 +136,10 @@ class GCMStoreImpl::Backend |
| void RemoveUserSerialNumber(const std::string& username, |
| const UpdateCallback& callback); |
| void SetNextSerialNumber(int64 serial_number, const UpdateCallback& callback); |
| + void UpdateGServicesSettings( |
| + const std::vector<std::string>& settings_to_remove, |
| + const std::map<std::string, std::string>& settings_to_add, |
| + const UpdateCallback& callback); |
| private: |
| friend class base::RefCountedThreadSafe<Backend>; |
| @@ -127,6 +149,8 @@ class GCMStoreImpl::Backend |
| bool LoadRegistrations(RegistrationInfoMap* registrations); |
| bool LoadIncomingMessages(std::vector<std::string>* incoming_messages); |
| bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages); |
| + bool LoadGServicesSettings(std::map<std::string, std::string>* settings, |
| + base::Time* last_checkin_time); |
| const base::FilePath path_; |
| scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_; |
| @@ -171,12 +195,15 @@ void GCMStoreImpl::Backend::Load(const LoadCallback& callback) { |
| &result->device_security_token) || |
| !LoadRegistrations(&result->registrations) || |
| !LoadIncomingMessages(&result->incoming_messages) || |
| - !LoadOutgoingMessages(&result->outgoing_messages)) { |
| + !LoadOutgoingMessages(&result->outgoing_messages) || |
| + !LoadGServicesSettings(&result->g_services_settings, |
| + &result->last_checkin_time)) { |
| result->device_android_id = 0; |
| result->device_security_token = 0; |
| result->registrations.clear(); |
| result->incoming_messages.clear(); |
| result->outgoing_messages.clear(); |
| + result->last_checkin_time = base::Time::FromInternalValue(0LL); |
| foreground_task_runner_->PostTask(FROM_HERE, |
| base::Bind(callback, |
| base::Passed(&result))); |
| @@ -445,6 +472,44 @@ void GCMStoreImpl::Backend::RemoveOutgoingMessages( |
| AppIdToMessageCountMap())); |
| } |
| + |
|
fgorski
2014/03/28 14:30:51
remove extra lines.
fgorski
2014/03/29 01:09:32
Done.
|
| + |
| +void GCMStoreImpl::Backend::UpdateGServicesSettings( |
| + const std::vector<std::string>& settings_to_remove, |
| + const std::map<std::string, std::string>& settings_to_add, |
| + const UpdateCallback& callback) { |
| + leveldb::WriteBatch write_batch; |
| + |
| + // Delete settings to remove. |
| + for (std::vector<std::string>::const_iterator iter = |
| + settings_to_remove.begin(); |
| + iter != settings_to_remove.end(); ++iter) { |
| + write_batch.Delete(MakeSlice(MakeGServiceSettingKey(*iter))); |
| + } |
| + |
| + // Add settings to add. |
| + for (std::map<std::string, std::string>::const_iterator iter = |
| + settings_to_add.begin(); |
| + iter != settings_to_add.end(); ++iter) { |
| + write_batch.Put(MakeSlice(MakeGServiceSettingKey(iter->first)), |
| + MakeSlice(iter->second)); |
| + } |
| + |
| + // Update last checkin time. (To Now) |
|
fgorski
2014/03/28 14:30:51
use the last_checkin_time provided as parameter.
fgorski
2014/03/29 01:09:32
Done.
|
| + int64 now = base::Time::Now().ToInternalValue(); |
| + std::string now_str = base::Int64ToString(now); |
| + write_batch.Put(MakeSlice(kLastCheckinTimeKey), MakeSlice(now_str)); |
| + |
| + // Write it all in 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())); |
| +} |
| + |
| bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id, |
| uint64* security_token) { |
| leveldb::ReadOptions read_options; |
| @@ -560,6 +625,43 @@ bool GCMStoreImpl::Backend::LoadOutgoingMessages( |
| return true; |
| } |
| +bool GCMStoreImpl::Backend::LoadGServicesSettings( |
| + std::map<std::string, std::string>* settings, |
| + base::Time* last_checkin_time) { |
| + 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()) { |
| + if (iter->value().size() <= 1) { |
|
fgorski
2014/03/28 14:30:51
std::string value = iter->value().ToString(); in t
fgorski
2014/03/29 01:09:32
Done.
|
| + LOG(ERROR) << "Error reading GService Settings " |
| + << iter->value().ToString(); |
| + return false; |
| + } |
| + std::string id = ParseGServiceSettingKey(iter->key().ToString()); |
| + (*settings)[id] = iter->value().ToString(); |
| + DVLOG(1) << "Found G Service setting with key: " << id |
| + << ", and value: " << (*settings)[id]; |
| + } |
| + |
| + std::string result; |
| + leveldb::Status s = db_->Get(read_options, |
| + MakeSlice(kLastCheckinTimeKey), |
| + &result); |
| + int64 time_internal; |
| + if (s.ok()) { |
|
fgorski
2014/03/28 14:30:51
add defaulting in else to enable smooth upgrade...
fgorski
2014/03/29 01:09:32
Done.
|
| + if (!base::StringToInt64(result, &time_internal)) { |
| + LOG(ERROR) << "Failed to restore last checkin time."; |
| + return false; |
| + } |
| + *last_checkin_time = base::Time::FromInternalValue(time_internal); |
| + } |
| + |
| + return true; |
| +} |
| + |
| GCMStoreImpl::GCMStoreImpl( |
| bool use_mock_keychain, |
| const base::FilePath& path, |
| @@ -734,6 +836,19 @@ void GCMStoreImpl::RemoveOutgoingMessages( |
| callback))); |
| } |
| +void GCMStoreImpl::UpdateGServicesSettings( |
| + const std::vector<std::string>& settings_to_remove, |
| + const std::map<std::string, std::string>& settings_to_add, |
| + const UpdateCallback& callback) { |
| + blocking_task_runner_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&GCMStoreImpl::Backend::UpdateGServicesSettings, |
| + backend_, |
| + settings_to_remove, |
| + settings_to_add, |
| + callback)); |
| +} |
| + |
| void GCMStoreImpl::LoadContinuation(const LoadCallback& callback, |
| scoped_ptr<LoadResult> result) { |
| if (!result->success) { |