Update ASan/Android runtime and setup script to LLVM r200682.
[chromium-blink-merge.git] / google_apis / gcm / engine / gcm_store_impl.cc
blobdaf7d362fd90adb3005a612c7d894a872e4e2fd4
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
3 // found in the LICENSE file.
5 #include "google_apis/gcm/engine/gcm_store_impl.h"
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/file_util.h"
11 #include "base/files/file_path.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/metrics/histogram.h"
15 #include "base/sequenced_task_runner.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_piece.h"
19 #include "base/tracked_objects.h"
20 #include "components/webdata/encryptor/encryptor.h"
21 #include "google_apis/gcm/base/mcs_message.h"
22 #include "google_apis/gcm/base/mcs_util.h"
23 #include "google_apis/gcm/protocol/mcs.pb.h"
24 #include "third_party/leveldatabase/src/include/leveldb/db.h"
26 namespace gcm {
28 namespace {
30 // Limit to the number of outstanding messages per app.
31 const int kMessagesPerAppLimit = 20;
33 // ---- LevelDB keys. ----
34 // Key for this device's android id.
35 const char kDeviceAIDKey[] = "device_aid_key";
36 // Key for this device's android security token.
37 const char kDeviceTokenKey[] = "device_token_key";
38 // Lowest lexicographically ordered incoming message key.
39 // Used for prefixing messages.
40 const char kIncomingMsgKeyStart[] = "incoming1-";
41 // Key guaranteed to be higher than all incoming message keys.
42 // Used for limiting iteration.
43 const char kIncomingMsgKeyEnd[] = "incoming2-";
44 // Key for next serial number assigned to the user.
45 const char kNextSerialNumberKey[] = "next_serial_number_key";
46 // Lowest lexicographically ordered outgoing message key.
47 // Used for prefixing outgoing messages.
48 const char kOutgoingMsgKeyStart[] = "outgoing1-";
49 // Key guaranteed to be higher than all outgoing message keys.
50 // Used for limiting iteration.
51 const char kOutgoingMsgKeyEnd[] = "outgoing2-";
52 // Lowest lexicographically ordered username.
53 // Used for prefixing username to serial number mappings.
54 const char kUserSerialNumberKeyStart[] = "user1-";
55 // Key guaranteed to be higher than all usernames.
56 // Used for limiting iteration.
57 const char kUserSerialNumberKeyEnd[] = "user2-";
59 // Value indicating that serial number was not assigned.
60 const int64 kSerialNumberMissing = -1LL;
62 std::string MakeIncomingKey(const std::string& persistent_id) {
63 return kIncomingMsgKeyStart + persistent_id;
66 std::string MakeOutgoingKey(const std::string& persistent_id) {
67 return kOutgoingMsgKeyStart + persistent_id;
70 std::string MakeUserSerialNumberKey(const std::string& username) {
71 return kUserSerialNumberKeyStart + username;
74 std::string ParseOutgoingKey(const std::string& key) {
75 return key.substr(arraysize(kOutgoingMsgKeyStart) - 1);
78 std::string ParseUsername(const std::string& key) {
79 return key.substr(arraysize(kUserSerialNumberKeyStart) - 1);
82 // Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore
83 // outlive the slice.
84 // For example: MakeSlice(MakeOutgoingKey(x)) is invalid.
85 leveldb::Slice MakeSlice(const base::StringPiece& s) {
86 return leveldb::Slice(s.begin(), s.size());
89 } // namespace
91 class GCMStoreImpl::Backend
92 : public base::RefCountedThreadSafe<GCMStoreImpl::Backend> {
93 public:
94 Backend(const base::FilePath& path,
95 scoped_refptr<base::SequencedTaskRunner> foreground_runner);
97 // Blocking implementations of GCMStoreImpl methods.
98 void Load(const LoadCallback& callback);
99 void Destroy(const UpdateCallback& callback);
100 void SetDeviceCredentials(uint64 device_android_id,
101 uint64 device_security_token,
102 const UpdateCallback& callback);
103 void AddIncomingMessage(const std::string& persistent_id,
104 const UpdateCallback& callback);
105 void RemoveIncomingMessages(const PersistentIdList& persistent_ids,
106 const UpdateCallback& callback);
107 void AddOutgoingMessage(const std::string& persistent_id,
108 const MCSMessage& message,
109 const UpdateCallback& callback);
110 void RemoveOutgoingMessages(
111 const PersistentIdList& persistent_ids,
112 const base::Callback<void(bool, const AppIdToMessageCountMap&)>
113 callback);
114 void AddUserSerialNumber(const std::string& username,
115 int64 serial_number,
116 const UpdateCallback& callback);
117 void RemoveUserSerialNumber(const std::string& username,
118 const UpdateCallback& callback);
119 void SetNextSerialNumber(int64 serial_number, const UpdateCallback& callback);
121 private:
122 friend class base::RefCountedThreadSafe<Backend>;
123 ~Backend();
125 bool LoadDeviceCredentials(uint64* android_id, uint64* security_token);
126 bool LoadIncomingMessages(std::vector<std::string>* incoming_messages);
127 bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages);
128 bool LoadNextSerialNumber(int64* next_serial_number);
129 bool LoadUserSerialNumberMap(
130 std::map<std::string, int64>* user_serial_number_map);
132 const base::FilePath path_;
133 scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
135 scoped_ptr<leveldb::DB> db_;
138 GCMStoreImpl::Backend::Backend(
139 const base::FilePath& path,
140 scoped_refptr<base::SequencedTaskRunner> foreground_task_runner)
141 : path_(path), foreground_task_runner_(foreground_task_runner) {}
143 GCMStoreImpl::Backend::~Backend() {}
145 void GCMStoreImpl::Backend::Load(const LoadCallback& callback) {
146 scoped_ptr<LoadResult> result(new LoadResult());
147 if (db_.get()) {
148 LOG(ERROR) << "Attempting to reload open database.";
149 foreground_task_runner_->PostTask(FROM_HERE,
150 base::Bind(callback,
151 base::Passed(&result)));
152 return;
155 leveldb::Options options;
156 options.create_if_missing = true;
157 leveldb::DB* db;
158 leveldb::Status status =
159 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db);
160 UMA_HISTOGRAM_BOOLEAN("GCM.LoadSucceeded", status.ok());
161 if (!status.ok()) {
162 LOG(ERROR) << "Failed to open database " << path_.value() << ": "
163 << status.ToString();
164 foreground_task_runner_->PostTask(FROM_HERE,
165 base::Bind(callback,
166 base::Passed(&result)));
167 return;
169 db_.reset(db);
171 if (!LoadDeviceCredentials(&result->device_android_id,
172 &result->device_security_token) ||
173 !LoadIncomingMessages(&result->incoming_messages) ||
174 !LoadOutgoingMessages(&result->outgoing_messages) ||
175 !LoadNextSerialNumber(
176 &result->serial_number_mappings.next_serial_number) ||
177 !LoadUserSerialNumberMap(
178 &result->serial_number_mappings.user_serial_numbers)) {
179 result->device_android_id = 0;
180 result->device_security_token = 0;
181 result->incoming_messages.clear();
182 result->outgoing_messages.clear();
183 foreground_task_runner_->PostTask(FROM_HERE,
184 base::Bind(callback,
185 base::Passed(&result)));
186 return;
189 // Only record histograms if GCM had already been set up for this device.
190 if (result->device_android_id != 0 && result->device_security_token != 0) {
191 int64 file_size = 0;
192 if (base::GetFileSize(path_, &file_size)) {
193 UMA_HISTOGRAM_COUNTS("GCM.StoreSizeKB",
194 static_cast<int>(file_size / 1024));
196 UMA_HISTOGRAM_COUNTS("GCM.RestoredOutgoingMessages",
197 result->outgoing_messages.size());
198 UMA_HISTOGRAM_COUNTS("GCM.RestoredIncomingMessages",
199 result->incoming_messages.size());
200 UMA_HISTOGRAM_COUNTS(
201 "GCM.NumUsers",
202 result->serial_number_mappings.user_serial_numbers.size());
205 DVLOG(1) << "Succeeded in loading " << result->incoming_messages.size()
206 << " unacknowledged incoming messages and "
207 << result->outgoing_messages.size()
208 << " unacknowledged outgoing messages.";
209 result->success = true;
210 foreground_task_runner_->PostTask(FROM_HERE,
211 base::Bind(callback,
212 base::Passed(&result)));
213 return;
216 void GCMStoreImpl::Backend::Destroy(const UpdateCallback& callback) {
217 DVLOG(1) << "Destroying GCM store.";
218 db_.reset();
219 const leveldb::Status s =
220 leveldb::DestroyDB(path_.AsUTF8Unsafe(), leveldb::Options());
221 if (s.ok()) {
222 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
223 return;
225 LOG(ERROR) << "Destroy failed: " << s.ToString();
226 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
229 void GCMStoreImpl::Backend::SetDeviceCredentials(
230 uint64 device_android_id,
231 uint64 device_security_token,
232 const UpdateCallback& callback) {
233 DVLOG(1) << "Saving device credentials with AID " << device_android_id;
234 if (!db_.get()) {
235 LOG(ERROR) << "GCMStore db doesn't exist.";
236 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
237 return;
240 leveldb::WriteOptions write_options;
241 write_options.sync = true;
243 std::string encrypted_token;
244 Encryptor::EncryptString(base::Uint64ToString(device_security_token),
245 &encrypted_token);
246 std::string android_id_str = base::Uint64ToString(device_android_id);
247 leveldb::Status s =
248 db_->Put(write_options,
249 MakeSlice(kDeviceAIDKey),
250 MakeSlice(android_id_str));
251 if (s.ok()) {
252 s = db_->Put(
253 write_options, MakeSlice(kDeviceTokenKey), MakeSlice(encrypted_token));
255 if (s.ok()) {
256 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
257 return;
259 LOG(ERROR) << "LevelDB put failed: " << s.ToString();
260 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
263 void GCMStoreImpl::Backend::AddIncomingMessage(const std::string& persistent_id,
264 const UpdateCallback& callback) {
265 DVLOG(1) << "Saving incoming message with id " << persistent_id;
266 if (!db_.get()) {
267 LOG(ERROR) << "GCMStore db doesn't exist.";
268 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
269 return;
272 leveldb::WriteOptions write_options;
273 write_options.sync = true;
275 std::string key = MakeIncomingKey(persistent_id);
276 const leveldb::Status s = db_->Put(write_options,
277 MakeSlice(key),
278 MakeSlice(persistent_id));
279 if (s.ok()) {
280 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
281 return;
283 LOG(ERROR) << "LevelDB put failed: " << s.ToString();
284 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
287 void GCMStoreImpl::Backend::RemoveIncomingMessages(
288 const PersistentIdList& persistent_ids,
289 const UpdateCallback& callback) {
290 if (!db_.get()) {
291 LOG(ERROR) << "GCMStore db doesn't exist.";
292 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
293 return;
295 leveldb::WriteOptions write_options;
296 write_options.sync = true;
298 leveldb::Status s;
299 for (PersistentIdList::const_iterator iter = persistent_ids.begin();
300 iter != persistent_ids.end();
301 ++iter) {
302 DVLOG(1) << "Removing incoming message with id " << *iter;
303 std::string key = MakeIncomingKey(*iter);
304 s = db_->Delete(write_options, MakeSlice(key));
305 if (!s.ok())
306 break;
308 if (s.ok()) {
309 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
310 return;
312 LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
313 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
316 void GCMStoreImpl::Backend::AddOutgoingMessage(const std::string& persistent_id,
317 const MCSMessage& message,
318 const UpdateCallback& callback) {
319 DVLOG(1) << "Saving outgoing message with id " << persistent_id;
320 if (!db_.get()) {
321 LOG(ERROR) << "GCMStore db doesn't exist.";
322 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
323 return;
325 leveldb::WriteOptions write_options;
326 write_options.sync = true;
328 std::string data =
329 static_cast<char>(message.tag()) + message.SerializeAsString();
330 std::string key = MakeOutgoingKey(persistent_id);
331 const leveldb::Status s = db_->Put(write_options,
332 MakeSlice(key),
333 MakeSlice(data));
334 if (s.ok()) {
335 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
336 return;
338 LOG(ERROR) << "LevelDB put failed: " << s.ToString();
339 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
342 void GCMStoreImpl::Backend::RemoveOutgoingMessages(
343 const PersistentIdList& persistent_ids,
344 const base::Callback<void(bool, const AppIdToMessageCountMap&)>
345 callback) {
346 if (!db_.get()) {
347 LOG(ERROR) << "GCMStore db doesn't exist.";
348 foreground_task_runner_->PostTask(FROM_HERE,
349 base::Bind(callback,
350 false,
351 AppIdToMessageCountMap()));
352 return;
354 leveldb::ReadOptions read_options;
355 leveldb::WriteOptions write_options;
356 write_options.sync = true;
358 AppIdToMessageCountMap removed_message_counts;
360 leveldb::Status s;
361 for (PersistentIdList::const_iterator iter = persistent_ids.begin();
362 iter != persistent_ids.end();
363 ++iter) {
364 DVLOG(1) << "Removing outgoing message with id " << *iter;
365 std::string outgoing_message;
366 std::string key = MakeOutgoingKey(*iter);
367 s = db_->Get(read_options,
368 MakeSlice(key),
369 &outgoing_message);
370 if (!s.ok())
371 break;
372 mcs_proto::DataMessageStanza data_message;
373 // Skip the initial tag byte and parse the rest to extract the message.
374 if (data_message.ParseFromString(outgoing_message.substr(1))) {
375 DCHECK(!data_message.from().empty());
376 if (removed_message_counts.count(data_message.from()) != 0)
377 removed_message_counts[data_message.from()]++;
378 else
379 removed_message_counts[data_message.from()] = 1;
381 DVLOG(1) << "Removing outgoing message with id " << *iter;
382 s = db_->Delete(write_options, MakeSlice(key));
383 if (!s.ok())
384 break;
386 if (s.ok()) {
387 foreground_task_runner_->PostTask(FROM_HERE,
388 base::Bind(callback,
389 true,
390 removed_message_counts));
391 return;
393 LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
394 foreground_task_runner_->PostTask(FROM_HERE,
395 base::Bind(callback,
396 false,
397 AppIdToMessageCountMap()));
400 void GCMStoreImpl::Backend::AddUserSerialNumber(
401 const std::string& username,
402 int64 serial_number,
403 const UpdateCallback& callback) {
404 DVLOG(1) << "Saving username to serial number mapping for user: " << username;
405 if (!db_.get()) {
406 LOG(ERROR) << "GCMStore db doesn't exist.";
407 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
408 return;
410 leveldb::WriteOptions write_options;
411 write_options.sync = true;
413 std::string key = MakeUserSerialNumberKey(username);
414 std::string serial_number_str = base::Int64ToString(serial_number);
415 const leveldb::Status status =
416 db_->Put(write_options,
417 MakeSlice(key),
418 MakeSlice(serial_number_str));
419 if (status.ok()) {
420 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
421 return;
423 LOG(ERROR) << "LevelDB put failed: " << status.ToString();
424 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
427 void GCMStoreImpl::Backend::RemoveUserSerialNumber(
428 const std::string& username,
429 const UpdateCallback& callback) {
430 if (!db_.get()) {
431 LOG(ERROR) << "GCMStore db doesn't exist.";
432 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
433 return;
435 leveldb::WriteOptions write_options;
436 write_options.sync = true;
438 leveldb::Status status = db_->Delete(write_options, MakeSlice(username));
439 if (status.ok()) {
440 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
441 return;
443 LOG(ERROR) << "LevelDB remove failed: " << status.ToString();
444 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
447 void GCMStoreImpl::Backend::SetNextSerialNumber(
448 int64 next_serial_number,
449 const UpdateCallback& callback) {
450 DVLOG(1) << "Updating the value of next user serial number to: "
451 << next_serial_number;
452 if (!db_.get()) {
453 LOG(ERROR) << "GCMStore db doesn't exist.";
454 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
455 return;
457 leveldb::WriteOptions write_options;
458 write_options.sync = true;
460 std::string serial_number_str = base::Int64ToString(next_serial_number);
461 const leveldb::Status status =
462 db_->Put(write_options,
463 MakeSlice(kNextSerialNumberKey),
464 MakeSlice(serial_number_str));
465 if (status.ok()) {
466 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
467 return;
469 LOG(ERROR) << "LevelDB put failed: " << status.ToString();
470 foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
473 bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id,
474 uint64* security_token) {
475 leveldb::ReadOptions read_options;
476 read_options.verify_checksums = true;
478 std::string result;
479 leveldb::Status s = db_->Get(read_options, MakeSlice(kDeviceAIDKey), &result);
480 if (s.ok()) {
481 if (!base::StringToUint64(result, android_id)) {
482 LOG(ERROR) << "Failed to restore device id.";
483 return false;
485 result.clear();
486 s = db_->Get(read_options, MakeSlice(kDeviceTokenKey), &result);
488 if (s.ok()) {
489 std::string decrypted_token;
490 Encryptor::DecryptString(result, &decrypted_token);
491 if (!base::StringToUint64(decrypted_token, security_token)) {
492 LOG(ERROR) << "Failed to restore security token.";
493 return false;
495 return true;
498 if (s.IsNotFound()) {
499 DVLOG(1) << "No credentials found.";
500 return true;
503 LOG(ERROR) << "Error reading credentials from store.";
504 return false;
507 bool GCMStoreImpl::Backend::LoadIncomingMessages(
508 std::vector<std::string>* incoming_messages) {
509 leveldb::ReadOptions read_options;
510 read_options.verify_checksums = true;
512 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
513 for (iter->Seek(MakeSlice(kIncomingMsgKeyStart));
514 iter->Valid() && iter->key().ToString() < kIncomingMsgKeyEnd;
515 iter->Next()) {
516 leveldb::Slice s = iter->value();
517 if (s.empty()) {
518 LOG(ERROR) << "Error reading incoming message with key "
519 << iter->key().ToString();
520 return false;
522 DVLOG(1) << "Found incoming message with id " << s.ToString();
523 incoming_messages->push_back(s.ToString());
526 return true;
529 bool GCMStoreImpl::Backend::LoadOutgoingMessages(
530 OutgoingMessageMap* outgoing_messages) {
531 leveldb::ReadOptions read_options;
532 read_options.verify_checksums = true;
534 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
535 for (iter->Seek(MakeSlice(kOutgoingMsgKeyStart));
536 iter->Valid() && iter->key().ToString() < kOutgoingMsgKeyEnd;
537 iter->Next()) {
538 leveldb::Slice s = iter->value();
539 if (s.size() <= 1) {
540 LOG(ERROR) << "Error reading incoming message with key " << s.ToString();
541 return false;
543 uint8 tag = iter->value().data()[0];
544 std::string id = ParseOutgoingKey(iter->key().ToString());
545 scoped_ptr<google::protobuf::MessageLite> message(
546 BuildProtobufFromTag(tag));
547 if (!message.get() ||
548 !message->ParseFromString(iter->value().ToString().substr(1))) {
549 LOG(ERROR) << "Failed to parse outgoing message with id " << id
550 << " and tag " << tag;
551 return false;
553 DVLOG(1) << "Found outgoing message with id " << id << " of type "
554 << base::IntToString(tag);
555 (*outgoing_messages)[id] = make_linked_ptr(message.release());
558 return true;
561 bool GCMStoreImpl::Backend::LoadNextSerialNumber(int64* next_serial_number) {
562 leveldb::ReadOptions read_options;
563 read_options.verify_checksums = true;
565 std::string result;
566 leveldb::Status status =
567 db_->Get(read_options, MakeSlice(kNextSerialNumberKey), &result);
568 if (status.ok()) {
569 if (!base::StringToInt64(result, next_serial_number)) {
570 LOG(ERROR) << "Failed to restore the next serial number.";
571 return false;
573 return true;
576 if (status.IsNotFound()) {
577 DVLOG(1) << "No next serial number found.";
578 return true;
581 LOG(ERROR) << "Error when reading the next serial number.";
582 return false;
585 bool GCMStoreImpl::Backend::LoadUserSerialNumberMap(
586 std::map<std::string, int64>* user_serial_number_map) {
587 leveldb::ReadOptions read_options;
588 read_options.verify_checksums = true;
590 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
591 for (iter->Seek(MakeSlice(kUserSerialNumberKeyStart));
592 iter->Valid() && iter->key().ToString() < kUserSerialNumberKeyEnd;
593 iter->Next()) {
594 std::string username = ParseUsername(iter->key().ToString());
595 if (username.empty()) {
596 LOG(ERROR) << "Error reading username. It should not be empty.";
597 return false;
599 std::string serial_number_string = iter->value().ToString();
600 int64 serial_number = kSerialNumberMissing;
601 if (!base::StringToInt64(serial_number_string, &serial_number)) {
602 LOG(ERROR) << "Error reading user serial number for user: " << username;
603 return false;
606 (*user_serial_number_map)[username] = serial_number;
609 return true;
612 GCMStoreImpl::GCMStoreImpl(
613 bool use_mock_keychain,
614 const base::FilePath& path,
615 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
616 : backend_(new Backend(path, base::MessageLoopProxy::current())),
617 blocking_task_runner_(blocking_task_runner),
618 weak_ptr_factory_(this) {
619 // On OSX, prevent the Keychain permissions popup during unit tests.
620 #if defined(OS_MACOSX)
621 Encryptor::UseMockKeychain(use_mock_keychain);
622 #endif
625 GCMStoreImpl::~GCMStoreImpl() {}
627 void GCMStoreImpl::Load(const LoadCallback& callback) {
628 blocking_task_runner_->PostTask(
629 FROM_HERE,
630 base::Bind(&GCMStoreImpl::Backend::Load,
631 backend_,
632 base::Bind(&GCMStoreImpl::LoadContinuation,
633 weak_ptr_factory_.GetWeakPtr(),
634 callback)));
637 void GCMStoreImpl::Destroy(const UpdateCallback& callback) {
638 blocking_task_runner_->PostTask(
639 FROM_HERE,
640 base::Bind(&GCMStoreImpl::Backend::Destroy, backend_, callback));
643 void GCMStoreImpl::SetDeviceCredentials(uint64 device_android_id,
644 uint64 device_security_token,
645 const UpdateCallback& callback) {
646 blocking_task_runner_->PostTask(
647 FROM_HERE,
648 base::Bind(&GCMStoreImpl::Backend::SetDeviceCredentials,
649 backend_,
650 device_android_id,
651 device_security_token,
652 callback));
655 void GCMStoreImpl::AddIncomingMessage(const std::string& persistent_id,
656 const UpdateCallback& callback) {
657 blocking_task_runner_->PostTask(
658 FROM_HERE,
659 base::Bind(&GCMStoreImpl::Backend::AddIncomingMessage,
660 backend_,
661 persistent_id,
662 callback));
665 void GCMStoreImpl::RemoveIncomingMessage(const std::string& persistent_id,
666 const UpdateCallback& callback) {
667 blocking_task_runner_->PostTask(
668 FROM_HERE,
669 base::Bind(&GCMStoreImpl::Backend::RemoveIncomingMessages,
670 backend_,
671 PersistentIdList(1, persistent_id),
672 callback));
675 void GCMStoreImpl::RemoveIncomingMessages(
676 const PersistentIdList& persistent_ids,
677 const UpdateCallback& callback) {
678 blocking_task_runner_->PostTask(
679 FROM_HERE,
680 base::Bind(&GCMStoreImpl::Backend::RemoveIncomingMessages,
681 backend_,
682 persistent_ids,
683 callback));
686 bool GCMStoreImpl::AddOutgoingMessage(const std::string& persistent_id,
687 const MCSMessage& message,
688 const UpdateCallback& callback) {
689 DCHECK_EQ(message.tag(), kDataMessageStanzaTag);
690 std::string app_id = reinterpret_cast<const mcs_proto::DataMessageStanza*>(
691 &message.GetProtobuf())->from();
692 DCHECK(!app_id.empty());
693 if (app_message_counts_.count(app_id) == 0)
694 app_message_counts_[app_id] = 0;
695 if (app_message_counts_[app_id] < kMessagesPerAppLimit) {
696 app_message_counts_[app_id]++;
698 blocking_task_runner_->PostTask(
699 FROM_HERE,
700 base::Bind(&GCMStoreImpl::Backend::AddOutgoingMessage,
701 backend_,
702 persistent_id,
703 message,
704 base::Bind(&GCMStoreImpl::AddOutgoingMessageContinuation,
705 weak_ptr_factory_.GetWeakPtr(),
706 callback,
707 app_id)));
708 return true;
710 return false;
713 void GCMStoreImpl::RemoveOutgoingMessage(const std::string& persistent_id,
714 const UpdateCallback& callback) {
715 blocking_task_runner_->PostTask(
716 FROM_HERE,
717 base::Bind(&GCMStoreImpl::Backend::RemoveOutgoingMessages,
718 backend_,
719 PersistentIdList(1, persistent_id),
720 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation,
721 weak_ptr_factory_.GetWeakPtr(),
722 callback)));
725 void GCMStoreImpl::RemoveOutgoingMessages(
726 const PersistentIdList& persistent_ids,
727 const UpdateCallback& callback) {
728 blocking_task_runner_->PostTask(
729 FROM_HERE,
730 base::Bind(&GCMStoreImpl::Backend::RemoveOutgoingMessages,
731 backend_,
732 persistent_ids,
733 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation,
734 weak_ptr_factory_.GetWeakPtr(),
735 callback)));
738 void GCMStoreImpl::SetNextSerialNumber(int64 next_serial_number,
739 const UpdateCallback& callback) {
740 blocking_task_runner_->PostTask(
741 FROM_HERE,
742 base::Bind(&GCMStoreImpl::Backend::SetNextSerialNumber,
743 backend_,
744 next_serial_number,
745 callback));
748 void GCMStoreImpl::AddUserSerialNumber(const std::string& username,
749 int64 serial_number,
750 const UpdateCallback& callback) {
751 blocking_task_runner_->PostTask(
752 FROM_HERE,
753 base::Bind(&GCMStoreImpl::Backend::AddUserSerialNumber,
754 backend_,
755 username,
756 serial_number,
757 callback));
760 void GCMStoreImpl::RemoveUserSerialNumber(const std::string& username,
761 const UpdateCallback& callback) {
762 blocking_task_runner_->PostTask(
763 FROM_HERE,
764 base::Bind(&GCMStoreImpl::Backend::RemoveUserSerialNumber,
765 backend_,
766 username,
767 callback));
770 void GCMStoreImpl::LoadContinuation(const LoadCallback& callback,
771 scoped_ptr<LoadResult> result) {
772 if (!result->success) {
773 callback.Run(result.Pass());
774 return;
776 int num_throttled_apps = 0;
777 for (OutgoingMessageMap::const_iterator
778 iter = result->outgoing_messages.begin();
779 iter != result->outgoing_messages.end(); ++iter) {
780 const mcs_proto::DataMessageStanza* data_message =
781 reinterpret_cast<mcs_proto::DataMessageStanza*>(iter->second.get());
782 DCHECK(!data_message->from().empty());
783 if (app_message_counts_.count(data_message->from()) == 0)
784 app_message_counts_[data_message->from()] = 1;
785 else
786 app_message_counts_[data_message->from()]++;
787 if (app_message_counts_[data_message->from()] == kMessagesPerAppLimit)
788 num_throttled_apps++;
790 UMA_HISTOGRAM_COUNTS("GCM.NumThrottledApps", num_throttled_apps);
791 callback.Run(result.Pass());
794 void GCMStoreImpl::AddOutgoingMessageContinuation(
795 const UpdateCallback& callback,
796 const std::string& app_id,
797 bool success) {
798 if (!success) {
799 DCHECK(app_message_counts_[app_id] > 0);
800 app_message_counts_[app_id]--;
802 callback.Run(success);
805 void GCMStoreImpl::RemoveOutgoingMessagesContinuation(
806 const UpdateCallback& callback,
807 bool success,
808 const AppIdToMessageCountMap& removed_message_counts) {
809 if (!success) {
810 callback.Run(false);
811 return;
813 for (AppIdToMessageCountMap::const_iterator iter =
814 removed_message_counts.begin();
815 iter != removed_message_counts.end(); ++iter) {
816 DCHECK_NE(app_message_counts_.count(iter->first), 0U);
817 app_message_counts_[iter->first] -= iter->second;
818 DCHECK_GE(app_message_counts_[iter->first], 0);
820 callback.Run(true);
823 } // namespace gcm