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 24using syncer::PREFERENCES; 25using syncer::PRIORITY_PREFERENCES; 26 27namespace { 28 29const 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 39sync_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// List of migrated preference name pairs. If a preference is migrated 52// (meaning renamed) adding the old and new preference names here will ensure 53// that the sync engine knows how to deal with the synced values coming in 54// with the old name. Preference migration itself doesn't happen here. It may 55// happen in session_startup_pref.cc. 56const struct MigratedPreferences { 57 const char* const old_name; 58 const char* const new_name; 59} kMigratedPreferences[] = { 60 { prefs::kURLsToRestoreOnStartupOld, prefs::kURLsToRestoreOnStartup }, 61}; 62 63std::string GetOldMigratedPreferenceName(const char* preference_name) { 64 for (size_t i = 0; i < arraysize(kMigratedPreferences); ++i) { 65 if (!strcmp(kMigratedPreferences[i].new_name, preference_name)) 66 return kMigratedPreferences[i].old_name; 67 } 68 return std::string(); 69} 70 71std::string GetNewMigratedPreferenceName(const char* old_preference_name) { 72 for (size_t i = 0; i < arraysize(kMigratedPreferences); ++i) { 73 if (!strcmp(kMigratedPreferences[i].old_name, old_preference_name)) 74 return kMigratedPreferences[i].new_name; 75 } 76 return std::string(); 77} 78 79} // namespace 80 81PrefModelAssociator::PrefModelAssociator(syncer::ModelType type) 82 : models_associated_(false), 83 processing_syncer_changes_(false), 84 pref_service_(NULL), 85 type_(type) { 86 DCHECK(CalledOnValidThread()); 87 DCHECK(type_ == PREFERENCES || type_ == PRIORITY_PREFERENCES); 88} 89 90PrefModelAssociator::~PrefModelAssociator() { 91 DCHECK(CalledOnValidThread()); 92 pref_service_ = NULL; 93 94 STLDeleteContainerPairSecondPointers(synced_pref_observers_.begin(), 95 synced_pref_observers_.end()); 96 synced_pref_observers_.clear(); 97} 98 99void PrefModelAssociator::InitPrefAndAssociate( 100 const syncer::SyncData& sync_pref, 101 const std::string& pref_name, 102 syncer::SyncChangeList* sync_changes, 103 SyncDataMap* migrated_preference_list) { 104 const Value* user_pref_value = pref_service_->GetUserPrefValue( 105 pref_name.c_str()); 106 VLOG(1) << "Associating preference " << pref_name; 107 108 if (sync_pref.IsValid()) { 109 const sync_pb::PreferenceSpecifics& preference = GetSpecifics(sync_pref); 110 DCHECK(pref_name == preference.name() || 111 (IsMigratedPreference(pref_name.c_str()) && 112 preference.name() == 113 GetOldMigratedPreferenceName(pref_name.c_str()))); 114 base::JSONReader reader; 115 scoped_ptr<Value> sync_value(reader.ReadToValue(preference.value())); 116 if (!sync_value.get()) { 117 LOG(ERROR) << "Failed to deserialize preference value: " 118 << reader.GetErrorMessage(); 119 return; 120 } 121 122 if (user_pref_value) { 123 DVLOG(1) << "Found user pref value for " << pref_name; 124 // We have both server and local values. Merge them. 125 scoped_ptr<Value> new_value( 126 MergePreference(pref_name, *user_pref_value, *sync_value)); 127 128 // Update the local preference based on what we got from the 129 // sync server. Note: this only updates the user value store, which is 130 // ignored if the preference is policy controlled. 131 if (new_value->IsType(Value::TYPE_NULL)) { 132 LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str(); 133 pref_service_->ClearPref(pref_name.c_str()); 134 } else if (!new_value->IsType(user_pref_value->GetType())) { 135 LOG(WARNING) << "Synced value for " << preference.name() 136 << " is of type " << new_value->GetType() 137 << " which doesn't match pref type " 138 << user_pref_value->GetType(); 139 } else if (!user_pref_value->Equals(new_value.get())) { 140 pref_service_->Set(pref_name.c_str(), *new_value); 141 } 142 143 // If the merge resulted in an updated value, inform the syncer. 144 if (!sync_value->Equals(new_value.get())) { 145 syncer::SyncData sync_data; 146 if (!CreatePrefSyncData(pref_name, *new_value, &sync_data)) { 147 LOG(ERROR) << "Failed to update preference."; 148 return; 149 } 150 151 if (IsMigratedPreference(pref_name.c_str())) { 152 // This preference has been migrated from an old version that must be 153 // kept in sync on older versions of Chrome. 154 std::string old_pref_name = 155 GetOldMigratedPreferenceName(pref_name.c_str()); 156 157 if (preference.name() == old_pref_name) { 158 DCHECK(migrated_preference_list); 159 // If the name the syncer has is the old pre-migration value, then 160 // it's possible the new migrated preference name hasn't been synced 161 // yet. In that case the SyncChange should be an ACTION_ADD rather 162 // than an ACTION_UPDATE. Defer the decision of whether to sync with 163 // ACTION_ADD or ACTION_UPDATE until the migrated_preferences phase. 164 if (migrated_preference_list) 165 (*migrated_preference_list)[pref_name] = sync_data; 166 } else { 167 DCHECK_EQ(preference.name(), pref_name); 168 sync_changes->push_back( 169 syncer::SyncChange(FROM_HERE, 170 syncer::SyncChange::ACTION_UPDATE, 171 sync_data)); 172 } 173 174 syncer::SyncData old_sync_data; 175 if (!CreatePrefSyncData(old_pref_name, *new_value, &old_sync_data)) { 176 LOG(ERROR) << "Failed to update preference."; 177 return; 178 } 179 if (migrated_preference_list) 180 (*migrated_preference_list)[old_pref_name] = old_sync_data; 181 } else { 182 sync_changes->push_back( 183 syncer::SyncChange(FROM_HERE, 184 syncer::SyncChange::ACTION_UPDATE, 185 sync_data)); 186 } 187 } 188 } else if (!sync_value->IsType(Value::TYPE_NULL)) { 189 // Only a server value exists. Just set the local user value. 190 pref_service_->Set(pref_name.c_str(), *sync_value); 191 } else { 192 LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str(); 193 } 194 synced_preferences_.insert(preference.name()); 195 } else if (user_pref_value) { 196 // The server does not know about this preference and should be added 197 // to the syncer's database. 198 syncer::SyncData sync_data; 199 if (!CreatePrefSyncData(pref_name, *user_pref_value, &sync_data)) { 200 LOG(ERROR) << "Failed to update preference."; 201 return; 202 } 203 sync_changes->push_back( 204 syncer::SyncChange(FROM_HERE, 205 syncer::SyncChange::ACTION_ADD, 206 sync_data)); 207 synced_preferences_.insert(pref_name); 208 } 209 210 // Else this pref does not have a sync value but also does not have a user 211 // controlled value (either it's a default value or it's policy controlled, 212 // either way it's not interesting). We can ignore it. Once it gets changed, 213 // we'll send the new user controlled value to the syncer. 214} 215 216syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing( 217 syncer::ModelType type, 218 const syncer::SyncDataList& initial_sync_data, 219 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 220 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { 221 DCHECK_EQ(type_, type); 222 DCHECK(CalledOnValidThread()); 223 DCHECK(pref_service_); 224 DCHECK(!sync_processor_.get()); 225 DCHECK(sync_processor.get()); 226 DCHECK(sync_error_factory.get()); 227 syncer::SyncMergeResult merge_result(type); 228 sync_processor_ = sync_processor.Pass(); 229 sync_error_factory_ = sync_error_factory.Pass(); 230 231 syncer::SyncChangeList new_changes; 232 std::set<std::string> remaining_preferences = registered_preferences_; 233 234 // Maintains a list of old migrated preference names that we wish to sync. 235 // Keep track of these in a list such that when the preference iteration 236 // loops below are complete we can go back and determine whether 237 SyncDataMap migrated_preference_list; 238 239 // Go through and check for all preferences we care about that sync already 240 // knows about. 241 for (syncer::SyncDataList::const_iterator sync_iter = 242 initial_sync_data.begin(); 243 sync_iter != initial_sync_data.end(); 244 ++sync_iter) { 245 DCHECK_EQ(type_, sync_iter->GetDataType()); 246 247 const sync_pb::PreferenceSpecifics& preference = GetSpecifics(*sync_iter); 248 std::string sync_pref_name = preference.name(); 249 250 if (remaining_preferences.count(sync_pref_name) == 0) { 251 if (IsOldMigratedPreference(sync_pref_name.c_str())) { 252 // This old pref name is not syncable locally anymore but we accept 253 // changes from other Chrome installs of previous versions and migrate 254 // them to the new name. Note that we will be merging any differences 255 // between the new and old values and sync'ing them back. 256 sync_pref_name = GetNewMigratedPreferenceName(sync_pref_name.c_str()); 257 } else { 258 // We're not syncing this preference locally, ignore the sync data. 259 // TODO(zea): Eventually we want to be able to have the syncable service 260 // reconstruct all sync data for its datatype (therefore having 261 // GetAllSyncData be a complete representation). We should store this 262 // data somewhere, even if we don't use it. 263 continue; 264 } 265 } else { 266 remaining_preferences.erase(sync_pref_name); 267 } 268 InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_changes, 269 &migrated_preference_list); 270 } 271 272 // Go through and build sync data for any remaining preferences. 273 for (std::set<std::string>::iterator pref_name_iter = 274 remaining_preferences.begin(); 275 pref_name_iter != remaining_preferences.end(); 276 ++pref_name_iter) { 277 InitPrefAndAssociate(syncer::SyncData(), *pref_name_iter, &new_changes, 278 &migrated_preference_list); 279 } 280 281 // Now go over any migrated preference names and build sync data for them too. 282 for (SyncDataMap::const_iterator migrated_pref_iter = 283 migrated_preference_list.begin(); 284 migrated_pref_iter != migrated_preference_list.end(); 285 ++migrated_pref_iter) { 286 syncer::SyncChange::SyncChangeType change_type = 287 (synced_preferences_.count(migrated_pref_iter->first) == 0) ? 288 syncer::SyncChange::ACTION_ADD : 289 syncer::SyncChange::ACTION_UPDATE; 290 new_changes.push_back( 291 syncer::SyncChange(FROM_HERE, change_type, migrated_pref_iter->second)); 292 synced_preferences_.insert(migrated_pref_iter->first); 293 } 294 295 // Push updates to sync. 296 merge_result.set_error( 297 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); 298 if (merge_result.error().IsSet()) 299 return merge_result; 300 301 models_associated_ = true; 302 pref_service_->OnIsSyncingChanged(); 303 return merge_result; 304} 305 306void PrefModelAssociator::StopSyncing(syncer::ModelType type) { 307 DCHECK_EQ(type_, type); 308 models_associated_ = false; 309 sync_processor_.reset(); 310 sync_error_factory_.reset(); 311 pref_service_->OnIsSyncingChanged(); 312} 313 314scoped_ptr<Value> PrefModelAssociator::MergePreference( 315 const std::string& name, 316 const Value& local_value, 317 const Value& server_value) { 318 // This function special cases preferences individually, so don't attempt 319 // to merge for all migrated values. 320 if (name == prefs::kURLsToRestoreOnStartup || 321 name == prefs::kURLsToRestoreOnStartupOld) { 322 return scoped_ptr<Value>(MergeListValues(local_value, server_value)).Pass(); 323 } 324 325 if (name == prefs::kContentSettingsPatternPairs) { 326 return scoped_ptr<Value>( 327 MergeDictionaryValues(local_value, server_value)).Pass(); 328 } 329 330 // If this is not a specially handled preference, server wins. 331 return scoped_ptr<Value>(server_value.DeepCopy()).Pass(); 332} 333 334bool PrefModelAssociator::CreatePrefSyncData( 335 const std::string& name, 336 const Value& value, 337 syncer::SyncData* sync_data) const { 338 if (value.IsType(Value::TYPE_NULL)) { 339 LOG(ERROR) << "Attempting to sync a null pref value for " << name; 340 return false; 341 } 342 343 std::string serialized; 344 // TODO(zea): consider JSONWriter::Write since you don't have to check 345 // failures to deserialize. 346 JSONStringValueSerializer json(&serialized); 347 if (!json.Serialize(value)) { 348 LOG(ERROR) << "Failed to serialize preference value."; 349 return false; 350 } 351 352 sync_pb::EntitySpecifics specifics; 353 sync_pb::PreferenceSpecifics* pref_specifics = 354 GetMutableSpecifics(type_, &specifics); 355 356 pref_specifics->set_name(name); 357 pref_specifics->set_value(serialized); 358 *sync_data = syncer::SyncData::CreateLocalData(name, name, specifics); 359 return true; 360} 361 362Value* PrefModelAssociator::MergeListValues(const Value& from_value, 363 const Value& to_value) { 364 if (from_value.GetType() == Value::TYPE_NULL) 365 return to_value.DeepCopy(); 366 if (to_value.GetType() == Value::TYPE_NULL) 367 return from_value.DeepCopy(); 368 369 DCHECK(from_value.GetType() == Value::TYPE_LIST); 370 DCHECK(to_value.GetType() == Value::TYPE_LIST); 371 const ListValue& from_list_value = static_cast<const ListValue&>(from_value); 372 const ListValue& to_list_value = static_cast<const ListValue&>(to_value); 373 ListValue* result = to_list_value.DeepCopy(); 374 375 for (ListValue::const_iterator i = from_list_value.begin(); 376 i != from_list_value.end(); ++i) { 377 Value* value = (*i)->DeepCopy(); 378 result->AppendIfNotPresent(value); 379 } 380 return result; 381} 382 383Value* PrefModelAssociator::MergeDictionaryValues( 384 const Value& from_value, 385 const Value& to_value) { 386 if (from_value.GetType() == Value::TYPE_NULL) 387 return to_value.DeepCopy(); 388 if (to_value.GetType() == Value::TYPE_NULL) 389 return from_value.DeepCopy(); 390 391 DCHECK_EQ(from_value.GetType(), Value::TYPE_DICTIONARY); 392 DCHECK_EQ(to_value.GetType(), Value::TYPE_DICTIONARY); 393 const DictionaryValue& from_dict_value = 394 static_cast<const DictionaryValue&>(from_value); 395 const DictionaryValue& to_dict_value = 396 static_cast<const DictionaryValue&>(to_value); 397 DictionaryValue* result = to_dict_value.DeepCopy(); 398 399 for (DictionaryValue::Iterator it(from_dict_value); !it.IsAtEnd(); 400 it.Advance()) { 401 const Value* from_value = &it.value(); 402 Value* to_key_value; 403 if (result->GetWithoutPathExpansion(it.key(), &to_key_value)) { 404 if (to_key_value->GetType() == Value::TYPE_DICTIONARY) { 405 Value* merged_value = MergeDictionaryValues(*from_value, *to_key_value); 406 result->SetWithoutPathExpansion(it.key(), merged_value); 407 } 408 // Note that for all other types we want to preserve the "to" 409 // values so we do nothing here. 410 } else { 411 result->SetWithoutPathExpansion(it.key(), from_value->DeepCopy()); 412 } 413 } 414 return result; 415} 416 417// static 418bool PrefModelAssociator::IsMigratedPreference(const char* preference_name) { 419 return !GetOldMigratedPreferenceName(preference_name).empty(); 420} 421 422// static 423bool PrefModelAssociator::IsOldMigratedPreference( 424 const char* old_preference_name) { 425 return !GetNewMigratedPreferenceName(old_preference_name).empty(); 426} 427 428// Note: This will build a model of all preferences registered as syncable 429// with user controlled data. We do not track any information for preferences 430// not registered locally as syncable and do not inform the syncer of 431// non-user controlled preferences. 432syncer::SyncDataList PrefModelAssociator::GetAllSyncData( 433 syncer::ModelType type) 434 const { 435 DCHECK_EQ(type_, type); 436 syncer::SyncDataList current_data; 437 for (PreferenceSet::const_iterator iter = synced_preferences_.begin(); 438 iter != synced_preferences_.end(); 439 ++iter) { 440 std::string name = *iter; 441 const PrefService::Preference* pref = 442 pref_service_->FindPreference(name.c_str()); 443 DCHECK(pref); 444 if (!pref->IsUserControlled() || pref->IsDefaultValue()) 445 continue; // This is not data we care about. 446 // TODO(zea): plumb a way to read the user controlled value. 447 syncer::SyncData sync_data; 448 if (!CreatePrefSyncData(name, *pref->GetValue(), &sync_data)) 449 continue; 450 current_data.push_back(sync_data); 451 } 452 return current_data; 453} 454 455syncer::SyncError PrefModelAssociator::ProcessSyncChanges( 456 const tracked_objects::Location& from_here, 457 const syncer::SyncChangeList& change_list) { 458 if (!models_associated_) { 459 syncer::SyncError error(FROM_HERE, 460 syncer::SyncError::DATATYPE_ERROR, 461 "Models not yet associated.", 462 PREFERENCES); 463 return error; 464 } 465 base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true); 466 syncer::SyncChangeList::const_iterator iter; 467 for (iter = change_list.begin(); iter != change_list.end(); ++iter) { 468 DCHECK_EQ(type_, iter->sync_data().GetDataType()); 469 470 std::string name; 471 const sync_pb::PreferenceSpecifics& pref_specifics = 472 GetSpecifics(iter->sync_data()); 473 474 scoped_ptr<Value> value(ReadPreferenceSpecifics(pref_specifics, 475 &name)); 476 477 if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) { 478 // We never delete preferences. 479 NOTREACHED() << "Attempted to process sync delete change for " << name 480 << ". Skipping."; 481 continue; 482 } 483 484 // Skip values we can't deserialize. 485 // TODO(zea): consider taking some further action such as erasing the bad 486 // data. 487 if (!value.get()) 488 continue; 489 490 // It is possible that we may receive a change to a preference we do not 491 // want to sync. For example if the user is syncing a Mac client and a 492 // Windows client, the Windows client does not support 493 // kConfirmToQuitEnabled. Ignore updates from these preferences. 494 const char* pref_name = name.c_str(); 495 std::string new_name; 496 // We migrated this preference name, so do as if the name had not changed. 497 if (IsOldMigratedPreference(pref_name)) { 498 new_name = GetNewMigratedPreferenceName(pref_name); 499 pref_name = new_name.c_str(); 500 } 501 502 if (!IsPrefRegistered(pref_name)) 503 continue; 504 505 const PrefService::Preference* pref = 506 pref_service_->FindPreference(pref_name); 507 DCHECK(pref); 508 509 // This will only modify the user controlled value store, which takes 510 // priority over the default value but is ignored if the preference is 511 // policy controlled. 512 pref_service_->Set(pref_name, *value); 513 514 NotifySyncedPrefObservers(name, true /*from_sync*/); 515 516 // Keep track of any newly synced preferences. 517 if (iter->change_type() == syncer::SyncChange::ACTION_ADD) { 518 synced_preferences_.insert(name); 519 } 520 } 521 return syncer::SyncError(); 522} 523 524Value* PrefModelAssociator::ReadPreferenceSpecifics( 525 const sync_pb::PreferenceSpecifics& preference, 526 std::string* name) { 527 base::JSONReader reader; 528 scoped_ptr<Value> value(reader.ReadToValue(preference.value())); 529 if (!value.get()) { 530 std::string err = "Failed to deserialize preference value: " + 531 reader.GetErrorMessage(); 532 LOG(ERROR) << err; 533 return NULL; 534 } 535 *name = preference.name(); 536 return value.release(); 537} 538 539bool PrefModelAssociator::IsPrefSynced(const std::string& name) const { 540 return synced_preferences_.find(name) != synced_preferences_.end(); 541} 542 543void PrefModelAssociator::AddSyncedPrefObserver(const std::string& name, 544 SyncedPrefObserver* observer) { 545 SyncedPrefObserverList* observers = synced_pref_observers_[name]; 546 if (observers == NULL) { 547 observers = new SyncedPrefObserverList; 548 synced_pref_observers_[name] = observers; 549 } 550 observers->AddObserver(observer); 551} 552 553void PrefModelAssociator::RemoveSyncedPrefObserver(const std::string& name, 554 SyncedPrefObserver* observer) { 555 SyncedPrefObserverMap::iterator observer_iter = 556 synced_pref_observers_.find(name); 557 if (observer_iter == synced_pref_observers_.end()) 558 return; 559 SyncedPrefObserverList* observers = observer_iter->second; 560 observers->RemoveObserver(observer); 561} 562 563std::set<std::string> PrefModelAssociator::registered_preferences() const { 564 return registered_preferences_; 565} 566 567void PrefModelAssociator::RegisterPref(const char* name) { 568 DCHECK(!models_associated_ && registered_preferences_.count(name) == 0); 569 registered_preferences_.insert(name); 570} 571 572bool PrefModelAssociator::IsPrefRegistered(const char* name) { 573 return registered_preferences_.count(name) > 0; 574} 575 576void PrefModelAssociator::ProcessPrefChange(const std::string& name) { 577 if (processing_syncer_changes_) 578 return; // These are changes originating from us, ignore. 579 580 // We only process changes if we've already associated models. 581 if (!models_associated_) 582 return; 583 584 const PrefService::Preference* preference = 585 pref_service_->FindPreference(name.c_str()); 586 if (!preference) 587 return; 588 589 if (!IsPrefRegistered(name.c_str())) 590 return; // We are not syncing this preference. 591 592 syncer::SyncChangeList changes; 593 594 if (!preference->IsUserModifiable()) { 595 // If the preference is no longer user modifiable, it must now be controlled 596 // by policy, whose values we do not sync. Just return. If the preference 597 // stops being controlled by policy, it will revert back to the user value 598 // (which we continue to update with sync changes). 599 return; 600 } 601 602 base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true); 603 604 NotifySyncedPrefObservers(name, false /*from_sync*/); 605 606 if (synced_preferences_.count(name) == 0) { 607 // Not in synced_preferences_ means no synced data. InitPrefAndAssociate(..) 608 // will determine if we care about its data (e.g. if it has a default value 609 // and hasn't been changed yet we don't) and take care syncing any new data. 610 InitPrefAndAssociate(syncer::SyncData(), name, &changes, NULL); 611 } else { 612 // We are already syncing this preference, just update it's sync node. 613 syncer::SyncData sync_data; 614 if (!CreatePrefSyncData(name, *preference->GetValue(), &sync_data)) { 615 LOG(ERROR) << "Failed to update preference."; 616 return; 617 } 618 changes.push_back( 619 syncer::SyncChange(FROM_HERE, 620 syncer::SyncChange::ACTION_UPDATE, 621 sync_data)); 622 // This preference has been migrated from an old version that must be kept 623 // in sync on older versions of Chrome. 624 if (IsMigratedPreference(name.c_str())) { 625 std::string old_pref_name = GetOldMigratedPreferenceName(name.c_str()); 626 if (!CreatePrefSyncData(old_pref_name, 627 *preference->GetValue(), 628 &sync_data)) { 629 LOG(ERROR) << "Failed to update preference."; 630 return; 631 } 632 633 syncer::SyncChange::SyncChangeType change_type = 634 (synced_preferences_.count(old_pref_name) == 0) ? 635 syncer::SyncChange::ACTION_ADD : 636 syncer::SyncChange::ACTION_UPDATE; 637 changes.push_back( 638 syncer::SyncChange(FROM_HERE, change_type, sync_data)); 639 } 640 } 641 642 syncer::SyncError error = 643 sync_processor_->ProcessSyncChanges(FROM_HERE, changes); 644} 645 646void PrefModelAssociator::SetPrefService(PrefServiceSyncable* pref_service) { 647 DCHECK(pref_service_ == NULL); 648 pref_service_ = pref_service; 649} 650 651void PrefModelAssociator::NotifySyncedPrefObservers(const std::string& path, 652 bool from_sync) const { 653 SyncedPrefObserverMap::const_iterator observer_iter = 654 synced_pref_observers_.find(path); 655 if (observer_iter == synced_pref_observers_.end()) 656 return; 657 SyncedPrefObserverList* observers = observer_iter->second; 658 FOR_EACH_OBSERVER(SyncedPrefObserver, *observers, 659 OnSyncedPrefChanged(path, from_sync)); 660} 661