| 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 df35925a5bc0ea6ca51ca4cf08e3db85c2e2223b..3764d0fbb5a3f6d3be3ef798b1d017d0427097f6 100644
|
| --- a/google_apis/gcm/engine/gcm_store_impl.cc
|
| +++ b/google_apis/gcm/engine/gcm_store_impl.cc
|
| @@ -68,6 +68,12 @@ const char kGServiceSettingsDigestKey[] = "gservices_digest";
|
| const char kLastCheckinAccountsKey[] = "last_checkin_accounts_count";
|
| // Key used to timestamp last checkin (marked with G services settings update).
|
| const char kLastCheckinTimeKey[] = "last_checkin_time";
|
| +// Lowest lexicographically ordered account key.
|
| +// Used for prefixing account information.
|
| +const char kAccountKeyStart[] = "account1-";
|
| +// Key guaranteed to be higher than all account keys.
|
| +// Used for limiting iteration.
|
| +const char kAccountKeyEnd[] = "account2-";
|
|
|
| std::string MakeRegistrationKey(const std::string& app_id) {
|
| return kRegistrationKeyStart + app_id;
|
| @@ -97,6 +103,14 @@ std::string ParseGServiceSettingKey(const std::string& key) {
|
| return key.substr(arraysize(kGServiceSettingKeyStart) - 1);
|
| }
|
|
|
| +std::string MakeAccountKey(const std::string& account_id) {
|
| + return kAccountKeyStart + account_id;
|
| +}
|
| +
|
| +std::string ParseAccountKey(const std::string& key) {
|
| + return key.substr(arraysize(kAccountKeyStart) - 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.
|
| @@ -148,6 +162,10 @@ class GCMStoreImpl::Backend
|
| const std::map<std::string, std::string>& settings,
|
| const std::string& digest,
|
| const UpdateCallback& callback);
|
| + void AddAccountMapping(const AccountInfo& account_info,
|
| + const UpdateCallback& callback);
|
| + void RemoveAccountMapping(const std::string& account_id,
|
| + const UpdateCallback& callback);
|
|
|
| private:
|
| friend class base::RefCountedThreadSafe<Backend>;
|
| @@ -161,6 +179,7 @@ class GCMStoreImpl::Backend
|
| std::set<std::string>* accounts);
|
| bool LoadGServicesSettings(std::map<std::string, std::string>* settings,
|
| std::string* digest);
|
| + bool LoadAccountMappingInfo(AccountInfoMap* account_infos);
|
|
|
| const base::FilePath path_;
|
| scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
|
| @@ -214,15 +233,9 @@ void GCMStoreImpl::Backend::Load(const LoadCallback& callback) {
|
| !LoadLastCheckinInfo(&result->last_checkin_time,
|
| &result->last_checkin_accounts) ||
|
| !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);
|
| + &result->gservices_digest) ||
|
| + !LoadAccountMappingInfo(&result->account_infos)) {
|
| + result->Reset();
|
| foreground_task_runner_->PostTask(FROM_HERE,
|
| base::Bind(callback,
|
| base::Passed(&result)));
|
| @@ -561,6 +574,48 @@ void GCMStoreImpl::Backend::SetGServicesSettings(
|
| foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
|
| }
|
|
|
| +void GCMStoreImpl::Backend::AddAccountMapping(const AccountInfo& account_info,
|
| + const UpdateCallback& callback) {
|
| + DVLOG(1) << "Saving account info for account with email: "
|
| + << account_info.email;
|
| + if (!db_.get()) {
|
| + LOG(ERROR) << "GCMStore db doesn't exist.";
|
| + foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
|
| + return;
|
| + }
|
| +
|
| + leveldb::WriteOptions write_options;
|
| + write_options.sync = true;
|
| +
|
| + std::string data = account_info.SerializeAsString();
|
| + std::string key = MakeAccountKey(account_info.account_id);
|
| + const leveldb::Status s =
|
| + db_->Put(write_options, MakeSlice(key), MakeSlice(data));
|
| + if (!s.ok())
|
| + LOG(ERROR) << "LevelDB adding account mapping failed: " << s.ToString();
|
| + foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
|
| +}
|
| +
|
| +void GCMStoreImpl::Backend::RemoveAccountMapping(
|
| + const std::string& account_id,
|
| + const UpdateCallback& callback) {
|
| + if (!db_.get()) {
|
| + LOG(ERROR) << "GCMStore db doesn't exist.";
|
| + foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
|
| + return;
|
| + }
|
| +
|
| + leveldb::WriteOptions write_options;
|
| + write_options.sync = true;
|
| +
|
| + leveldb::Status s =
|
| + db_->Delete(write_options, MakeSlice(MakeAccountKey(account_id)));
|
| +
|
| + if (!s.ok())
|
| + LOG(ERROR) << "LevelDB removal of account mapping 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;
|
| @@ -734,6 +789,29 @@ bool GCMStoreImpl::Backend::LoadGServicesSettings(
|
| return true;
|
| }
|
|
|
| +bool GCMStoreImpl::Backend::LoadAccountMappingInfo(
|
| + AccountInfoMap* account_infos) {
|
| + leveldb::ReadOptions read_options;
|
| + read_options.verify_checksums = true;
|
| +
|
| + scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
|
| + for (iter->Seek(MakeSlice(kAccountKeyStart));
|
| + iter->Valid() && iter->key().ToString() < kAccountKeyEnd;
|
| + iter->Next()) {
|
| + AccountInfo account_info;
|
| + account_info.account_id = ParseAccountKey(iter->key().ToString());
|
| + if (!account_info.ParseFromString(iter->value().ToString())) {
|
| + DVLOG(1) << "Failed to parse account info with ID: "
|
| + << account_info.account_id;
|
| + return false;
|
| + }
|
| + DVLOG(1) << "Found account mapping with ID: " << account_info.account_id;
|
| + (*account_infos)[account_info.account_id] = account_info;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| GCMStoreImpl::GCMStoreImpl(
|
| const base::FilePath& path,
|
| scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
|
| @@ -933,6 +1011,26 @@ void GCMStoreImpl::SetGServicesSettings(
|
| callback));
|
| }
|
|
|
| +void GCMStoreImpl::AddAccountMapping(const AccountInfo& account_info,
|
| + const UpdateCallback& callback) {
|
| + blocking_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&GCMStoreImpl::Backend::AddAccountMapping,
|
| + backend_,
|
| + account_info,
|
| + callback));
|
| +}
|
| +
|
| +void GCMStoreImpl::RemoveAccountMapping(const std::string& account_id,
|
| + const UpdateCallback& callback) {
|
| + blocking_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&GCMStoreImpl::Backend::RemoveAccountMapping,
|
| + backend_,
|
| + account_id,
|
| + callback));
|
| +}
|
| +
|
| void GCMStoreImpl::LoadContinuation(const LoadCallback& callback,
|
| scoped_ptr<LoadResult> result) {
|
| if (!result->success) {
|
|
|