| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync/engine/syncapi.h" | 5 #include "chrome/browser/sync/engine/syncapi.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <bitset> | 8 #include <bitset> |
| 9 #include <iomanip> | 9 #include <iomanip> |
| 10 #include <list> | 10 #include <list> |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 } | 195 } |
| 196 } | 196 } |
| 197 | 197 |
| 198 UserShare::UserShare() {} | 198 UserShare::UserShare() {} |
| 199 | 199 |
| 200 UserShare::~UserShare() {} | 200 UserShare::~UserShare() {} |
| 201 | 201 |
| 202 //////////////////////////////////// | 202 //////////////////////////////////// |
| 203 // BaseNode member definitions. | 203 // BaseNode member definitions. |
| 204 | 204 |
| 205 BaseNode::BaseNode() {} | 205 BaseNode::BaseNode() : password_data_(new sync_pb::PasswordSpecificsData) {} |
| 206 | 206 |
| 207 BaseNode::~BaseNode() {} | 207 BaseNode::~BaseNode() {} |
| 208 | 208 |
| 209 std::string BaseNode::GenerateSyncableHash( | 209 std::string BaseNode::GenerateSyncableHash( |
| 210 syncable::ModelType model_type, const std::string& client_tag) { | 210 syncable::ModelType model_type, const std::string& client_tag) { |
| 211 // blank PB with just the extension in it has termination symbol, | 211 // blank PB with just the extension in it has termination symbol, |
| 212 // handy for delimiter | 212 // handy for delimiter |
| 213 sync_pb::EntitySpecifics serialized_type; | 213 sync_pb::EntitySpecifics serialized_type; |
| 214 syncable::AddDefaultExtensionValue(model_type, &serialized_type); | 214 syncable::AddDefaultExtensionValue(model_type, &serialized_type); |
| 215 std::string hash_input; | 215 std::string hash_input; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 238 } | 238 } |
| 239 | 239 |
| 240 bool BaseNode::DecryptIfNecessary() { | 240 bool BaseNode::DecryptIfNecessary() { |
| 241 if (GetIsFolder()) return true; // Ignore the top-level datatype folder. | 241 if (GetIsFolder()) return true; // Ignore the top-level datatype folder. |
| 242 const sync_pb::EntitySpecifics& specifics = | 242 const sync_pb::EntitySpecifics& specifics = |
| 243 GetEntry()->Get(syncable::SPECIFICS); | 243 GetEntry()->Get(syncable::SPECIFICS); |
| 244 if (specifics.HasExtension(sync_pb::password)) { | 244 if (specifics.HasExtension(sync_pb::password)) { |
| 245 // Passwords have their own legacy encryption structure. | 245 // Passwords have their own legacy encryption structure. |
| 246 scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics( | 246 scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics( |
| 247 specifics, GetTransaction()->GetCryptographer())); | 247 specifics, GetTransaction()->GetCryptographer())); |
| 248 if (!data.get()) | 248 if (!data.get()) { |
| 249 LOG(ERROR) << "Failed to decrypt password specifics."; |
| 249 return false; | 250 return false; |
| 251 } |
| 250 password_data_.swap(data); | 252 password_data_.swap(data); |
| 251 return true; | 253 return true; |
| 252 } | 254 } |
| 253 | 255 |
| 254 // We assume any node with the encrypted field set has encrypted data. | 256 // We assume any node with the encrypted field set has encrypted data. |
| 255 if (!specifics.has_encrypted()) | 257 if (!specifics.has_encrypted()) |
| 256 return true; | 258 return true; |
| 257 | 259 |
| 258 const sync_pb::EncryptedData& encrypted = | 260 const sync_pb::EncryptedData& encrypted = |
| 259 specifics.encrypted(); | 261 specifics.encrypted(); |
| 260 std::string plaintext_data = GetTransaction()->GetCryptographer()-> | 262 std::string plaintext_data = GetTransaction()->GetCryptographer()-> |
| 261 DecryptToString(encrypted); | 263 DecryptToString(encrypted); |
| 262 if (plaintext_data.length() == 0) | 264 if (plaintext_data.length() == 0 || |
| 263 return false; | 265 !unencrypted_data_.ParseFromString(plaintext_data)) { |
| 264 if (!unencrypted_data_.ParseFromString(plaintext_data)) { | |
| 265 LOG(ERROR) << "Failed to decrypt encrypted node of type " << | 266 LOG(ERROR) << "Failed to decrypt encrypted node of type " << |
| 266 syncable::ModelTypeToString(GetModelType()) << "."; | 267 syncable::ModelTypeToString(GetModelType()) << "."; |
| 267 return false; | 268 return false; |
| 268 } | 269 } |
| 269 return true; | 270 return true; |
| 270 } | 271 } |
| 271 | 272 |
| 272 const sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics( | 273 const sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics( |
| 273 const syncable::Entry* entry) const { | 274 const syncable::Entry* entry) const { |
| 274 const sync_pb::EntitySpecifics& specifics = entry->Get(SPECIFICS); | 275 const sync_pb::EntitySpecifics& specifics = entry->Get(SPECIFICS); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 return GetEntitySpecifics().GetExtension(sync_pb::bookmark); | 398 return GetEntitySpecifics().GetExtension(sync_pb::bookmark); |
| 398 } | 399 } |
| 399 | 400 |
| 400 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const { | 401 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const { |
| 401 DCHECK_EQ(syncable::NIGORI, GetModelType()); | 402 DCHECK_EQ(syncable::NIGORI, GetModelType()); |
| 402 return GetEntitySpecifics().GetExtension(sync_pb::nigori); | 403 return GetEntitySpecifics().GetExtension(sync_pb::nigori); |
| 403 } | 404 } |
| 404 | 405 |
| 405 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const { | 406 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const { |
| 406 DCHECK_EQ(syncable::PASSWORDS, GetModelType()); | 407 DCHECK_EQ(syncable::PASSWORDS, GetModelType()); |
| 407 DCHECK(password_data_.get()); | |
| 408 return *password_data_; | 408 return *password_data_; |
| 409 } | 409 } |
| 410 | 410 |
| 411 const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const { | 411 const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const { |
| 412 DCHECK_EQ(syncable::THEMES, GetModelType()); | 412 DCHECK_EQ(syncable::THEMES, GetModelType()); |
| 413 return GetEntitySpecifics().GetExtension(sync_pb::theme); | 413 return GetEntitySpecifics().GetExtension(sync_pb::theme); |
| 414 } | 414 } |
| 415 | 415 |
| 416 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const { | 416 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const { |
| 417 DCHECK_EQ(syncable::TYPED_URLS, GetModelType()); | 417 DCHECK_EQ(syncable::TYPED_URLS, GetModelType()); |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 scoped_ptr<sync_pb::PasswordSpecificsData> old_plaintext( | 564 scoped_ptr<sync_pb::PasswordSpecificsData> old_plaintext( |
| 565 DecryptPasswordSpecifics(GetEntry()->Get(SPECIFICS), cryptographer)); | 565 DecryptPasswordSpecifics(GetEntry()->Get(SPECIFICS), cryptographer)); |
| 566 if (old_plaintext.get() && | 566 if (old_plaintext.get() && |
| 567 old_plaintext->SerializeAsString() == data.SerializeAsString() && | 567 old_plaintext->SerializeAsString() == data.SerializeAsString() && |
| 568 cryptographer->CanDecryptUsingDefaultKey(old_ciphertext)) { | 568 cryptographer->CanDecryptUsingDefaultKey(old_ciphertext)) { |
| 569 return; | 569 return; |
| 570 } | 570 } |
| 571 | 571 |
| 572 sync_pb::PasswordSpecifics new_value; | 572 sync_pb::PasswordSpecifics new_value; |
| 573 if (!cryptographer->Encrypt(data, new_value.mutable_encrypted())) { | 573 if (!cryptographer->Encrypt(data, new_value.mutable_encrypted())) { |
| 574 NOTREACHED(); | 574 NOTREACHED() << "Failed to encrypt password, possibly due to sync node " |
| 575 << "corruption"; |
| 576 return; |
| 575 } | 577 } |
| 576 | 578 |
| 577 sync_pb::EntitySpecifics entity_specifics; | 579 sync_pb::EntitySpecifics entity_specifics; |
| 578 entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value); | 580 entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value); |
| 579 SetEntitySpecifics(entity_specifics); | 581 SetEntitySpecifics(entity_specifics); |
| 580 } | 582 } |
| 581 | 583 |
| 582 void WriteNode::SetThemeSpecifics( | 584 void WriteNode::SetThemeSpecifics( |
| 583 const sync_pb::ThemeSpecifics& new_value) { | 585 const sync_pb::ThemeSpecifics& new_value) { |
| 584 sync_pb::EntitySpecifics entity_specifics; | 586 sync_pb::EntitySpecifics entity_specifics; |
| (...skipping 611 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1196 | 1198 |
| 1197 // Called when the user disables or enables a sync type. | 1199 // Called when the user disables or enables a sync type. |
| 1198 void UpdateEnabledTypes(); | 1200 void UpdateEnabledTypes(); |
| 1199 | 1201 |
| 1200 // Tell the sync engine to start the syncing process. | 1202 // Tell the sync engine to start the syncing process. |
| 1201 void StartSyncingNormally(); | 1203 void StartSyncingNormally(); |
| 1202 | 1204 |
| 1203 // Whether or not the Nigori node is encrypted using an explicit passphrase. | 1205 // Whether or not the Nigori node is encrypted using an explicit passphrase. |
| 1204 bool IsUsingExplicitPassphrase(); | 1206 bool IsUsingExplicitPassphrase(); |
| 1205 | 1207 |
| 1208 // Update the Cryptographer from the current nigori node. |
| 1209 // Note: opens a transaction and can trigger an ON_PASSPHRASE_REQUIRED, so |
| 1210 // should only be called after syncapi is fully initialized. |
| 1211 // Returns true if cryptographer is ready, false otherwise. |
| 1212 bool UpdateCryptographerFromNigori(); |
| 1213 |
| 1206 // Set the datatypes we want to encrypt and encrypt any nodes as necessary. | 1214 // Set the datatypes we want to encrypt and encrypt any nodes as necessary. |
| 1207 void EncryptDataTypes(const syncable::ModelTypeSet& encrypted_types); | 1215 void EncryptDataTypes(const syncable::ModelTypeSet& encrypted_types); |
| 1208 | 1216 |
| 1209 // Try to set the current passphrase to |passphrase|, and record whether | 1217 // Try to set the current passphrase to |passphrase|, and record whether |
| 1210 // it is an explicit passphrase or implicitly using gaia in the Nigori | 1218 // it is an explicit passphrase or implicitly using gaia in the Nigori |
| 1211 // node. | 1219 // node. |
| 1212 void SetPassphrase(const std::string& passphrase, bool is_explicit); | 1220 void SetPassphrase(const std::string& passphrase, bool is_explicit); |
| 1213 | 1221 |
| 1214 // Call periodically from a database-safe thread to persist recent changes | 1222 // Call periodically from a database-safe thread to persist recent changes |
| 1215 // to the syncapi model. | 1223 // to the syncapi model. |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1793 } | 1801 } |
| 1794 | 1802 |
| 1795 // Do this once the directory is opened. | 1803 // Do this once the directory is opened. |
| 1796 BootstrapEncryption(restored_key_for_bootstrapping); | 1804 BootstrapEncryption(restored_key_for_bootstrapping); |
| 1797 MarkAndNotifyInitializationComplete(); | 1805 MarkAndNotifyInitializationComplete(); |
| 1798 return signed_in; | 1806 return signed_in; |
| 1799 } | 1807 } |
| 1800 | 1808 |
| 1801 void SyncManager::SyncInternal::BootstrapEncryption( | 1809 void SyncManager::SyncInternal::BootstrapEncryption( |
| 1802 const std::string& restored_key_for_bootstrapping) { | 1810 const std::string& restored_key_for_bootstrapping) { |
| 1811 // Cryptographer should only be accessed while holding a transaction. |
| 1812 ReadTransaction trans(GetUserShare()); |
| 1813 Cryptographer* cryptographer = trans.GetCryptographer(); |
| 1814 |
| 1815 // Set the bootstrap token before bailing out if nigori node is not there. |
| 1816 // This could happen if server asked us to migrate nigri. |
| 1817 cryptographer->Bootstrap(restored_key_for_bootstrapping); |
| 1818 } |
| 1819 |
| 1820 bool SyncManager::SyncInternal::UpdateCryptographerFromNigori() { |
| 1803 syncable::ScopedDirLookup lookup(dir_manager(), username_for_share()); | 1821 syncable::ScopedDirLookup lookup(dir_manager(), username_for_share()); |
| 1804 if (!lookup.good()) { | 1822 if (!lookup.good()) { |
| 1805 LOG(INFO) << "BootstrapEncryption: lookup not good so bailing out"; | 1823 NOTREACHED() << "BootstrapEncryption: lookup not good so bailing out"; |
| 1824 return false; |
| 1825 } |
| 1826 if (!lookup->initial_sync_ended_for_type(syncable::NIGORI)) |
| 1827 return false; // Should only happen during first time sync. |
| 1828 |
| 1829 ReadTransaction trans(GetUserShare()); |
| 1830 Cryptographer* cryptographer = trans.GetCryptographer(); |
| 1831 |
| 1832 ReadNode node(&trans); |
| 1833 if (!node.InitByTagLookup(kNigoriTag)) { |
| 1806 NOTREACHED(); | 1834 NOTREACHED(); |
| 1807 return; | 1835 return false; |
| 1836 } |
| 1837 Cryptographer::UpdateResult result = |
| 1838 cryptographer->Update(node.GetNigoriSpecifics()); |
| 1839 if (result == Cryptographer::NEEDS_PASSPHRASE) { |
| 1840 ObserverList<SyncManager::Observer> temp_obs_list; |
| 1841 CopyObservers(&temp_obs_list); |
| 1842 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list, |
| 1843 OnPassphraseRequired(sync_api::REASON_DECRYPTION)); |
| 1808 } | 1844 } |
| 1809 | 1845 |
| 1810 sync_pb::NigoriSpecifics nigori; | 1846 return cryptographer->is_ready(); |
| 1811 syncable::ModelTypeSet encrypted_types; | |
| 1812 { | |
| 1813 // Cryptographer should only be accessed while holding a transaction. | |
| 1814 ReadTransaction trans(GetUserShare()); | |
| 1815 Cryptographer* cryptographer = trans.GetCryptographer(); | |
| 1816 | |
| 1817 // Set the bootstrap token before bailing out if nigori node is not there. | |
| 1818 // This could happen if server asked us to migrate nigri. | |
| 1819 cryptographer->Bootstrap(restored_key_for_bootstrapping); | |
| 1820 | |
| 1821 if (!lookup->initial_sync_ended_for_type(syncable::NIGORI)) | |
| 1822 return; | |
| 1823 | |
| 1824 ReadNode node(&trans); | |
| 1825 if (!node.InitByTagLookup(kNigoriTag)) { | |
| 1826 NOTREACHED(); | |
| 1827 return; | |
| 1828 } | |
| 1829 | |
| 1830 nigori.CopyFrom(node.GetNigoriSpecifics()); | |
| 1831 Cryptographer::UpdateResult result = cryptographer->Update(nigori); | |
| 1832 if (result == Cryptographer::NEEDS_PASSPHRASE) { | |
| 1833 ObserverList<SyncManager::Observer> temp_obs_list; | |
| 1834 CopyObservers(&temp_obs_list); | |
| 1835 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list, | |
| 1836 OnPassphraseRequired(sync_api::REASON_DECRYPTION)); | |
| 1837 } | |
| 1838 | |
| 1839 // Refresh list of encrypted datatypes. | |
| 1840 encrypted_types = GetEncryptedTypes(&trans); | |
| 1841 } | |
| 1842 | |
| 1843 | |
| 1844 | |
| 1845 // Ensure any datatypes that need encryption are encrypted. | |
| 1846 EncryptDataTypes(encrypted_types); | |
| 1847 } | 1847 } |
| 1848 | 1848 |
| 1849 void SyncManager::SyncInternal::StartSyncingNormally() { | 1849 void SyncManager::SyncInternal::StartSyncingNormally() { |
| 1850 // Start the sync scheduler. This won't actually result in any | 1850 // Start the sync scheduler. This won't actually result in any |
| 1851 // syncing until at least the DirectoryManager broadcasts the OPENED | 1851 // syncing until at least the DirectoryManager broadcasts the OPENED |
| 1852 // event, and a valid server connection is detected. | 1852 // event, and a valid server connection is detected. |
| 1853 if (scheduler()) // NULL during certain unittests. | 1853 if (scheduler()) // NULL during certain unittests. |
| 1854 scheduler()->Start(SyncScheduler::NORMAL_MODE, NULL); | 1854 scheduler()->Start(SyncScheduler::NORMAL_MODE, NULL); |
| 1855 } | 1855 } |
| 1856 | 1856 |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2082 } | 2082 } |
| 2083 | 2083 |
| 2084 void SyncManager::SyncInternal::EncryptDataTypes( | 2084 void SyncManager::SyncInternal::EncryptDataTypes( |
| 2085 const syncable::ModelTypeSet& encrypted_types) { | 2085 const syncable::ModelTypeSet& encrypted_types) { |
| 2086 VLOG(1) << "Attempting to encrypt datatypes " | 2086 VLOG(1) << "Attempting to encrypt datatypes " |
| 2087 << syncable::ModelTypeSetToString(encrypted_types); | 2087 << syncable::ModelTypeSetToString(encrypted_types); |
| 2088 | 2088 |
| 2089 WriteTransaction trans(GetUserShare()); | 2089 WriteTransaction trans(GetUserShare()); |
| 2090 WriteNode node(&trans); | 2090 WriteNode node(&trans); |
| 2091 if (!node.InitByTagLookup(kNigoriTag)) { | 2091 if (!node.InitByTagLookup(kNigoriTag)) { |
| 2092 LOG(ERROR) << "Unable to set encrypted datatypes because Nigori node not " | 2092 NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not " |
| 2093 << "found."; | 2093 << "found."; |
| 2094 NOTREACHED(); | |
| 2095 return; | 2094 return; |
| 2096 } | 2095 } |
| 2097 | 2096 |
| 2098 Cryptographer* cryptographer = trans.GetCryptographer(); | 2097 Cryptographer* cryptographer = trans.GetCryptographer(); |
| 2099 | 2098 |
| 2099 if (!cryptographer->is_initialized()) { |
| 2100 NOTREACHED() << "Attempting to encrypt datatypes when cryptographer not " |
| 2101 << "initialized."; |
| 2102 return; |
| 2103 } |
| 2104 |
| 2100 // Update the Nigori node set of encrypted datatypes so other machines notice. | 2105 // Update the Nigori node set of encrypted datatypes so other machines notice. |
| 2101 // Note, we merge the current encrypted types with those requested. Once a | 2106 // Note, we merge the current encrypted types with those requested. Once a |
| 2102 // datatypes is marked as needing encryption, it is never unmarked. | 2107 // datatypes is marked as needing encryption, it is never unmarked. |
| 2103 sync_pb::NigoriSpecifics nigori; | 2108 sync_pb::NigoriSpecifics nigori; |
| 2104 nigori.CopyFrom(node.GetNigoriSpecifics()); | 2109 nigori.CopyFrom(node.GetNigoriSpecifics()); |
| 2105 syncable::ModelTypeSet current_encrypted_types = GetEncryptedTypes(&trans); | 2110 syncable::ModelTypeSet current_encrypted_types = GetEncryptedTypes(&trans); |
| 2106 syncable::ModelTypeSet newly_encrypted_types; | 2111 syncable::ModelTypeSet newly_encrypted_types; |
| 2107 std::set_union(current_encrypted_types.begin(), current_encrypted_types.end(), | 2112 std::set_union(current_encrypted_types.begin(), current_encrypted_types.end(), |
| 2108 encrypted_types.begin(), encrypted_types.end(), | 2113 encrypted_types.begin(), encrypted_types.end(), |
| 2109 std::inserter(newly_encrypted_types, | 2114 std::inserter(newly_encrypted_types, |
| (...skipping 885 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2995 } | 3000 } |
| 2996 BaseTransaction::~BaseTransaction() { | 3001 BaseTransaction::~BaseTransaction() { |
| 2997 delete lookup_; | 3002 delete lookup_; |
| 2998 } | 3003 } |
| 2999 | 3004 |
| 3000 UserShare* SyncManager::GetUserShare() const { | 3005 UserShare* SyncManager::GetUserShare() const { |
| 3001 DCHECK(data_->initialized()) << "GetUserShare requires initialization!"; | 3006 DCHECK(data_->initialized()) << "GetUserShare requires initialization!"; |
| 3002 return data_->GetUserShare(); | 3007 return data_->GetUserShare(); |
| 3003 } | 3008 } |
| 3004 | 3009 |
| 3010 void SyncManager::RefreshEncryption() { |
| 3011 DCHECK(data_->initialized()); |
| 3012 if (data_->UpdateCryptographerFromNigori()) |
| 3013 data_->EncryptDataTypes(syncable::ModelTypeSet()); |
| 3014 } |
| 3015 |
| 3005 syncable::ModelTypeSet SyncManager::GetEncryptedDataTypes() const { | 3016 syncable::ModelTypeSet SyncManager::GetEncryptedDataTypes() const { |
| 3006 sync_api::ReadTransaction trans(GetUserShare()); | 3017 sync_api::ReadTransaction trans(GetUserShare()); |
| 3007 return GetEncryptedTypes(&trans); | 3018 return GetEncryptedTypes(&trans); |
| 3008 } | 3019 } |
| 3009 | 3020 |
| 3010 | |
| 3011 bool SyncManager::HasUnsyncedItems() const { | 3021 bool SyncManager::HasUnsyncedItems() const { |
| 3012 sync_api::ReadTransaction trans(GetUserShare()); | 3022 sync_api::ReadTransaction trans(GetUserShare()); |
| 3013 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0); | 3023 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0); |
| 3014 } | 3024 } |
| 3015 | 3025 |
| 3016 void SyncManager::LogUnsyncedItems(int level) const { | 3026 void SyncManager::LogUnsyncedItems(int level) const { |
| 3017 std::vector<int64> unsynced_handles; | 3027 std::vector<int64> unsynced_handles; |
| 3018 sync_api::ReadTransaction trans(GetUserShare()); | 3028 sync_api::ReadTransaction trans(GetUserShare()); |
| 3019 trans.GetWrappedTrans()->directory()->GetUnsyncedMetaHandles( | 3029 trans.GetWrappedTrans()->directory()->GetUnsyncedMetaHandles( |
| 3020 trans.GetWrappedTrans(), &unsynced_handles); | 3030 trans.GetWrappedTrans(), &unsynced_handles); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 3039 void SyncManager::TriggerOnIncomingNotificationForTest( | 3049 void SyncManager::TriggerOnIncomingNotificationForTest( |
| 3040 const syncable::ModelTypeBitSet& model_types) { | 3050 const syncable::ModelTypeBitSet& model_types) { |
| 3041 syncable::ModelTypePayloadMap model_types_with_payloads = | 3051 syncable::ModelTypePayloadMap model_types_with_payloads = |
| 3042 syncable::ModelTypePayloadMapFromBitSet(model_types, | 3052 syncable::ModelTypePayloadMapFromBitSet(model_types, |
| 3043 std::string()); | 3053 std::string()); |
| 3044 | 3054 |
| 3045 data_->OnIncomingNotification(model_types_with_payloads); | 3055 data_->OnIncomingNotification(model_types_with_payloads); |
| 3046 } | 3056 } |
| 3047 | 3057 |
| 3048 } // namespace sync_api | 3058 } // namespace sync_api |
| OLD | NEW |