OLD | NEW |
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/syncable_settings_storage.h" | 5 #include "chrome/browser/extensions/api/storage/syncable_settings_storage.h" |
6 | 6 |
7 #include "base/strings/stringprintf.h" | 7 #include "base/strings/stringprintf.h" |
8 #include "chrome/browser/extensions/api/storage/settings_sync_processor.h" | 8 #include "chrome/browser/extensions/api/storage/settings_sync_processor.h" |
9 #include "chrome/browser/extensions/api/storage/settings_sync_util.h" | 9 #include "chrome/browser/extensions/api/storage/settings_sync_util.h" |
10 #include "content/public/browser/browser_thread.h" | 10 #include "content/public/browser/browser_thread.h" |
11 #include "extensions/browser/api/storage/settings_namespace.h" | 11 #include "extensions/browser/api/storage/settings_namespace.h" |
12 #include "sync/api/sync_data.h" | 12 #include "sync/api/sync_data.h" |
13 #include "sync/protocol/extension_setting_specifics.pb.h" | 13 #include "sync/protocol/extension_setting_specifics.pb.h" |
14 | 14 |
| 15 using content::BrowserThread; |
| 16 |
15 namespace extensions { | 17 namespace extensions { |
16 | 18 |
17 using content::BrowserThread; | |
18 | |
19 SyncableSettingsStorage::SyncableSettingsStorage( | 19 SyncableSettingsStorage::SyncableSettingsStorage( |
20 const scoped_refptr<ObserverListThreadSafe<SettingsObserver> >& | 20 const scoped_refptr<ObserverListThreadSafe<SettingsObserver> >& |
21 observers, | 21 observers, |
22 const std::string& extension_id, | 22 const std::string& extension_id, |
23 ValueStore* delegate, | 23 ValueStore* delegate, |
24 syncer::ModelType sync_type, | 24 syncer::ModelType sync_type, |
25 const syncer::SyncableService::StartSyncFlare& flare) | 25 const syncer::SyncableService::StartSyncFlare& flare) |
26 : observers_(observers), | 26 : observers_(observers), |
27 extension_id_(extension_id), | 27 extension_id_(extension_id), |
28 delegate_(delegate), | 28 delegate_(delegate), |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 // Tell sync to try and start soon, because syncable changes to sync_type_ | 157 // Tell sync to try and start soon, because syncable changes to sync_type_ |
158 // have started happening. This will cause sync to call us back | 158 // have started happening. This will cause sync to call us back |
159 // asynchronously via StartSyncing(...) as soon as possible. | 159 // asynchronously via StartSyncing(...) as soon as possible. |
160 flare_.Run(sync_type_); | 160 flare_.Run(sync_type_); |
161 } | 161 } |
162 } | 162 } |
163 | 163 |
164 // Sync-related methods. | 164 // Sync-related methods. |
165 | 165 |
166 syncer::SyncError SyncableSettingsStorage::StartSyncing( | 166 syncer::SyncError SyncableSettingsStorage::StartSyncing( |
167 const base::DictionaryValue& sync_state, | 167 scoped_ptr<base::DictionaryValue> sync_state, |
168 scoped_ptr<SettingsSyncProcessor> sync_processor) { | 168 scoped_ptr<SettingsSyncProcessor> sync_processor) { |
169 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 169 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 170 DCHECK(sync_state); |
170 DCHECK(!sync_processor_.get()); | 171 DCHECK(!sync_processor_.get()); |
171 | 172 |
172 sync_processor_ = sync_processor.Pass(); | 173 sync_processor_ = sync_processor.Pass(); |
173 sync_processor_->Init(sync_state); | 174 sync_processor_->Init(*sync_state); |
174 | 175 |
175 ReadResult maybe_settings = delegate_->Get(); | 176 ReadResult maybe_settings = delegate_->Get(); |
176 if (maybe_settings->HasError()) { | 177 if (maybe_settings->HasError()) { |
177 return syncer::SyncError( | 178 return syncer::SyncError( |
178 FROM_HERE, | 179 FROM_HERE, syncer::SyncError::DATATYPE_ERROR, |
179 syncer::SyncError::DATATYPE_ERROR, | |
180 base::StringPrintf("Failed to get settings: %s", | 180 base::StringPrintf("Failed to get settings: %s", |
181 maybe_settings->error().message.c_str()), | 181 maybe_settings->error().message.c_str()), |
182 sync_processor_->type()); | 182 sync_processor_->type()); |
183 } | 183 } |
184 | 184 |
185 const base::DictionaryValue& settings = maybe_settings->settings(); | 185 scoped_ptr<base::DictionaryValue> current_settings = |
186 return sync_state.empty() ? | 186 maybe_settings->PassSettings(); |
187 SendLocalSettingsToSync(settings) : | 187 return sync_state->empty() ? SendLocalSettingsToSync(current_settings.Pass()) |
188 OverwriteLocalSettingsWithSync(sync_state, settings); | 188 : OverwriteLocalSettingsWithSync( |
| 189 sync_state.Pass(), current_settings.Pass()); |
189 } | 190 } |
190 | 191 |
191 syncer::SyncError SyncableSettingsStorage::SendLocalSettingsToSync( | 192 syncer::SyncError SyncableSettingsStorage::SendLocalSettingsToSync( |
192 const base::DictionaryValue& settings) { | 193 scoped_ptr<base::DictionaryValue> local_state) { |
193 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 194 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
194 | 195 |
| 196 if (local_state->empty()) |
| 197 return syncer::SyncError(); |
| 198 |
| 199 // Transform the current settings into a list of sync changes. |
195 ValueStoreChangeList changes; | 200 ValueStoreChangeList changes; |
196 for (base::DictionaryValue::Iterator i(settings); !i.IsAtEnd(); i.Advance()) { | 201 while (!local_state->empty()) { |
197 changes.push_back(ValueStoreChange(i.key(), NULL, i.value().DeepCopy())); | 202 // It's not possible to iterate over a DictionaryValue and modify it at the |
| 203 // same time, so hack around that restriction. |
| 204 std::string key = base::DictionaryValue::Iterator(*local_state).key(); |
| 205 scoped_ptr<base::Value> value; |
| 206 local_state->RemoveWithoutPathExpansion(key, &value); |
| 207 changes.push_back(ValueStoreChange(key, nullptr, value.release())); |
198 } | 208 } |
199 | 209 |
200 if (changes.empty()) | |
201 return syncer::SyncError(); | |
202 | |
203 syncer::SyncError error = sync_processor_->SendChanges(changes); | 210 syncer::SyncError error = sync_processor_->SendChanges(changes); |
204 if (error.IsSet()) | 211 if (error.IsSet()) |
205 StopSyncing(); | 212 StopSyncing(); |
206 | |
207 return error; | 213 return error; |
208 } | 214 } |
209 | 215 |
210 syncer::SyncError SyncableSettingsStorage::OverwriteLocalSettingsWithSync( | 216 syncer::SyncError SyncableSettingsStorage::OverwriteLocalSettingsWithSync( |
211 const base::DictionaryValue& sync_state, | 217 scoped_ptr<base::DictionaryValue> sync_state, |
212 const base::DictionaryValue& settings) { | 218 scoped_ptr<base::DictionaryValue> local_state) { |
213 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 219 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
214 // Treat this as a list of changes to sync and use ProcessSyncChanges. | 220 // This is implemented by building up a list of sync changes then sending |
215 // This gives notifications etc for free. | 221 // those to ProcessSyncChanges. This generates events like onStorageChanged. |
216 scoped_ptr<base::DictionaryValue> new_sync_state(sync_state.DeepCopy()); | 222 scoped_ptr<SettingSyncDataList> changes(new SettingSyncDataList()); |
217 | 223 |
218 SettingSyncDataList changes; | 224 for (base::DictionaryValue::Iterator it(*local_state); !it.IsAtEnd(); |
219 for (base::DictionaryValue::Iterator it(settings); | 225 it.Advance()) { |
220 !it.IsAtEnd(); it.Advance()) { | |
221 scoped_ptr<base::Value> sync_value; | 226 scoped_ptr<base::Value> sync_value; |
222 if (new_sync_state->RemoveWithoutPathExpansion(it.key(), &sync_value)) { | 227 if (sync_state->RemoveWithoutPathExpansion(it.key(), &sync_value)) { |
223 if (sync_value->Equals(&it.value())) { | 228 if (sync_value->Equals(&it.value())) { |
224 // Sync and local values are the same, no changes to send. | 229 // Sync and local values are the same, no changes to send. |
225 } else { | 230 } else { |
226 // Sync value is different, update local setting with new value. | 231 // Sync value is different, update local setting with new value. |
227 changes.push_back( | 232 changes->push_back( |
228 SettingSyncData( | 233 new SettingSyncData(syncer::SyncChange::ACTION_UPDATE, |
229 syncer::SyncChange::ACTION_UPDATE, | 234 extension_id_, it.key(), sync_value.Pass())); |
230 extension_id_, | |
231 it.key(), | |
232 sync_value.Pass())); | |
233 } | 235 } |
234 } else { | 236 } else { |
235 // Not synced, delete local setting. | 237 // Not synced, delete local setting. |
236 changes.push_back( | 238 changes->push_back(new SettingSyncData( |
237 SettingSyncData( | 239 syncer::SyncChange::ACTION_DELETE, extension_id_, it.key(), |
238 syncer::SyncChange::ACTION_DELETE, | 240 scoped_ptr<base::Value>(new base::DictionaryValue()))); |
239 extension_id_, | |
240 it.key(), | |
241 scoped_ptr<base::Value>(new base::DictionaryValue()))); | |
242 } | 241 } |
243 } | 242 } |
244 | 243 |
245 // Add all new settings to local settings. | 244 // Add all new settings to local settings. |
246 while (!new_sync_state->empty()) { | 245 while (!sync_state->empty()) { |
247 base::DictionaryValue::Iterator first_entry(*new_sync_state); | 246 // It's not possible to iterate over a DictionaryValue and modify it at the |
248 std::string key = first_entry.key(); | 247 // same time, so hack around that restriction. |
| 248 std::string key = base::DictionaryValue::Iterator(*sync_state).key(); |
249 scoped_ptr<base::Value> value; | 249 scoped_ptr<base::Value> value; |
250 CHECK(new_sync_state->RemoveWithoutPathExpansion(key, &value)); | 250 CHECK(sync_state->RemoveWithoutPathExpansion(key, &value)); |
251 changes.push_back( | 251 changes->push_back(new SettingSyncData(syncer::SyncChange::ACTION_ADD, |
252 SettingSyncData( | 252 extension_id_, key, value.Pass())); |
253 syncer::SyncChange::ACTION_ADD, | |
254 extension_id_, | |
255 key, | |
256 value.Pass())); | |
257 } | 253 } |
258 | 254 |
259 if (changes.empty()) | 255 if (changes->empty()) |
260 return syncer::SyncError(); | 256 return syncer::SyncError(); |
261 | 257 return ProcessSyncChanges(changes.Pass()); |
262 return ProcessSyncChanges(changes); | |
263 } | 258 } |
264 | 259 |
265 void SyncableSettingsStorage::StopSyncing() { | 260 void SyncableSettingsStorage::StopSyncing() { |
266 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 261 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
267 sync_processor_.reset(); | 262 sync_processor_.reset(); |
268 } | 263 } |
269 | 264 |
270 syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges( | 265 syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges( |
271 const SettingSyncDataList& sync_changes) { | 266 scoped_ptr<SettingSyncDataList> sync_changes) { |
272 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 267 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
273 DCHECK(!sync_changes.empty()) << "No sync changes for " << extension_id_; | 268 DCHECK(!sync_changes->empty()) << "No sync changes for " << extension_id_; |
274 | 269 |
275 if (!sync_processor_.get()) { | 270 if (!sync_processor_.get()) { |
276 return syncer::SyncError( | 271 return syncer::SyncError( |
277 FROM_HERE, | 272 FROM_HERE, |
278 syncer::SyncError::DATATYPE_ERROR, | 273 syncer::SyncError::DATATYPE_ERROR, |
279 std::string("Sync is inactive for ") + extension_id_, | 274 std::string("Sync is inactive for ") + extension_id_, |
280 syncer::UNSPECIFIED); | 275 syncer::UNSPECIFIED); |
281 } | 276 } |
282 | 277 |
283 std::vector<syncer::SyncError> errors; | 278 std::vector<syncer::SyncError> errors; |
284 ValueStoreChangeList changes; | 279 ValueStoreChangeList changes; |
285 | 280 |
286 for (SettingSyncDataList::const_iterator it = sync_changes.begin(); | 281 for (SettingSyncDataList::iterator it = sync_changes->begin(); |
287 it != sync_changes.end(); ++it) { | 282 it != sync_changes->end(); ++it) { |
288 DCHECK_EQ(extension_id_, it->extension_id()); | 283 DCHECK_EQ(extension_id_, (*it)->extension_id()); |
289 | 284 const std::string& key = (*it)->key(); |
290 const std::string& key = it->key(); | 285 scoped_ptr<base::Value> change_value = (*it)->PassValue(); |
291 const base::Value& value = it->value(); | |
292 | 286 |
293 scoped_ptr<base::Value> current_value; | 287 scoped_ptr<base::Value> current_value; |
294 { | 288 { |
295 ReadResult maybe_settings = Get(it->key()); | 289 ReadResult maybe_settings = Get(key); |
296 if (maybe_settings->HasError()) { | 290 if (maybe_settings->HasError()) { |
297 errors.push_back(syncer::SyncError( | 291 errors.push_back(syncer::SyncError( |
298 FROM_HERE, | 292 FROM_HERE, |
299 syncer::SyncError::DATATYPE_ERROR, | 293 syncer::SyncError::DATATYPE_ERROR, |
300 base::StringPrintf("Error getting current sync state for %s/%s: %s", | 294 base::StringPrintf("Error getting current sync state for %s/%s: %s", |
301 extension_id_.c_str(), key.c_str(), | 295 extension_id_.c_str(), key.c_str(), |
302 maybe_settings->error().message.c_str()), | 296 maybe_settings->error().message.c_str()), |
303 sync_processor_->type())); | 297 sync_processor_->type())); |
304 continue; | 298 continue; |
305 } | 299 } |
306 maybe_settings->settings().RemoveWithoutPathExpansion(key, | 300 maybe_settings->settings().RemoveWithoutPathExpansion(key, |
307 ¤t_value); | 301 ¤t_value); |
308 } | 302 } |
309 | 303 |
310 syncer::SyncError error; | 304 syncer::SyncError error; |
311 | 305 |
312 switch (it->change_type()) { | 306 switch ((*it)->change_type()) { |
313 case syncer::SyncChange::ACTION_ADD: | 307 case syncer::SyncChange::ACTION_ADD: |
314 if (!current_value.get()) { | 308 if (!current_value.get()) { |
315 error = OnSyncAdd(key, value.DeepCopy(), &changes); | 309 error = OnSyncAdd(key, change_value.release(), &changes); |
316 } else { | 310 } else { |
317 // Already a value; hopefully a local change has beaten sync in a | 311 // Already a value; hopefully a local change has beaten sync in a |
318 // race and it's not a bug, so pretend it's an update. | 312 // race and change's not a bug, so pretend change's an update. |
319 LOG(WARNING) << "Got add from sync for existing setting " << | 313 LOG(WARNING) << "Got add from sync for existing setting " << |
320 extension_id_ << "/" << key; | 314 extension_id_ << "/" << key; |
321 error = OnSyncUpdate( | 315 error = OnSyncUpdate(key, current_value.release(), |
322 key, current_value.release(), value.DeepCopy(), &changes); | 316 change_value.release(), &changes); |
323 } | 317 } |
324 break; | 318 break; |
325 | 319 |
326 case syncer::SyncChange::ACTION_UPDATE: | 320 case syncer::SyncChange::ACTION_UPDATE: |
327 if (current_value.get()) { | 321 if (current_value.get()) { |
328 error = OnSyncUpdate( | 322 error = OnSyncUpdate(key, current_value.release(), |
329 key, current_value.release(), value.DeepCopy(), &changes); | 323 change_value.release(), &changes); |
330 } else { | 324 } else { |
331 // Similarly, pretend it's an add. | 325 // Similarly, pretend change's an add. |
332 LOG(WARNING) << "Got update from sync for nonexistent setting" << | 326 LOG(WARNING) << "Got update from sync for nonexistent setting" << |
333 extension_id_ << "/" << key; | 327 extension_id_ << "/" << key; |
334 error = OnSyncAdd(key, value.DeepCopy(), &changes); | 328 error = OnSyncAdd(key, change_value.release(), &changes); |
335 } | 329 } |
336 break; | 330 break; |
337 | 331 |
338 case syncer::SyncChange::ACTION_DELETE: | 332 case syncer::SyncChange::ACTION_DELETE: |
339 if (current_value.get()) { | 333 if (current_value.get()) { |
340 error = OnSyncDelete(key, current_value.release(), &changes); | 334 error = OnSyncDelete(key, current_value.release(), &changes); |
341 } else { | 335 } else { |
342 // Similarly, ignore it. | 336 // Similarly, ignore change. |
343 LOG(WARNING) << "Got delete from sync for nonexistent setting " << | 337 LOG(WARNING) << "Got delete from sync for nonexistent setting " << |
344 extension_id_ << "/" << key; | 338 extension_id_ << "/" << key; |
345 } | 339 } |
346 break; | 340 break; |
347 | 341 |
348 default: | 342 default: |
349 NOTREACHED(); | 343 NOTREACHED(); |
350 } | 344 } |
351 | 345 |
352 if (error.IsSet()) { | 346 if (error.IsSet()) { |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 syncer::SyncError::DATATYPE_ERROR, | 408 syncer::SyncError::DATATYPE_ERROR, |
415 base::StringPrintf("Error pushing sync remove to local settings: %s", | 409 base::StringPrintf("Error pushing sync remove to local settings: %s", |
416 result->error().message.c_str()), | 410 result->error().message.c_str()), |
417 sync_processor_->type()); | 411 sync_processor_->type()); |
418 } | 412 } |
419 changes->push_back(ValueStoreChange(key, old_value, NULL)); | 413 changes->push_back(ValueStoreChange(key, old_value, NULL)); |
420 return syncer::SyncError(); | 414 return syncer::SyncError(); |
421 } | 415 } |
422 | 416 |
423 } // namespace extensions | 417 } // namespace extensions |
OLD | NEW |