Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/extensions/api/storage/sync_storage_backend.h" | 5 #include "chrome/browser/extensions/api/storage/sync_storage_backend.h" |
| 6 | 6 |
| 7 #include "base/files/file_enumerator.h" | 7 #include "base/files/file_enumerator.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "chrome/browser/extensions/api/storage/settings_sync_processor.h" | 9 #include "chrome/browser/extensions/api/storage/settings_sync_processor.h" |
| 10 #include "chrome/browser/extensions/api/storage/settings_sync_util.h" | 10 #include "chrome/browser/extensions/api/storage/settings_sync_util.h" |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 void AddAllSyncData(const std::string& extension_id, | 21 void AddAllSyncData(const std::string& extension_id, |
| 22 const base::DictionaryValue& src, | 22 const base::DictionaryValue& src, |
| 23 syncer::ModelType type, | 23 syncer::ModelType type, |
| 24 syncer::SyncDataList* dst) { | 24 syncer::SyncDataList* dst) { |
| 25 for (base::DictionaryValue::Iterator it(src); !it.IsAtEnd(); it.Advance()) { | 25 for (base::DictionaryValue::Iterator it(src); !it.IsAtEnd(); it.Advance()) { |
| 26 dst->push_back(settings_sync_util::CreateData( | 26 dst->push_back(settings_sync_util::CreateData( |
| 27 extension_id, it.key(), it.value(), type)); | 27 extension_id, it.key(), it.value(), type)); |
| 28 } | 28 } |
| 29 } | 29 } |
| 30 | 30 |
| 31 scoped_ptr<base::DictionaryValue> EmptyDictionaryValue() { | |
| 32 return make_scoped_ptr(new base::DictionaryValue()); | |
| 33 } | |
| 34 | |
| 31 } // namespace | 35 } // namespace |
| 32 | 36 |
| 33 SyncStorageBackend::SyncStorageBackend( | 37 SyncStorageBackend::SyncStorageBackend( |
| 34 const scoped_refptr<SettingsStorageFactory>& storage_factory, | 38 const scoped_refptr<SettingsStorageFactory>& storage_factory, |
| 35 const base::FilePath& base_path, | 39 const base::FilePath& base_path, |
| 36 const SettingsStorageQuotaEnforcer::Limits& quota, | 40 const SettingsStorageQuotaEnforcer::Limits& quota, |
| 37 const scoped_refptr<SettingsObserverList>& observers, | 41 const scoped_refptr<SettingsObserverList>& observers, |
| 38 syncer::ModelType sync_type, | 42 syncer::ModelType sync_type, |
| 39 const syncer::SyncableService::StartSyncFlare& flare) | 43 const syncer::SyncableService::StartSyncFlare& flare) |
| 40 : storage_factory_(storage_factory), | 44 : storage_factory_(storage_factory), |
| 41 base_path_(base_path), | 45 base_path_(base_path), |
| 42 quota_(quota), | 46 quota_(quota), |
| 43 observers_(observers), | 47 observers_(observers), |
| 44 sync_type_(sync_type), | 48 sync_type_(sync_type), |
| 45 flare_(flare) { | 49 flare_(flare) { |
| 46 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 50 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 47 DCHECK(sync_type_ == syncer::EXTENSION_SETTINGS || | 51 DCHECK(sync_type_ == syncer::EXTENSION_SETTINGS || |
| 48 sync_type_ == syncer::APP_SETTINGS); | 52 sync_type_ == syncer::APP_SETTINGS); |
| 49 } | 53 } |
| 50 | 54 |
| 51 SyncStorageBackend::~SyncStorageBackend() {} | 55 SyncStorageBackend::~SyncStorageBackend() {} |
| 52 | 56 |
| 53 ValueStore* SyncStorageBackend::GetStorage(const std::string& extension_id) { | 57 ValueStore* SyncStorageBackend::GetStorage(const std::string& extension_id) { |
| 54 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 58 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 55 base::DictionaryValue empty; | 59 return GetOrCreateStorageWithSyncData(extension_id, EmptyDictionaryValue()); |
| 56 return GetOrCreateStorageWithSyncData(extension_id, empty); | |
| 57 } | 60 } |
| 58 | 61 |
| 59 SyncableSettingsStorage* SyncStorageBackend::GetOrCreateStorageWithSyncData( | 62 SyncableSettingsStorage* SyncStorageBackend::GetOrCreateStorageWithSyncData( |
| 60 const std::string& extension_id, | 63 const std::string& extension_id, |
| 61 const base::DictionaryValue& sync_data) const { | 64 scoped_ptr<base::DictionaryValue> sync_data) const { |
| 62 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 65 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 63 | 66 |
| 64 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id); | 67 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id); |
| 65 if (maybe_storage != storage_objs_.end()) { | 68 if (maybe_storage != storage_objs_.end()) { |
| 66 return maybe_storage->second.get(); | 69 return maybe_storage->second.get(); |
| 67 } | 70 } |
| 68 | 71 |
| 69 scoped_ptr<SettingsStorageQuotaEnforcer> storage( | 72 scoped_ptr<SettingsStorageQuotaEnforcer> storage( |
| 70 new SettingsStorageQuotaEnforcer( | 73 new SettingsStorageQuotaEnforcer( |
| 71 quota_, storage_factory_->Create(base_path_, extension_id))); | 74 quota_, storage_factory_->Create(base_path_, extension_id))); |
| 72 | 75 |
| 73 // It's fine to create the quota enforcer underneath the sync layer, since | 76 // It's fine to create the quota enforcer underneath the sync layer, since |
| 74 // sync will only go ahead if each underlying storage operation succeeds. | 77 // sync will only go ahead if each underlying storage operation succeeds. |
| 75 linked_ptr<SyncableSettingsStorage> syncable_storage( | 78 linked_ptr<SyncableSettingsStorage> syncable_storage( |
| 76 new SyncableSettingsStorage( | 79 new SyncableSettingsStorage( |
| 77 observers_, extension_id, storage.release(), sync_type_, flare_)); | 80 observers_, extension_id, storage.release(), sync_type_, flare_)); |
| 78 storage_objs_[extension_id] = syncable_storage; | 81 storage_objs_[extension_id] = syncable_storage; |
| 79 | 82 |
| 80 if (sync_processor_.get()) { | 83 if (sync_processor_.get()) { |
| 81 syncer::SyncError error = syncable_storage->StartSyncing( | 84 syncer::SyncError error = syncable_storage->StartSyncing( |
| 82 sync_data, CreateSettingsSyncProcessor(extension_id).Pass()); | 85 sync_data.Pass(), CreateSettingsSyncProcessor(extension_id).Pass()); |
| 83 if (error.IsSet()) | 86 if (error.IsSet()) |
| 84 syncable_storage.get()->StopSyncing(); | 87 syncable_storage->StopSyncing(); |
| 85 } | 88 } |
| 86 return syncable_storage.get(); | 89 return syncable_storage.get(); |
| 87 } | 90 } |
| 88 | 91 |
| 89 void SyncStorageBackend::DeleteStorage(const std::string& extension_id) { | 92 void SyncStorageBackend::DeleteStorage(const std::string& extension_id) { |
| 90 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 93 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 91 | 94 |
| 92 // Clear settings when the extension is uninstalled. Leveldb implementations | 95 // Clear settings when the extension is uninstalled. Leveldb implementations |
| 93 // will also delete the database from disk when the object is destroyed as a | 96 // will also delete the database from disk when the object is destroyed as a |
| 94 // result of being removed from |storage_objs_|. | 97 // result of being removed from |storage_objs_|. |
| 95 // | 98 // |
| 96 // TODO(kalman): always GetStorage here (rather than only clearing if it | 99 // TODO(kalman): always GetStorage here (rather than only clearing if it |
| 97 // exists) since the storage area may have been unloaded, but we still want | 100 // exists) since the storage area may have been unloaded, but we still want |
| 98 // to clear the data from disk. | 101 // to clear the data from disk. |
| 99 // However, this triggers http://crbug.com/111072. | 102 // However, this triggers http://crbug.com/111072. |
| 100 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id); | 103 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id); |
| 101 if (maybe_storage == storage_objs_.end()) | 104 if (maybe_storage == storage_objs_.end()) |
| 102 return; | 105 return; |
| 103 maybe_storage->second->Clear(); | 106 maybe_storage->second->Clear(); |
| 104 storage_objs_.erase(extension_id); | 107 storage_objs_.erase(extension_id); |
| 105 } | 108 } |
| 106 | 109 |
| 107 std::set<std::string> SyncStorageBackend::GetKnownExtensionIDs() const { | 110 std::set<std::string> SyncStorageBackend::GetKnownExtensionIDs() const { |
| 108 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 111 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 109 std::set<std::string> result; | 112 std::set<std::string> result; |
| 110 | 113 |
| 111 // Storage areas can be in-memory as well as on disk. |storage_objs_| will | 114 // Storage areas can be in-memory as well as on disk. |storage_objs_| will |
| 112 // contain all that are in-memory. | 115 // contain all that are in-memory. |
| 113 for (StorageObjMap::iterator it = storage_objs_.begin(); | 116 for (const auto& storage_obj : storage_objs_) { |
| 114 it != storage_objs_.end(); | 117 result.insert(storage_obj.first); |
| 115 ++it) { | |
| 116 result.insert(it->first); | |
| 117 } | 118 } |
| 118 | 119 |
| 119 // Leveldb databases are directories inside |base_path_|. | 120 // Leveldb databases are directories inside |base_path_|. |
| 120 base::FileEnumerator extension_dirs( | 121 base::FileEnumerator extension_dirs( |
| 121 base_path_, false, base::FileEnumerator::DIRECTORIES); | 122 base_path_, false, base::FileEnumerator::DIRECTORIES); |
| 122 while (!extension_dirs.Next().empty()) { | 123 while (!extension_dirs.Next().empty()) { |
| 123 base::FilePath extension_dir = extension_dirs.GetInfo().GetName(); | 124 base::FilePath extension_dir = extension_dirs.GetInfo().GetName(); |
| 124 DCHECK(!extension_dir.IsAbsolute()); | 125 DCHECK(!extension_dir.IsAbsolute()); |
| 125 // Extension IDs are created as std::strings so they *should* be ASCII. | 126 // Extension IDs are created as std::strings so they *should* be ASCII. |
| 126 std::string maybe_as_ascii(extension_dir.MaybeAsASCII()); | 127 std::string maybe_as_ascii(extension_dir.MaybeAsASCII()); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 141 | 142 |
| 142 // For all extensions, get all their settings. This has the effect | 143 // For all extensions, get all their settings. This has the effect |
| 143 // of bringing in the entire state of extension settings in memory; sad. | 144 // of bringing in the entire state of extension settings in memory; sad. |
| 144 syncer::SyncDataList all_sync_data; | 145 syncer::SyncDataList all_sync_data; |
| 145 std::set<std::string> known_extension_ids(GetKnownExtensionIDs()); | 146 std::set<std::string> known_extension_ids(GetKnownExtensionIDs()); |
| 146 | 147 |
| 147 for (std::set<std::string>::const_iterator it = known_extension_ids.begin(); | 148 for (std::set<std::string>::const_iterator it = known_extension_ids.begin(); |
| 148 it != known_extension_ids.end(); | 149 it != known_extension_ids.end(); |
| 149 ++it) { | 150 ++it) { |
| 150 ValueStore::ReadResult maybe_settings = | 151 ValueStore::ReadResult maybe_settings = |
| 151 GetOrCreateStorageWithSyncData(*it, base::DictionaryValue())->Get(); | 152 GetOrCreateStorageWithSyncData(*it, EmptyDictionaryValue())->Get(); |
| 152 if (maybe_settings->HasError()) { | 153 if (maybe_settings->HasError()) { |
| 153 LOG(WARNING) << "Failed to get settings for " << *it << ": " | 154 LOG(WARNING) << "Failed to get settings for " << *it << ": " |
| 154 << maybe_settings->error().message; | 155 << maybe_settings->error().message; |
| 155 continue; | 156 continue; |
| 156 } | 157 } |
| 157 AddAllSyncData(*it, maybe_settings->settings(), type, &all_sync_data); | 158 AddAllSyncData(*it, maybe_settings->settings(), type, &all_sync_data); |
| 158 } | 159 } |
| 159 | 160 |
| 160 return all_sync_data; | 161 return all_sync_data; |
| 161 } | 162 } |
| 162 | 163 |
| 163 syncer::SyncMergeResult SyncStorageBackend::MergeDataAndStartSyncing( | 164 syncer::SyncMergeResult SyncStorageBackend::MergeDataAndStartSyncing( |
| 164 syncer::ModelType type, | 165 syncer::ModelType type, |
| 165 const syncer::SyncDataList& initial_sync_data, | 166 const syncer::SyncDataList& initial_sync_data, |
| 166 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, | 167 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, |
| 167 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { | 168 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { |
| 168 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 169 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 169 DCHECK_EQ(sync_type_, type); | 170 DCHECK_EQ(sync_type_, type); |
| 170 DCHECK(!sync_processor_.get()); | 171 DCHECK(!sync_processor_.get()); |
| 171 DCHECK(sync_processor.get()); | 172 DCHECK(sync_processor.get()); |
| 172 DCHECK(sync_error_factory.get()); | 173 DCHECK(sync_error_factory.get()); |
| 173 | 174 |
| 174 sync_processor_ = sync_processor.Pass(); | 175 sync_processor_ = sync_processor.Pass(); |
| 175 sync_error_factory_ = sync_error_factory.Pass(); | 176 sync_error_factory_ = sync_error_factory.Pass(); |
| 176 | 177 |
| 177 // Group the initial sync data by extension id. | 178 // Group the initial sync data by extension id. |
| 178 std::map<std::string, linked_ptr<base::DictionaryValue> > grouped_sync_data; | 179 std::map<std::string, base::DictionaryValue*> grouped_sync_data; |
|
Devlin
2015/05/15 21:59:07
This is scary - easy leaking if we ever early-retu
not at google - send to devlin
2015/05/15 23:28:30
I don't really see the point. The reason to have R
Devlin
2015/05/15 23:58:18
Meh, fine then. :P At the very least, can you doc
not at google - send to devlin
2015/05/19 19:43:57
Documented.
| |
| 179 for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin(); | 180 for (const syncer::SyncData& sync_data : initial_sync_data) { |
| 180 it != initial_sync_data.end(); | 181 SettingSyncData data(sync_data); |
| 181 ++it) { | 182 base::DictionaryValue*& settings = grouped_sync_data[data.extension_id()]; |
|
Devlin
2015/05/15 21:59:07
This is kinda cool, but honestly, it might be wort
not at google - send to devlin
2015/05/15 23:28:30
haha ok.
| |
| 182 SettingSyncData data(*it); | 183 if (!settings) |
| 183 linked_ptr<base::DictionaryValue> sync_data = | 184 settings = new base::DictionaryValue(); |
| 184 grouped_sync_data[data.extension_id()]; | 185 DCHECK(!settings->HasKey(data.key())) << "Duplicate settings for " |
| 185 if (!sync_data.get()) { | 186 << data.extension_id() << "/" |
| 186 sync_data = | 187 << data.key(); |
| 187 linked_ptr<base::DictionaryValue>(new base::DictionaryValue()); | 188 settings->SetWithoutPathExpansion(data.key(), data.PassValue()); |
| 188 grouped_sync_data[data.extension_id()] = sync_data; | |
| 189 } | |
| 190 DCHECK(!sync_data->HasKey(data.key())) << "Duplicate settings for " | |
| 191 << data.extension_id() << "/" | |
| 192 << data.key(); | |
| 193 sync_data->SetWithoutPathExpansion(data.key(), data.value().DeepCopy()); | |
| 194 } | 189 } |
| 195 | 190 |
| 196 // Start syncing all existing storage areas. Any storage areas created in | 191 // Start syncing all existing storage areas. Any storage areas created in |
| 197 // the future will start being synced as part of the creation process. | 192 // the future will start being synced as part of the creation process. |
| 198 for (StorageObjMap::iterator it = storage_objs_.begin(); | 193 for (const auto& storage_obj : storage_objs_) { |
| 199 it != storage_objs_.end(); | 194 const std::string& extension_id = storage_obj.first; |
| 200 ++it) { | 195 SyncableSettingsStorage* storage = storage_obj.second.get(); |
| 201 std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator | 196 |
| 202 maybe_sync_data = grouped_sync_data.find(it->first); | |
| 203 syncer::SyncError error; | 197 syncer::SyncError error; |
| 204 if (maybe_sync_data != grouped_sync_data.end()) { | 198 if (grouped_sync_data.count(extension_id)) { |
| 205 error = it->second->StartSyncing( | 199 error = storage->StartSyncing( |
| 206 *maybe_sync_data->second, | 200 make_scoped_ptr(grouped_sync_data[extension_id]), |
|
Devlin
2015/05/15 21:59:07
this does result in a trip lookup (one in the if o
not at google - send to devlin
2015/05/15 23:28:30
Done.
| |
| 207 CreateSettingsSyncProcessor(it->first).Pass()); | 201 CreateSettingsSyncProcessor(extension_id).Pass()); |
| 208 grouped_sync_data.erase(it->first); | 202 grouped_sync_data.erase(extension_id); |
| 209 } else { | 203 } else { |
| 210 base::DictionaryValue empty; | 204 error = storage->StartSyncing( |
| 211 error = it->second->StartSyncing( | 205 EmptyDictionaryValue(), |
| 212 empty, CreateSettingsSyncProcessor(it->first).Pass()); | 206 CreateSettingsSyncProcessor(extension_id).Pass()); |
| 213 } | 207 } |
| 208 | |
| 214 if (error.IsSet()) | 209 if (error.IsSet()) |
| 215 it->second->StopSyncing(); | 210 storage->StopSyncing(); |
| 216 } | 211 } |
| 217 | 212 |
| 218 // Eagerly create and init the rest of the storage areas that have sync data. | 213 // Eagerly create and init the rest of the storage areas that have sync data. |
| 219 // Under normal circumstances (i.e. not first-time sync) this will be all of | 214 // Under normal circumstances (i.e. not first-time sync) this will be all of |
| 220 // them. | 215 // them. |
| 221 for (std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator it = | 216 for (const auto& group : grouped_sync_data) { |
| 222 grouped_sync_data.begin(); | 217 GetOrCreateStorageWithSyncData(group.first, make_scoped_ptr(group.second)); |
| 223 it != grouped_sync_data.end(); | |
| 224 ++it) { | |
| 225 GetOrCreateStorageWithSyncData(it->first, *it->second); | |
| 226 } | 218 } |
| 227 | 219 |
| 228 return syncer::SyncMergeResult(type); | 220 return syncer::SyncMergeResult(type); |
| 229 } | 221 } |
| 230 | 222 |
| 231 syncer::SyncError SyncStorageBackend::ProcessSyncChanges( | 223 syncer::SyncError SyncStorageBackend::ProcessSyncChanges( |
| 232 const tracked_objects::Location& from_here, | 224 const tracked_objects::Location& from_here, |
| 233 const syncer::SyncChangeList& sync_changes) { | 225 const syncer::SyncChangeList& sync_changes) { |
| 234 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 226 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 235 DCHECK(sync_processor_.get()); | 227 DCHECK(sync_processor_.get()); |
| 236 | 228 |
| 237 // Group changes by extension, to pass all changes in a single method call. | 229 // Group changes by extension, to pass all changes in a single method call. |
| 238 std::map<std::string, SettingSyncDataList> grouped_sync_data; | 230 std::map<std::string, SettingSyncDataList*> grouped_sync_data; |
|
Devlin
2015/05/15 21:59:07
ditto here, though this one's a little less scary
not at google - send to devlin
2015/05/19 19:43:57
Documented.
| |
| 239 for (syncer::SyncChangeList::const_iterator it = sync_changes.begin(); | 231 for (const syncer::SyncChange& change : sync_changes) { |
| 240 it != sync_changes.end(); | 232 SettingSyncData data(change); |
| 241 ++it) { | 233 SettingSyncDataList*& group = grouped_sync_data[data.extension_id()]; |
| 242 SettingSyncData data(*it); | 234 if (!group) |
| 243 grouped_sync_data[data.extension_id()].push_back(data); | 235 group = new SettingSyncDataList(); |
| 236 group->push_back(data); | |
| 244 } | 237 } |
| 245 | 238 |
| 246 // Create any storage areas that don't exist yet but have sync data. | 239 // Create any storage areas that don't exist yet but have sync data. |
| 247 base::DictionaryValue empty; | 240 for (const auto& group : grouped_sync_data) { |
| 248 for (std::map<std::string, SettingSyncDataList>::iterator it = | |
| 249 grouped_sync_data.begin(); | |
| 250 it != grouped_sync_data.end(); | |
| 251 ++it) { | |
| 252 SyncableSettingsStorage* storage = | 241 SyncableSettingsStorage* storage = |
| 253 GetOrCreateStorageWithSyncData(it->first, empty); | 242 GetOrCreateStorageWithSyncData(group.first, EmptyDictionaryValue()); |
| 254 syncer::SyncError error = storage->ProcessSyncChanges(it->second); | 243 syncer::SyncError error = |
| 244 storage->ProcessSyncChanges(make_scoped_ptr(group.second)); | |
| 255 if (error.IsSet()) | 245 if (error.IsSet()) |
| 256 storage->StopSyncing(); | 246 storage->StopSyncing(); |
| 257 } | 247 } |
| 258 | 248 |
| 259 return syncer::SyncError(); | 249 return syncer::SyncError(); |
| 260 } | 250 } |
| 261 | 251 |
| 262 void SyncStorageBackend::StopSyncing(syncer::ModelType type) { | 252 void SyncStorageBackend::StopSyncing(syncer::ModelType type) { |
| 263 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 253 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 264 DCHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS); | 254 DCHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS); |
| 265 DCHECK_EQ(sync_type_, type); | 255 DCHECK_EQ(sync_type_, type); |
| 266 | 256 |
| 267 for (StorageObjMap::iterator it = storage_objs_.begin(); | 257 for (const auto& storage_obj : storage_objs_) { |
| 268 it != storage_objs_.end(); | |
| 269 ++it) { | |
| 270 // Some storage areas may have already stopped syncing if they had areas | 258 // Some storage areas may have already stopped syncing if they had areas |
| 271 // and syncing was disabled, but StopSyncing is safe to call multiple times. | 259 // and syncing was disabled, but StopSyncing is safe to call multiple times. |
| 272 it->second->StopSyncing(); | 260 storage_obj.second->StopSyncing(); |
| 273 } | 261 } |
| 274 | 262 |
| 275 sync_processor_.reset(); | 263 sync_processor_.reset(); |
| 276 sync_error_factory_.reset(); | 264 sync_error_factory_.reset(); |
| 277 } | 265 } |
| 278 | 266 |
| 279 scoped_ptr<SettingsSyncProcessor> | 267 scoped_ptr<SettingsSyncProcessor> |
| 280 SyncStorageBackend::CreateSettingsSyncProcessor(const std::string& extension_id) | 268 SyncStorageBackend::CreateSettingsSyncProcessor(const std::string& extension_id) |
| 281 const { | 269 const { |
| 282 CHECK(sync_processor_.get()); | 270 CHECK(sync_processor_.get()); |
| 283 return scoped_ptr<SettingsSyncProcessor>(new SettingsSyncProcessor( | 271 return scoped_ptr<SettingsSyncProcessor>(new SettingsSyncProcessor( |
| 284 extension_id, sync_type_, sync_processor_.get())); | 272 extension_id, sync_type_, sync_processor_.get())); |
| 285 } | 273 } |
| 286 | 274 |
| 287 } // namespace extensions | 275 } // namespace extensions |
| OLD | NEW |