| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "google_apis/gcm/engine/gcm_store_impl.h" | 5 #include "google_apis/gcm/engine/gcm_store_impl.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/callback.h" | 9 #include "base/callback.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 const char kGServiceSettingKeyStart[] = "gservice1-"; | 61 const char kGServiceSettingKeyStart[] = "gservice1-"; |
| 62 // Key guaranteed to be higher than all G-services settings keys. | 62 // Key guaranteed to be higher than all G-services settings keys. |
| 63 // Used for limiting iteration. | 63 // Used for limiting iteration. |
| 64 const char kGServiceSettingKeyEnd[] = "gservice2-"; | 64 const char kGServiceSettingKeyEnd[] = "gservice2-"; |
| 65 // Key for digest of the last G-services settings update. | 65 // Key for digest of the last G-services settings update. |
| 66 const char kGServiceSettingsDigestKey[] = "gservices_digest"; | 66 const char kGServiceSettingsDigestKey[] = "gservices_digest"; |
| 67 // Key used to indicate how many accounts were last checked in with this device. | 67 // Key used to indicate how many accounts were last checked in with this device. |
| 68 const char kLastCheckinAccountsKey[] = "last_checkin_accounts_count"; | 68 const char kLastCheckinAccountsKey[] = "last_checkin_accounts_count"; |
| 69 // Key used to timestamp last checkin (marked with G services settings update). | 69 // Key used to timestamp last checkin (marked with G services settings update). |
| 70 const char kLastCheckinTimeKey[] = "last_checkin_time"; | 70 const char kLastCheckinTimeKey[] = "last_checkin_time"; |
| 71 // Lowest lexicographically ordered account key. |
| 72 // Used for prefixing account information. |
| 73 const char kAccountKeyStart[] = "account1-"; |
| 74 // Key guaranteed to be higher than all account keys. |
| 75 // Used for limiting iteration. |
| 76 const char kAccountKeyEnd[] = "account2-"; |
| 71 | 77 |
| 72 std::string MakeRegistrationKey(const std::string& app_id) { | 78 std::string MakeRegistrationKey(const std::string& app_id) { |
| 73 return kRegistrationKeyStart + app_id; | 79 return kRegistrationKeyStart + app_id; |
| 74 } | 80 } |
| 75 | 81 |
| 76 std::string ParseRegistrationKey(const std::string& key) { | 82 std::string ParseRegistrationKey(const std::string& key) { |
| 77 return key.substr(arraysize(kRegistrationKeyStart) - 1); | 83 return key.substr(arraysize(kRegistrationKeyStart) - 1); |
| 78 } | 84 } |
| 79 | 85 |
| 80 std::string MakeIncomingKey(const std::string& persistent_id) { | 86 std::string MakeIncomingKey(const std::string& persistent_id) { |
| 81 return kIncomingMsgKeyStart + persistent_id; | 87 return kIncomingMsgKeyStart + persistent_id; |
| 82 } | 88 } |
| 83 | 89 |
| 84 std::string MakeOutgoingKey(const std::string& persistent_id) { | 90 std::string MakeOutgoingKey(const std::string& persistent_id) { |
| 85 return kOutgoingMsgKeyStart + persistent_id; | 91 return kOutgoingMsgKeyStart + persistent_id; |
| 86 } | 92 } |
| 87 | 93 |
| 88 std::string ParseOutgoingKey(const std::string& key) { | 94 std::string ParseOutgoingKey(const std::string& key) { |
| 89 return key.substr(arraysize(kOutgoingMsgKeyStart) - 1); | 95 return key.substr(arraysize(kOutgoingMsgKeyStart) - 1); |
| 90 } | 96 } |
| 91 | 97 |
| 92 std::string MakeGServiceSettingKey(const std::string& setting_name) { | 98 std::string MakeGServiceSettingKey(const std::string& setting_name) { |
| 93 return kGServiceSettingKeyStart + setting_name; | 99 return kGServiceSettingKeyStart + setting_name; |
| 94 } | 100 } |
| 95 | 101 |
| 96 std::string ParseGServiceSettingKey(const std::string& key) { | 102 std::string ParseGServiceSettingKey(const std::string& key) { |
| 97 return key.substr(arraysize(kGServiceSettingKeyStart) - 1); | 103 return key.substr(arraysize(kGServiceSettingKeyStart) - 1); |
| 98 } | 104 } |
| 99 | 105 |
| 106 std::string MakeAccountKey(const std::string& account_id) { |
| 107 return kAccountKeyStart + account_id; |
| 108 } |
| 109 |
| 110 std::string ParseAccountKey(const std::string& key) { |
| 111 return key.substr(arraysize(kAccountKeyStart) - 1); |
| 112 } |
| 113 |
| 100 // Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore | 114 // Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore |
| 101 // outlive the slice. | 115 // outlive the slice. |
| 102 // For example: MakeSlice(MakeOutgoingKey(x)) is invalid. | 116 // For example: MakeSlice(MakeOutgoingKey(x)) is invalid. |
| 103 leveldb::Slice MakeSlice(const base::StringPiece& s) { | 117 leveldb::Slice MakeSlice(const base::StringPiece& s) { |
| 104 return leveldb::Slice(s.begin(), s.size()); | 118 return leveldb::Slice(s.begin(), s.size()); |
| 105 } | 119 } |
| 106 | 120 |
| 107 } // namespace | 121 } // namespace |
| 108 | 122 |
| 109 class GCMStoreImpl::Backend | 123 class GCMStoreImpl::Backend |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 const UpdateCallback& callback); | 155 const UpdateCallback& callback); |
| 142 void RemoveUserSerialNumber(const std::string& username, | 156 void RemoveUserSerialNumber(const std::string& username, |
| 143 const UpdateCallback& callback); | 157 const UpdateCallback& callback); |
| 144 void SetLastCheckinInfo(const base::Time& time, | 158 void SetLastCheckinInfo(const base::Time& time, |
| 145 const std::set<std::string>& accounts, | 159 const std::set<std::string>& accounts, |
| 146 const UpdateCallback& callback); | 160 const UpdateCallback& callback); |
| 147 void SetGServicesSettings( | 161 void SetGServicesSettings( |
| 148 const std::map<std::string, std::string>& settings, | 162 const std::map<std::string, std::string>& settings, |
| 149 const std::string& digest, | 163 const std::string& digest, |
| 150 const UpdateCallback& callback); | 164 const UpdateCallback& callback); |
| 165 void AddAccountMapping(const AccountInfo& account_info, |
| 166 const UpdateCallback& callback); |
| 167 void RemoveAccountMapping(const std::string& account_id, |
| 168 const UpdateCallback& callback); |
| 151 | 169 |
| 152 private: | 170 private: |
| 153 friend class base::RefCountedThreadSafe<Backend>; | 171 friend class base::RefCountedThreadSafe<Backend>; |
| 154 ~Backend(); | 172 ~Backend(); |
| 155 | 173 |
| 156 bool LoadDeviceCredentials(uint64* android_id, uint64* security_token); | 174 bool LoadDeviceCredentials(uint64* android_id, uint64* security_token); |
| 157 bool LoadRegistrations(RegistrationInfoMap* registrations); | 175 bool LoadRegistrations(RegistrationInfoMap* registrations); |
| 158 bool LoadIncomingMessages(std::vector<std::string>* incoming_messages); | 176 bool LoadIncomingMessages(std::vector<std::string>* incoming_messages); |
| 159 bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages); | 177 bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages); |
| 160 bool LoadLastCheckinInfo(base::Time* last_checkin_time, | 178 bool LoadLastCheckinInfo(base::Time* last_checkin_time, |
| 161 std::set<std::string>* accounts); | 179 std::set<std::string>* accounts); |
| 162 bool LoadGServicesSettings(std::map<std::string, std::string>* settings, | 180 bool LoadGServicesSettings(std::map<std::string, std::string>* settings, |
| 163 std::string* digest); | 181 std::string* digest); |
| 182 bool LoadAccountMappingInfo(AccountInfoMap* account_infos); |
| 164 | 183 |
| 165 const base::FilePath path_; | 184 const base::FilePath path_; |
| 166 scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_; | 185 scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_; |
| 167 scoped_ptr<Encryptor> encryptor_; | 186 scoped_ptr<Encryptor> encryptor_; |
| 168 | 187 |
| 169 scoped_ptr<leveldb::DB> db_; | 188 scoped_ptr<leveldb::DB> db_; |
| 170 }; | 189 }; |
| 171 | 190 |
| 172 GCMStoreImpl::Backend::Backend( | 191 GCMStoreImpl::Backend::Backend( |
| 173 const base::FilePath& path, | 192 const base::FilePath& path, |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 db_.reset(db); | 226 db_.reset(db); |
| 208 | 227 |
| 209 if (!LoadDeviceCredentials(&result->device_android_id, | 228 if (!LoadDeviceCredentials(&result->device_android_id, |
| 210 &result->device_security_token) || | 229 &result->device_security_token) || |
| 211 !LoadRegistrations(&result->registrations) || | 230 !LoadRegistrations(&result->registrations) || |
| 212 !LoadIncomingMessages(&result->incoming_messages) || | 231 !LoadIncomingMessages(&result->incoming_messages) || |
| 213 !LoadOutgoingMessages(&result->outgoing_messages) || | 232 !LoadOutgoingMessages(&result->outgoing_messages) || |
| 214 !LoadLastCheckinInfo(&result->last_checkin_time, | 233 !LoadLastCheckinInfo(&result->last_checkin_time, |
| 215 &result->last_checkin_accounts) || | 234 &result->last_checkin_accounts) || |
| 216 !LoadGServicesSettings(&result->gservices_settings, | 235 !LoadGServicesSettings(&result->gservices_settings, |
| 217 &result->gservices_digest)) { | 236 &result->gservices_digest) || |
| 218 result->device_android_id = 0; | 237 !LoadAccountMappingInfo(&result->account_infos)) { |
| 219 result->device_security_token = 0; | 238 result->Reset(); |
| 220 result->registrations.clear(); | |
| 221 result->incoming_messages.clear(); | |
| 222 result->outgoing_messages.clear(); | |
| 223 result->gservices_settings.clear(); | |
| 224 result->gservices_digest.clear(); | |
| 225 result->last_checkin_time = base::Time::FromInternalValue(0LL); | |
| 226 foreground_task_runner_->PostTask(FROM_HERE, | 239 foreground_task_runner_->PostTask(FROM_HERE, |
| 227 base::Bind(callback, | 240 base::Bind(callback, |
| 228 base::Passed(&result))); | 241 base::Passed(&result))); |
| 229 return; | 242 return; |
| 230 } | 243 } |
| 231 | 244 |
| 232 // Only record histograms if GCM had already been set up for this device. | 245 // Only record histograms if GCM had already been set up for this device. |
| 233 if (result->device_android_id != 0 && result->device_security_token != 0) { | 246 if (result->device_android_id != 0 && result->device_security_token != 0) { |
| 234 int64 file_size = 0; | 247 int64 file_size = 0; |
| 235 if (base::GetFileSize(path_, &file_size)) { | 248 if (base::GetFileSize(path_, &file_size)) { |
| (...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 554 // Write it all in a batch. | 567 // Write it all in a batch. |
| 555 leveldb::WriteOptions write_options; | 568 leveldb::WriteOptions write_options; |
| 556 write_options.sync = true; | 569 write_options.sync = true; |
| 557 | 570 |
| 558 leveldb::Status s = db_->Write(write_options, &write_batch); | 571 leveldb::Status s = db_->Write(write_options, &write_batch); |
| 559 if (!s.ok()) | 572 if (!s.ok()) |
| 560 LOG(ERROR) << "LevelDB GService Settings update failed: " << s.ToString(); | 573 LOG(ERROR) << "LevelDB GService Settings update failed: " << s.ToString(); |
| 561 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok())); | 574 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok())); |
| 562 } | 575 } |
| 563 | 576 |
| 577 void GCMStoreImpl::Backend::AddAccountMapping(const AccountInfo& account_info, |
| 578 const UpdateCallback& callback) { |
| 579 DVLOG(1) << "Saving account info for account with email: " |
| 580 << account_info.email; |
| 581 if (!db_.get()) { |
| 582 LOG(ERROR) << "GCMStore db doesn't exist."; |
| 583 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false)); |
| 584 return; |
| 585 } |
| 586 |
| 587 leveldb::WriteOptions write_options; |
| 588 write_options.sync = true; |
| 589 |
| 590 std::string data = account_info.SerializeAsString(); |
| 591 std::string key = MakeAccountKey(account_info.account_id); |
| 592 const leveldb::Status s = |
| 593 db_->Put(write_options, MakeSlice(key), MakeSlice(data)); |
| 594 if (!s.ok()) |
| 595 LOG(ERROR) << "LevelDB adding account mapping failed: " << s.ToString(); |
| 596 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok())); |
| 597 } |
| 598 |
| 599 void GCMStoreImpl::Backend::RemoveAccountMapping( |
| 600 const std::string& account_id, |
| 601 const UpdateCallback& callback) { |
| 602 if (!db_.get()) { |
| 603 LOG(ERROR) << "GCMStore db doesn't exist."; |
| 604 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false)); |
| 605 return; |
| 606 } |
| 607 |
| 608 leveldb::WriteOptions write_options; |
| 609 write_options.sync = true; |
| 610 |
| 611 leveldb::Status s = |
| 612 db_->Delete(write_options, MakeSlice(MakeAccountKey(account_id))); |
| 613 |
| 614 if (!s.ok()) |
| 615 LOG(ERROR) << "LevelDB removal of account mapping failed: " << s.ToString(); |
| 616 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok())); |
| 617 } |
| 618 |
| 564 bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id, | 619 bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id, |
| 565 uint64* security_token) { | 620 uint64* security_token) { |
| 566 leveldb::ReadOptions read_options; | 621 leveldb::ReadOptions read_options; |
| 567 read_options.verify_checksums = true; | 622 read_options.verify_checksums = true; |
| 568 | 623 |
| 569 std::string result; | 624 std::string result; |
| 570 leveldb::Status s = db_->Get(read_options, MakeSlice(kDeviceAIDKey), &result); | 625 leveldb::Status s = db_->Get(read_options, MakeSlice(kDeviceAIDKey), &result); |
| 571 if (s.ok()) { | 626 if (s.ok()) { |
| 572 if (!base::StringToUint64(result, android_id)) { | 627 if (!base::StringToUint64(result, android_id)) { |
| 573 LOG(ERROR) << "Failed to restore device id."; | 628 LOG(ERROR) << "Failed to restore device id."; |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 727 DVLOG(1) << "Found G Service setting with key: " << id | 782 DVLOG(1) << "Found G Service setting with key: " << id |
| 728 << ", and value: " << value; | 783 << ", and value: " << value; |
| 729 } | 784 } |
| 730 | 785 |
| 731 // Load the settings digest. It's ok if it is empty. | 786 // Load the settings digest. It's ok if it is empty. |
| 732 db_->Get(read_options, MakeSlice(kGServiceSettingsDigestKey), digest); | 787 db_->Get(read_options, MakeSlice(kGServiceSettingsDigestKey), digest); |
| 733 | 788 |
| 734 return true; | 789 return true; |
| 735 } | 790 } |
| 736 | 791 |
| 792 bool GCMStoreImpl::Backend::LoadAccountMappingInfo( |
| 793 AccountInfoMap* account_infos) { |
| 794 leveldb::ReadOptions read_options; |
| 795 read_options.verify_checksums = true; |
| 796 |
| 797 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options)); |
| 798 for (iter->Seek(MakeSlice(kAccountKeyStart)); |
| 799 iter->Valid() && iter->key().ToString() < kAccountKeyEnd; |
| 800 iter->Next()) { |
| 801 AccountInfo account_info; |
| 802 account_info.account_id = ParseAccountKey(iter->key().ToString()); |
| 803 if (!account_info.ParseFromString(iter->value().ToString())) { |
| 804 DVLOG(1) << "Failed to parse account info with ID: " |
| 805 << account_info.account_id; |
| 806 return false; |
| 807 } |
| 808 DVLOG(1) << "Found account mapping with ID: " << account_info.account_id; |
| 809 (*account_infos)[account_info.account_id] = account_info; |
| 810 } |
| 811 |
| 812 return true; |
| 813 } |
| 814 |
| 737 GCMStoreImpl::GCMStoreImpl( | 815 GCMStoreImpl::GCMStoreImpl( |
| 738 const base::FilePath& path, | 816 const base::FilePath& path, |
| 739 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, | 817 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, |
| 740 scoped_ptr<Encryptor> encryptor) | 818 scoped_ptr<Encryptor> encryptor) |
| 741 : backend_(new Backend(path, | 819 : backend_(new Backend(path, |
| 742 base::MessageLoopProxy::current(), | 820 base::MessageLoopProxy::current(), |
| 743 encryptor.Pass())), | 821 encryptor.Pass())), |
| 744 blocking_task_runner_(blocking_task_runner), | 822 blocking_task_runner_(blocking_task_runner), |
| 745 weak_ptr_factory_(this) { | 823 weak_ptr_factory_(this) { |
| 746 } | 824 } |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 926 const UpdateCallback& callback) { | 1004 const UpdateCallback& callback) { |
| 927 blocking_task_runner_->PostTask( | 1005 blocking_task_runner_->PostTask( |
| 928 FROM_HERE, | 1006 FROM_HERE, |
| 929 base::Bind(&GCMStoreImpl::Backend::SetGServicesSettings, | 1007 base::Bind(&GCMStoreImpl::Backend::SetGServicesSettings, |
| 930 backend_, | 1008 backend_, |
| 931 settings, | 1009 settings, |
| 932 digest, | 1010 digest, |
| 933 callback)); | 1011 callback)); |
| 934 } | 1012 } |
| 935 | 1013 |
| 1014 void GCMStoreImpl::AddAccountMapping(const AccountInfo& account_info, |
| 1015 const UpdateCallback& callback) { |
| 1016 blocking_task_runner_->PostTask( |
| 1017 FROM_HERE, |
| 1018 base::Bind(&GCMStoreImpl::Backend::AddAccountMapping, |
| 1019 backend_, |
| 1020 account_info, |
| 1021 callback)); |
| 1022 } |
| 1023 |
| 1024 void GCMStoreImpl::RemoveAccountMapping(const std::string& account_id, |
| 1025 const UpdateCallback& callback) { |
| 1026 blocking_task_runner_->PostTask( |
| 1027 FROM_HERE, |
| 1028 base::Bind(&GCMStoreImpl::Backend::RemoveAccountMapping, |
| 1029 backend_, |
| 1030 account_id, |
| 1031 callback)); |
| 1032 } |
| 1033 |
| 936 void GCMStoreImpl::LoadContinuation(const LoadCallback& callback, | 1034 void GCMStoreImpl::LoadContinuation(const LoadCallback& callback, |
| 937 scoped_ptr<LoadResult> result) { | 1035 scoped_ptr<LoadResult> result) { |
| 938 if (!result->success) { | 1036 if (!result->success) { |
| 939 callback.Run(result.Pass()); | 1037 callback.Run(result.Pass()); |
| 940 return; | 1038 return; |
| 941 } | 1039 } |
| 942 int num_throttled_apps = 0; | 1040 int num_throttled_apps = 0; |
| 943 for (OutgoingMessageMap::const_iterator | 1041 for (OutgoingMessageMap::const_iterator |
| 944 iter = result->outgoing_messages.begin(); | 1042 iter = result->outgoing_messages.begin(); |
| 945 iter != result->outgoing_messages.end(); ++iter) { | 1043 iter != result->outgoing_messages.end(); ++iter) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 980 removed_message_counts.begin(); | 1078 removed_message_counts.begin(); |
| 981 iter != removed_message_counts.end(); ++iter) { | 1079 iter != removed_message_counts.end(); ++iter) { |
| 982 DCHECK_NE(app_message_counts_.count(iter->first), 0U); | 1080 DCHECK_NE(app_message_counts_.count(iter->first), 0U); |
| 983 app_message_counts_[iter->first] -= iter->second; | 1081 app_message_counts_[iter->first] -= iter->second; |
| 984 DCHECK_GE(app_message_counts_[iter->first], 0); | 1082 DCHECK_GE(app_message_counts_[iter->first], 0); |
| 985 } | 1083 } |
| 986 callback.Run(true); | 1084 callback.Run(true); |
| 987 } | 1085 } |
| 988 | 1086 |
| 989 } // namespace gcm | 1087 } // namespace gcm |
| OLD | NEW |