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) { |