gcm_store_impl.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/engine/gcm_store_impl.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/basictypes.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/callback.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/file_util.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/files/file_path.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/logging.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/sequenced_task_runner.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/stl_util.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_piece.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/tracked_objects.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/webdata/encryptor/encryptor.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/base/mcs_message.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/base/mcs_util.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/protocol/mcs.pb.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/db.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace gcm {
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Limit to the number of outstanding messages per app.
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kMessagesPerAppLimit = 20;
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// ---- LevelDB keys. ----
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key for this device's android id.
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeviceAIDKey[] = "device_aid_key";
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key for this device's android security token.
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeviceTokenKey[] = "device_token_key";
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Lowest lexicographically ordered incoming message key.
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for prefixing messages.
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kIncomingMsgKeyStart[] = "incoming1-";
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key guaranteed to be higher than all incoming message keys.
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for limiting iteration.
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kIncomingMsgKeyEnd[] = "incoming2-";
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key for next serial number assigned to the user.
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kNextSerialNumberKey[] = "next_serial_number_key";
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Lowest lexicographically ordered outgoing message key.
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for prefixing outgoing messages.
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kOutgoingMsgKeyStart[] = "outgoing1-";
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key guaranteed to be higher than all outgoing message keys.
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for limiting iteration.
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kOutgoingMsgKeyEnd[] = "outgoing2-";
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Lowest lexicographically ordered username.
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for prefixing username to serial number mappings.
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kUserSerialNumberKeyStart[] = "user1-";
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key guaranteed to be higher than all usernames.
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for limiting iteration.
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kUserSerialNumberKeyEnd[] = "user2-";
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Value indicating that serial number was not assigned.
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int64 kSerialNumberMissing = -1LL;
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string MakeIncomingKey(const std::string& persistent_id) {
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return kIncomingMsgKeyStart + persistent_id;
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string MakeOutgoingKey(const std::string& persistent_id) {
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return kOutgoingMsgKeyStart + persistent_id;
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string MakeUserSerialNumberKey(const std::string& username) {
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return kUserSerialNumberKeyStart + username;
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string ParseOutgoingKey(const std::string& key) {
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return key.substr(arraysize(kOutgoingMsgKeyStart) - 1);
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string ParseUsername(const std::string& key) {
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return key.substr(arraysize(kUserSerialNumberKeyStart) - 1);
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// outlive the slice.
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// For example: MakeSlice(MakeOutgoingKey(x)) is invalid.
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)leveldb::Slice MakeSlice(const base::StringPiece& s) {
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return leveldb::Slice(s.begin(), s.size());
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class GCMStoreImpl::Backend
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : public base::RefCountedThreadSafe<GCMStoreImpl::Backend> {
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Backend(const base::FilePath& path,
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          scoped_refptr<base::SequencedTaskRunner> foreground_runner);
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Blocking implementations of GCMStoreImpl methods.
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Load(const LoadCallback& callback);
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Destroy(const UpdateCallback& callback);
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void SetDeviceCredentials(uint64 device_android_id,
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            uint64 device_security_token,
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const UpdateCallback& callback);
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddIncomingMessage(const std::string& persistent_id,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const UpdateCallback& callback);
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveIncomingMessages(const PersistentIdList& persistent_ids,
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const UpdateCallback& callback);
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddOutgoingMessage(const std::string& persistent_id,
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const MCSMessage& message,
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const UpdateCallback& callback);
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveOutgoingMessages(
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const PersistentIdList& persistent_ids,
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::Callback<void(bool, const AppIdToMessageCountMap&)>
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          callback);
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddUserSerialNumber(const std::string& username,
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           int64 serial_number,
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           const UpdateCallback& callback);
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveUserSerialNumber(const std::string& username,
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const UpdateCallback& callback);
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void SetNextSerialNumber(int64 serial_number, const UpdateCallback& callback);
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Backend>;
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~Backend();
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadDeviceCredentials(uint64* android_id, uint64* security_token);
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadIncomingMessages(std::vector<std::string>* incoming_messages);
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages);
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadNextSerialNumber(int64* next_serial_number);
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadUserSerialNumberMap(
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::map<std::string, int64>* user_serial_number_map);
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::FilePath path_;
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::DB> db_;
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::Backend::Backend(
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path,
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> foreground_task_runner)
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : path_(path), foreground_task_runner_(foreground_task_runner) {}
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::Backend::~Backend() {}
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::Load(const LoadCallback& callback) {
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<LoadResult> result(new LoadResult());
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (db_.get()) {
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Attempting to reload open database.";
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Options options;
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  options.create_if_missing = true;
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::DB* db;
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status status =
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db);
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("GCM.LoadSucceeded", status.ok());
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!status.ok()) {
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Failed to open database " << path_.value() << ": "
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << status.ToString();
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  db_.reset(db);
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!LoadDeviceCredentials(&result->device_android_id,
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             &result->device_security_token) ||
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !LoadIncomingMessages(&result->incoming_messages) ||
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !LoadOutgoingMessages(&result->outgoing_messages) ||
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !LoadNextSerialNumber(
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           &result->serial_number_mappings.next_serial_number) ||
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !LoadUserSerialNumberMap(
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           &result->serial_number_mappings.user_serial_numbers)) {
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->device_android_id = 0;
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->device_security_token = 0;
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->incoming_messages.clear();
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->outgoing_messages.clear();
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Only record histograms if GCM had already been set up for this device.
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result->device_android_id != 0 && result->device_security_token != 0) {
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64 file_size = 0;
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (base::GetFileSize(path_, &file_size)) {
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      UMA_HISTOGRAM_COUNTS("GCM.StoreSizeKB",
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           static_cast<int>(file_size / 1024));
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.RestoredOutgoingMessages",
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         result->outgoing_messages.size());
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.RestoredIncomingMessages",
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         result->incoming_messages.size());
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS(
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "GCM.NumUsers",
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        result->serial_number_mappings.user_serial_numbers.size());
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Succeeded in loading " << result->incoming_messages.size()
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << " unacknowledged incoming messages and "
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << result->outgoing_messages.size()
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << " unacknowledged outgoing messages.";
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->success = true;
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE,
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::Bind(callback,
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               base::Passed(&result)));
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return;
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::Destroy(const UpdateCallback& callback) {
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Destroying GCM store.";
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  db_.reset();
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s =
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      leveldb::DestroyDB(path_.AsUTF8Unsafe(), leveldb::Options());
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Destroy failed: " << s.ToString();
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::SetDeviceCredentials(
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 device_android_id,
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 device_security_token,
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving device credentials with AID " << device_android_id;
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string encrypted_token;
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Encryptor::EncryptString(base::Uint64ToString(device_security_token),
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &encrypted_token);
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string android_id_str = base::Uint64ToString(device_android_id);
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s =
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      db_->Put(write_options,
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(kDeviceAIDKey),
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(android_id_str));
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Put(
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        write_options, MakeSlice(kDeviceTokenKey), MakeSlice(encrypted_token));
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::AddIncomingMessage(const std::string& persistent_id,
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const UpdateCallback& callback) {
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving incoming message with id " << persistent_id;
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key = MakeIncomingKey(persistent_id);
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s = db_->Put(write_options,
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(key),
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(persistent_id));
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::RemoveIncomingMessages(
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s;
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (PersistentIdList::const_iterator iter = persistent_ids.begin();
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != persistent_ids.end();
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing incoming message with id " << *iter;
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string key = MakeIncomingKey(*iter);
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Delete(write_options, MakeSlice(key));
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::AddOutgoingMessage(const std::string& persistent_id,
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const MCSMessage& message,
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const UpdateCallback& callback) {
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving outgoing message with id " << persistent_id;
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string data =
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<char>(message.tag()) + message.SerializeAsString();
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key = MakeOutgoingKey(persistent_id);
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s = db_->Put(write_options,
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(key),
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(data));
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::RemoveOutgoingMessages(
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Callback<void(bool, const AppIdToMessageCountMap&)>
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        callback) {
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 false,
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 AppIdToMessageCountMap()));
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AppIdToMessageCountMap removed_message_counts;
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s;
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (PersistentIdList::const_iterator iter = persistent_ids.begin();
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != persistent_ids.end();
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing outgoing message with id " << *iter;
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string outgoing_message;
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string key = MakeOutgoingKey(*iter);
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Get(read_options,
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 MakeSlice(key),
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 &outgoing_message);
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mcs_proto::DataMessageStanza data_message;
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Skip the initial tag byte and parse the rest to extract the message.
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (data_message.ParseFromString(outgoing_message.substr(1))) {
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(!data_message.category().empty());
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (removed_message_counts.count(data_message.category()) != 0)
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        removed_message_counts[data_message.category()]++;
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      else
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        removed_message_counts[data_message.category()] = 1;
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing outgoing message with id " << *iter;
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Delete(write_options, MakeSlice(key));
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 true,
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 removed_message_counts));
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE,
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::Bind(callback,
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               false,
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               AppIdToMessageCountMap()));
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::AddUserSerialNumber(
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& username,
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64 serial_number,
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving username to serial number mapping for user: " << username;
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key = MakeUserSerialNumberKey(username);
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string serial_number_str = base::Int64ToString(serial_number);
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status status =
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      db_->Put(write_options,
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(key),
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(serial_number_str));
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status.ok()) {
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << status.ToString();
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::RemoveUserSerialNumber(
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& username,
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status status = db_->Delete(write_options, MakeSlice(username));
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status.ok()) {
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB remove failed: " << status.ToString();
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::SetNextSerialNumber(
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64 next_serial_number,
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Updating the value of next user serial number to: "
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << next_serial_number;
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string serial_number_str = base::Int64ToString(next_serial_number);
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status status =
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      db_->Put(write_options,
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(kNextSerialNumberKey),
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(serial_number_str));
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status.ok()) {
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << status.ToString();
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id,
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                  uint64* security_token) {
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string result;
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s = db_->Get(read_options, MakeSlice(kDeviceAIDKey), &result);
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToUint64(result, android_id)) {
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to restore device id.";
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.clear();
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Get(read_options, MakeSlice(kDeviceTokenKey), &result);
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string decrypted_token;
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Encryptor::DecryptString(result, &decrypted_token);
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToUint64(decrypted_token, security_token)) {
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to restore security token.";
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.IsNotFound()) {
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "No credentials found.";
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Error reading credentials from store.";
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadIncomingMessages(
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<std::string>* incoming_messages) {
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (iter->Seek(MakeSlice(kIncomingMsgKeyStart));
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Valid() && iter->key().ToString() < kIncomingMsgKeyEnd;
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Next()) {
5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    leveldb::Slice s = iter->value();
5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (s.empty()) {
5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading incoming message with key "
5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << iter->key().ToString();
5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Found incoming message with id " << s.ToString();
5235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    incoming_messages->push_back(s.ToString());
5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadOutgoingMessages(
5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OutgoingMessageMap* outgoing_messages) {
5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (iter->Seek(MakeSlice(kOutgoingMsgKeyStart));
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Valid() && iter->key().ToString() < kOutgoingMsgKeyEnd;
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Next()) {
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    leveldb::Slice s = iter->value();
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (s.size() <= 1) {
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading incoming message with key " << s.ToString();
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint8 tag = iter->value().data()[0];
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string id = ParseOutgoingKey(iter->key().ToString());
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<google::protobuf::MessageLite> message(
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BuildProtobufFromTag(tag));
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!message.get() ||
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        !message->ParseFromString(iter->value().ToString().substr(1))) {
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to parse outgoing message with id " << id
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << " and tag " << tag;
5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Found outgoing message with id " << id << " of type "
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << base::IntToString(tag);
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*outgoing_messages)[id] = make_linked_ptr(message.release());
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadNextSerialNumber(int64* next_serial_number) {
5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string result;
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status status =
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      db_->Get(read_options, MakeSlice(kNextSerialNumberKey), &result);
5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status.ok()) {
5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToInt64(result, next_serial_number)) {
5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to restore the next serial number.";
5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status.IsNotFound()) {
5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "No next serial number found.";
5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Error when reading the next serial number.";
5825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadUserSerialNumberMap(
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::map<std::string, int64>* user_serial_number_map) {
5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (iter->Seek(MakeSlice(kUserSerialNumberKeyStart));
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Valid() && iter->key().ToString() < kUserSerialNumberKeyEnd;
5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Next()) {
5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string username = ParseUsername(iter->key().ToString());
5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (username.empty()) {
5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading username. It should not be empty.";
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string serial_number_string = iter->value().ToString();
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64 serial_number = kSerialNumberMissing;
6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToInt64(serial_number_string, &serial_number)) {
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading user serial number for user: " << username;
6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
6045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*user_serial_number_map)[username] = serial_number;
6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
6105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::GCMStoreImpl(
6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool use_mock_keychain,
6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path,
6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : backend_(new Backend(path, base::MessageLoopProxy::current())),
6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blocking_task_runner_(blocking_task_runner),
6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_ptr_factory_(this) {
6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// On OSX, prevent the Keychain permissions popup during unit tests.
6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_MACOSX)
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Encryptor::UseMockKeychain(use_mock_keychain);
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::~GCMStoreImpl() {}
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Load(const LoadCallback& callback) {
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Load,
6315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
6325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::LoadContinuation,
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
6345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Destroy(const UpdateCallback& callback) {
6385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
6405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Destroy, backend_, callback));
6415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::SetDeviceCredentials(uint64 device_android_id,
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        uint64 device_security_token,
6455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        const UpdateCallback& callback) {
6465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
6475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
6485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::SetDeviceCredentials,
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
6505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 device_android_id,
6515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 device_security_token,
6525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
6535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::AddIncomingMessage(const std::string& persistent_id,
6565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const UpdateCallback& callback) {
6575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
6585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
6595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::AddIncomingMessage,
6605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
6615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_id,
6625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
6635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveIncomingMessage(const std::string& persistent_id,
6665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         const UpdateCallback& callback) {
6675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
6685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveIncomingMessages,
6705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
6715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 PersistentIdList(1, persistent_id),
6725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
6735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveIncomingMessages(
6765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
6775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
6785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
6795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
6805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveIncomingMessages,
6815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
6825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_ids,
6835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
6845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::AddOutgoingMessage(const std::string& persistent_id,
6875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const MCSMessage& message,
6885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const UpdateCallback& callback) {
6895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(message.tag(), kDataMessageStanzaTag);
6905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = reinterpret_cast<const mcs_proto::DataMessageStanza*>(
6915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &message.GetProtobuf())->category();
6925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!app_id.empty());
6935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_message_counts_.count(app_id) == 0)
6945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id] = 0;
6955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_message_counts_[app_id] < kMessagesPerAppLimit) {
6965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id]++;
6975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    blocking_task_runner_->PostTask(
6995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
7005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&GCMStoreImpl::Backend::AddOutgoingMessage,
7015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   backend_,
7025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   persistent_id,
7035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   message,
7045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   base::Bind(&GCMStoreImpl::AddOutgoingMessageContinuation,
7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              weak_ptr_factory_.GetWeakPtr(),
7065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              callback,
7075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              app_id)));
7085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
7095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
7115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::OverwriteOutgoingMessage(const std::string& persistent_id,
7145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const MCSMessage& message,
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const UpdateCallback& callback) {
7165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(message.tag(), kDataMessageStanzaTag);
7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = reinterpret_cast<const mcs_proto::DataMessageStanza*>(
7185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &message.GetProtobuf())->category();
7195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!app_id.empty());
7205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There should already be pending messages for this app.
7215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(app_message_counts_.count(app_id));
7225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(zea): consider verifying the specific message already exists.
7235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::AddOutgoingMessage,
7265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_id,
7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 message,
7295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessage(const std::string& persistent_id,
7335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         const UpdateCallback& callback) {
7345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveOutgoingMessages,
7375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 PersistentIdList(1, persistent_id),
7395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation,
7405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
7415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
7425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessages(
7455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
7465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
7475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveOutgoingMessages,
7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_ids,
7525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation,
7535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
7545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
7555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::SetNextSerialNumber(int64 next_serial_number,
7585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       const UpdateCallback& callback) {
7595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::SetNextSerialNumber,
7625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 next_serial_number,
7645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::AddUserSerialNumber(const std::string& username,
7685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       int64 serial_number,
7695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       const UpdateCallback& callback) {
7705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::AddUserSerialNumber,
7735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 username,
7755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 serial_number,
7765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveUserSerialNumber(const std::string& username,
7805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          const UpdateCallback& callback) {
7815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveUserSerialNumber,
7845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 username,
7865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::LoadContinuation(const LoadCallback& callback,
7905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    scoped_ptr<LoadResult> result) {
7915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!result->success) {
7925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(result.Pass());
7935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
7945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int num_throttled_apps = 0;
7965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (OutgoingMessageMap::const_iterator
7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           iter = result->outgoing_messages.begin();
7985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != result->outgoing_messages.end(); ++iter) {
7995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const mcs_proto::DataMessageStanza* data_message =
8005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        reinterpret_cast<mcs_proto::DataMessageStanza*>(iter->second.get());
8015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(!data_message->category().empty());
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (app_message_counts_.count(data_message->category()) == 0)
8035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_message_counts_[data_message->category()] = 1;
8045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else
8055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_message_counts_[data_message->category()]++;
8065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (app_message_counts_[data_message->category()] == kMessagesPerAppLimit)
8075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      num_throttled_apps++;
8085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("GCM.NumThrottledApps", num_throttled_apps);
8105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(result.Pass());
8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::AddOutgoingMessageContinuation(
8145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback,
8155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& app_id,
8165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success) {
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!success) {
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(app_message_counts_[app_id] > 0);
8195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id]--;
8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(success);
8225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessagesContinuation(
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback,
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success,
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const AppIdToMessageCountMap& removed_message_counts) {
8285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!success) {
8295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false);
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (AppIdToMessageCountMap::const_iterator iter =
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           removed_message_counts.begin();
8345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != removed_message_counts.end(); ++iter) {
8355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_NE(app_message_counts_.count(iter->first), 0U);
8365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[iter->first] -= iter->second;
8375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_GE(app_message_counts_[iter->first], 0);
8385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(true);
8405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace gcm
843