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