gcm_store_impl.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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";
38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Lowest lexicographically ordered app ids.
39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Used for prefixing app id.
40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char kRegistrationKeyStart[] = "reg1-";
41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Key guaranteed to be higher than all app ids.
42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Used for limiting iteration.
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char kRegistrationKeyEnd[] = "reg2-";
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Lowest lexicographically ordered incoming message key.
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for prefixing messages.
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kIncomingMsgKeyStart[] = "incoming1-";
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key guaranteed to be higher than all incoming message keys.
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for limiting iteration.
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kIncomingMsgKeyEnd[] = "incoming2-";
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Lowest lexicographically ordered outgoing message key.
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for prefixing outgoing messages.
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kOutgoingMsgKeyStart[] = "outgoing1-";
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key guaranteed to be higher than all outgoing message keys.
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for limiting iteration.
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kOutgoingMsgKeyEnd[] = "outgoing2-";
56c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Key used to timestamp last checkin (marked with G services settings update).
57c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kLastCheckinTimeKey[] = "last_checkin_time";
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string MakeRegistrationKey(const std::string& app_id) {
60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return kRegistrationKeyStart + app_id;
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string ParseRegistrationKey(const std::string& key) {
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return key.substr(arraysize(kRegistrationKeyStart) - 1);
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string MakeIncomingKey(const std::string& persistent_id) {
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return kIncomingMsgKeyStart + persistent_id;
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string MakeOutgoingKey(const std::string& persistent_id) {
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return kOutgoingMsgKeyStart + persistent_id;
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string ParseOutgoingKey(const std::string& key) {
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return key.substr(arraysize(kOutgoingMsgKeyStart) - 1);
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// outlive the slice.
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// For example: MakeSlice(MakeOutgoingKey(x)) is invalid.
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)leveldb::Slice MakeSlice(const base::StringPiece& s) {
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return leveldb::Slice(s.begin(), s.size());
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class GCMStoreImpl::Backend
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : public base::RefCountedThreadSafe<GCMStoreImpl::Backend> {
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Backend(const base::FilePath& path,
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          scoped_refptr<base::SequencedTaskRunner> foreground_runner);
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Blocking implementations of GCMStoreImpl methods.
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Load(const LoadCallback& callback);
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void Close();
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Destroy(const UpdateCallback& callback);
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void SetDeviceCredentials(uint64 device_android_id,
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            uint64 device_security_token,
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const UpdateCallback& callback);
101effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void AddRegistration(const std::string& app_id,
102effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                       const linked_ptr<RegistrationInfo>& registration,
103effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                       const UpdateCallback& callback);
104effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void RemoveRegistration(const std::string& app_id,
105effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                          const UpdateCallback& callback);
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddIncomingMessage(const std::string& persistent_id,
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const UpdateCallback& callback);
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveIncomingMessages(const PersistentIdList& persistent_ids,
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const UpdateCallback& callback);
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddOutgoingMessage(const std::string& persistent_id,
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const MCSMessage& message,
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const UpdateCallback& callback);
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveOutgoingMessages(
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const PersistentIdList& persistent_ids,
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::Callback<void(bool, const AppIdToMessageCountMap&)>
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          callback);
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddUserSerialNumber(const std::string& username,
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           int64 serial_number,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           const UpdateCallback& callback);
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveUserSerialNumber(const std::string& username,
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const UpdateCallback& callback);
122c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  void SetLastCheckinTime(const base::Time& last_checkin_time,
123c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                          const UpdateCallback& callback);
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Backend>;
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~Backend();
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadDeviceCredentials(uint64* android_id, uint64* security_token);
130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  bool LoadRegistrations(RegistrationInfoMap* registrations);
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadIncomingMessages(std::vector<std::string>* incoming_messages);
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages);
133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bool LoadLastCheckinTime(base::Time* last_checkin_time);
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::FilePath path_;
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::DB> db_;
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::Backend::Backend(
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path,
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> foreground_task_runner)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : path_(path), foreground_task_runner_(foreground_task_runner) {}
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::Backend::~Backend() {}
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::Load(const LoadCallback& callback) {
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<LoadResult> result(new LoadResult());
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (db_.get()) {
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Attempting to reload open database.";
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Options options;
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  options.create_if_missing = true;
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::DB* db;
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status status =
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db);
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("GCM.LoadSucceeded", status.ok());
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!status.ok()) {
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Failed to open database " << path_.value() << ": "
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << status.ToString();
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  db_.reset(db);
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!LoadDeviceCredentials(&result->device_android_id,
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             &result->device_security_token) ||
176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      !LoadRegistrations(&result->registrations) ||
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !LoadIncomingMessages(&result->incoming_messages) ||
178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      !LoadOutgoingMessages(&result->outgoing_messages) ||
179c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      !LoadLastCheckinTime(&result->last_checkin_time)) {
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->device_android_id = 0;
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->device_security_token = 0;
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    result->registrations.clear();
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->incoming_messages.clear();
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->outgoing_messages.clear();
185c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    result->last_checkin_time = base::Time::FromInternalValue(0LL);
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Only record histograms if GCM had already been set up for this device.
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result->device_android_id != 0 && result->device_security_token != 0) {
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64 file_size = 0;
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (base::GetFileSize(path_, &file_size)) {
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      UMA_HISTOGRAM_COUNTS("GCM.StoreSizeKB",
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           static_cast<int>(file_size / 1024));
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
199effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    UMA_HISTOGRAM_COUNTS("GCM.RestoredRegistrations",
200effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         result->registrations.size());
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.RestoredOutgoingMessages",
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         result->outgoing_messages.size());
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.RestoredIncomingMessages",
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         result->incoming_messages.size());
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
207effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DVLOG(1) << "Succeeded in loading " << result->registrations.size()
208effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           << " registrations, "
209effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           << result->incoming_messages.size()
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << " unacknowledged incoming messages and "
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << result->outgoing_messages.size()
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << " unacknowledged outgoing messages.";
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->success = true;
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE,
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::Bind(callback,
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               base::Passed(&result)));
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return;
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMStoreImpl::Backend::Close() {
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DVLOG(1) << "Closing GCM store.";
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  db_.reset();
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::Destroy(const UpdateCallback& callback) {
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Destroying GCM store.";
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  db_.reset();
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s =
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      leveldb::DestroyDB(path_.AsUTF8Unsafe(), leveldb::Options());
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Destroy failed: " << s.ToString();
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::SetDeviceCredentials(
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 device_android_id,
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 device_security_token,
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving device credentials with AID " << device_android_id;
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string encrypted_token;
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  OSCrypt::EncryptString(base::Uint64ToString(device_security_token),
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         &encrypted_token);
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string android_id_str = base::Uint64ToString(device_android_id);
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s =
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      db_->Put(write_options,
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(kDeviceAIDKey),
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(android_id_str));
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Put(
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        write_options, MakeSlice(kDeviceTokenKey), MakeSlice(encrypted_token));
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
272effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::Backend::AddRegistration(
273effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& app_id,
274effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const linked_ptr<RegistrationInfo>& registration,
275effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const UpdateCallback& callback) {
276effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DVLOG(1) << "Saving registration info for app: " << app_id;
277effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!db_.get()) {
278effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LOG(ERROR) << "GCMStore db doesn't exist.";
279effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
280effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
281effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
282effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::WriteOptions write_options;
283effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  write_options.sync = true;
284effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
285effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string key = MakeRegistrationKey(app_id);
286effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string value = registration->SerializeAsString();
287effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const leveldb::Status status = db_->Put(write_options,
288effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          MakeSlice(key),
289effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          MakeSlice(value));
290effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (status.ok()) {
291effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
292effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
293effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
294effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  LOG(ERROR) << "LevelDB put failed: " << status.ToString();
295effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
296effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
297effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
298effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::Backend::RemoveRegistration(const std::string& app_id,
299effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                               const UpdateCallback& callback) {
300effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!db_.get()) {
301effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LOG(ERROR) << "GCMStore db doesn't exist.";
302effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
303effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
304effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
305effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::WriteOptions write_options;
306effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  write_options.sync = true;
307effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
308effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::Status status = db_->Delete(write_options, MakeSlice(app_id));
309effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (status.ok()) {
310effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
311effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
312effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
313effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  LOG(ERROR) << "LevelDB remove failed: " << status.ToString();
314effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
315effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
316effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::AddIncomingMessage(const std::string& persistent_id,
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const UpdateCallback& callback) {
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving incoming 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)
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key = MakeIncomingKey(persistent_id);
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s = db_->Put(write_options,
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(key),
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(persistent_id));
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::RemoveIncomingMessages(
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s;
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (PersistentIdList::const_iterator iter = persistent_ids.begin();
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != persistent_ids.end();
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing incoming message with id " << *iter;
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string key = MakeIncomingKey(*iter);
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Delete(write_options, MakeSlice(key));
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::AddOutgoingMessage(const std::string& persistent_id,
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const MCSMessage& message,
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const UpdateCallback& callback) {
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving outgoing message with id " << persistent_id;
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string data =
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<char>(message.tag()) + message.SerializeAsString();
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key = MakeOutgoingKey(persistent_id);
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s = db_->Put(write_options,
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(key),
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(data));
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::RemoveOutgoingMessages(
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Callback<void(bool, const AppIdToMessageCountMap&)>
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        callback) {
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 false,
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 AppIdToMessageCountMap()));
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AppIdToMessageCountMap removed_message_counts;
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s;
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (PersistentIdList::const_iterator iter = persistent_ids.begin();
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != persistent_ids.end();
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing outgoing message with id " << *iter;
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string outgoing_message;
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string key = MakeOutgoingKey(*iter);
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Get(read_options,
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 MakeSlice(key),
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 &outgoing_message);
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mcs_proto::DataMessageStanza data_message;
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Skip the initial tag byte and parse the rest to extract the message.
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (data_message.ParseFromString(outgoing_message.substr(1))) {
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(!data_message.category().empty());
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (removed_message_counts.count(data_message.category()) != 0)
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        removed_message_counts[data_message.category()]++;
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      else
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        removed_message_counts[data_message.category()] = 1;
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing outgoing message with id " << *iter;
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Delete(write_options, MakeSlice(key));
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 true,
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 removed_message_counts));
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE,
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::Bind(callback,
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               false,
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               AppIdToMessageCountMap()));
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
454c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid GCMStoreImpl::Backend::SetLastCheckinTime(
455c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const base::Time& last_checkin_time,
456c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const UpdateCallback& callback) {
457c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::WriteOptions write_options;
458c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  write_options.sync = true;
459c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
460c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int64 last_checkin_time_internal = last_checkin_time.ToInternalValue();
461c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const leveldb::Status s =
462c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      db_->Put(write_options,
463c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch               MakeSlice(kLastCheckinTimeKey),
464c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch               MakeSlice(base::Int64ToString(last_checkin_time_internal)));
465c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
466c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!s.ok())
467c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LOG(ERROR) << "LevelDB set last checkin time failed: " << s.ToString();
468c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
469c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
470c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
471c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id,
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                  uint64* security_token) {
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string result;
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s = db_->Get(read_options, MakeSlice(kDeviceAIDKey), &result);
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToUint64(result, android_id)) {
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to restore device id.";
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.clear();
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Get(read_options, MakeSlice(kDeviceTokenKey), &result);
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string decrypted_token;
489a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    OSCrypt::DecryptString(result, &decrypted_token);
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToUint64(decrypted_token, security_token)) {
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to restore security token.";
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.IsNotFound()) {
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "No credentials found.";
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Error reading credentials from store.";
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
506effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool GCMStoreImpl::Backend::LoadRegistrations(
507effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    RegistrationInfoMap* registrations) {
508effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::ReadOptions read_options;
509effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  read_options.verify_checksums = true;
510effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
511effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
512effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (iter->Seek(MakeSlice(kRegistrationKeyStart));
513effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       iter->Valid() && iter->key().ToString() < kRegistrationKeyEnd;
514effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       iter->Next()) {
515effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    leveldb::Slice s = iter->value();
516effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (s.size() <= 1) {
517effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LOG(ERROR) << "Error reading registration with key " << s.ToString();
518effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return false;
519effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
520effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::string app_id = ParseRegistrationKey(iter->key().ToString());
521effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    linked_ptr<RegistrationInfo> registration(new RegistrationInfo);
522effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (!registration->ParseFromString(iter->value().ToString())) {
523effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LOG(ERROR) << "Failed to parse registration with app id " << app_id;
524effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return false;
525effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
526effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DVLOG(1) << "Found registration with app id " << app_id;
527effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    (*registrations)[app_id] = registration;
528effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
529effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
530effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return true;
531effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
532effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadIncomingMessages(
5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<std::string>* incoming_messages) {
5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (iter->Seek(MakeSlice(kIncomingMsgKeyStart));
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Valid() && iter->key().ToString() < kIncomingMsgKeyEnd;
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Next()) {
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    leveldb::Slice s = iter->value();
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (s.empty()) {
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading incoming message with key "
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << iter->key().ToString();
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Found incoming message with id " << s.ToString();
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    incoming_messages->push_back(s.ToString());
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadOutgoingMessages(
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OutgoingMessageMap* outgoing_messages) {
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (iter->Seek(MakeSlice(kOutgoingMsgKeyStart));
5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Valid() && iter->key().ToString() < kOutgoingMsgKeyEnd;
5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Next()) {
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    leveldb::Slice s = iter->value();
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (s.size() <= 1) {
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading incoming message with key " << s.ToString();
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint8 tag = iter->value().data()[0];
5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string id = ParseOutgoingKey(iter->key().ToString());
5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<google::protobuf::MessageLite> message(
5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BuildProtobufFromTag(tag));
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!message.get() ||
5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        !message->ParseFromString(iter->value().ToString().substr(1))) {
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to parse outgoing message with id " << id
5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << " and tag " << tag;
5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Found outgoing message with id " << id << " of type "
5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << base::IntToString(tag);
5815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*outgoing_messages)[id] = make_linked_ptr(message.release());
5825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
587c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool GCMStoreImpl::Backend::LoadLastCheckinTime(
588c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    base::Time* last_checkin_time) {
589c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::ReadOptions read_options;
590c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  read_options.verify_checksums = true;
591c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
592c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::string result;
593c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::Status s = db_->Get(read_options,
594c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                               MakeSlice(kLastCheckinTimeKey),
595c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                               &result);
596c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int64 time_internal = 0LL;
597c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (s.ok() && !base::StringToInt64(result, &time_internal))
598c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LOG(ERROR) << "Failed to restore last checkin time. Using default = 0.";
599c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
600c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // In case we cannot read last checkin time, we default it to 0, as we don't
601c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // want that situation to cause the whole load to fail.
602c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  *last_checkin_time = base::Time::FromInternalValue(time_internal);
603c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
604c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return true;
605c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
606c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::GCMStoreImpl(
6085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool use_mock_keychain,
6095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path,
6105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : backend_(new Backend(path, base::MessageLoopProxy::current())),
6125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blocking_task_runner_(blocking_task_runner),
6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_ptr_factory_(this) {
6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// On OSX, prevent the Keychain permissions popup during unit tests.
6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_MACOSX)
616a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  OSCrypt::UseMockKeychain(use_mock_keychain);
6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::~GCMStoreImpl() {}
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Load(const LoadCallback& callback) {
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Load,
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::LoadContinuation,
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
632a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMStoreImpl::Close() {
633a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  blocking_task_runner_->PostTask(
634a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
635a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Close, backend_));
636a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
637a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
6385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Destroy(const UpdateCallback& callback) {
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
6405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
6415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Destroy, backend_, callback));
6425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::SetDeviceCredentials(uint64 device_android_id,
6455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        uint64 device_security_token,
6465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        const UpdateCallback& callback) {
6475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
6485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::SetDeviceCredentials,
6505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
6515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 device_android_id,
6525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 device_security_token,
6535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
6545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
656effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::AddRegistration(
657effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& app_id,
658effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const linked_ptr<RegistrationInfo>& registration,
659effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const UpdateCallback& callback) {
660effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  blocking_task_runner_->PostTask(
661effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
662effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&GCMStoreImpl::Backend::AddRegistration,
663effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 backend_,
664effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 app_id,
665effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 registration,
666effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 callback));
667effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
668effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
669effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::RemoveRegistration(const std::string& app_id,
670effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          const UpdateCallback& callback) {
671effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  blocking_task_runner_->PostTask(
672effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
673effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&GCMStoreImpl::Backend::RemoveRegistration,
674effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 backend_,
675effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 app_id,
676effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 callback));
677effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
678effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
6795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::AddIncomingMessage(const std::string& persistent_id,
6805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const UpdateCallback& callback) {
6815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
6825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
6835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::AddIncomingMessage,
6845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
6855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_id,
6865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
6875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveIncomingMessage(const std::string& persistent_id,
6905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         const UpdateCallback& callback) {
6915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
6925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
6935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveIncomingMessages,
6945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
6955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 PersistentIdList(1, persistent_id),
6965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
6975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveIncomingMessages(
7005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
7015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
7025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveIncomingMessages,
7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_ids,
7075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::AddOutgoingMessage(const std::string& persistent_id,
7115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const MCSMessage& message,
7125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const UpdateCallback& callback) {
7135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(message.tag(), kDataMessageStanzaTag);
7145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = reinterpret_cast<const mcs_proto::DataMessageStanza*>(
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &message.GetProtobuf())->category();
7165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!app_id.empty());
7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_message_counts_.count(app_id) == 0)
7185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id] = 0;
7195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_message_counts_[app_id] < kMessagesPerAppLimit) {
7205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id]++;
7215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    blocking_task_runner_->PostTask(
7235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
7245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&GCMStoreImpl::Backend::AddOutgoingMessage,
7255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   backend_,
7265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   persistent_id,
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   message,
7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   base::Bind(&GCMStoreImpl::AddOutgoingMessageContinuation,
7295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              weak_ptr_factory_.GetWeakPtr(),
7305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              callback,
7315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              app_id)));
7325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
7335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
7355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::OverwriteOutgoingMessage(const std::string& persistent_id,
7385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const MCSMessage& message,
7395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const UpdateCallback& callback) {
7405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(message.tag(), kDataMessageStanzaTag);
7415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = reinterpret_cast<const mcs_proto::DataMessageStanza*>(
7425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &message.GetProtobuf())->category();
7435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!app_id.empty());
7445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There should already be pending messages for this app.
7455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(app_message_counts_.count(app_id));
7465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(zea): consider verifying the specific message already exists.
7475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::AddOutgoingMessage,
7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_id,
7525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 message,
7535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessage(const std::string& persistent_id,
7575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         const UpdateCallback& callback) {
7585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveOutgoingMessages,
7615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 PersistentIdList(1, persistent_id),
7635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation,
7645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
7655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
7665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessages(
7695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
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::RemoveOutgoingMessages,
7745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_ids,
7765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation,
7775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
7795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
781c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid GCMStoreImpl::SetLastCheckinTime(const base::Time& last_checkin_time,
782c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      const UpdateCallback& callback) {
783c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  blocking_task_runner_->PostTask(
784c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      FROM_HERE,
785c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Bind(&GCMStoreImpl::Backend::SetLastCheckinTime,
786c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 backend_,
787c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 last_checkin_time,
788c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 callback));
789c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
790c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
7915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::LoadContinuation(const LoadCallback& callback,
7925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    scoped_ptr<LoadResult> result) {
7935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!result->success) {
7945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(result.Pass());
7955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
7965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int num_throttled_apps = 0;
7985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (OutgoingMessageMap::const_iterator
7995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           iter = result->outgoing_messages.begin();
8005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != result->outgoing_messages.end(); ++iter) {
8015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const mcs_proto::DataMessageStanza* data_message =
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        reinterpret_cast<mcs_proto::DataMessageStanza*>(iter->second.get());
8035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(!data_message->category().empty());
8045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (app_message_counts_.count(data_message->category()) == 0)
8055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_message_counts_[data_message->category()] = 1;
8065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else
8075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_message_counts_[data_message->category()]++;
8085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (app_message_counts_[data_message->category()] == kMessagesPerAppLimit)
8095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      num_throttled_apps++;
8105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("GCM.NumThrottledApps", num_throttled_apps);
8125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(result.Pass());
8135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::AddOutgoingMessageContinuation(
8165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback,
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& app_id,
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success) {
8195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!success) {
8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(app_message_counts_[app_id] > 0);
8215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id]--;
8225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(success);
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessagesContinuation(
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback,
8285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success,
8295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const AppIdToMessageCountMap& removed_message_counts) {
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!success) {
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false);
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (AppIdToMessageCountMap::const_iterator iter =
8355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           removed_message_counts.begin();
8365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != removed_message_counts.end(); ++iter) {
8375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_NE(app_message_counts_.count(iter->first), 0U);
8385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[iter->first] -= iter->second;
8395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_GE(app_message_counts_[iter->first], 0);
8405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(true);
8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace gcm
845