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