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/files/file_path.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.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"
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/string_tokenizer.h"
20a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/time/time.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/tracked_objects.h"
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "google_apis/gcm/base/encryptor.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/base/mcs_message.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/base/mcs_util.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/protocol/mcs.pb.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/db.h"
27a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace gcm {
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Limit to the number of outstanding messages per app.
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kMessagesPerAppLimit = 20;
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// ---- LevelDB keys. ----
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key for this device's android id.
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeviceAIDKey[] = "device_aid_key";
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key for this device's android security token.
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeviceTokenKey[] = "device_token_key";
41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Lowest lexicographically ordered app ids.
42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Used for prefixing app id.
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char kRegistrationKeyStart[] = "reg1-";
44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Key guaranteed to be higher than all app ids.
45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Used for limiting iteration.
46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char kRegistrationKeyEnd[] = "reg2-";
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Lowest lexicographically ordered incoming message key.
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for prefixing messages.
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kIncomingMsgKeyStart[] = "incoming1-";
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key guaranteed to be higher than all incoming message keys.
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for limiting iteration.
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kIncomingMsgKeyEnd[] = "incoming2-";
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Lowest lexicographically ordered outgoing message key.
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for prefixing outgoing messages.
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kOutgoingMsgKeyStart[] = "outgoing1-";
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Key guaranteed to be higher than all outgoing message keys.
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Used for limiting iteration.
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kOutgoingMsgKeyEnd[] = "outgoing2-";
59a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Lowest lexicographically ordered G-service settings key.
60a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Used for prefixing G-services settings.
61a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst char kGServiceSettingKeyStart[] = "gservice1-";
62a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Key guaranteed to be higher than all G-services settings keys.
63a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Used for limiting iteration.
64a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst char kGServiceSettingKeyEnd[] = "gservice2-";
65a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Key for digest of the last G-services settings update.
66a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst char kGServiceSettingsDigestKey[] = "gservices_digest";
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Key used to indicate how many accounts were last checked in with this device.
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst char kLastCheckinAccountsKey[] = "last_checkin_accounts_count";
69c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Key used to timestamp last checkin (marked with G services settings update).
70c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kLastCheckinTimeKey[] = "last_checkin_time";
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Lowest lexicographically ordered account key.
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Used for prefixing account information.
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const char kAccountKeyStart[] = "account1-";
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Key guaranteed to be higher than all account keys.
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Used for limiting iteration.
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const char kAccountKeyEnd[] = "account2-";
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string MakeRegistrationKey(const std::string& app_id) {
79effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return kRegistrationKeyStart + app_id;
80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
82effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string ParseRegistrationKey(const std::string& key) {
83effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return key.substr(arraysize(kRegistrationKeyStart) - 1);
84effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string MakeIncomingKey(const std::string& persistent_id) {
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return kIncomingMsgKeyStart + persistent_id;
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string MakeOutgoingKey(const std::string& persistent_id) {
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return kOutgoingMsgKeyStart + persistent_id;
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string ParseOutgoingKey(const std::string& key) {
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return key.substr(arraysize(kOutgoingMsgKeyStart) - 1);
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
98a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochstd::string MakeGServiceSettingKey(const std::string& setting_name) {
99a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return kGServiceSettingKeyStart + setting_name;
100a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
101a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
102a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochstd::string ParseGServiceSettingKey(const std::string& key) {
103a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return key.substr(arraysize(kGServiceSettingKeyStart) - 1);
104a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
105a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)std::string MakeAccountKey(const std::string& account_id) {
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return kAccountKeyStart + account_id;
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)std::string ParseAccountKey(const std::string& key) {
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return key.substr(arraysize(kAccountKeyStart) - 1);
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Note: leveldb::Slice keeps a pointer to the data in |s|, which must therefore
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// outlive the slice.
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// For example: MakeSlice(MakeOutgoingKey(x)) is invalid.
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)leveldb::Slice MakeSlice(const base::StringPiece& s) {
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return leveldb::Slice(s.begin(), s.size());
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class GCMStoreImpl::Backend
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : public base::RefCountedThreadSafe<GCMStoreImpl::Backend> {
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Backend(const base::FilePath& path,
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          scoped_refptr<base::SequencedTaskRunner> foreground_runner,
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          scoped_ptr<Encryptor> encryptor);
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Blocking implementations of GCMStoreImpl methods.
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Load(const LoadCallback& callback);
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void Close();
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Destroy(const UpdateCallback& callback);
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void SetDeviceCredentials(uint64 device_android_id,
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            uint64 device_security_token,
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const UpdateCallback& callback);
137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void AddRegistration(const std::string& app_id,
138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                       const linked_ptr<RegistrationInfo>& registration,
139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                       const UpdateCallback& callback);
140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void RemoveRegistration(const std::string& app_id,
141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                          const UpdateCallback& callback);
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddIncomingMessage(const std::string& persistent_id,
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const UpdateCallback& callback);
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveIncomingMessages(const PersistentIdList& persistent_ids,
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const UpdateCallback& callback);
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddOutgoingMessage(const std::string& persistent_id,
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const MCSMessage& message,
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const UpdateCallback& callback);
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveOutgoingMessages(
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const PersistentIdList& persistent_ids,
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::Callback<void(bool, const AppIdToMessageCountMap&)>
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          callback);
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddUserSerialNumber(const std::string& username,
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           int64 serial_number,
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           const UpdateCallback& callback);
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveUserSerialNumber(const std::string& username,
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const UpdateCallback& callback);
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  void SetLastCheckinInfo(const base::Time& time,
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          const std::set<std::string>& accounts,
160c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                          const UpdateCallback& callback);
161a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  void SetGServicesSettings(
162a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const std::map<std::string, std::string>& settings,
163a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const std::string& digest,
164a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const UpdateCallback& callback);
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void AddAccountMapping(const AccountMapping& account_mapping,
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         const UpdateCallback& callback);
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void RemoveAccountMapping(const std::string& account_id,
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            const UpdateCallback& callback);
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Backend>;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~Backend();
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadDeviceCredentials(uint64* android_id, uint64* security_token);
175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  bool LoadRegistrations(RegistrationInfoMap* registrations);
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadIncomingMessages(std::vector<std::string>* incoming_messages);
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages);
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool LoadLastCheckinInfo(base::Time* last_checkin_time,
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           std::set<std::string>* accounts);
180a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  bool LoadGServicesSettings(std::map<std::string, std::string>* settings,
181a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                             std::string* digest);
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool LoadAccountMappingInfo(AccountMappings* account_mappings);
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::FilePath path_;
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<Encryptor> encryptor_;
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::DB> db_;
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::Backend::Backend(
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path,
193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> foreground_task_runner,
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_ptr<Encryptor> encryptor)
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : path_(path),
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      foreground_task_runner_(foreground_task_runner),
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      encryptor_(encryptor.Pass()) {
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::Backend::~Backend() {}
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::Load(const LoadCallback& callback) {
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<LoadResult> result(new LoadResult());
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (db_.get()) {
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Attempting to reload open database.";
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Options options;
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  options.create_if_missing = true;
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::DB* db;
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status status =
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db);
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("GCM.LoadSucceeded", status.ok());
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!status.ok()) {
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Failed to open database " << path_.value() << ": "
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << status.ToString();
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  db_.reset(db);
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!LoadDeviceCredentials(&result->device_android_id,
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             &result->device_security_token) ||
230effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      !LoadRegistrations(&result->registrations) ||
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !LoadIncomingMessages(&result->incoming_messages) ||
232c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      !LoadOutgoingMessages(&result->outgoing_messages) ||
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      !LoadLastCheckinInfo(&result->last_checkin_time,
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           &result->last_checkin_accounts) ||
235a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      !LoadGServicesSettings(&result->gservices_settings,
2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                             &result->gservices_digest) ||
2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      !LoadAccountMappingInfo(&result->account_mappings)) {
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    result->Reset();
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 base::Passed(&result)));
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Only record histograms if GCM had already been set up for this device.
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result->device_android_id != 0 && result->device_security_token != 0) {
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64 file_size = 0;
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (base::GetFileSize(path_, &file_size)) {
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      UMA_HISTOGRAM_COUNTS("GCM.StoreSizeKB",
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           static_cast<int>(file_size / 1024));
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
252effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    UMA_HISTOGRAM_COUNTS("GCM.RestoredRegistrations",
253effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         result->registrations.size());
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.RestoredOutgoingMessages",
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         result->outgoing_messages.size());
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.RestoredIncomingMessages",
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         result->incoming_messages.size());
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
260effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DVLOG(1) << "Succeeded in loading " << result->registrations.size()
261effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           << " registrations, "
262effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           << result->incoming_messages.size()
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << " unacknowledged incoming messages and "
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << result->outgoing_messages.size()
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << " unacknowledged outgoing messages.";
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->success = true;
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE,
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::Bind(callback,
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               base::Passed(&result)));
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return;
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMStoreImpl::Backend::Close() {
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DVLOG(1) << "Closing GCM store.";
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  db_.reset();
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::Destroy(const UpdateCallback& callback) {
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Destroying GCM store.";
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  db_.reset();
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s =
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      leveldb::DestroyDB(path_.AsUTF8Unsafe(), leveldb::Options());
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Destroy failed: " << s.ToString();
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::SetDeviceCredentials(
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 device_android_id,
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 device_security_token,
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving device credentials with AID " << device_android_id;
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string encrypted_token;
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  encryptor_->EncryptString(base::Uint64ToString(device_security_token),
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            &encrypted_token);
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string android_id_str = base::Uint64ToString(device_android_id);
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s =
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      db_->Put(write_options,
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(kDeviceAIDKey),
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               MakeSlice(android_id_str));
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Put(
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        write_options, MakeSlice(kDeviceTokenKey), MakeSlice(encrypted_token));
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::Backend::AddRegistration(
326effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& app_id,
327effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const linked_ptr<RegistrationInfo>& registration,
328effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const UpdateCallback& callback) {
329effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DVLOG(1) << "Saving registration info for app: " << app_id;
330effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!db_.get()) {
331effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LOG(ERROR) << "GCMStore db doesn't exist.";
332effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
333effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
334effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
335effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::WriteOptions write_options;
336effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  write_options.sync = true;
337effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
338effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string key = MakeRegistrationKey(app_id);
339effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string value = registration->SerializeAsString();
340effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const leveldb::Status status = db_->Put(write_options,
341effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          MakeSlice(key),
342effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          MakeSlice(value));
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 put failed: " << status.ToString();
348effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
349effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
350effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
351effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::Backend::RemoveRegistration(const std::string& app_id,
352effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                               const UpdateCallback& callback) {
353effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!db_.get()) {
354effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LOG(ERROR) << "GCMStore db doesn't exist.";
355effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
356effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
357effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
358effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::WriteOptions write_options;
359effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  write_options.sync = true;
360effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
3616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  leveldb::Status status =
3626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      db_->Delete(write_options, MakeSlice(MakeRegistrationKey(app_id)));
363effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (status.ok()) {
364effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
365effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
366effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
367effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  LOG(ERROR) << "LevelDB remove failed: " << status.ToString();
368effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
369effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
370effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::AddIncomingMessage(const std::string& persistent_id,
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const UpdateCallback& callback) {
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving incoming message with id " << persistent_id;
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key = MakeIncomingKey(persistent_id);
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s = db_->Put(write_options,
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(key),
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(persistent_id));
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::RemoveIncomingMessages(
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s;
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (PersistentIdList::const_iterator iter = persistent_ids.begin();
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != persistent_ids.end();
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing incoming message with id " << *iter;
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string key = MakeIncomingKey(*iter);
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Delete(write_options, MakeSlice(key));
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::AddOutgoingMessage(const std::string& persistent_id,
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const MCSMessage& message,
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const UpdateCallback& callback) {
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Saving outgoing message with id " << persistent_id;
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string data =
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<char>(message.tag()) + message.SerializeAsString();
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string key = MakeOutgoingKey(persistent_id);
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Status s = db_->Put(write_options,
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(key),
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     MakeSlice(data));
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB put failed: " << s.ToString();
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Backend::RemoveOutgoingMessages(
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Callback<void(bool, const AppIdToMessageCountMap&)>
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        callback) {
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!db_.get()) {
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 false,
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 AppIdToMessageCountMap()));
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::WriteOptions write_options;
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  write_options.sync = true;
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AppIdToMessageCountMap removed_message_counts;
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s;
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (PersistentIdList::const_iterator iter = persistent_ids.begin();
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != persistent_ids.end();
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing outgoing message with id " << *iter;
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string outgoing_message;
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string key = MakeOutgoingKey(*iter);
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Get(read_options,
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 MakeSlice(key),
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 &outgoing_message);
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mcs_proto::DataMessageStanza data_message;
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Skip the initial tag byte and parse the rest to extract the message.
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (data_message.ParseFromString(outgoing_message.substr(1))) {
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(!data_message.category().empty());
4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (removed_message_counts.count(data_message.category()) != 0)
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        removed_message_counts[data_message.category()]++;
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      else
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        removed_message_counts[data_message.category()] = 1;
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Removing outgoing message with id " << *iter;
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Delete(write_options, MakeSlice(key));
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!s.ok())
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE,
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::Bind(callback,
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 true,
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 removed_message_counts));
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE,
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::Bind(callback,
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               false,
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               AppIdToMessageCountMap()));
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
508116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid GCMStoreImpl::Backend::SetLastCheckinInfo(
509116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::Time& time,
510116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::set<std::string>& accounts,
511c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const UpdateCallback& callback) {
512116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  leveldb::WriteBatch write_batch;
513116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
514116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int64 last_checkin_time_internal = time.ToInternalValue();
515116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  write_batch.Put(MakeSlice(kLastCheckinTimeKey),
516116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                  MakeSlice(base::Int64ToString(last_checkin_time_internal)));
517116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
518116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string serialized_accounts;
519116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (std::set<std::string>::iterator iter = accounts.begin();
520116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != accounts.end();
521116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++iter) {
522116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    serialized_accounts += *iter;
523116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    serialized_accounts += ",";
524116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
525116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!serialized_accounts.empty())
526116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    serialized_accounts.erase(serialized_accounts.length() - 1);
527116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
528116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  write_batch.Put(MakeSlice(kLastCheckinAccountsKey),
529116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                  MakeSlice(serialized_accounts));
530116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
531c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::WriteOptions write_options;
532c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  write_options.sync = true;
533116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const leveldb::Status s = db_->Write(write_options, &write_batch);
534c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
535c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!s.ok())
536116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG(ERROR) << "LevelDB set last checkin info failed: " << s.ToString();
537a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
538a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
539a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
540a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid GCMStoreImpl::Backend::SetGServicesSettings(
541a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::map<std::string, std::string>& settings,
542a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::string& settings_digest,
543a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const UpdateCallback& callback) {
544a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::WriteBatch write_batch;
545a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
546a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Remove all existing settings.
547a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::ReadOptions read_options;
548a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  read_options.verify_checksums = true;
549a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
550a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  for (iter->Seek(MakeSlice(kGServiceSettingKeyStart));
551a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Valid() && iter->key().ToString() < kGServiceSettingKeyEnd;
552a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Next()) {
553a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    write_batch.Delete(iter->key());
554a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
555a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
556a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Add the new settings.
557a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  for (std::map<std::string, std::string>::const_iterator iter =
558a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch           settings.begin();
559a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter != settings.end(); ++iter) {
560a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    write_batch.Put(MakeSlice(MakeGServiceSettingKey(iter->first)),
561a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                    MakeSlice(iter->second));
562a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
563a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
564a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Update the settings digest.
565a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  write_batch.Put(MakeSlice(kGServiceSettingsDigestKey),
566a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                  MakeSlice(settings_digest));
567a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
568a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Write it all in a batch.
569a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::WriteOptions write_options;
570a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  write_options.sync = true;
571c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
572a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::Status s = db_->Write(write_options, &write_batch);
573a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!s.ok())
574a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    LOG(ERROR) << "LevelDB GService Settings update failed: " << s.ToString();
575c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
576c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
577c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
5785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void GCMStoreImpl::Backend::AddAccountMapping(
5795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const AccountMapping& account_mapping,
5805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const UpdateCallback& callback) {
5815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DVLOG(1) << "Saving account info for account with email: "
5825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           << account_mapping.email;
5835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!db_.get()) {
5845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
5855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
5865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
5875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
5885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  leveldb::WriteOptions write_options;
5905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  write_options.sync = true;
5915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string data = account_mapping.SerializeAsString();
5935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string key = MakeAccountKey(account_mapping.account_id);
5945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const leveldb::Status s =
5955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      db_->Put(write_options, MakeSlice(key), MakeSlice(data));
5965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!s.ok())
5975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "LevelDB adding account mapping failed: " << s.ToString();
5985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
5995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
6005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void GCMStoreImpl::Backend::RemoveAccountMapping(
6025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& account_id,
6035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const UpdateCallback& callback) {
6045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!db_.get()) {
6055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "GCMStore db doesn't exist.";
6065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
6075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
6085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  leveldb::WriteOptions write_options;
6115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  write_options.sync = true;
6125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  leveldb::Status s =
6145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      db_->Delete(write_options, MakeSlice(MakeAccountKey(account_id)));
6155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!s.ok())
6175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "LevelDB removal of account mapping failed: " << s.ToString();
6185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, s.ok()));
6195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
6205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id,
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                  uint64* security_token) {
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string result;
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::Status s = db_->Get(read_options, MakeSlice(kDeviceAIDKey), &result);
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToUint64(result, android_id)) {
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to restore device id.";
6315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
6325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.clear();
6345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    s = db_->Get(read_options, MakeSlice(kDeviceTokenKey), &result);
6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.ok()) {
6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string decrypted_token;
638cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    encryptor_->DecryptString(result, &decrypted_token);
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::StringToUint64(decrypted_token, security_token)) {
6405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to restore security token.";
6415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
6425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (s.IsNotFound()) {
6475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "No credentials found.";
6485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(ERROR) << "Error reading credentials from store.";
6525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
6535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool GCMStoreImpl::Backend::LoadRegistrations(
656effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    RegistrationInfoMap* registrations) {
657effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  leveldb::ReadOptions read_options;
658effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  read_options.verify_checksums = true;
659effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
660effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
661effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (iter->Seek(MakeSlice(kRegistrationKeyStart));
662effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       iter->Valid() && iter->key().ToString() < kRegistrationKeyEnd;
663effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       iter->Next()) {
664effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    leveldb::Slice s = iter->value();
665effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (s.size() <= 1) {
666effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LOG(ERROR) << "Error reading registration with key " << s.ToString();
667effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return false;
668effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
669effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::string app_id = ParseRegistrationKey(iter->key().ToString());
670effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    linked_ptr<RegistrationInfo> registration(new RegistrationInfo);
671effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (!registration->ParseFromString(iter->value().ToString())) {
672effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LOG(ERROR) << "Failed to parse registration with app id " << app_id;
673effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return false;
674effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
675effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DVLOG(1) << "Found registration with app id " << app_id;
676effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    (*registrations)[app_id] = registration;
677effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
678effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
679effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return true;
680effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
681effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
6825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadIncomingMessages(
6835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<std::string>* incoming_messages) {
6845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
6855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
6865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
6885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (iter->Seek(MakeSlice(kIncomingMsgKeyStart));
6895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Valid() && iter->key().ToString() < kIncomingMsgKeyEnd;
6905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Next()) {
6915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    leveldb::Slice s = iter->value();
6925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (s.empty()) {
6935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading incoming message with key "
6945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << iter->key().ToString();
6955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
6965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Found incoming message with id " << s.ToString();
6985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    incoming_messages->push_back(s.ToString());
6995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
7025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::Backend::LoadOutgoingMessages(
7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OutgoingMessageMap* outgoing_messages) {
7065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  leveldb::ReadOptions read_options;
7075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_options.verify_checksums = true;
7085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
7105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (iter->Seek(MakeSlice(kOutgoingMsgKeyStart));
7115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Valid() && iter->key().ToString() < kOutgoingMsgKeyEnd;
7125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter->Next()) {
7135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    leveldb::Slice s = iter->value();
7145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (s.size() <= 1) {
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Error reading incoming message with key " << s.ToString();
7165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
7185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint8 tag = iter->value().data()[0];
7195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string id = ParseOutgoingKey(iter->key().ToString());
7205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<google::protobuf::MessageLite> message(
7215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BuildProtobufFromTag(tag));
7225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!message.get() ||
7235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        !message->ParseFromString(iter->value().ToString().substr(1))) {
7245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Failed to parse outgoing message with id " << id
7255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << " and tag " << tag;
7265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Found outgoing message with id " << id << " of type "
7295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << base::IntToString(tag);
7305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*outgoing_messages)[id] = make_linked_ptr(message.release());
7315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
7345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
736116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool GCMStoreImpl::Backend::LoadLastCheckinInfo(
737116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    base::Time* last_checkin_time,
738116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    std::set<std::string>* accounts) {
739c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::ReadOptions read_options;
740c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  read_options.verify_checksums = true;
741c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
742c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::string result;
743c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  leveldb::Status s = db_->Get(read_options,
744c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                               MakeSlice(kLastCheckinTimeKey),
745c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                               &result);
746c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int64 time_internal = 0LL;
747c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (s.ok() && !base::StringToInt64(result, &time_internal))
748c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LOG(ERROR) << "Failed to restore last checkin time. Using default = 0.";
749c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
750c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // In case we cannot read last checkin time, we default it to 0, as we don't
751c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // want that situation to cause the whole load to fail.
752c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  *last_checkin_time = base::Time::FromInternalValue(time_internal);
753c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
754116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  accounts->clear();
755116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  s = db_->Get(read_options, MakeSlice(kLastCheckinAccountsKey), &result);
756116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!s.ok())
757116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DVLOG(1) << "No accounts where stored during last run.";
758116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
759116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::StringTokenizer t(result, ",");
760116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  while (t.GetNext())
761116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    accounts->insert(t.token());
762116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
763c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return true;
764c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
765c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
766a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool GCMStoreImpl::Backend::LoadGServicesSettings(
767a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::map<std::string, std::string>* settings,
768a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::string* digest) {
769a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  leveldb::ReadOptions read_options;
770a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  read_options.verify_checksums = true;
771a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
772a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Load all of the GServices settings.
773a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
774a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  for (iter->Seek(MakeSlice(kGServiceSettingKeyStart));
775a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Valid() && iter->key().ToString() < kGServiceSettingKeyEnd;
776a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       iter->Next()) {
777a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::string value = iter->value().ToString();
778a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    if (value.empty()) {
779a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      LOG(ERROR) << "Error reading GService Settings " << value;
780a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      return false;
781a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    }
782a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::string id = ParseGServiceSettingKey(iter->key().ToString());
783a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    (*settings)[id] = value;
784a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    DVLOG(1) << "Found G Service setting with key: " << id
785a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch             << ", and value: " << value;
786a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
787a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
788a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Load the settings digest. It's ok if it is empty.
789a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  db_->Get(read_options, MakeSlice(kGServiceSettingsDigestKey), digest);
790a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
791a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return true;
792a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
793a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
7945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool GCMStoreImpl::Backend::LoadAccountMappingInfo(
7951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    AccountMappings* account_mappings) {
7965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  leveldb::ReadOptions read_options;
7975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  read_options.verify_checksums = true;
7985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options));
8005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (iter->Seek(MakeSlice(kAccountKeyStart));
8015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       iter->Valid() && iter->key().ToString() < kAccountKeyEnd;
8025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       iter->Next()) {
8035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    AccountMapping account_mapping;
8045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    account_mapping.account_id = ParseAccountKey(iter->key().ToString());
8055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!account_mapping.ParseFromString(iter->value().ToString())) {
8065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      DVLOG(1) << "Failed to parse account info with ID: "
8075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)               << account_mapping.account_id;
8085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
8095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
8105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DVLOG(1) << "Found account mapping with ID: " << account_mapping.account_id;
8111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    account_mappings->push_back(account_mapping);
8125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
8135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
8155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
8165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::GCMStoreImpl(
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path,
819cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
820cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_ptr<Encryptor> encryptor)
821cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : backend_(new Backend(path,
822cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           base::MessageLoopProxy::current(),
823cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           encryptor.Pass())),
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blocking_task_runner_(blocking_task_runner),
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_ptr_factory_(this) {
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GCMStoreImpl::~GCMStoreImpl() {}
8295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Load(const LoadCallback& callback) {
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Load,
8345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
8355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&GCMStoreImpl::LoadContinuation,
8365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
8375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            callback)));
8385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
840a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMStoreImpl::Close() {
841f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
842f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  app_message_counts_.clear();
843a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  blocking_task_runner_->PostTask(
844a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
845a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Close, backend_));
846a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
847a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
8485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::Destroy(const UpdateCallback& callback) {
8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
8505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
8515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::Destroy, backend_, callback));
8525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::SetDeviceCredentials(uint64 device_android_id,
8555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        uint64 device_security_token,
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::SetDeviceCredentials,
8605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
8615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 device_android_id,
8625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 device_security_token,
8635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
8645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
866effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::AddRegistration(
867effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& app_id,
868effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const linked_ptr<RegistrationInfo>& registration,
869effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const UpdateCallback& callback) {
870effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  blocking_task_runner_->PostTask(
871effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
872effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&GCMStoreImpl::Backend::AddRegistration,
873effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 backend_,
874effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 app_id,
875effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 registration,
876effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 callback));
877effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
878effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
879effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid GCMStoreImpl::RemoveRegistration(const std::string& app_id,
880effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                          const UpdateCallback& callback) {
881effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  blocking_task_runner_->PostTask(
882effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
883effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&GCMStoreImpl::Backend::RemoveRegistration,
884effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 backend_,
885effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 app_id,
886effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 callback));
887effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
888effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
8895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::AddIncomingMessage(const std::string& persistent_id,
8905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const UpdateCallback& callback) {
8915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
8925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
8935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::AddIncomingMessage,
8945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
8955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_id,
8965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
8975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveIncomingMessage(const std::string& persistent_id,
9005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         const UpdateCallback& callback) {
9015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
9025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
9035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveIncomingMessages,
9045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
9055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 PersistentIdList(1, persistent_id),
9065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
9075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::RemoveIncomingMessages(
9105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PersistentIdList& persistent_ids,
9115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UpdateCallback& callback) {
9125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
9135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
9145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::RemoveIncomingMessages,
9155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
9165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_ids,
9175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
9185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GCMStoreImpl::AddOutgoingMessage(const std::string& persistent_id,
9215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const MCSMessage& message,
9225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const UpdateCallback& callback) {
9235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(message.tag(), kDataMessageStanzaTag);
9245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = reinterpret_cast<const mcs_proto::DataMessageStanza*>(
9255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &message.GetProtobuf())->category();
9265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!app_id.empty());
9275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_message_counts_.count(app_id) == 0)
9285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id] = 0;
9295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_message_counts_[app_id] < kMessagesPerAppLimit) {
9305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_message_counts_[app_id]++;
9315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    blocking_task_runner_->PostTask(
9335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
9345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&GCMStoreImpl::Backend::AddOutgoingMessage,
9355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   backend_,
9365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   persistent_id,
9375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   message,
9385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   base::Bind(&GCMStoreImpl::AddOutgoingMessageContinuation,
9395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              weak_ptr_factory_.GetWeakPtr(),
9405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              callback,
9415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              app_id)));
9425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
9435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
9455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GCMStoreImpl::OverwriteOutgoingMessage(const std::string& persistent_id,
9485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const MCSMessage& message,
9495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const UpdateCallback& callback) {
9505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(message.tag(), kDataMessageStanzaTag);
9515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = reinterpret_cast<const mcs_proto::DataMessageStanza*>(
9525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &message.GetProtobuf())->category();
9535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!app_id.empty());
9545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There should already be pending messages for this app.
9555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(app_message_counts_.count(app_id));
9565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(zea): consider verifying the specific message already exists.
9575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blocking_task_runner_->PostTask(
9585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
9595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&GCMStoreImpl::Backend::AddOutgoingMessage,
9605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 backend_,
9615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 persistent_id,
9625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 message,
9635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
964