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 |