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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/api/storage/syncable_settings_storage.h" 6 7 #include "chrome/browser/extensions/api/storage/settings_namespace.h" 8 #include "chrome/browser/extensions/api/storage/settings_sync_processor.h" 9 #include "chrome/browser/extensions/api/storage/settings_sync_util.h" 10 #include "content/public/browser/browser_thread.h" 11 #include "sync/api/sync_data.h" 12 #include "sync/protocol/extension_setting_specifics.pb.h" 13 14 namespace extensions { 15 16 using content::BrowserThread; 17 18 SyncableSettingsStorage::SyncableSettingsStorage( 19 const scoped_refptr<ObserverListThreadSafe<SettingsObserver> >& 20 observers, 21 const std::string& extension_id, 22 ValueStore* delegate) 23 : observers_(observers), 24 extension_id_(extension_id), 25 delegate_(delegate) { 26 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 27 } 28 29 SyncableSettingsStorage::~SyncableSettingsStorage() { 30 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 31 } 32 33 size_t SyncableSettingsStorage::GetBytesInUse(const std::string& key) { 34 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 35 return delegate_->GetBytesInUse(key); 36 } 37 38 size_t SyncableSettingsStorage::GetBytesInUse( 39 const std::vector<std::string>& keys) { 40 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 41 return delegate_->GetBytesInUse(keys); 42 } 43 44 size_t SyncableSettingsStorage::GetBytesInUse() { 45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 46 return delegate_->GetBytesInUse(); 47 } 48 49 ValueStore::ReadResult SyncableSettingsStorage::Get( 50 const std::string& key) { 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 52 return delegate_->Get(key); 53 } 54 55 ValueStore::ReadResult SyncableSettingsStorage::Get( 56 const std::vector<std::string>& keys) { 57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 58 return delegate_->Get(keys); 59 } 60 61 ValueStore::ReadResult SyncableSettingsStorage::Get() { 62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 63 return delegate_->Get(); 64 } 65 66 ValueStore::WriteResult SyncableSettingsStorage::Set( 67 WriteOptions options, const std::string& key, const Value& value) { 68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 69 WriteResult result = delegate_->Set(options, key, value); 70 if (result->HasError()) { 71 return result.Pass(); 72 } 73 SyncResultIfEnabled(result); 74 return result.Pass(); 75 } 76 77 ValueStore::WriteResult SyncableSettingsStorage::Set( 78 WriteOptions options, const base::DictionaryValue& values) { 79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 80 WriteResult result = delegate_->Set(options, values); 81 if (result->HasError()) { 82 return result.Pass(); 83 } 84 SyncResultIfEnabled(result); 85 return result.Pass(); 86 } 87 88 ValueStore::WriteResult SyncableSettingsStorage::Remove( 89 const std::string& key) { 90 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 91 WriteResult result = delegate_->Remove(key); 92 if (result->HasError()) { 93 return result.Pass(); 94 } 95 SyncResultIfEnabled(result); 96 return result.Pass(); 97 } 98 99 ValueStore::WriteResult SyncableSettingsStorage::Remove( 100 const std::vector<std::string>& keys) { 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 102 WriteResult result = delegate_->Remove(keys); 103 if (result->HasError()) { 104 return result.Pass(); 105 } 106 SyncResultIfEnabled(result); 107 return result.Pass(); 108 } 109 110 ValueStore::WriteResult SyncableSettingsStorage::Clear() { 111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 112 WriteResult result = delegate_->Clear(); 113 if (result->HasError()) { 114 return result.Pass(); 115 } 116 SyncResultIfEnabled(result); 117 return result.Pass(); 118 } 119 120 void SyncableSettingsStorage::SyncResultIfEnabled( 121 const ValueStore::WriteResult& result) { 122 if (sync_processor_.get() && !result->changes().empty()) { 123 syncer::SyncError error = sync_processor_->SendChanges(result->changes()); 124 if (error.IsSet()) 125 StopSyncing(); 126 } 127 } 128 129 // Sync-related methods. 130 131 syncer::SyncError SyncableSettingsStorage::StartSyncing( 132 const base::DictionaryValue& sync_state, 133 scoped_ptr<SettingsSyncProcessor> sync_processor) { 134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 135 DCHECK(!sync_processor_.get()); 136 137 sync_processor_ = sync_processor.Pass(); 138 sync_processor_->Init(sync_state); 139 140 ReadResult maybe_settings = delegate_->Get(); 141 if (maybe_settings->HasError()) { 142 return syncer::SyncError( 143 FROM_HERE, 144 syncer::SyncError::DATATYPE_ERROR, 145 std::string("Failed to get settings: ") + maybe_settings->error(), 146 sync_processor_->type()); 147 } 148 149 const base::DictionaryValue& settings = *maybe_settings->settings().get(); 150 if (sync_state.empty()) 151 return SendLocalSettingsToSync(settings); 152 else 153 return OverwriteLocalSettingsWithSync(sync_state, settings); 154 } 155 156 syncer::SyncError SyncableSettingsStorage::SendLocalSettingsToSync( 157 const base::DictionaryValue& settings) { 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 159 160 ValueStoreChangeList changes; 161 for (base::DictionaryValue::Iterator i(settings); !i.IsAtEnd(); i.Advance()) { 162 changes.push_back(ValueStoreChange(i.key(), NULL, i.value().DeepCopy())); 163 } 164 165 if (changes.empty()) 166 return syncer::SyncError(); 167 168 syncer::SyncError error = sync_processor_->SendChanges(changes); 169 if (error.IsSet()) 170 StopSyncing(); 171 172 return error; 173 } 174 175 syncer::SyncError SyncableSettingsStorage::OverwriteLocalSettingsWithSync( 176 const base::DictionaryValue& sync_state, 177 const base::DictionaryValue& settings) { 178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 179 // Treat this as a list of changes to sync and use ProcessSyncChanges. 180 // This gives notifications etc for free. 181 scoped_ptr<base::DictionaryValue> new_sync_state(sync_state.DeepCopy()); 182 183 SettingSyncDataList changes; 184 for (base::DictionaryValue::Iterator it(settings); !it.IsAtEnd(); it.Advance()) { 185 scoped_ptr<Value> sync_value; 186 if (new_sync_state->RemoveWithoutPathExpansion(it.key(), &sync_value)) { 187 if (sync_value->Equals(&it.value())) { 188 // Sync and local values are the same, no changes to send. 189 } else { 190 // Sync value is different, update local setting with new value. 191 changes.push_back( 192 SettingSyncData( 193 syncer::SyncChange::ACTION_UPDATE, 194 extension_id_, 195 it.key(), 196 sync_value.Pass())); 197 } 198 } else { 199 // Not synced, delete local setting. 200 changes.push_back( 201 SettingSyncData( 202 syncer::SyncChange::ACTION_DELETE, 203 extension_id_, 204 it.key(), 205 scoped_ptr<Value>(new base::DictionaryValue()))); 206 } 207 } 208 209 // Add all new settings to local settings. 210 while (!new_sync_state->empty()) { 211 base::DictionaryValue::Iterator first_entry(*new_sync_state); 212 std::string key = first_entry.key(); 213 scoped_ptr<Value> value; 214 CHECK(new_sync_state->RemoveWithoutPathExpansion(key, &value)); 215 changes.push_back( 216 SettingSyncData( 217 syncer::SyncChange::ACTION_ADD, 218 extension_id_, 219 key, 220 value.Pass())); 221 } 222 223 if (changes.empty()) 224 return syncer::SyncError(); 225 226 return ProcessSyncChanges(changes); 227 } 228 229 void SyncableSettingsStorage::StopSyncing() { 230 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 231 sync_processor_.reset(); 232 } 233 234 syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges( 235 const SettingSyncDataList& sync_changes) { 236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 237 DCHECK(!sync_changes.empty()) << "No sync changes for " << extension_id_; 238 239 if (!sync_processor_.get()) { 240 return syncer::SyncError( 241 FROM_HERE, 242 syncer::SyncError::DATATYPE_ERROR, 243 std::string("Sync is inactive for ") + extension_id_, 244 syncer::UNSPECIFIED); 245 } 246 247 std::vector<syncer::SyncError> errors; 248 ValueStoreChangeList changes; 249 250 for (SettingSyncDataList::const_iterator it = sync_changes.begin(); 251 it != sync_changes.end(); ++it) { 252 DCHECK_EQ(extension_id_, it->extension_id()); 253 254 const std::string& key = it->key(); 255 const Value& value = it->value(); 256 257 scoped_ptr<Value> current_value; 258 { 259 ReadResult maybe_settings = Get(it->key()); 260 if (maybe_settings->HasError()) { 261 errors.push_back(syncer::SyncError( 262 FROM_HERE, 263 syncer::SyncError::DATATYPE_ERROR, 264 std::string("Error getting current sync state for ") + 265 extension_id_ + "/" + key + ": " + maybe_settings->error(), 266 sync_processor_->type())); 267 continue; 268 } 269 Value* value = NULL; 270 if (maybe_settings->settings()->GetWithoutPathExpansion(key, &value)) { 271 current_value.reset(value->DeepCopy()); 272 } 273 } 274 275 syncer::SyncError error; 276 277 switch (it->change_type()) { 278 case syncer::SyncChange::ACTION_ADD: 279 if (!current_value.get()) { 280 error = OnSyncAdd(key, value.DeepCopy(), &changes); 281 } else { 282 // Already a value; hopefully a local change has beaten sync in a 283 // race and it's not a bug, so pretend it's an update. 284 LOG(WARNING) << "Got add from sync for existing setting " << 285 extension_id_ << "/" << key; 286 error = OnSyncUpdate( 287 key, current_value.release(), value.DeepCopy(), &changes); 288 } 289 break; 290 291 case syncer::SyncChange::ACTION_UPDATE: 292 if (current_value.get()) { 293 error = OnSyncUpdate( 294 key, current_value.release(), value.DeepCopy(), &changes); 295 } else { 296 // Similarly, pretend it's an add. 297 LOG(WARNING) << "Got update from sync for nonexistent setting" << 298 extension_id_ << "/" << key; 299 error = OnSyncAdd(key, value.DeepCopy(), &changes); 300 } 301 break; 302 303 case syncer::SyncChange::ACTION_DELETE: 304 if (current_value.get()) { 305 error = OnSyncDelete(key, current_value.release(), &changes); 306 } else { 307 // Similarly, ignore it. 308 LOG(WARNING) << "Got delete from sync for nonexistent setting " << 309 extension_id_ << "/" << key; 310 } 311 break; 312 313 default: 314 NOTREACHED(); 315 } 316 317 if (error.IsSet()) { 318 errors.push_back(error); 319 } 320 } 321 322 sync_processor_->NotifyChanges(changes); 323 324 observers_->Notify( 325 &SettingsObserver::OnSettingsChanged, 326 extension_id_, 327 settings_namespace::SYNC, 328 ValueStoreChange::ToJson(changes)); 329 330 // TODO(kalman): Something sensible with multiple errors. 331 return errors.empty() ? syncer::SyncError() : errors[0]; 332 } 333 334 syncer::SyncError SyncableSettingsStorage::OnSyncAdd( 335 const std::string& key, 336 Value* new_value, 337 ValueStoreChangeList* changes) { 338 DCHECK(new_value); 339 WriteResult result = delegate_->Set(IGNORE_QUOTA, key, *new_value); 340 if (result->HasError()) { 341 return syncer::SyncError( 342 FROM_HERE, 343 syncer::SyncError::DATATYPE_ERROR, 344 std::string("Error pushing sync add to local settings: ") + 345 result->error(), 346 sync_processor_->type()); 347 } 348 changes->push_back(ValueStoreChange(key, NULL, new_value)); 349 return syncer::SyncError(); 350 } 351 352 syncer::SyncError SyncableSettingsStorage::OnSyncUpdate( 353 const std::string& key, 354 Value* old_value, 355 Value* new_value, 356 ValueStoreChangeList* changes) { 357 DCHECK(old_value); 358 DCHECK(new_value); 359 WriteResult result = delegate_->Set(IGNORE_QUOTA, key, *new_value); 360 if (result->HasError()) { 361 return syncer::SyncError( 362 FROM_HERE, 363 syncer::SyncError::DATATYPE_ERROR, 364 std::string("Error pushing sync update to local settings: ") + 365 result->error(), 366 sync_processor_->type()); 367 } 368 changes->push_back(ValueStoreChange(key, old_value, new_value)); 369 return syncer::SyncError(); 370 } 371 372 syncer::SyncError SyncableSettingsStorage::OnSyncDelete( 373 const std::string& key, 374 Value* old_value, 375 ValueStoreChangeList* changes) { 376 DCHECK(old_value); 377 WriteResult result = delegate_->Remove(key); 378 if (result->HasError()) { 379 return syncer::SyncError( 380 FROM_HERE, 381 syncer::SyncError::DATATYPE_ERROR, 382 std::string("Error pushing sync remove to local settings: ") + 383 result->error(), 384 sync_processor_->type()); 385 } 386 changes->push_back(ValueStoreChange(key, old_value, NULL)); 387 return syncer::SyncError(); 388 } 389 390 } // namespace extensions 391