gcm_store_impl.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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"
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "google_apis/gcm/base/encryptor.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,
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          scoped_refptr<base::SequencedTaskRunner> foreground_runner,
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          scoped_ptr<Encryptor> encryptor);
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Blocking implementations of GCMStoreImpl methods.
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Load(const LoadCallback& callback);
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void Close();
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Destroy(const UpdateCallback& callback);
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void SetDeviceCredentials(uint64 device_android_id,
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            uint64 device_security_token,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const UpdateCallback& callback);
120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void AddRegistration(const std::string& app_id,
121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                       const linked_ptr<RegistrationInfo>& registration,
122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                       const UpdateCallback& callback);
123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void RemoveRegistration(const std::string& app_id,
124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                          const UpdateCallback& callback);
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddIncomingMessage(const std::string& persistent_id,
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const UpdateCallback& callback);
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveIncomingMessages(const PersistentIdList& persistent_ids,
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const UpdateCallback& callback);
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddOutgoingMessage(const std::string& persistent_id,
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const MCSMessage& message,
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const UpdateCallback& callback);
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveOutgoingMessages(
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const PersistentIdList& persistent_ids,
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::Callback<void(bool, const AppIdToMessageCountMap&)>
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          callback);
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddUserSerialNumber(const std::string& username,
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           int64 serial_number,
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           const UpdateCallback& callback);
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveUserSerialNumber(const std::string& username,
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const UpdateCallback& callback);
141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  void SetLastCheckinTime(const base::Time& last_checkin_time,
142c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                          const UpdateCallback& callback);
143a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  void SetGServicesSettings(
144a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const std::map<std::string, std::string>& settings,
145a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const std::string& digest,
146a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const UpdateCallback& callback);
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Backend>;
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~Backend();
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadDeviceCredentials(uint64* android_id, uint64* security_token);
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  bool LoadRegistrations(RegistrationInfoMap* registrations);
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadIncomingMessages(std::vector<std::string>* incoming_messages);
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages);
156c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bool LoadLastCheckinTime(base::Time* last_checkin_time);
157a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  bool LoadGServicesSettings(std::map<std::string, std::string>* settings,
158a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                             std::string* digest);
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::FilePath path_;
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<Encryptor> encryptor_;
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::DB> db_;
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::Backend::Backend(
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path,
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> foreground_task_runner,
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_ptr<Encryptor> encryptor)
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : path_(path),
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      foreground_task_runner_(foreground_task_runner),
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      encryptor_(encryptor.Pass()) {
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::Backend::~Backend() {}
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::Load(const LoadCallback& callback) {
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<LoadResult> result(new LoadResult());
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (db_.get()) {
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Attempting to reload open database.";
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Options options;
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  options.create_if_missing = true;
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::DB* db;
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status status =
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db);
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("GCM.LoadSucceeded", status.ok());
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!status.ok()) {
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Failed to open database " << path_.value() << ": "
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << status.ToString();
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  db_.reset(db);
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!LoadDeviceCredentials(&result->device_android_id,
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             &result->device_security_token) ||
206effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      !LoadRegistrations(&result->registrations) ||
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !LoadIncomingMessages(&result->incoming_messages) ||
208c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      !LoadOutgoingMessages(&result->outgoing_messages) ||
209a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      !LoadLastCheckinTime(&result->last_checkin_time) ||
210a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      !LoadGServicesSettings(&result->gservices_settings,
211a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                             &result->gservices_digest)) {
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->device_android_id = 0;
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->device_security_token = 0;
214effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    result->registrations.clear();
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->incoming_messages.clear();
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->outgoing_messages.clear();
217a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    result->gservices_settings.clear();
218a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    result->gservices_digest.clear();
219c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    result->last_checkin_time = base::Time::FromInternalValue(0LL);
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Only record histograms if GCM had already been set up for this device.
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result->device_android_id != 0 && result->device_security_token != 0) {
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64 file_size = 0;
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (base::GetFileSize(path_, &file_size)) {
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      UMA_HISTOGRAM_COUNTS("GCM.StoreSizeKB",
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           static_cast<int>(file_size / 1024));
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
233effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    UMA_HISTOGRAM_COUNTS("GCM.RestoredRegistrations",
234effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         result->registrations.size());
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.RestoredOutgoingMessages",
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         result->outgoing_messages.size());
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.RestoredIncomingMessages",
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         result->incoming_messages.size());
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
241effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DVLOG(1) << "Succeeded in loading " << result->registrations.size()
242effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           << " registrations, "
243effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           << result->incoming_messages.size()
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << " unacknowledged incoming messages and "
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << result->outgoing_messages.size()
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << " unacknowledged outgoing messages.";
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->success = true;
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE,
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::Bind(callback,
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               base::Passed(&result)));
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return;
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMStoreImpl::Backend::Close() {
255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DVLOG(1) << "Closing GCM store.";
256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  db_.reset();
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::Destroy(const UpdateCallback& callback) {
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Destroying GCM store.";
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  db_.reset();
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s =
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      leveldb::DestroyDB(path_.AsUTF8Unsafe(), leveldb::Options());
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Destroy failed: " << s.ToString();
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::SetDeviceCredentials(
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 device_android_id,
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 device_security_token,
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving device credentials with AID " << device_android_id;
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string encrypted_token;
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  encryptor_->EncryptString(base::Uint64ToString(device_security_token),
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            &encrypted_token);
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string android_id_str = base::Uint64ToString(device_android_id);
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s =
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      db_->Put(write_options,
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(kDeviceAIDKey),
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(android_id_str));
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Put(
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        write_options, MakeSlice(kDeviceTokenKey), MakeSlice(encrypted_token));
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
306effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::Backend::AddRegistration(
307effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& app_id,
308effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const linked_ptr<RegistrationInfo>& registration,
309effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const UpdateCallback& callback) {
310effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DVLOG(1) << "Saving registration info for app: " << app_id;
311effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!db_.get()) {
312effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LOG(ERROR) << "GCMStore db doesn't exist.";
313effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
314effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
315effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
316effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::WriteOptions write_options;
317effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  write_options.sync = true;
318effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
319effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string key = MakeRegistrationKey(app_id);
320effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string value = registration->SerializeAsString();
321effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const leveldb::Status status = db_->Put(write_options,
322effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          MakeSlice(key),
323effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          MakeSlice(value));
324effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (status.ok()) {
325effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
326effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
327effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
328effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  LOG(ERROR) << "LevelDB put failed: " << status.ToString();
329effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
330effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
331effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
332effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::Backend::RemoveRegistration(const std::string& app_id,
333effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                               const UpdateCallback& callback) {
334effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!db_.get()) {
335effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LOG(ERROR) << "GCMStore db doesn't exist.";
336effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
337effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
338effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
339effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::WriteOptions write_options;
340effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  write_options.sync = true;
341effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
342effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::Status status = db_->Delete(write_options, MakeSlice(app_id));
343effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (status.ok()) {
344effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
345effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
346effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
347effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  LOG(ERROR) << "LevelDB remove failed: " << status.ToString();
348effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
349effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
350effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::AddIncomingMessage(const std::string& persistent_id,
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const UpdateCallback& callback) {
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving incoming message with id " << persistent_id;
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key = MakeIncomingKey(persistent_id);
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s = db_->Put(write_options,
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(key),
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(persistent_id));
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::RemoveIncomingMessages(
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s;
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (PersistentIdList::const_iterator iter = persistent_ids.begin();
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != persistent_ids.end();
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing incoming message with id " << *iter;
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string key = MakeIncomingKey(*iter);
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Delete(write_options, MakeSlice(key));
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::AddOutgoingMessage(const std::string& persistent_id,
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const MCSMessage& message,
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const UpdateCallback& callback) {
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving outgoing message with id " << persistent_id;
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string data =
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<char>(message.tag()) + message.SerializeAsString();
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key = MakeOutgoingKey(persistent_id);
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s = db_->Put(write_options,
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(key),
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(data));
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::RemoveOutgoingMessages(
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Callback<void(bool, const AppIdToMessageCountMap&)>
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        callback) {
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 false,
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 AppIdToMessageCountMap()));
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AppIdToMessageCountMap removed_message_counts;
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s;
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (PersistentIdList::const_iterator iter = persistent_ids.begin();
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != persistent_ids.end();
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing outgoing message with id " << *iter;
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string outgoing_message;
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string key = MakeOutgoingKey(*iter);
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Get(read_options,
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 MakeSlice(key),
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 &outgoing_message);
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mcs_proto::DataMessageStanza data_message;
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Skip the initial tag byte and parse the rest to extract the message.
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (data_message.ParseFromString(outgoing_message.substr(1))) {
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(!data_message.category().empty());
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (removed_message_counts.count(data_message.category()) != 0)
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        removed_message_counts[data_message.category()]++;
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      else
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        removed_message_counts[data_message.category()] = 1;
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing outgoing message with id " << *iter;
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Delete(write_options, MakeSlice(key));
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 true,
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 removed_message_counts));
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE,
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::Bind(callback,
4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               false,
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               AppIdToMessageCountMap()));
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
488c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid GCMStoreImpl::Backend::SetLastCheckinTime(
489c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const base::Time& last_checkin_time,
490c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const UpdateCallback& callback) {
491c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::WriteOptions write_options;
492c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  write_options.sync = true;
493c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
494c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int64 last_checkin_time_internal = last_checkin_time.ToInternalValue();
495c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const leveldb::Status s =
496c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      db_->Put(write_options,
497c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch               MakeSlice(kLastCheckinTimeKey),
498c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch               MakeSlice(base::Int64ToString(last_checkin_time_internal)));
499c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
500c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!s.ok())
501c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LOG(ERROR) << "LevelDB set last checkin time failed: " << s.ToString();
502a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
503a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
504a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
505a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid GCMStoreImpl::Backend::SetGServicesSettings(
506a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::map<std::string, std::string>& settings,
507a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::string& settings_digest,
508a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const UpdateCallback& callback) {
509a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::WriteBatch write_batch;
510a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
511a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Remove all existing settings.
512a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::ReadOptions read_options;
513a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  read_options.verify_checksums = true;
514a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
515a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  for (iter->Seek(MakeSlice(kGServiceSettingKeyStart));
516a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Valid() && iter->key().ToString() < kGServiceSettingKeyEnd;
517a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Next()) {
518a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    write_batch.Delete(iter->key());
519a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
520a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
521a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Add the new settings.
522a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  for (std::map<std::string, std::string>::const_iterator iter =
523a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch           settings.begin();
524a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter != settings.end(); ++iter) {
525a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    write_batch.Put(MakeSlice(MakeGServiceSettingKey(iter->first)),
526a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                    MakeSlice(iter->second));
527a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
528a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
529a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Update the settings digest.
530a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  write_batch.Put(MakeSlice(kGServiceSettingsDigestKey),
531a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                  MakeSlice(settings_digest));
532a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
533a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Write it all in a batch.
534a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::WriteOptions write_options;
535a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  write_options.sync = true;
536c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
537a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::Status s = db_->Write(write_options, &write_batch);
538a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!s.ok())
539a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    LOG(ERROR) << "LevelDB GService Settings update failed: " << s.ToString();
540c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
541c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
542c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id,
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                  uint64* security_token) {
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string result;
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s = db_->Get(read_options, MakeSlice(kDeviceAIDKey), &result);
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToUint64(result, android_id)) {
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to restore device id.";
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.clear();
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Get(read_options, MakeSlice(kDeviceTokenKey), &result);
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string decrypted_token;
560cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    encryptor_->DecryptString(result, &decrypted_token);
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToUint64(decrypted_token, security_token)) {
5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to restore security token.";
5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.IsNotFound()) {
5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "No credentials found.";
5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Error reading credentials from store.";
5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
577effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool GCMStoreImpl::Backend::LoadRegistrations(
578effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    RegistrationInfoMap* registrations) {
579effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::ReadOptions read_options;
580effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  read_options.verify_checksums = true;
581effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
582effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
583effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (iter->Seek(MakeSlice(kRegistrationKeyStart));
584effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       iter->Valid() && iter->key().ToString() < kRegistrationKeyEnd;
585effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       iter->Next()) {
586effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    leveldb::Slice s = iter->value();
587effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (s.size() <= 1) {
588effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LOG(ERROR) << "Error reading registration with key " << s.ToString();
589effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return false;
590effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
591effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::string app_id = ParseRegistrationKey(iter->key().ToString());
592effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    linked_ptr<RegistrationInfo> registration(new RegistrationInfo);
593effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (!registration->ParseFromString(iter->value().ToString())) {
594effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LOG(ERROR) << "Failed to parse registration with app id " << app_id;
595effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return false;
596effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
597effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DVLOG(1) << "Found registration with app id " << app_id;
598effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    (*registrations)[app_id] = registration;
599effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
600effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
601effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return true;
602effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
603effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
6045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadIncomingMessages(
6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<std::string>* incoming_messages) {
6065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
6085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
6105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (iter->Seek(MakeSlice(kIncomingMsgKeyStart));
6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Valid() && iter->key().ToString() < kIncomingMsgKeyEnd;
6125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Next()) {
6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    leveldb::Slice s = iter->value();
6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (s.empty()) {
6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading incoming message with key "
6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << iter->key().ToString();
6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Found incoming message with id " << s.ToString();
6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    incoming_messages->push_back(s.ToString());
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadOutgoingMessages(
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OutgoingMessageMap* outgoing_messages) {
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
6325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (iter->Seek(MakeSlice(kOutgoingMsgKeyStart));
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Valid() && iter->key().ToString() < kOutgoingMsgKeyEnd;
6345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Next()) {
6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    leveldb::Slice s = iter->value();
6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (s.size() <= 1) {
6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading incoming message with key " << s.ToString();
6385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint8 tag = iter->value().data()[0];
6415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string id = ParseOutgoingKey(iter->key().ToString());
6425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<google::protobuf::MessageLite> message(
6435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BuildProtobufFromTag(tag));
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!message.get() ||
6455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        !message->ParseFromString(iter->value().ToString().substr(1))) {
6465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to parse outgoing message with id " << id
6475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << " and tag " << tag;
6485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Found outgoing message with id " << id << " of type "
6515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << base::IntToString(tag);
6525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*outgoing_messages)[id] = make_linked_ptr(message.release());
6535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
6565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
658c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool GCMStoreImpl::Backend::LoadLastCheckinTime(
659c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    base::Time* last_checkin_time) {
660c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::ReadOptions read_options;
661c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  read_options.verify_checksums = true;
662c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
663c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::string result;
664c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::Status s = db_->Get(read_options,
665c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                               MakeSlice(kLastCheckinTimeKey),
666c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                               &result);
667c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int64 time_internal = 0LL;
668c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (s.ok() && !base::StringToInt64(result, &time_internal))
669c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LOG(ERROR) << "Failed to restore last checkin time. Using default = 0.";
670c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
671c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // In case we cannot read last checkin time, we default it to 0, as we don't
672c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // want that situation to cause the whole load to fail.
673c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  *last_checkin_time = base::Time::FromInternalValue(time_internal);
674c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
675c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return true;
676c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
677c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
678a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool GCMStoreImpl::Backend::LoadGServicesSettings(
679a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::map<std::string, std::string>* settings,
680a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::string* digest) {
681a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::ReadOptions read_options;
682a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  read_options.verify_checksums = true;
683a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
684a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Load all of the GServices settings.
685a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
686a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  for (iter->Seek(MakeSlice(kGServiceSettingKeyStart));
687a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Valid() && iter->key().ToString() < kGServiceSettingKeyEnd;
688a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Next()) {
689a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::string value = iter->value().ToString();
690a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    if (value.empty()) {
691a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      LOG(ERROR) << "Error reading GService Settings " << value;
692a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      return false;
693a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    }
694a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::string id = ParseGServiceSettingKey(iter->key().ToString());
695a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    (*settings)[id] = value;
696a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    DVLOG(1) << "Found G Service setting with key: " << id
697a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch             << ", and value: " << value;
698a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
699a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
700a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Load the settings digest. It's ok if it is empty.
701a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  db_->Get(read_options, MakeSlice(kGServiceSettingsDigestKey), digest);
702a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
703a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return true;
704a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
705a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
7065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::GCMStoreImpl(
7075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path,
708cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
709cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_ptr<Encryptor> encryptor)
710cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : backend_(new Backend(path,
711cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           base::MessageLoopProxy::current(),
712cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           encryptor.Pass())),
7135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blocking_task_runner_(blocking_task_runner),
7145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_ptr_factory_(this) {
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::~GCMStoreImpl() {}
7185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Load(const LoadCallback& callback) {
7205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Load,
7235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::LoadContinuation,
7255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
7265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
729a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMStoreImpl::Close() {
730f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
731f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  app_message_counts_.clear();
732a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  blocking_task_runner_->PostTask(
733a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
734a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Close, backend_));
735a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
736a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Destroy(const UpdateCallback& callback) {
7385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Destroy, backend_, callback));
7415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::SetDeviceCredentials(uint64 device_android_id,
7445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        uint64 device_security_token,
7455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        const UpdateCallback& callback) {
7465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::SetDeviceCredentials,
7495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 device_android_id,
7515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 device_security_token,
7525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
755effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::AddRegistration(
756effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& app_id,
757effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const linked_ptr<RegistrationInfo>& registration,
758effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const UpdateCallback& callback) {
759effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  blocking_task_runner_->PostTask(
760effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
761effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&GCMStoreImpl::Backend::AddRegistration,
762effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 backend_,
763effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 app_id,
764effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 registration,
765effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 callback));
766effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
767effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
768effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::RemoveRegistration(const std::string& app_id,
769effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          const UpdateCallback& callback) {
770effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  blocking_task_runner_->PostTask(
771effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
772effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&GCMStoreImpl::Backend::RemoveRegistration,
773effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 backend_,
774effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 app_id,
775effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 callback));
776effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
777effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::AddIncomingMessage(const std::string& persistent_id,
7795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const UpdateCallback& callback) {
7805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
7815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
7825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::AddIncomingMessage,
7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
7845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_id,
7855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveIncomingMessage(const std::string& persistent_id,
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)                 PersistentIdList(1, persistent_id),
7955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
7965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveIncomingMessages(
7995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
8005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
8015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
8035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveIncomingMessages,
8045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
8055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_ids,
8065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
8075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::AddOutgoingMessage(const std::string& persistent_id,
8105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const MCSMessage& message,
8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const UpdateCallback& callback) {
8125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(message.tag(), kDataMessageStanzaTag);
8135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = reinterpret_cast<const mcs_proto::DataMessageStanza*>(
8145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &message.GetProtobuf())->category();
8155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!app_id.empty());
8165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_message_counts_.count(app_id) == 0)
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id] = 0;
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_message_counts_[app_id] < kMessagesPerAppLimit) {
8195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id]++;
8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    blocking_task_runner_->PostTask(
8225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&GCMStoreImpl::Backend::AddOutgoingMessage,
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   backend_,
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   persistent_id,
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   message,
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   base::Bind(&GCMStoreImpl::AddOutgoingMessageContinuation,
8285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              weak_ptr_factory_.GetWeakPtr(),
8295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              callback,
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              app_id)));
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
8345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::OverwriteOutgoingMessage(const std::string& persistent_id,
8375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const MCSMessage& message,
8385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const UpdateCallback& callback) {
8395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(message.tag(), kDataMessageStanzaTag);
8405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = reinterpret_cast<const mcs_proto::DataMessageStanza*>(
8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &message.GetProtobuf())->category();
8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!app_id.empty());
8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There should already be pending messages for this app.
8445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(app_message_counts_.count(app_id));
8455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(zea): consider verifying the specific message already exists.
8465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
8475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
8485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::AddOutgoingMessage,
8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
8505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_id,
8515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 message,
8525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
8535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessage(const std::string& persistent_id,
8565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         const UpdateCallback& callback) {
8575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
8585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
8595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveOutgoingMessages,
8605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
8615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 PersistentIdList(1, persistent_id),
8625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation,
8635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
8645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
8655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessages(
8685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
8695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
8705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
8715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
8725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveOutgoingMessages,
8735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
8745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_ids,
8755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::RemoveOutgoingMessagesContinuation,
8765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
8775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
8785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
880c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid GCMStoreImpl::SetLastCheckinTime(const base::Time& last_checkin_time,
881c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      const UpdateCallback& callback) {
882c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  blocking_task_runner_->PostTask(
883c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      FROM_HERE,
884c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Bind(&GCMStoreImpl::Backend::SetLastCheckinTime,
885c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 backend_,
886c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 last_checkin_time,
887c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 callback));
888c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
889c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
890a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid GCMStoreImpl::SetGServicesSettings(
891a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::map<std::string, std::string>& settings,
892a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::string& digest,
893a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const UpdateCallback& callback) {
894a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  blocking_task_runner_->PostTask(
895a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      FROM_HERE,
896a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      base::Bind(&GCMStoreImpl::Backend::SetGServicesSettings,
897a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                 backend_,
898a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                 settings,
899a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                 digest,
900a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                 callback));
901a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
902a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
9035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::LoadContinuation(const LoadCallback& callback,
9045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    scoped_ptr<LoadResult> result) {
9055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!result->success) {
9065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(result.Pass());
9075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
9085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int num_throttled_apps = 0;
9105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (OutgoingMessageMap::const_iterator
9115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           iter = result->outgoing_messages.begin();
9125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != result->outgoing_messages.end(); ++iter) {
9135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const mcs_proto::DataMessageStanza* data_message =
9145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        reinterpret_cast<mcs_proto::DataMessageStanza*>(iter->second.get());
9155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(!data_message->category().empty());
9165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (app_message_counts_.count(data_message->category()) == 0)
9175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_message_counts_[data_message->category()] = 1;
9185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else
9195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_message_counts_[data_message->category()]++;
9205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (app_message_counts_[data_message->category()] == kMessagesPerAppLimit)
9215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      num_throttled_apps++;
9225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("GCM.NumThrottledApps", num_throttled_apps);
9245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(result.Pass());
9255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::AddOutgoingMessageContinuation(
9285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback,
9295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& app_id,
9305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success) {
9315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!success) {
9325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(app_message_counts_[app_id] > 0);
9335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id]--;
9345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(success);
9365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveOutgoingMessagesContinuation(
9395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback,
9405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success,
9415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const AppIdToMessageCountMap& removed_message_counts) {
9425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!success) {
9435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(false);
9445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
9455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (AppIdToMessageCountMap::const_iterator iter =
9475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           removed_message_counts.begin();
9485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != removed_message_counts.end(); ++iter) {
9495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_NE(app_message_counts_.count(iter->first), 0U);
9505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[iter->first] -= iter->second;
9515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_GE(app_message_counts_[iter->first], 0);
9525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(true);
9545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace gcm
957