Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: chrome/browser/extensions/api/storage/sync_storage_backend.cc

Issue 165223003: Add a Restore() method to ValueStore and make StorageAPI use it (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Latest master Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/settings_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"
11 #include "chrome/browser/extensions/api/storage/syncable_settings_storage.h" 11 #include "chrome/browser/extensions/api/storage/syncable_settings_storage.h"
12 #include "content/public/browser/browser_thread.h" 12 #include "content/public/browser/browser_thread.h"
13 #include "sync/api/sync_error_factory.h" 13 #include "sync/api/sync_error_factory.h"
14 14
15 using content::BrowserThread; 15 using content::BrowserThread;
16 16
17 namespace extensions { 17 namespace extensions {
18 18
19 SettingsBackend::SettingsBackend( 19 namespace {
20
21 void AddAllSyncData(const std::string& extension_id,
22 const base::DictionaryValue& src,
23 syncer::ModelType type,
24 syncer::SyncDataList* dst) {
25 for (base::DictionaryValue::Iterator it(src); !it.IsAtEnd(); it.Advance()) {
26 dst->push_back(settings_sync_util::CreateData(
27 extension_id, it.key(), it.value(), type));
28 }
29 }
30
31 } // namespace
32
33 SyncStorageBackend::SyncStorageBackend(
20 const scoped_refptr<SettingsStorageFactory>& storage_factory, 34 const scoped_refptr<SettingsStorageFactory>& storage_factory,
21 const base::FilePath& base_path, 35 const base::FilePath& base_path,
36 const SettingsStorageQuotaEnforcer::Limits& quota,
37 const scoped_refptr<SettingsObserverList>& observers,
22 syncer::ModelType sync_type, 38 syncer::ModelType sync_type,
23 const syncer::SyncableService::StartSyncFlare& flare, 39 const syncer::SyncableService::StartSyncFlare& flare)
24 const SettingsStorageQuotaEnforcer::Limits& quota, 40 : SettingsBackend(storage_factory, base_path, quota),
25 const scoped_refptr<SettingsObserverList>& observers)
26 : storage_factory_(storage_factory),
27 base_path_(base_path),
28 quota_(quota),
29 observers_(observers), 41 observers_(observers),
30 sync_type_(sync_type), 42 sync_type_(sync_type),
31 flare_(flare) { 43 flare_(flare) {
32 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
33 DCHECK(sync_type_ == syncer::EXTENSION_SETTINGS || 45 DCHECK(sync_type_ == syncer::EXTENSION_SETTINGS ||
34 sync_type_ == syncer::APP_SETTINGS); 46 sync_type_ == syncer::APP_SETTINGS);
35 } 47 }
36 48
37 SettingsBackend::~SettingsBackend() { 49 SyncStorageBackend::~SyncStorageBackend() {}
38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
39 }
40 50
41 ValueStore* SettingsBackend::GetStorage( 51 ValueStore* SyncStorageBackend::GetStorage(const std::string& extension_id) {
42 const std::string& extension_id) const {
43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
44 base::DictionaryValue empty; 53 base::DictionaryValue empty;
45 return GetOrCreateStorageWithSyncData(extension_id, empty); 54 return GetOrCreateStorageWithSyncData(extension_id, empty);
46 } 55 }
47 56
48 SyncableSettingsStorage* SettingsBackend::GetOrCreateStorageWithSyncData( 57 SyncableSettingsStorage* SyncStorageBackend::GetOrCreateStorageWithSyncData(
49 const std::string& extension_id, 58 const std::string& extension_id,
50 const base::DictionaryValue& sync_data) const { 59 const base::DictionaryValue& sync_data) const {
51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
52 61
53 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id); 62 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id);
54 if (maybe_storage != storage_objs_.end()) { 63 if (maybe_storage != storage_objs_.end()) {
55 return maybe_storage->second.get(); 64 return maybe_storage->second.get();
56 } 65 }
57 66
58 ValueStore* storage = storage_factory_->Create(base_path_, extension_id); 67 scoped_ptr<SettingsStorageQuotaEnforcer> storage =
59 CHECK(storage); 68 CreateStorageForExtension(extension_id);
60 69
61 // It's fine to create the quota enforcer underneath the sync layer, since 70 // It's fine to create the quota enforcer underneath the sync layer, since
62 // sync will only go ahead if each underlying storage operation succeeds. 71 // sync will only go ahead if each underlying storage operation succeeds.
63 storage = new SettingsStorageQuotaEnforcer(quota_, storage);
64
65 linked_ptr<SyncableSettingsStorage> syncable_storage( 72 linked_ptr<SyncableSettingsStorage> syncable_storage(
66 new SyncableSettingsStorage( 73 new SyncableSettingsStorage(
67 observers_, 74 observers_, extension_id, storage.release(), sync_type_, flare_));
68 extension_id,
69 storage,
70 sync_type_,
71 flare_));
72 storage_objs_[extension_id] = syncable_storage; 75 storage_objs_[extension_id] = syncable_storage;
73 76
74 if (sync_processor_.get()) { 77 if (sync_processor_.get()) {
75 syncer::SyncError error = 78 syncer::SyncError error = syncable_storage->StartSyncing(
76 syncable_storage->StartSyncing( 79 sync_data, CreateSettingsSyncProcessor(extension_id).Pass());
77 sync_data,
78 CreateSettingsSyncProcessor(extension_id).Pass());
79 if (error.IsSet()) 80 if (error.IsSet())
80 syncable_storage.get()->StopSyncing(); 81 syncable_storage.get()->StopSyncing();
81 } 82 }
82 return syncable_storage.get(); 83 return syncable_storage.get();
83 } 84 }
84 85
85 void SettingsBackend::DeleteStorage(const std::string& extension_id) { 86 void SyncStorageBackend::DeleteStorage(const std::string& extension_id) {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
87 88
88 // Clear settings when the extension is uninstalled. Leveldb implementations 89 // Clear settings when the extension is uninstalled. Leveldb implementations
89 // will also delete the database from disk when the object is destroyed as a 90 // will also delete the database from disk when the object is destroyed as a
90 // result of being removed from |storage_objs_|. 91 // result of being removed from |storage_objs_|.
91 // 92 //
92 // TODO(kalman): always GetStorage here (rather than only clearing if it 93 // TODO(kalman): always GetStorage here (rather than only clearing if it
93 // exists) since the storage area may have been unloaded, but we still want 94 // exists) since the storage area may have been unloaded, but we still want
94 // to clear the data from disk. 95 // to clear the data from disk.
95 // However, this triggers http://crbug.com/111072. 96 // However, this triggers http://crbug.com/111072.
96 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id); 97 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id);
97 if (maybe_storage == storage_objs_.end()) 98 if (maybe_storage == storage_objs_.end())
98 return; 99 return;
99 maybe_storage->second->Clear(); 100 maybe_storage->second->Clear();
100 storage_objs_.erase(extension_id); 101 storage_objs_.erase(extension_id);
101 } 102 }
102 103
103 std::set<std::string> SettingsBackend::GetKnownExtensionIDs() const { 104 syncer::SyncableService* SyncStorageBackend::GetAsSyncableService() {
105 return this;
106 }
107
108 std::set<std::string> SyncStorageBackend::GetKnownExtensionIDs() const {
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
105 std::set<std::string> result; 110 std::set<std::string> result;
106 111
107 // Storage areas can be in-memory as well as on disk. |storage_objs_| will 112 // Storage areas can be in-memory as well as on disk. |storage_objs_| will
108 // contain all that are in-memory. 113 // contain all that are in-memory.
109 for (StorageObjMap::iterator it = storage_objs_.begin(); 114 for (StorageObjMap::iterator it = storage_objs_.begin();
110 it != storage_objs_.end(); ++it) { 115 it != storage_objs_.end();
116 ++it) {
111 result.insert(it->first); 117 result.insert(it->first);
112 } 118 }
113 119
114 // Leveldb databases are directories inside base_path_. 120 // Leveldb databases are directories inside base_path().
115 base::FileEnumerator extension_dirs( 121 base::FileEnumerator extension_dirs(
116 base_path_, false, base::FileEnumerator::DIRECTORIES); 122 base_path(), false, base::FileEnumerator::DIRECTORIES);
117 while (!extension_dirs.Next().empty()) { 123 while (!extension_dirs.Next().empty()) {
118 base::FilePath extension_dir = extension_dirs.GetInfo().GetName(); 124 base::FilePath extension_dir = extension_dirs.GetInfo().GetName();
119 DCHECK(!extension_dir.IsAbsolute()); 125 DCHECK(!extension_dir.IsAbsolute());
120 // 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.
121 std::string maybe_as_ascii(extension_dir.MaybeAsASCII()); 127 std::string maybe_as_ascii(extension_dir.MaybeAsASCII());
122 if (!maybe_as_ascii.empty()) { 128 if (!maybe_as_ascii.empty()) {
123 result.insert(maybe_as_ascii); 129 result.insert(maybe_as_ascii);
124 } 130 }
125 } 131 }
126 132
127 return result; 133 return result;
128 } 134 }
129 135
130 static void AddAllSyncData( 136 syncer::SyncDataList SyncStorageBackend::GetAllSyncData(syncer::ModelType type)
131 const std::string& extension_id, 137 const {
132 const base::DictionaryValue& src,
133 syncer::ModelType type,
134 syncer::SyncDataList* dst) {
135 for (base::DictionaryValue::Iterator it(src); !it.IsAtEnd(); it.Advance()) {
136 dst->push_back(settings_sync_util::CreateData(
137 extension_id, it.key(), it.value(), type));
138 }
139 }
140
141 syncer::SyncDataList SettingsBackend::GetAllSyncData(
142 syncer::ModelType type) const {
143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
144 // Ignore the type, it's just for sanity checking; assume that whatever base 139 // Ignore the type, it's just for sanity checking; assume that whatever base
145 // path we're constructed with is correct for the sync type. 140 // path we're constructed with is correct for the sync type.
146 DCHECK(type == syncer::EXTENSION_SETTINGS || 141 DCHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS);
147 type == syncer::APP_SETTINGS);
148 142
149 // For all extensions, get all their settings. This has the effect 143 // For all extensions, get all their settings. This has the effect
150 // 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.
151 syncer::SyncDataList all_sync_data; 145 syncer::SyncDataList all_sync_data;
152 std::set<std::string> known_extension_ids(GetKnownExtensionIDs()); 146 std::set<std::string> known_extension_ids(GetKnownExtensionIDs());
153 147
154 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();
155 it != known_extension_ids.end(); ++it) { 149 it != known_extension_ids.end();
156 ValueStore::ReadResult maybe_settings = GetStorage(*it)->Get(); 150 ++it) {
151 ValueStore::ReadResult maybe_settings =
152 GetOrCreateStorageWithSyncData(*it, base::DictionaryValue())->Get();
157 if (maybe_settings->HasError()) { 153 if (maybe_settings->HasError()) {
158 LOG(WARNING) << "Failed to get settings for " << *it << ": " << 154 LOG(WARNING) << "Failed to get settings for " << *it << ": "
159 maybe_settings->error().message; 155 << maybe_settings->error().message;
160 continue; 156 continue;
161 } 157 }
162 AddAllSyncData(*it, maybe_settings->settings(), type, &all_sync_data); 158 AddAllSyncData(*it, maybe_settings->settings(), type, &all_sync_data);
163 } 159 }
164 160
165 return all_sync_data; 161 return all_sync_data;
166 } 162 }
167 163
168 syncer::SyncMergeResult SettingsBackend::MergeDataAndStartSyncing( 164 syncer::SyncMergeResult SyncStorageBackend::MergeDataAndStartSyncing(
169 syncer::ModelType type, 165 syncer::ModelType type,
170 const syncer::SyncDataList& initial_sync_data, 166 const syncer::SyncDataList& initial_sync_data,
171 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 167 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
172 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { 168 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
174 DCHECK_EQ(sync_type_, type); 170 DCHECK_EQ(sync_type_, type);
175 DCHECK(!sync_processor_.get()); 171 DCHECK(!sync_processor_.get());
176 DCHECK(sync_processor.get()); 172 DCHECK(sync_processor.get());
177 DCHECK(sync_error_factory.get()); 173 DCHECK(sync_error_factory.get());
178 174
179 sync_processor_ = sync_processor.Pass(); 175 sync_processor_ = sync_processor.Pass();
180 sync_error_factory_ = sync_error_factory.Pass(); 176 sync_error_factory_ = sync_error_factory.Pass();
181 177
182 // Group the initial sync data by extension id. 178 // Group the initial sync data by extension id.
183 std::map<std::string, linked_ptr<base::DictionaryValue> > grouped_sync_data; 179 std::map<std::string, linked_ptr<base::DictionaryValue> > grouped_sync_data;
184 for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin(); 180 for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
185 it != initial_sync_data.end(); ++it) { 181 it != initial_sync_data.end();
182 ++it) {
186 SettingSyncData data(*it); 183 SettingSyncData data(*it);
187 linked_ptr<base::DictionaryValue> sync_data = 184 linked_ptr<base::DictionaryValue> sync_data =
188 grouped_sync_data[data.extension_id()]; 185 grouped_sync_data[data.extension_id()];
189 if (!sync_data.get()) { 186 if (!sync_data.get()) {
190 sync_data = linked_ptr<base::DictionaryValue>( 187 sync_data =
191 new base::DictionaryValue()); 188 linked_ptr<base::DictionaryValue>(new base::DictionaryValue());
192 grouped_sync_data[data.extension_id()] = sync_data; 189 grouped_sync_data[data.extension_id()] = sync_data;
193 } 190 }
194 DCHECK(!sync_data->HasKey(data.key())) << 191 DCHECK(!sync_data->HasKey(data.key())) << "Duplicate settings for "
195 "Duplicate settings for " << data.extension_id() << "/" << data.key(); 192 << data.extension_id() << "/"
193 << data.key();
196 sync_data->SetWithoutPathExpansion(data.key(), data.value().DeepCopy()); 194 sync_data->SetWithoutPathExpansion(data.key(), data.value().DeepCopy());
197 } 195 }
198 196
199 // Start syncing all existing storage areas. Any storage areas created in 197 // Start syncing all existing storage areas. Any storage areas created in
200 // the future will start being synced as part of the creation process. 198 // the future will start being synced as part of the creation process.
201 for (StorageObjMap::iterator it = storage_objs_.begin(); 199 for (StorageObjMap::iterator it = storage_objs_.begin();
202 it != storage_objs_.end(); ++it) { 200 it != storage_objs_.end();
201 ++it) {
203 std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator 202 std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator
204 maybe_sync_data = grouped_sync_data.find(it->first); 203 maybe_sync_data = grouped_sync_data.find(it->first);
205 syncer::SyncError error; 204 syncer::SyncError error;
206 if (maybe_sync_data != grouped_sync_data.end()) { 205 if (maybe_sync_data != grouped_sync_data.end()) {
207 error = it->second->StartSyncing( 206 error = it->second->StartSyncing(
208 *maybe_sync_data->second, 207 *maybe_sync_data->second,
209 CreateSettingsSyncProcessor(it->first).Pass()); 208 CreateSettingsSyncProcessor(it->first).Pass());
210 grouped_sync_data.erase(it->first); 209 grouped_sync_data.erase(it->first);
211 } else { 210 } else {
212 base::DictionaryValue empty; 211 base::DictionaryValue empty;
213 error = it->second->StartSyncing( 212 error = it->second->StartSyncing(
214 empty, 213 empty, CreateSettingsSyncProcessor(it->first).Pass());
215 CreateSettingsSyncProcessor(it->first).Pass());
216 } 214 }
217 if (error.IsSet()) 215 if (error.IsSet())
218 it->second->StopSyncing(); 216 it->second->StopSyncing();
219 } 217 }
220 218
221 // Eagerly create and init the rest of the storage areas that have sync data. 219 // Eagerly create and init the rest of the storage areas that have sync data.
222 // Under normal circumstances (i.e. not first-time sync) this will be all of 220 // Under normal circumstances (i.e. not first-time sync) this will be all of
223 // them. 221 // them.
224 for (std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator it = 222 for (std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator it =
225 grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) { 223 grouped_sync_data.begin();
224 it != grouped_sync_data.end();
225 ++it) {
226 GetOrCreateStorageWithSyncData(it->first, *it->second); 226 GetOrCreateStorageWithSyncData(it->first, *it->second);
227 } 227 }
228 228
229 return syncer::SyncMergeResult(type); 229 return syncer::SyncMergeResult(type);
230 } 230 }
231 231
232 syncer::SyncError SettingsBackend::ProcessSyncChanges( 232 syncer::SyncError SyncStorageBackend::ProcessSyncChanges(
233 const tracked_objects::Location& from_here, 233 const tracked_objects::Location& from_here,
234 const syncer::SyncChangeList& sync_changes) { 234 const syncer::SyncChangeList& sync_changes) {
235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
236 DCHECK(sync_processor_.get()); 236 DCHECK(sync_processor_.get());
237 237
238 // Group changes by extension, to pass all changes in a single method call. 238 // Group changes by extension, to pass all changes in a single method call.
239 std::map<std::string, SettingSyncDataList> grouped_sync_data; 239 std::map<std::string, SettingSyncDataList> grouped_sync_data;
240 for (syncer::SyncChangeList::const_iterator it = sync_changes.begin(); 240 for (syncer::SyncChangeList::const_iterator it = sync_changes.begin();
241 it != sync_changes.end(); ++it) { 241 it != sync_changes.end();
242 ++it) {
242 SettingSyncData data(*it); 243 SettingSyncData data(*it);
243 grouped_sync_data[data.extension_id()].push_back(data); 244 grouped_sync_data[data.extension_id()].push_back(data);
244 } 245 }
245 246
246 // Create any storage areas that don't exist yet but have sync data. 247 // Create any storage areas that don't exist yet but have sync data.
247 base::DictionaryValue empty; 248 base::DictionaryValue empty;
248 for (std::map<std::string, SettingSyncDataList>::iterator 249 for (std::map<std::string, SettingSyncDataList>::iterator it =
249 it = grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) { 250 grouped_sync_data.begin();
251 it != grouped_sync_data.end();
252 ++it) {
250 SyncableSettingsStorage* storage = 253 SyncableSettingsStorage* storage =
251 GetOrCreateStorageWithSyncData(it->first, empty); 254 GetOrCreateStorageWithSyncData(it->first, empty);
252 syncer::SyncError error = storage->ProcessSyncChanges(it->second); 255 syncer::SyncError error = storage->ProcessSyncChanges(it->second);
253 if (error.IsSet()) 256 if (error.IsSet())
254 storage->StopSyncing(); 257 storage->StopSyncing();
255 } 258 }
256 259
257 return syncer::SyncError(); 260 return syncer::SyncError();
258 } 261 }
259 262
260 void SettingsBackend::StopSyncing(syncer::ModelType type) { 263 void SyncStorageBackend::StopSyncing(syncer::ModelType type) {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
262 DCHECK(type == syncer::EXTENSION_SETTINGS || 265 DCHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS);
263 type == syncer::APP_SETTINGS);
264 DCHECK_EQ(sync_type_, type); 266 DCHECK_EQ(sync_type_, type);
265 267
266 for (StorageObjMap::iterator it = storage_objs_.begin(); 268 for (StorageObjMap::iterator it = storage_objs_.begin();
267 it != storage_objs_.end(); ++it) { 269 it != storage_objs_.end();
270 ++it) {
268 // Some storage areas may have already stopped syncing if they had areas 271 // Some storage areas may have already stopped syncing if they had areas
269 // and syncing was disabled, but StopSyncing is safe to call multiple times. 272 // and syncing was disabled, but StopSyncing is safe to call multiple times.
270 it->second->StopSyncing(); 273 it->second->StopSyncing();
271 } 274 }
272 275
273 sync_processor_.reset(); 276 sync_processor_.reset();
274 sync_error_factory_.reset(); 277 sync_error_factory_.reset();
275 } 278 }
276 279
277 scoped_ptr<SettingsSyncProcessor> SettingsBackend::CreateSettingsSyncProcessor( 280 scoped_ptr<SettingsSyncProcessor>
278 const std::string& extension_id) const { 281 SyncStorageBackend::CreateSettingsSyncProcessor(const std::string& extension_id)
282 const {
279 CHECK(sync_processor_.get()); 283 CHECK(sync_processor_.get());
280 return scoped_ptr<SettingsSyncProcessor>( 284 return scoped_ptr<SettingsSyncProcessor>(new SettingsSyncProcessor(
281 new SettingsSyncProcessor(extension_id, 285 extension_id, sync_type_, sync_processor_.get()));
282 sync_type_,
283 sync_processor_.get()));
284 } 286 }
285 287
286 } // namespace extensions 288 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698