Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(992)

Side by Side Diff: google_apis/gcm/engine/gcm_store_impl.cc

Issue 215363007: [GCM] Adding basic G-services handling (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Converting service write to the store to a full replace, adding digest to checkin request, addressi… Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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"
11 #include "base/files/file_path.h" 11 #include "base/files/file_path.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/message_loop/message_loop_proxy.h" 13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
15 #include "base/sequenced_task_runner.h" 15 #include "base/sequenced_task_runner.h"
16 #include "base/stl_util.h" 16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_piece.h" 18 #include "base/strings/string_piece.h"
19 #include "base/time/time.h"
19 #include "base/tracked_objects.h" 20 #include "base/tracked_objects.h"
20 #include "components/os_crypt/os_crypt.h" 21 #include "components/os_crypt/os_crypt.h"
21 #include "google_apis/gcm/base/mcs_message.h" 22 #include "google_apis/gcm/base/mcs_message.h"
22 #include "google_apis/gcm/base/mcs_util.h" 23 #include "google_apis/gcm/base/mcs_util.h"
23 #include "google_apis/gcm/protocol/mcs.pb.h" 24 #include "google_apis/gcm/protocol/mcs.pb.h"
24 #include "third_party/leveldatabase/src/include/leveldb/db.h" 25 #include "third_party/leveldatabase/src/include/leveldb/db.h"
26 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
25 27
26 namespace gcm { 28 namespace gcm {
27 29
28 namespace { 30 namespace {
29 31
30 // Limit to the number of outstanding messages per app. 32 // Limit to the number of outstanding messages per app.
31 const int kMessagesPerAppLimit = 20; 33 const int kMessagesPerAppLimit = 20;
32 34
33 // ---- LevelDB keys. ---- 35 // ---- LevelDB keys. ----
34 // Key for this device's android id. 36 // Key for this device's android id.
(...skipping 11 matching lines...) Expand all
46 const char kIncomingMsgKeyStart[] = "incoming1-"; 48 const char kIncomingMsgKeyStart[] = "incoming1-";
47 // Key guaranteed to be higher than all incoming message keys. 49 // Key guaranteed to be higher than all incoming message keys.
48 // Used for limiting iteration. 50 // Used for limiting iteration.
49 const char kIncomingMsgKeyEnd[] = "incoming2-"; 51 const char kIncomingMsgKeyEnd[] = "incoming2-";
50 // Lowest lexicographically ordered outgoing message key. 52 // Lowest lexicographically ordered outgoing message key.
51 // Used for prefixing outgoing messages. 53 // Used for prefixing outgoing messages.
52 const char kOutgoingMsgKeyStart[] = "outgoing1-"; 54 const char kOutgoingMsgKeyStart[] = "outgoing1-";
53 // Key guaranteed to be higher than all outgoing message keys. 55 // Key guaranteed to be higher than all outgoing message keys.
54 // Used for limiting iteration. 56 // Used for limiting iteration.
55 const char kOutgoingMsgKeyEnd[] = "outgoing2-"; 57 const char kOutgoingMsgKeyEnd[] = "outgoing2-";
58 // Lowest lexicographically ordered G service settings key.
jianli 2014/04/01 20:17:17 nit: G-service
fgorski 2014/04/01 20:47:54 Done.
59 // Used for prefixing G services settings.
60 const char kGServiceSettingKeyStart[] = "Gservice1-";
jianli 2014/04/01 20:17:17 nit: Make the 1st letter lower case in order to be
fgorski 2014/04/01 20:47:54 Done.
61 // Key guaranteed to be higher than all G services settings keys.
62 // Used for limiting iteration.
63 const char kGServiceSettingKeyEnd[] = "Gservice2-";
64 // Key for digest of the last G services settings update.
65 const char kGServiceSettingsDigestKey[] = "gservices_digest";
66 // Key used to timestamp last checkin (marked with G services settings update).
67 const char kLastCheckinTimeKey[] = "last_checkin_time";
56 68
57 std::string MakeRegistrationKey(const std::string& app_id) { 69 std::string MakeRegistrationKey(const std::string& app_id) {
58 return kRegistrationKeyStart + app_id; 70 return kRegistrationKeyStart + app_id;
59 } 71 }
60 72
61 std::string ParseRegistrationKey(const std::string& key) { 73 std::string ParseRegistrationKey(const std::string& key) {
62 return key.substr(arraysize(kRegistrationKeyStart) - 1); 74 return key.substr(arraysize(kRegistrationKeyStart) - 1);
63 } 75 }
64 76
65 std::string MakeIncomingKey(const std::string& persistent_id) { 77 std::string MakeIncomingKey(const std::string& persistent_id) {
66 return kIncomingMsgKeyStart + persistent_id; 78 return kIncomingMsgKeyStart + persistent_id;
67 } 79 }
68 80
69 std::string MakeOutgoingKey(const std::string& persistent_id) { 81 std::string MakeOutgoingKey(const std::string& persistent_id) {
70 return kOutgoingMsgKeyStart + persistent_id; 82 return kOutgoingMsgKeyStart + persistent_id;
71 } 83 }
72 84
73 std::string ParseOutgoingKey(const std::string& key) { 85 std::string ParseOutgoingKey(const std::string& key) {
74 return key.substr(arraysize(kOutgoingMsgKeyStart) - 1); 86 return key.substr(arraysize(kOutgoingMsgKeyStart) - 1);
75 } 87 }
76 88
89 std::string MakeGServiceSettingKey(const std::string& setting_name) {
90 return kGServiceSettingKeyStart + setting_name;
91 }
92
93 std::string ParseGServiceSettingKey(const std::string& key) {
94 return key.substr(arraysize(kGServiceSettingKeyStart) - 1);
95 }
96
77 // Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore 97 // Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore
78 // outlive the slice. 98 // outlive the slice.
79 // For example: MakeSlice(MakeOutgoingKey(x)) is invalid. 99 // For example: MakeSlice(MakeOutgoingKey(x)) is invalid.
80 leveldb::Slice MakeSlice(const base::StringPiece& s) { 100 leveldb::Slice MakeSlice(const base::StringPiece& s) {
81 return leveldb::Slice(s.begin(), s.size()); 101 return leveldb::Slice(s.begin(), s.size());
82 } 102 }
83 103
84 } // namespace 104 } // namespace
85 105
86 class GCMStoreImpl::Backend 106 class GCMStoreImpl::Backend
(...skipping 24 matching lines...) Expand all
111 void RemoveOutgoingMessages( 131 void RemoveOutgoingMessages(
112 const PersistentIdList& persistent_ids, 132 const PersistentIdList& persistent_ids,
113 const base::Callback<void(bool, const AppIdToMessageCountMap&)> 133 const base::Callback<void(bool, const AppIdToMessageCountMap&)>
114 callback); 134 callback);
115 void AddUserSerialNumber(const std::string& username, 135 void AddUserSerialNumber(const std::string& username,
116 int64 serial_number, 136 int64 serial_number,
117 const UpdateCallback& callback); 137 const UpdateCallback& callback);
118 void RemoveUserSerialNumber(const std::string& username, 138 void RemoveUserSerialNumber(const std::string& username,
119 const UpdateCallback& callback); 139 const UpdateCallback& callback);
120 void SetNextSerialNumber(int64 serial_number, const UpdateCallback& callback); 140 void SetNextSerialNumber(int64 serial_number, const UpdateCallback& callback);
141 void UpdateGServicesSettings(
jianli 2014/04/01 20:17:17 nit: SetGServicesSettings
fgorski 2014/04/01 20:47:54 Done.
142 const std::map<std::string, std::string>& new_settings,
jianli 2014/04/01 20:17:17 nit: settings
fgorski 2014/04/01 20:47:54 Done.
143 const std::string& digest,
144 const base::Time& last_checkin_time,
145 const UpdateCallback& callback);
121 146
122 private: 147 private:
123 friend class base::RefCountedThreadSafe<Backend>; 148 friend class base::RefCountedThreadSafe<Backend>;
124 ~Backend(); 149 ~Backend();
125 150
126 bool LoadDeviceCredentials(uint64* android_id, uint64* security_token); 151 bool LoadDeviceCredentials(uint64* android_id, uint64* security_token);
127 bool LoadRegistrations(RegistrationInfoMap* registrations); 152 bool LoadRegistrations(RegistrationInfoMap* registrations);
128 bool LoadIncomingMessages(std::vector<std::string>* incoming_messages); 153 bool LoadIncomingMessages(std::vector<std::string>* incoming_messages);
129 bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages); 154 bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages);
155 bool LoadGServicesSettings(std::map<std::string, std::string>* settings,
156 std::string* digest,
157 base::Time* last_checkin_time);
130 158
131 const base::FilePath path_; 159 const base::FilePath path_;
132 scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_; 160 scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
133 161
134 scoped_ptr<leveldb::DB> db_; 162 scoped_ptr<leveldb::DB> db_;
135 }; 163 };
136 164
137 GCMStoreImpl::Backend::Backend( 165 GCMStoreImpl::Backend::Backend(
138 const base::FilePath& path, 166 const base::FilePath& path,
139 scoped_refptr<base::SequencedTaskRunner> foreground_task_runner) 167 scoped_refptr<base::SequencedTaskRunner> foreground_task_runner)
(...skipping 24 matching lines...) Expand all
164 base::Bind(callback, 192 base::Bind(callback,
165 base::Passed(&result))); 193 base::Passed(&result)));
166 return; 194 return;
167 } 195 }
168 db_.reset(db); 196 db_.reset(db);
169 197
170 if (!LoadDeviceCredentials(&result->device_android_id, 198 if (!LoadDeviceCredentials(&result->device_android_id,
171 &result->device_security_token) || 199 &result->device_security_token) ||
172 !LoadRegistrations(&result->registrations) || 200 !LoadRegistrations(&result->registrations) ||
173 !LoadIncomingMessages(&result->incoming_messages) || 201 !LoadIncomingMessages(&result->incoming_messages) ||
174 !LoadOutgoingMessages(&result->outgoing_messages)) { 202 !LoadOutgoingMessages(&result->outgoing_messages) ||
203 !LoadGServicesSettings(&result->gservices_settings,
204 &result->gservices_digest,
205 &result->last_checkin_time)) {
175 result->device_android_id = 0; 206 result->device_android_id = 0;
176 result->device_security_token = 0; 207 result->device_security_token = 0;
177 result->registrations.clear(); 208 result->registrations.clear();
178 result->incoming_messages.clear(); 209 result->incoming_messages.clear();
179 result->outgoing_messages.clear(); 210 result->outgoing_messages.clear();
211 result->last_checkin_time = base::Time::FromInternalValue(0LL);
jianli 2014/04/01 20:17:17 Do we also want to clear gservices_settings when t
fgorski 2014/04/01 20:47:54 Done.
180 foreground_task_runner_->PostTask(FROM_HERE, 212 foreground_task_runner_->PostTask(FROM_HERE,
181 base::Bind(callback, 213 base::Bind(callback,
182 base::Passed(&result))); 214 base::Passed(&result)));
183 return; 215 return;
184 } 216 }
185 217
186 // Only record histograms if GCM had already been set up for this device. 218 // Only record histograms if GCM had already been set up for this device.
187 if (result->device_android_id != 0 && result->device_security_token != 0) { 219 if (result->device_android_id != 0 && result->device_security_token != 0) {
188 int64 file_size = 0; 220 int64 file_size = 0;
189 if (base::GetFileSize(path_, &file_size)) { 221 if (base::GetFileSize(path_, &file_size)) {
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 removed_message_counts)); 470 removed_message_counts));
439 return; 471 return;
440 } 472 }
441 LOG(ERROR) << "LevelDB remove failed: " << s.ToString(); 473 LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
442 foreground_task_runner_->PostTask(FROM_HERE, 474 foreground_task_runner_->PostTask(FROM_HERE,
443 base::Bind(callback, 475 base::Bind(callback,
444 false, 476 false,
445 AppIdToMessageCountMap())); 477 AppIdToMessageCountMap()));
446 } 478 }
447 479
480 void GCMStoreImpl::Backend::UpdateGServicesSettings(
481 const std::map<std::string, std::string>& new_settings,
482 const std::string& settings_digest,
483 const base::Time& last_checkin_time,
484 const UpdateCallback& callback) {
485 leveldb::WriteBatch write_batch;
486
487 // Remove all existing settings.
488 leveldb::ReadOptions read_options;
489 read_options.verify_checksums = true;
490 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
491 for (iter->Seek(MakeSlice(kGServiceSettingKeyStart));
492 iter->Valid() && iter->key().ToString() < kGServiceSettingKeyEnd;
493 iter->Next()) {
494 write_batch.Delete(iter->key());
495 }
496
497 // Add the new settings.
498 for (std::map<std::string, std::string>::const_iterator iter =
499 new_settings.begin();
500 iter != new_settings.end(); ++iter) {
501 write_batch.Put(MakeSlice(MakeGServiceSettingKey(iter->first)),
502 MakeSlice(iter->second));
503 }
504
505 // Update the settings digest.
506 write_batch.Put(MakeSlice(kGServiceSettingsDigestKey),
507 MakeSlice(settings_digest));
508
509 // Update last checkin time.
510 int64 last_checkin_time_internal = last_checkin_time.ToInternalValue();
511 write_batch.Put(MakeSlice(kLastCheckinTimeKey),
512 MakeSlice(base::Int64ToString(last_checkin_time_internal)));
513
514 // Write it all in batch.
jianli 2014/04/01 20:17:17 nit: in a batch
fgorski 2014/04/01 20:47:54 Done.
515 leveldb::WriteOptions write_options;
516 write_options.sync = true;
517
518 leveldb::Status s = db_->Write(write_options, &write_batch);
519 if (!s.ok())
520 LOG(ERROR) << "LevelDB GService Settings update failed: " << s.ToString();
521 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
522 }
523
448 bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id, 524 bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id,
449 uint64* security_token) { 525 uint64* security_token) {
450 leveldb::ReadOptions read_options; 526 leveldb::ReadOptions read_options;
451 read_options.verify_checksums = true; 527 read_options.verify_checksums = true;
452 528
453 std::string result; 529 std::string result;
454 leveldb::Status s = db_->Get(read_options, MakeSlice(kDeviceAIDKey), &result); 530 leveldb::Status s = db_->Get(read_options, MakeSlice(kDeviceAIDKey), &result);
455 if (s.ok()) { 531 if (s.ok()) {
456 if (!base::StringToUint64(result, android_id)) { 532 if (!base::StringToUint64(result, android_id)) {
457 LOG(ERROR) << "Failed to restore device id."; 533 LOG(ERROR) << "Failed to restore device id.";
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 return false; 629 return false;
554 } 630 }
555 DVLOG(1) << "Found outgoing message with id " << id << " of type " 631 DVLOG(1) << "Found outgoing message with id " << id << " of type "
556 << base::IntToString(tag); 632 << base::IntToString(tag);
557 (*outgoing_messages)[id] = make_linked_ptr(message.release()); 633 (*outgoing_messages)[id] = make_linked_ptr(message.release());
558 } 634 }
559 635
560 return true; 636 return true;
561 } 637 }
562 638
639 bool GCMStoreImpl::Backend::LoadGServicesSettings(
640 std::map<std::string, std::string>* settings,
641 std::string* digest,
642 base::Time* last_checkin_time) {
643 leveldb::ReadOptions read_options;
644 read_options.verify_checksums = true;
645
646 // Load all of the GServices settings.
647 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
648 for (iter->Seek(MakeSlice(kGServiceSettingKeyStart));
649 iter->Valid() && iter->key().ToString() < kGServiceSettingKeyEnd;
650 iter->Next()) {
651 std::string value = iter->value().ToString();
652 if (value.empty()) {
653 LOG(ERROR) << "Error reading GService Settings " << value;
654 return false;
655 }
656 std::string id = ParseGServiceSettingKey(iter->key().ToString());
657 (*settings)[id] = value;
658 DVLOG(1) << "Found G Service setting with key: " << id
659 << ", and value: " << value;
660 }
661
662 // Load the settings digest. It's ok if it is empty.
663 db_->Get(read_options, MakeSlice(kGServiceSettingsDigestKey), digest);
664
665 // Load the last checkin time.
666 std::string result;
667 leveldb::Status s = db_->Get(read_options,
668 MakeSlice(kLastCheckinTimeKey),
669 &result);
670 int64 time_internal = 0LL;
671 if (s.ok()) {
672 if (!base::StringToInt64(result, &time_internal)) {
673 LOG(ERROR) << "Failed to restore last checkin time.";
674 return false;
675 }
676 }
677
678 // In case we cannot read last checkin time, we default it to 0, as we don't
679 // want that situation to cause the whole load to fail.
680 *last_checkin_time = base::Time::FromInternalValue(time_internal);
681
682 return true;
683 }
684
563 GCMStoreImpl::GCMStoreImpl( 685 GCMStoreImpl::GCMStoreImpl(
564 bool use_mock_keychain, 686 bool use_mock_keychain,
565 const base::FilePath& path, 687 const base::FilePath& path,
566 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) 688 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
567 : backend_(new Backend(path, base::MessageLoopProxy::current())), 689 : backend_(new Backend(path, base::MessageLoopProxy::current())),
568 blocking_task_runner_(blocking_task_runner), 690 blocking_task_runner_(blocking_task_runner),
569 weak_ptr_factory_(this) { 691 weak_ptr_factory_(this) {
570 // On OSX, prevent the Keychain permissions popup during unit tests. 692 // On OSX, prevent the Keychain permissions popup during unit tests.
571 #if defined(OS_MACOSX) 693 #if defined(OS_MACOSX)
572 OSCrypt::UseMockKeychain(use_mock_keychain); 694 OSCrypt::UseMockKeychain(use_mock_keychain);
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
727 blocking_task_runner_->PostTask( 849 blocking_task_runner_->PostTask(
728 FROM_HERE, 850 FROM_HERE,
729 base::Bind(&GCMStoreImpl::Backend::RemoveOutgoingMessages, 851 base::Bind(&GCMStoreImpl::Backend::RemoveOutgoingMessages,
730 backend_, 852 backend_,
731 persistent_ids, 853 persistent_ids,
732 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation, 854 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation,
733 weak_ptr_factory_.GetWeakPtr(), 855 weak_ptr_factory_.GetWeakPtr(),
734 callback))); 856 callback)));
735 } 857 }
736 858
859 void GCMStoreImpl::UpdateGServicesSettings(
860 const std::map<std::string, std::string>& new_settings,
861 const std::string& digest,
862 const base::Time& last_checkin_time,
863 const UpdateCallback& callback) {
864 blocking_task_runner_->PostTask(
865 FROM_HERE,
866 base::Bind(&GCMStoreImpl::Backend::UpdateGServicesSettings,
867 backend_,
868 new_settings,
869 digest,
870 last_checkin_time,
871 callback));
872 }
873
737 void GCMStoreImpl::LoadContinuation(const LoadCallback& callback, 874 void GCMStoreImpl::LoadContinuation(const LoadCallback& callback,
738 scoped_ptr<LoadResult> result) { 875 scoped_ptr<LoadResult> result) {
739 if (!result->success) { 876 if (!result->success) {
740 callback.Run(result.Pass()); 877 callback.Run(result.Pass());
741 return; 878 return;
742 } 879 }
743 int num_throttled_apps = 0; 880 int num_throttled_apps = 0;
744 for (OutgoingMessageMap::const_iterator 881 for (OutgoingMessageMap::const_iterator
745 iter = result->outgoing_messages.begin(); 882 iter = result->outgoing_messages.begin();
746 iter != result->outgoing_messages.end(); ++iter) { 883 iter != result->outgoing_messages.end(); ++iter) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 removed_message_counts.begin(); 918 removed_message_counts.begin();
782 iter != removed_message_counts.end(); ++iter) { 919 iter != removed_message_counts.end(); ++iter) {
783 DCHECK_NE(app_message_counts_.count(iter->first), 0U); 920 DCHECK_NE(app_message_counts_.count(iter->first), 0U);
784 app_message_counts_[iter->first] -= iter->second; 921 app_message_counts_[iter->first] -= iter->second;
785 DCHECK_GE(app_message_counts_[iter->first], 0); 922 DCHECK_GE(app_message_counts_[iter->first], 0);
786 } 923 }
787 callback.Run(true); 924 callback.Run(true);
788 } 925 }
789 926
790 } // namespace gcm 927 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698