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/prefs/pref_model_associator.h" 6 7 #include "base/auto_reset.h" 8 #include "base/json/json_reader.h" 9 #include "base/json/json_string_value_serializer.h" 10 #include "base/location.h" 11 #include "base/logging.h" 12 #include "base/prefs/pref_service.h" 13 #include "base/stl_util.h" 14 #include "base/strings/utf_string_conversions.h" 15 #include "base/values.h" 16 #include "chrome/browser/chrome_notification_types.h" 17 #include "chrome/browser/prefs/pref_service_syncable.h" 18 #include "chrome/common/pref_names.h" 19 #include "sync/api/sync_change.h" 20 #include "sync/api/sync_error_factory.h" 21 #include "sync/protocol/preference_specifics.pb.h" 22 #include "sync/protocol/sync.pb.h" 23 24 using syncer::PREFERENCES; 25 using syncer::PRIORITY_PREFERENCES; 26 27 namespace { 28 29 const sync_pb::PreferenceSpecifics& GetSpecifics(const syncer::SyncData& pref) { 30 DCHECK(pref.GetDataType() == syncer::PREFERENCES || 31 pref.GetDataType() == syncer::PRIORITY_PREFERENCES); 32 if (pref.GetDataType() == syncer::PRIORITY_PREFERENCES) { 33 return pref.GetSpecifics().priority_preference().preference(); 34 } else { 35 return pref.GetSpecifics().preference(); 36 } 37 } 38 39 sync_pb::PreferenceSpecifics* GetMutableSpecifics( 40 const syncer::ModelType type, 41 sync_pb::EntitySpecifics* specifics) { 42 if (type == syncer::PRIORITY_PREFERENCES) { 43 DCHECK(!specifics->has_preference()); 44 return specifics->mutable_priority_preference()->mutable_preference(); 45 } else { 46 DCHECK(!specifics->has_priority_preference()); 47 return specifics->mutable_preference(); 48 } 49 } 50 51 } // namespace 52 53 PrefModelAssociator::PrefModelAssociator(syncer::ModelType type) 54 : models_associated_(false), 55 processing_syncer_changes_(false), 56 pref_service_(NULL), 57 type_(type) { 58 DCHECK(CalledOnValidThread()); 59 DCHECK(type_ == PREFERENCES || type_ == PRIORITY_PREFERENCES); 60 } 61 62 PrefModelAssociator::~PrefModelAssociator() { 63 DCHECK(CalledOnValidThread()); 64 pref_service_ = NULL; 65 66 STLDeleteContainerPairSecondPointers(synced_pref_observers_.begin(), 67 synced_pref_observers_.end()); 68 synced_pref_observers_.clear(); 69 } 70 71 void PrefModelAssociator::InitPrefAndAssociate( 72 const syncer::SyncData& sync_pref, 73 const std::string& pref_name, 74 syncer::SyncChangeList* sync_changes) { 75 const Value* user_pref_value = pref_service_->GetUserPrefValue( 76 pref_name.c_str()); 77 VLOG(1) << "Associating preference " << pref_name; 78 79 if (sync_pref.IsValid()) { 80 const sync_pb::PreferenceSpecifics& preference = GetSpecifics(sync_pref); 81 DCHECK_EQ(pref_name, preference.name()); 82 83 base::JSONReader reader; 84 scoped_ptr<Value> sync_value(reader.ReadToValue(preference.value())); 85 if (!sync_value.get()) { 86 LOG(ERROR) << "Failed to deserialize preference value: " 87 << reader.GetErrorMessage(); 88 return; 89 } 90 91 if (user_pref_value) { 92 // We have both server and local values. Merge them. 93 scoped_ptr<Value> new_value( 94 MergePreference(pref_name, *user_pref_value, *sync_value)); 95 96 // Update the local preference based on what we got from the 97 // sync server. Note: this only updates the user value store, which is 98 // ignored if the preference is policy controlled. 99 if (new_value->IsType(Value::TYPE_NULL)) { 100 LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str(); 101 pref_service_->ClearPref(pref_name.c_str()); 102 } else if (!new_value->IsType(user_pref_value->GetType())) { 103 LOG(WARNING) << "Synced value for " << preference.name() 104 << " is of type " << new_value->GetType() 105 << " which doesn't match pref type " 106 << user_pref_value->GetType(); 107 } else if (!user_pref_value->Equals(new_value.get())) { 108 pref_service_->Set(pref_name.c_str(), *new_value); 109 } 110 111 // If the merge resulted in an updated value, inform the syncer. 112 if (!sync_value->Equals(new_value.get())) { 113 syncer::SyncData sync_data; 114 if (!CreatePrefSyncData(pref_name, *new_value, &sync_data)) { 115 LOG(ERROR) << "Failed to update preference."; 116 return; 117 } 118 sync_changes->push_back( 119 syncer::SyncChange(FROM_HERE, 120 syncer::SyncChange::ACTION_UPDATE, 121 sync_data)); 122 } 123 } else if (!sync_value->IsType(Value::TYPE_NULL)) { 124 // Only a server value exists. Just set the local user value. 125 pref_service_->Set(pref_name.c_str(), *sync_value); 126 } else { 127 LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str(); 128 } 129 } else if (user_pref_value) { 130 // The server does not know about this preference and should be added 131 // to the syncer's database. 132 syncer::SyncData sync_data; 133 if (!CreatePrefSyncData(pref_name, *user_pref_value, &sync_data)) { 134 LOG(ERROR) << "Failed to update preference."; 135 return; 136 } 137 sync_changes->push_back( 138 syncer::SyncChange(FROM_HERE, 139 syncer::SyncChange::ACTION_ADD, 140 sync_data)); 141 } else { 142 // This pref does not have a sync value but also does not have a user 143 // controlled value (either it's a default value or it's policy controlled, 144 // either way it's not interesting). We can ignore it. Once it gets changed, 145 // we'll send the new user controlled value to the syncer. 146 return; 147 } 148 149 // Make sure we add it to our list of synced preferences so we know what 150 // the server is aware of. 151 synced_preferences_.insert(pref_name); 152 return; 153 } 154 155 syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing( 156 syncer::ModelType type, 157 const syncer::SyncDataList& initial_sync_data, 158 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 159 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { 160 DCHECK_EQ(type_, type); 161 DCHECK(CalledOnValidThread()); 162 DCHECK(pref_service_); 163 DCHECK(!sync_processor_.get()); 164 DCHECK(sync_processor.get()); 165 DCHECK(sync_error_factory.get()); 166 syncer::SyncMergeResult merge_result(type); 167 sync_processor_ = sync_processor.Pass(); 168 sync_error_factory_ = sync_error_factory.Pass(); 169 170 syncer::SyncChangeList new_changes; 171 std::set<std::string> remaining_preferences = registered_preferences_; 172 173 // Go through and check for all preferences we care about that sync already 174 // knows about. 175 for (syncer::SyncDataList::const_iterator sync_iter = 176 initial_sync_data.begin(); 177 sync_iter != initial_sync_data.end(); 178 ++sync_iter) { 179 DCHECK_EQ(type_, sync_iter->GetDataType()); 180 181 const sync_pb::PreferenceSpecifics& preference = GetSpecifics(*sync_iter); 182 const std::string& sync_pref_name = preference.name(); 183 184 if (remaining_preferences.count(sync_pref_name) == 0) { 185 // We're not syncing this preference locally, ignore the sync data. 186 // TODO(zea): Eventually we want to be able to have the syncable service 187 // reconstruct all sync data for it's datatype (therefore having 188 // GetAllSyncData be a complete representation). We should store this data 189 // somewhere, even if we don't use it. 190 continue; 191 } 192 193 remaining_preferences.erase(sync_pref_name); 194 InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_changes); 195 } 196 197 // Go through and build sync data for any remaining preferences. 198 for (std::set<std::string>::iterator pref_name_iter = 199 remaining_preferences.begin(); 200 pref_name_iter != remaining_preferences.end(); 201 ++pref_name_iter) { 202 InitPrefAndAssociate(syncer::SyncData(), *pref_name_iter, &new_changes); 203 } 204 205 // Push updates to sync. 206 merge_result.set_error( 207 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); 208 if (merge_result.error().IsSet()) 209 return merge_result; 210 211 models_associated_ = true; 212 pref_service_->OnIsSyncingChanged(); 213 return merge_result; 214 } 215 216 void PrefModelAssociator::StopSyncing(syncer::ModelType type) { 217 DCHECK_EQ(type_, type); 218 models_associated_ = false; 219 sync_processor_.reset(); 220 sync_error_factory_.reset(); 221 pref_service_->OnIsSyncingChanged(); 222 } 223 224 scoped_ptr<Value> PrefModelAssociator::MergePreference( 225 const std::string& name, 226 const Value& local_value, 227 const Value& server_value) { 228 if (name == prefs::kURLsToRestoreOnStartup) { 229 return scoped_ptr<Value>(MergeListValues(local_value, server_value)).Pass(); 230 } 231 232 if (name == prefs::kContentSettingsPatternPairs) { 233 return scoped_ptr<Value>( 234 MergeDictionaryValues(local_value, server_value)).Pass(); 235 } 236 237 // If this is not a specially handled preference, server wins. 238 return scoped_ptr<Value>(server_value.DeepCopy()).Pass(); 239 } 240 241 bool PrefModelAssociator::CreatePrefSyncData( 242 const std::string& name, 243 const Value& value, 244 syncer::SyncData* sync_data) const { 245 if (value.IsType(Value::TYPE_NULL)) { 246 LOG(ERROR) << "Attempting to sync a null pref value for " << name; 247 return false; 248 } 249 250 std::string serialized; 251 // TODO(zea): consider JSONWriter::Write since you don't have to check 252 // failures to deserialize. 253 JSONStringValueSerializer json(&serialized); 254 if (!json.Serialize(value)) { 255 LOG(ERROR) << "Failed to serialize preference value."; 256 return false; 257 } 258 259 sync_pb::EntitySpecifics specifics; 260 sync_pb::PreferenceSpecifics* pref_specifics = 261 GetMutableSpecifics(type_, &specifics); 262 263 pref_specifics->set_name(name); 264 pref_specifics->set_value(serialized); 265 *sync_data = syncer::SyncData::CreateLocalData(name, name, specifics); 266 return true; 267 } 268 269 Value* PrefModelAssociator::MergeListValues(const Value& from_value, 270 const Value& to_value) { 271 if (from_value.GetType() == Value::TYPE_NULL) 272 return to_value.DeepCopy(); 273 if (to_value.GetType() == Value::TYPE_NULL) 274 return from_value.DeepCopy(); 275 276 DCHECK(from_value.GetType() == Value::TYPE_LIST); 277 DCHECK(to_value.GetType() == Value::TYPE_LIST); 278 const ListValue& from_list_value = static_cast<const ListValue&>(from_value); 279 const ListValue& to_list_value = static_cast<const ListValue&>(to_value); 280 ListValue* result = to_list_value.DeepCopy(); 281 282 for (ListValue::const_iterator i = from_list_value.begin(); 283 i != from_list_value.end(); ++i) { 284 Value* value = (*i)->DeepCopy(); 285 result->AppendIfNotPresent(value); 286 } 287 return result; 288 } 289 290 Value* PrefModelAssociator::MergeDictionaryValues( 291 const Value& from_value, 292 const Value& to_value) { 293 if (from_value.GetType() == Value::TYPE_NULL) 294 return to_value.DeepCopy(); 295 if (to_value.GetType() == Value::TYPE_NULL) 296 return from_value.DeepCopy(); 297 298 DCHECK_EQ(from_value.GetType(), Value::TYPE_DICTIONARY); 299 DCHECK_EQ(to_value.GetType(), Value::TYPE_DICTIONARY); 300 const DictionaryValue& from_dict_value = 301 static_cast<const DictionaryValue&>(from_value); 302 const DictionaryValue& to_dict_value = 303 static_cast<const DictionaryValue&>(to_value); 304 DictionaryValue* result = to_dict_value.DeepCopy(); 305 306 for (DictionaryValue::Iterator it(from_dict_value); !it.IsAtEnd(); 307 it.Advance()) { 308 const Value* from_value = &it.value(); 309 Value* to_key_value; 310 if (result->GetWithoutPathExpansion(it.key(), &to_key_value)) { 311 if (to_key_value->GetType() == Value::TYPE_DICTIONARY) { 312 Value* merged_value = MergeDictionaryValues(*from_value, *to_key_value); 313 result->SetWithoutPathExpansion(it.key(), merged_value); 314 } 315 // Note that for all other types we want to preserve the "to" 316 // values so we do nothing here. 317 } else { 318 result->SetWithoutPathExpansion(it.key(), from_value->DeepCopy()); 319 } 320 } 321 return result; 322 } 323 324 // Note: This will build a model of all preferences registered as syncable 325 // with user controlled data. We do not track any information for preferences 326 // not registered locally as syncable and do not inform the syncer of 327 // non-user controlled preferences. 328 syncer::SyncDataList PrefModelAssociator::GetAllSyncData( 329 syncer::ModelType type) 330 const { 331 DCHECK_EQ(type_, type); 332 syncer::SyncDataList current_data; 333 for (PreferenceSet::const_iterator iter = synced_preferences_.begin(); 334 iter != synced_preferences_.end(); 335 ++iter) { 336 std::string name = *iter; 337 const PrefService::Preference* pref = 338 pref_service_->FindPreference(name.c_str()); 339 DCHECK(pref); 340 if (!pref->IsUserControlled() || pref->IsDefaultValue()) 341 continue; // This is not data we care about. 342 // TODO(zea): plumb a way to read the user controlled value. 343 syncer::SyncData sync_data; 344 if (!CreatePrefSyncData(name, *pref->GetValue(), &sync_data)) 345 continue; 346 current_data.push_back(sync_data); 347 } 348 return current_data; 349 } 350 351 syncer::SyncError PrefModelAssociator::ProcessSyncChanges( 352 const tracked_objects::Location& from_here, 353 const syncer::SyncChangeList& change_list) { 354 if (!models_associated_) { 355 syncer::SyncError error(FROM_HERE, 356 syncer::SyncError::DATATYPE_ERROR, 357 "Models not yet associated.", 358 PREFERENCES); 359 return error; 360 } 361 base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true); 362 syncer::SyncChangeList::const_iterator iter; 363 for (iter = change_list.begin(); iter != change_list.end(); ++iter) { 364 DCHECK_EQ(type_, iter->sync_data().GetDataType()); 365 366 std::string name; 367 const sync_pb::PreferenceSpecifics& pref_specifics = 368 GetSpecifics(iter->sync_data()); 369 370 scoped_ptr<Value> value(ReadPreferenceSpecifics(pref_specifics, 371 &name)); 372 373 if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) { 374 // We never delete preferences. 375 NOTREACHED() << "Attempted to process sync delete change for " << name 376 << ". Skipping."; 377 continue; 378 } 379 380 // Skip values we can't deserialize. 381 // TODO(zea): consider taking some further action such as erasing the bad 382 // data. 383 if (!value.get()) 384 continue; 385 386 // It is possible that we may receive a change to a preference we do not 387 // want to sync. For example if the user is syncing a Mac client and a 388 // Windows client, the Windows client does not support 389 // kConfirmToQuitEnabled. Ignore updates from these preferences. 390 const char* pref_name = name.c_str(); 391 if (!IsPrefRegistered(pref_name)) 392 continue; 393 394 const PrefService::Preference* pref = 395 pref_service_->FindPreference(pref_name); 396 DCHECK(pref); 397 398 // This will only modify the user controlled value store, which takes 399 // priority over the default value but is ignored if the preference is 400 // policy controlled. 401 pref_service_->Set(pref_name, *value); 402 403 NotifySyncedPrefObservers(name, true /*from_sync*/); 404 405 // Keep track of any newly synced preferences. 406 if (iter->change_type() == syncer::SyncChange::ACTION_ADD) { 407 synced_preferences_.insert(name); 408 } 409 } 410 return syncer::SyncError(); 411 } 412 413 Value* PrefModelAssociator::ReadPreferenceSpecifics( 414 const sync_pb::PreferenceSpecifics& preference, 415 std::string* name) { 416 base::JSONReader reader; 417 scoped_ptr<Value> value(reader.ReadToValue(preference.value())); 418 if (!value.get()) { 419 std::string err = "Failed to deserialize preference value: " + 420 reader.GetErrorMessage(); 421 LOG(ERROR) << err; 422 return NULL; 423 } 424 *name = preference.name(); 425 return value.release(); 426 } 427 428 bool PrefModelAssociator::IsPrefSynced(const std::string& name) const { 429 return synced_preferences_.find(name) != synced_preferences_.end(); 430 } 431 432 void PrefModelAssociator::AddSyncedPrefObserver(const std::string& name, 433 SyncedPrefObserver* observer) { 434 SyncedPrefObserverList* observers = synced_pref_observers_[name]; 435 if (observers == NULL) { 436 observers = new SyncedPrefObserverList; 437 synced_pref_observers_[name] = observers; 438 } 439 observers->AddObserver(observer); 440 } 441 442 void PrefModelAssociator::RemoveSyncedPrefObserver(const std::string& name, 443 SyncedPrefObserver* observer) { 444 SyncedPrefObserverMap::iterator observer_iter = 445 synced_pref_observers_.find(name); 446 if (observer_iter == synced_pref_observers_.end()) 447 return; 448 SyncedPrefObserverList* observers = observer_iter->second; 449 observers->RemoveObserver(observer); 450 } 451 452 std::set<std::string> PrefModelAssociator::registered_preferences() const { 453 return registered_preferences_; 454 } 455 456 void PrefModelAssociator::RegisterPref(const char* name) { 457 DCHECK(!models_associated_ && registered_preferences_.count(name) == 0); 458 registered_preferences_.insert(name); 459 } 460 461 bool PrefModelAssociator::IsPrefRegistered(const char* name) { 462 return registered_preferences_.count(name) > 0; 463 } 464 465 void PrefModelAssociator::ProcessPrefChange(const std::string& name) { 466 if (processing_syncer_changes_) 467 return; // These are changes originating from us, ignore. 468 469 // We only process changes if we've already associated models. 470 if (!models_associated_) 471 return; 472 473 const PrefService::Preference* preference = 474 pref_service_->FindPreference(name.c_str()); 475 if (!preference) 476 return; 477 478 if (!IsPrefRegistered(name.c_str())) 479 return; // We are not syncing this preference. 480 481 syncer::SyncChangeList changes; 482 483 if (!preference->IsUserModifiable()) { 484 // If the preference is no longer user modifiable, it must now be controlled 485 // by policy, whose values we do not sync. Just return. If the preference 486 // stops being controlled by policy, it will revert back to the user value 487 // (which we continue to update with sync changes). 488 return; 489 } 490 491 base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true); 492 493 NotifySyncedPrefObservers(name, false /*from_sync*/); 494 495 if (synced_preferences_.count(name) == 0) { 496 // Not in synced_preferences_ means no synced data. InitPrefAndAssociate(..) 497 // will determine if we care about its data (e.g. if it has a default value 498 // and hasn't been changed yet we don't) and take care syncing any new data. 499 InitPrefAndAssociate(syncer::SyncData(), name, &changes); 500 } else { 501 // We are already syncing this preference, just update it's sync node. 502 syncer::SyncData sync_data; 503 if (!CreatePrefSyncData(name, *preference->GetValue(), &sync_data)) { 504 LOG(ERROR) << "Failed to update preference."; 505 return; 506 } 507 changes.push_back( 508 syncer::SyncChange(FROM_HERE, 509 syncer::SyncChange::ACTION_UPDATE, 510 sync_data)); 511 } 512 513 syncer::SyncError error = 514 sync_processor_->ProcessSyncChanges(FROM_HERE, changes); 515 } 516 517 void PrefModelAssociator::SetPrefService(PrefServiceSyncable* pref_service) { 518 DCHECK(pref_service_ == NULL); 519 pref_service_ = pref_service; 520 } 521 522 void PrefModelAssociator::NotifySyncedPrefObservers(const std::string& path, 523 bool from_sync) const { 524 SyncedPrefObserverMap::const_iterator observer_iter = 525 synced_pref_observers_.find(path); 526 if (observer_iter == synced_pref_observers_.end()) 527 return; 528 SyncedPrefObserverList* observers = observer_iter->second; 529 FOR_EACH_OBSERVER(SyncedPrefObserver, *observers, 530 OnSyncedPrefChanged(path, from_sync)); 531 } 532