gcm_store_impl.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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"
19a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/time/time.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/tracked_objects.h"
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/os_crypt/os_crypt.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/base/mcs_message.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/base/mcs_util.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/protocol/mcs.pb.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/db.h"
26a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace gcm {
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Limit to the number of outstanding messages per app.
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kMessagesPerAppLimit = 20;
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// ---- LevelDB keys. ----
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key for this device's android id.
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeviceAIDKey[] = "device_aid_key";
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key for this device's android security token.
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeviceTokenKey[] = "device_token_key";
40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Lowest lexicographically ordered app ids.
41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Used for prefixing app id.
42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char kRegistrationKeyStart[] = "reg1-";
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Key guaranteed to be higher than all app ids.
44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Used for limiting iteration.
45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char kRegistrationKeyEnd[] = "reg2-";
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Lowest lexicographically ordered incoming message key.
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for prefixing messages.
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kIncomingMsgKeyStart[] = "incoming1-";
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key guaranteed to be higher than all incoming message keys.
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for limiting iteration.
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kIncomingMsgKeyEnd[] = "incoming2-";
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Lowest lexicographically ordered outgoing message key.
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for prefixing outgoing messages.
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kOutgoingMsgKeyStart[] = "outgoing1-";
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key guaranteed to be higher than all outgoing message keys.
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for limiting iteration.
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kOutgoingMsgKeyEnd[] = "outgoing2-";
58a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Lowest lexicographically ordered G-service settings key.
59a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Used for prefixing G-services settings.
60a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst char kGServiceSettingKeyStart[] = "gservice1-";
61a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Key guaranteed to be higher than all G-services settings keys.
62a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Used for limiting iteration.
63a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst char kGServiceSettingKeyEnd[] = "gservice2-";
64a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Key for digest of the last G-services settings update.
65a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst char kGServiceSettingsDigestKey[] = "gservices_digest";
66c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Key used to timestamp last checkin (marked with G services settings update).
67c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kLastCheckinTimeKey[] = "last_checkin_time";
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string MakeRegistrationKey(const std::string& app_id) {
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return kRegistrationKeyStart + app_id;
71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string ParseRegistrationKey(const std::string& key) {
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return key.substr(arraysize(kRegistrationKeyStart) - 1);
75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string MakeIncomingKey(const std::string& persistent_id) {
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return kIncomingMsgKeyStart + persistent_id;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string MakeOutgoingKey(const std::string& persistent_id) {
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return kOutgoingMsgKeyStart + persistent_id;
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string ParseOutgoingKey(const std::string& key) {
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return key.substr(arraysize(kOutgoingMsgKeyStart) - 1);
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
89a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochstd::string MakeGServiceSettingKey(const std::string& setting_name) {
90a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return kGServiceSettingKeyStart + setting_name;
91a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
92a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
93a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochstd::string ParseGServiceSettingKey(const std::string& key) {
94a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return key.substr(arraysize(kGServiceSettingKeyStart) - 1);
95a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
96a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// outlive the slice.
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// For example: MakeSlice(MakeOutgoingKey(x)) is invalid.
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)leveldb::Slice MakeSlice(const base::StringPiece& s) {
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return leveldb::Slice(s.begin(), s.size());
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class GCMStoreImpl::Backend
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : public base::RefCountedThreadSafe<GCMStoreImpl::Backend> {
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Backend(const base::FilePath& path,
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          scoped_refptr<base::SequencedTaskRunner> foreground_runner);
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Blocking implementations of GCMStoreImpl methods.
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Load(const LoadCallback& callback);
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void Close();
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Destroy(const UpdateCallback& callback);
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void SetDeviceCredentials(uint64 device_android_id,
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            uint64 device_security_token,
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const UpdateCallback& callback);
119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void AddRegistration(const std::string& app_id,
120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                       const linked_ptr<RegistrationInfo>& registration,
121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                       const UpdateCallback& callback);
122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void RemoveRegistration(const std::string& app_id,
123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                          const UpdateCallback& callback);
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddIncomingMessage(const std::string& persistent_id,
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const UpdateCallback& callback);
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveIncomingMessages(const PersistentIdList& persistent_ids,
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const UpdateCallback& callback);
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddOutgoingMessage(const std::string& persistent_id,
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const MCSMessage& message,
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const UpdateCallback& callback);
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveOutgoingMessages(
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const PersistentIdList& persistent_ids,
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::Callback<void(bool, const AppIdToMessageCountMap&)>
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          callback);
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddUserSerialNumber(const std::string& username,
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           int64 serial_number,
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           const UpdateCallback& callback);
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveUserSerialNumber(const std::string& username,
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const UpdateCallback& callback);
140c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  void SetLastCheckinTime(const base::Time& last_checkin_time,
141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                          const UpdateCallback& callback);
142a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  void SetGServicesSettings(
143a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const std::map<std::string, std::string>& settings,
144a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const std::string& digest,
145a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const UpdateCallback& callback);
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Backend>;
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~Backend();
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadDeviceCredentials(uint64* android_id, uint64* security_token);
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  bool LoadRegistrations(RegistrationInfoMap* registrations);
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadIncomingMessages(std::vector<std::string>* incoming_messages);
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages);
155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bool LoadLastCheckinTime(base::Time* last_checkin_time);
156a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  bool LoadGServicesSettings(std::map<std::string, std::string>* settings,
157a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                             std::string* digest);
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::FilePath path_;
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::DB> db_;
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::Backend::Backend(
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path,
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> foreground_task_runner)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : path_(path), foreground_task_runner_(foreground_task_runner) {}
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::Backend::~Backend() {}
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::Load(const LoadCallback& callback) {
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<LoadResult> result(new LoadResult());
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (db_.get()) {
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Attempting to reload open database.";
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Options options;
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  options.create_if_missing = true;
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::DB* db;
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status status =
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db);
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("GCM.LoadSucceeded", status.ok());
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!status.ok()) {
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Failed to open database " << path_.value() << ": "
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << status.ToString();
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  db_.reset(db);
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!LoadDeviceCredentials(&result->device_android_id,
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             &result->device_security_token) ||
200effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      !LoadRegistrations(&result->registrations) ||
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !LoadIncomingMessages(&result->incoming_messages) ||
202c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      !LoadOutgoingMessages(&result->outgoing_messages) ||
203a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      !LoadLastCheckinTime(&result->last_checkin_time) ||
204a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      !LoadGServicesSettings(&result->gservices_settings,
205a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                             &result->gservices_digest)) {
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->device_android_id = 0;
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->device_security_token = 0;
208effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    result->registrations.clear();
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->incoming_messages.clear();
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->outgoing_messages.clear();
211a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    result->gservices_settings.clear();
212a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    result->gservices_digest.clear();
213c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    result->last_checkin_time = base::Time::FromInternalValue(0LL);
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)
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Only record histograms if GCM had already been set up for this device.
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result->device_android_id != 0 && result->device_security_token != 0) {
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64 file_size = 0;
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (base::GetFileSize(path_, &file_size)) {
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      UMA_HISTOGRAM_COUNTS("GCM.StoreSizeKB",
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           static_cast<int>(file_size / 1024));
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
227effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    UMA_HISTOGRAM_COUNTS("GCM.RestoredRegistrations",
228effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         result->registrations.size());
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.RestoredOutgoingMessages",
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         result->outgoing_messages.size());
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.RestoredIncomingMessages",
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         result->incoming_messages.size());
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
235effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DVLOG(1) << "Succeeded in loading " << result->registrations.size()
236effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           << " registrations, "
237effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           << result->incoming_messages.size()
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << " unacknowledged incoming messages and "
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << result->outgoing_messages.size()
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << " unacknowledged outgoing messages.";
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->success = true;
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE,
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::Bind(callback,
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               base::Passed(&result)));
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return;
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMStoreImpl::Backend::Close() {
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DVLOG(1) << "Closing GCM store.";
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  db_.reset();
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::Destroy(const UpdateCallback& callback) {
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Destroying GCM store.";
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  db_.reset();
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s =
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      leveldb::DestroyDB(path_.AsUTF8Unsafe(), leveldb::Options());
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Destroy failed: " << s.ToString();
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::SetDeviceCredentials(
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 device_android_id,
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 device_security_token,
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving device credentials with AID " << device_android_id;
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string encrypted_token;
281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  OSCrypt::EncryptString(base::Uint64ToString(device_security_token),
282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         &encrypted_token);
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string android_id_str = base::Uint64ToString(device_android_id);
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s =
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      db_->Put(write_options,
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(kDeviceAIDKey),
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(android_id_str));
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Put(
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        write_options, MakeSlice(kDeviceTokenKey), MakeSlice(encrypted_token));
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
300effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::Backend::AddRegistration(
301effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& app_id,
302effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const linked_ptr<RegistrationInfo>& registration,
303effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const UpdateCallback& callback) {
304effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DVLOG(1) << "Saving registration info for app: " << app_id;
305effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!db_.get()) {
306effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LOG(ERROR) << "GCMStore db doesn't exist.";
307effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
308effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
309effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
310effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::WriteOptions write_options;
311effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  write_options.sync = true;
312effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
313effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string key = MakeRegistrationKey(app_id);
314effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string value = registration->SerializeAsString();
315effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const leveldb::Status status = db_->Put(write_options,
316effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          MakeSlice(key),
317effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          MakeSlice(value));
318effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (status.ok()) {
319effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
320effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
321effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
322effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  LOG(ERROR) << "LevelDB put failed: " << status.ToString();
323effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
324effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
325effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
326effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::Backend::RemoveRegistration(const std::string& app_id,
327effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                               const UpdateCallback& callback) {
328effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!db_.get()) {
329effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LOG(ERROR) << "GCMStore db doesn't exist.";
330effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
331effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
332effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
333effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::WriteOptions write_options;
334effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  write_options.sync = true;
335effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
336effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::Status status = db_->Delete(write_options, MakeSlice(app_id));
337effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (status.ok()) {
338effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
339effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
340effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
341effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  LOG(ERROR) << "LevelDB remove failed: " << status.ToString();
342effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
343effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
344effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::AddIncomingMessage(const std::string& persistent_id,
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const UpdateCallback& callback) {
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving incoming message with id " << persistent_id;
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key = MakeIncomingKey(persistent_id);
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s = db_->Put(write_options,
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(key),
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(persistent_id));
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::RemoveIncomingMessages(
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s;
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (PersistentIdList::const_iterator iter = persistent_ids.begin();
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != persistent_ids.end();
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing incoming message with id " << *iter;
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string key = MakeIncomingKey(*iter);
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Delete(write_options, MakeSlice(key));
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::AddOutgoingMessage(const std::string& persistent_id,
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const MCSMessage& message,
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const UpdateCallback& callback) {
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving outgoing message with id " << persistent_id;
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string data =
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<char>(message.tag()) + message.SerializeAsString();
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key = MakeOutgoingKey(persistent_id);
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s = db_->Put(write_options,
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(key),
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(data));
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::RemoveOutgoingMessages(
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Callback<void(bool, const AppIdToMessageCountMap&)>
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        callback) {
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 false,
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 AppIdToMessageCountMap()));
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AppIdToMessageCountMap removed_message_counts;
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s;
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (PersistentIdList::const_iterator iter = persistent_ids.begin();
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != persistent_ids.end();
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing outgoing message with id " << *iter;
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string outgoing_message;
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string key = MakeOutgoingKey(*iter);
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Get(read_options,
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 MakeSlice(key),
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 &outgoing_message);
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mcs_proto::DataMessageStanza data_message;
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Skip the initial tag byte and parse the rest to extract the message.
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (data_message.ParseFromString(outgoing_message.substr(1))) {
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(!data_message.category().empty());
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (removed_message_counts.count(data_message.category()) != 0)
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        removed_message_counts[data_message.category()]++;
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      else
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        removed_message_counts[data_message.category()] = 1;
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing outgoing message with id " << *iter;
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Delete(write_options, MakeSlice(key));
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 true,
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 removed_message_counts));
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE,
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::Bind(callback,
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               false,
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               AppIdToMessageCountMap()));
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
482c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid GCMStoreImpl::Backend::SetLastCheckinTime(
483c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const base::Time& last_checkin_time,
484c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const UpdateCallback& callback) {
485c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::WriteOptions write_options;
486c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  write_options.sync = true;
487c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
488c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int64 last_checkin_time_internal = last_checkin_time.ToInternalValue();
489c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const leveldb::Status s =
490c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      db_->Put(write_options,
491c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch               MakeSlice(kLastCheckinTimeKey),
492c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch               MakeSlice(base::Int64ToString(last_checkin_time_internal)));
493c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
494c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!s.ok())
495c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LOG(ERROR) << "LevelDB set last checkin time failed: " << s.ToString();
496a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
497a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
498a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
499a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid GCMStoreImpl::Backend::SetGServicesSettings(
500a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::map<std::string, std::string>& settings,
501a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::string& settings_digest,
502a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const UpdateCallback& callback) {
503a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::WriteBatch write_batch;
504a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
505a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Remove all existing settings.
506a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::ReadOptions read_options;
507a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  read_options.verify_checksums = true;
508a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
509a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  for (iter->Seek(MakeSlice(kGServiceSettingKeyStart));
510a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Valid() && iter->key().ToString() < kGServiceSettingKeyEnd;
511a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Next()) {
512a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    write_batch.Delete(iter->key());
513a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
514a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
515a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Add the new settings.
516a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  for (std::map<std::string, std::string>::const_iterator iter =
517a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch           settings.begin();
518a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter != settings.end(); ++iter) {
519a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    write_batch.Put(MakeSlice(MakeGServiceSettingKey(iter->first)),
520a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                    MakeSlice(iter->second));
521a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
522a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
523a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Update the settings digest.
524a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  write_batch.Put(MakeSlice(kGServiceSettingsDigestKey),
525a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                  MakeSlice(settings_digest));
526a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
527a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Write it all in a batch.
528a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::WriteOptions write_options;
529a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  write_options.sync = true;
530c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
531a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::Status s = db_->Write(write_options, &write_batch);
532a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!s.ok())
533a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    LOG(ERROR) << "LevelDB GService Settings update failed: " << s.ToString();
534c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
535c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
536c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id,
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                  uint64* security_token) {
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string result;
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s = db_->Get(read_options, MakeSlice(kDeviceAIDKey), &result);
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToUint64(result, android_id)) {
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to restore device id.";
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.clear();
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Get(read_options, MakeSlice(kDeviceTokenKey), &result);
5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string decrypted_token;
554a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    OSCrypt::DecryptString(result, &decrypted_token);
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToUint64(decrypted_token, security_token)) {
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to restore security token.";
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.IsNotFound()) {
5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "No credentials found.";
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Error reading credentials from store.";
5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
571effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool GCMStoreImpl::Backend::LoadRegistrations(
572effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    RegistrationInfoMap* registrations) {
573effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::ReadOptions read_options;
574effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  read_options.verify_checksums = true;
575effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
576effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
577effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (iter->Seek(MakeSlice(kRegistrationKeyStart));
578effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       iter->Valid() && iter->key().ToString() < kRegistrationKeyEnd;
579effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       iter->Next()) {
580effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    leveldb::Slice s = iter->value();
581effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (s.size() <= 1) {
582effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LOG(ERROR) << "Error reading registration with key " << s.ToString();
583effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return false;
584effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
585effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::string app_id = ParseRegistrationKey(iter->key().ToString());
586effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    linked_ptr<RegistrationInfo> registration(new RegistrationInfo);
587effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (!registration->ParseFromString(iter->value().ToString())) {
588effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LOG(ERROR) << "Failed to parse registration with app id " << app_id;
589effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return false;
590effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
591effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DVLOG(1) << "Found registration with app id " << app_id;
592effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    (*registrations)[app_id] = registration;
593effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
594effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
595effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return true;
596effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
597effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadIncomingMessages(
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<std::string>* incoming_messages) {
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
6045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (iter->Seek(MakeSlice(kIncomingMsgKeyStart));
6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Valid() && iter->key().ToString() < kIncomingMsgKeyEnd;
6065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Next()) {
6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    leveldb::Slice s = iter->value();
6085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (s.empty()) {
6095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading incoming message with key "
6105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << iter->key().ToString();
6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
6125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Found incoming message with id " << s.ToString();
6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    incoming_messages->push_back(s.ToString());
6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadOutgoingMessages(
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OutgoingMessageMap* outgoing_messages) {
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (iter->Seek(MakeSlice(kOutgoingMsgKeyStart));
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Valid() && iter->key().ToString() < kOutgoingMsgKeyEnd;
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Next()) {
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    leveldb::Slice s = iter->value();
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (s.size() <= 1) {
6315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading incoming message with key " << s.ToString();
6325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint8 tag = iter->value().data()[0];
6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string id = ParseOutgoingKey(iter->key().ToString());
6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<google::protobuf::MessageLite> message(
6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BuildProtobufFromTag(tag));
6385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!message.get() ||
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        !message->ParseFromString(iter->value().ToString().substr(1))) {
6405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to parse outgoing message with id " << id
6415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << " and tag " << tag;
6425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
6435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Found outgoing message with id " << id << " of type "
6455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << base::IntToString(tag);
6465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*outgoing_messages)[id] = make_linked_ptr(message.release());
6475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
6505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
652c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool GCMStoreImpl::Backend::LoadLastCheckinTime(
653c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    base::Time* last_checkin_time) {
654c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::ReadOptions read_options;
655c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  read_options.verify_checksums = true;
656c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
657c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::string result;
658c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::Status s = db_->Get(read_options,
659c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                               MakeSlice(kLastCheckinTimeKey),
660c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                               &result);
661c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int64 time_internal = 0LL;
662c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (s.ok() && !base::StringToInt64(result, &time_internal))
663c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LOG(ERROR) << "Failed to restore last checkin time. Using default = 0.";
664c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
665c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // In case we cannot read last checkin time, we default it to 0, as we don't
666c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // want that situation to cause the whole load to fail.
667c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  *last_checkin_time = base::Time::FromInternalValue(time_internal);
668c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
669c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return true;
670c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
671c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
672a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool GCMStoreImpl::Backend::LoadGServicesSettings(
673a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::map<std::string, std::string>* settings,
674a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::string* digest) {
675a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::ReadOptions read_options;
676a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  read_options.verify_checksums = true;
677a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
678a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Load all of the GServices settings.
679a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
680a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  for (iter->Seek(MakeSlice(kGServiceSettingKeyStart));
681a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Valid() && iter->key().ToString() < kGServiceSettingKeyEnd;
682a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Next()) {
683a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::string value = iter->value().ToString();
684a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    if (value.empty()) {
685a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      LOG(ERROR) << "Error reading GService Settings " << value;
686a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      return false;
687a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    }
688a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::string id = ParseGServiceSettingKey(iter->key().ToString());
689a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    (*settings)[id] = value;
690a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    DVLOG(1) << "Found G Service setting with key: " << id
691a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch             << ", and value: " << value;
692a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
693a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
694a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Load the settings digest. It's ok if it is empty.
695a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  db_->Get(read_options, MakeSlice(kGServiceSettingsDigestKey), digest);
696a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
697a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return true;
698a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
699a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
7005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::GCMStoreImpl(
7015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path,
7025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
7035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : backend_(new Backend(path, base::MessageLoopProxy::current())),
7045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blocking_task_runner_(blocking_task_runner),
7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_ptr_factory_(this) {
7065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::~GCMStoreImpl() {}
7095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Load(const LoadCallback& callback) {
7115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Load,
7145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::LoadContinuation,
7165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
7185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
720a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMStoreImpl::Close() {
721a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  blocking_task_runner_->PostTask(
722a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
723a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Close, backend_));
724a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
725a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Destroy(const UpdateCallback& callback) {
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Destroy, backend_, callback));
7305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::SetDeviceCredentials(uint64 device_android_id,
7335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        uint64 device_security_token,
7345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        const UpdateCallback& callback) {
7355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::SetDeviceCredentials,
7385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 device_android_id,
7405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 device_security_token,
7415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
744effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::AddRegistration(
745effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& app_id,
746effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const linked_ptr<RegistrationInfo>& registration,
747effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const UpdateCallback& callback) {
748effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  blocking_task_runner_->PostTask(
749effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
750effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&GCMStoreImpl::Backend::AddRegistration,
751effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 backend_,
752effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 app_id,
753effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 registration,
754effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 callback));
755effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
756effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
757effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::RemoveRegistration(const std::string& app_id,
758effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          const UpdateCallback& callback) {
759effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  blocking_task_runner_->PostTask(
760effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
761effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&GCMStoreImpl::Backend::RemoveRegistration,
762effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 backend_,
763effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 app_id,
764effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 callback));
765effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
766effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::AddIncomingMessage(const std::string& persistent_id,
7685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const UpdateCallback& callback) {
7695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::AddIncomingMessage,
7725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_id,
7745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveIncomingMessage(const std::string& persistent_id,
7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         const UpdateCallback& callback) {
7795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveIncomingMessages,
7825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 PersistentIdList(1, persistent_id),
7845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveIncomingMessages(
7885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
7895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
7905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveIncomingMessages,
7935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_ids,
7955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::AddOutgoingMessage(const std::string& persistent_id,
7995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const MCSMessage& message,
8005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const UpdateCallback& callback) {
8015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(message.tag(), kDataMessageStanzaTag);
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = reinterpret_cast<const mcs_proto::DataMessageStanza*>(
8035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &message.GetProtobuf())->category();
8045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!app_id.empty());
8055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_message_counts_.count(app_id) == 0)
8065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id] = 0;
8075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_message_counts_[app_id] < kMessagesPerAppLimit) {
8085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id]++;
8095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    blocking_task_runner_->PostTask(
8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
8125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&GCMStoreImpl::Backend::AddOutgoingMessage,
8135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   backend_,
8145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   persistent_id,
8155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   message,
8165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   base::Bind(&GCMStoreImpl::AddOutgoingMessageContinuation,
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              weak_ptr_factory_.GetWeakPtr(),
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              callback,
8195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              app_id)));
8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
8215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::OverwriteOutgoingMessage(const std::string& persistent_id,
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const MCSMessage& message,
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const UpdateCallback& callback) {
8285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(message.tag(), kDataMessageStanzaTag);
8295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = reinterpret_cast<const mcs_proto::DataMessageStanza*>(
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &message.GetProtobuf())->category();
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!app_id.empty());
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There should already be pending messages for this app.
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(app_message_counts_.count(app_id));
8345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(zea): consider verifying the specific message already exists.
8355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
8365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
8375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::AddOutgoingMessage,
8385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
8395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_id,
8405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 message,
8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessage(const std::string& persistent_id,
8455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         const UpdateCallback& callback) {
8465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
8475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
8485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveOutgoingMessages,
8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
8505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 PersistentIdList(1, persistent_id),
8515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation,
8525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
8535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
8545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessages(
8575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
8585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
8595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
8605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
8615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveOutgoingMessages,
8625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
8635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_ids,
8645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation,
8655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
8665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
8675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
869c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid GCMStoreImpl::SetLastCheckinTime(const base::Time& last_checkin_time,
870c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      const UpdateCallback& callback) {
871c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  blocking_task_runner_->PostTask(
872c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      FROM_HERE,
873c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Bind(&GCMStoreImpl::Backend::SetLastCheckinTime,
874c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 backend_,
875c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 last_checkin_time,
876c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 callback));
877c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
878c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
879a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid GCMStoreImpl::SetGServicesSettings(
880a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::map<std::string, std::string>& settings,
881a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::string& digest,
882a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const UpdateCallback& callback) {
883a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  blocking_task_runner_->PostTask(
884a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      FROM_HERE,
885a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      base::Bind(&GCMStoreImpl::Backend::SetGServicesSettings,
886a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                 backend_,
887a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                 settings,
888a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                 digest,
889a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                 callback));
890a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
891a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
8925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::LoadContinuation(const LoadCallback& callback,
8935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    scoped_ptr<LoadResult> result) {
8945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!result->success) {
8955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(result.Pass());
8965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
8975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int num_throttled_apps = 0;
8995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (OutgoingMessageMap::const_iterator
9005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           iter = result->outgoing_messages.begin();
9015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != result->outgoing_messages.end(); ++iter) {
9025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const mcs_proto::DataMessageStanza* data_message =
9035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        reinterpret_cast<mcs_proto::DataMessageStanza*>(iter->second.get());
9045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(!data_message->category().empty());
9055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (app_message_counts_.count(data_message->category()) == 0)
9065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_message_counts_[data_message->category()] = 1;
9075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else
9085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_message_counts_[data_message->category()]++;
9095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (app_message_counts_[data_message->category()] == kMessagesPerAppLimit)
9105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      num_throttled_apps++;
9115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("GCM.NumThrottledApps", num_throttled_apps);
9135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(result.Pass());
9145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::AddOutgoingMessageContinuation(
9175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback,
9185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& app_id,
9195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success) {
9205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!success) {
9215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(app_message_counts_[app_id] > 0);
9225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id]--;
9235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(success);
9255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessagesContinuation(
9285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback,
9295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success,
9305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const AppIdToMessageCountMap& removed_message_counts) {
9315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!success) {
9325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false);
9335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
9345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (AppIdToMessageCountMap::const_iterator iter =
9365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           removed_message_counts.begin();
9375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != removed_message_counts.end(); ++iter) {
9385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_NE(app_message_counts_.count(iter->first), 0U);
9395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[iter->first] -= iter->second;
9405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_GE(app_message_counts_[iter->first], 0);
9415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(true);
9435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace gcm
946