Chromium Code Reviews| 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 "components/syncable_prefs/pref_model_associator.h" | 5 #include "components/syncable_prefs/pref_model_associator.h" |
| 6 | 6 |
| 7 #include "base/auto_reset.h" | 7 #include "base/auto_reset.h" |
| 8 #include "base/json/json_reader.h" | 8 #include "base/json/json_reader.h" |
| 9 #include "base/json/json_string_value_serializer.h" | 9 #include "base/json/json_string_value_serializer.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 pref_service_ = NULL; | 68 pref_service_ = NULL; |
| 69 | 69 |
| 70 STLDeleteContainerPairSecondPointers(synced_pref_observers_.begin(), | 70 STLDeleteContainerPairSecondPointers(synced_pref_observers_.begin(), |
| 71 synced_pref_observers_.end()); | 71 synced_pref_observers_.end()); |
| 72 synced_pref_observers_.clear(); | 72 synced_pref_observers_.clear(); |
| 73 } | 73 } |
| 74 | 74 |
| 75 void PrefModelAssociator::InitPrefAndAssociate( | 75 void PrefModelAssociator::InitPrefAndAssociate( |
| 76 const syncer::SyncData& sync_pref, | 76 const syncer::SyncData& sync_pref, |
| 77 const std::string& pref_name, | 77 const std::string& pref_name, |
| 78 syncer::SyncChangeList* sync_changes, | 78 syncer::SyncChangeList* sync_changes) { |
| 79 SyncDataMap* migrated_preference_list) { | |
| 80 const base::Value* user_pref_value = pref_service_->GetUserPrefValue( | 79 const base::Value* user_pref_value = pref_service_->GetUserPrefValue( |
| 81 pref_name.c_str()); | 80 pref_name.c_str()); |
| 82 VLOG(1) << "Associating preference " << pref_name; | 81 VLOG(1) << "Associating preference " << pref_name; |
| 83 | 82 |
| 84 if (sync_pref.IsValid()) { | 83 if (sync_pref.IsValid()) { |
| 85 const sync_pb::PreferenceSpecifics& preference = GetSpecifics(sync_pref); | 84 const sync_pb::PreferenceSpecifics& preference = GetSpecifics(sync_pref); |
| 86 std::string old_pref_name; | 85 DCHECK(pref_name == preference.name()); |
| 87 DCHECK(pref_name == preference.name() || | |
| 88 (client_ && | |
| 89 client_->IsMigratedPreference(pref_name, &old_pref_name) && | |
| 90 preference.name() == old_pref_name)); | |
| 91 base::JSONReader reader; | 86 base::JSONReader reader; |
| 92 scoped_ptr<base::Value> sync_value(reader.ReadToValue(preference.value())); | 87 scoped_ptr<base::Value> sync_value(reader.ReadToValue(preference.value())); |
| 93 if (!sync_value.get()) { | 88 if (!sync_value.get()) { |
| 94 LOG(ERROR) << "Failed to deserialize preference value: " | 89 LOG(ERROR) << "Failed to deserialize preference value: " |
| 95 << reader.GetErrorMessage(); | 90 << reader.GetErrorMessage(); |
| 96 return; | 91 return; |
| 97 } | 92 } |
| 98 | 93 |
| 99 if (user_pref_value) { | 94 if (user_pref_value) { |
| 100 DVLOG(1) << "Found user pref value for " << pref_name; | 95 DVLOG(1) << "Found user pref value for " << pref_name; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 118 } | 113 } |
| 119 | 114 |
| 120 // If the merge resulted in an updated value, inform the syncer. | 115 // If the merge resulted in an updated value, inform the syncer. |
| 121 if (!sync_value->Equals(new_value.get())) { | 116 if (!sync_value->Equals(new_value.get())) { |
| 122 syncer::SyncData sync_data; | 117 syncer::SyncData sync_data; |
| 123 if (!CreatePrefSyncData(pref_name, *new_value, &sync_data)) { | 118 if (!CreatePrefSyncData(pref_name, *new_value, &sync_data)) { |
| 124 LOG(ERROR) << "Failed to update preference."; | 119 LOG(ERROR) << "Failed to update preference."; |
| 125 return; | 120 return; |
| 126 } | 121 } |
| 127 | 122 |
| 128 std::string old_pref_name; | 123 sync_changes->push_back( |
| 129 if (client_ && | 124 syncer::SyncChange(FROM_HERE, |
| 130 client_->IsMigratedPreference(pref_name, &old_pref_name)) { | 125 syncer::SyncChange::ACTION_UPDATE, |
| 131 // This preference has been migrated from an old version that must be | 126 sync_data)); |
| 132 // kept in sync on older versions of Chrome. | |
| 133 if (preference.name() == old_pref_name) { | |
| 134 DCHECK(migrated_preference_list); | |
| 135 // If the name the syncer has is the old pre-migration value, then | |
| 136 // it's possible the new migrated preference name hasn't been synced | |
| 137 // yet. In that case the SyncChange should be an ACTION_ADD rather | |
| 138 // than an ACTION_UPDATE. Defer the decision of whether to sync with | |
| 139 // ACTION_ADD or ACTION_UPDATE until the migrated_preferences phase. | |
| 140 if (migrated_preference_list) | |
| 141 (*migrated_preference_list)[pref_name] = sync_data; | |
| 142 } else { | |
| 143 DCHECK_EQ(preference.name(), pref_name); | |
| 144 sync_changes->push_back( | |
| 145 syncer::SyncChange(FROM_HERE, | |
| 146 syncer::SyncChange::ACTION_UPDATE, | |
| 147 sync_data)); | |
| 148 } | |
| 149 | |
| 150 syncer::SyncData old_sync_data; | |
| 151 if (!CreatePrefSyncData(old_pref_name, *new_value, &old_sync_data)) { | |
| 152 LOG(ERROR) << "Failed to update preference."; | |
| 153 return; | |
| 154 } | |
| 155 if (migrated_preference_list) | |
| 156 (*migrated_preference_list)[old_pref_name] = old_sync_data; | |
| 157 } else { | |
| 158 sync_changes->push_back( | |
| 159 syncer::SyncChange(FROM_HERE, | |
| 160 syncer::SyncChange::ACTION_UPDATE, | |
| 161 sync_data)); | |
| 162 } | |
| 163 } | 127 } |
| 164 } else if (!sync_value->IsType(base::Value::TYPE_NULL)) { | 128 } else if (!sync_value->IsType(base::Value::TYPE_NULL)) { |
| 165 // Only a server value exists. Just set the local user value. | 129 // Only a server value exists. Just set the local user value. |
| 166 pref_service_->Set(pref_name.c_str(), *sync_value); | 130 pref_service_->Set(pref_name.c_str(), *sync_value); |
| 167 } else { | 131 } else { |
| 168 LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str(); | 132 LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str(); |
| 169 } | 133 } |
| 170 synced_preferences_.insert(preference.name()); | 134 synced_preferences_.insert(preference.name()); |
| 171 } else if (user_pref_value) { | 135 } else if (user_pref_value) { |
| 172 // The server does not know about this preference and should be added | 136 // The server does not know about this preference and should be added |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 200 DCHECK(!sync_processor_.get()); | 164 DCHECK(!sync_processor_.get()); |
| 201 DCHECK(sync_processor.get()); | 165 DCHECK(sync_processor.get()); |
| 202 DCHECK(sync_error_factory.get()); | 166 DCHECK(sync_error_factory.get()); |
| 203 syncer::SyncMergeResult merge_result(type); | 167 syncer::SyncMergeResult merge_result(type); |
| 204 sync_processor_ = sync_processor.Pass(); | 168 sync_processor_ = sync_processor.Pass(); |
| 205 sync_error_factory_ = sync_error_factory.Pass(); | 169 sync_error_factory_ = sync_error_factory.Pass(); |
| 206 | 170 |
| 207 syncer::SyncChangeList new_changes; | 171 syncer::SyncChangeList new_changes; |
| 208 std::set<std::string> remaining_preferences = registered_preferences_; | 172 std::set<std::string> remaining_preferences = registered_preferences_; |
| 209 | 173 |
| 210 // Maintains a list of old migrated preference names that we wish to sync. | |
| 211 // Keep track of these in a list such that when the preference iteration | |
| 212 // loops below are complete we can go back and determine whether | |
| 213 SyncDataMap migrated_preference_list; | |
| 214 | |
| 215 // Go through and check for all preferences we care about that sync already | 174 // Go through and check for all preferences we care about that sync already |
| 216 // knows about. | 175 // knows about. |
| 217 for (syncer::SyncDataList::const_iterator sync_iter = | 176 for (syncer::SyncDataList::const_iterator sync_iter = |
| 218 initial_sync_data.begin(); | 177 initial_sync_data.begin(); |
| 219 sync_iter != initial_sync_data.end(); | 178 sync_iter != initial_sync_data.end(); |
| 220 ++sync_iter) { | 179 ++sync_iter) { |
| 221 DCHECK_EQ(type_, sync_iter->GetDataType()); | 180 DCHECK_EQ(type_, sync_iter->GetDataType()); |
| 222 | 181 |
| 223 const sync_pb::PreferenceSpecifics& preference = GetSpecifics(*sync_iter); | 182 const sync_pb::PreferenceSpecifics& preference = GetSpecifics(*sync_iter); |
| 224 std::string sync_pref_name = preference.name(); | 183 std::string sync_pref_name = preference.name(); |
| 225 | 184 |
| 226 if (remaining_preferences.count(sync_pref_name) == 0) { | 185 if (remaining_preferences.count(sync_pref_name) == 0) { |
| 227 std::string new_pref_name; | 186 // We're not syncing this preference locally, ignore the sync data. |
| 228 if (client_ && | 187 // TODO(zea): Eventually we want to be able to have the syncable service |
| 229 client_->IsOldMigratedPreference(sync_pref_name, &new_pref_name)) { | 188 // reconstruct all sync data for its datatype (therefore having |
| 230 // This old pref name is not syncable locally anymore but we accept | 189 // GetAllSyncData be a complete representation). We should store this |
| 231 // changes from other Chrome installs of previous versions and migrate | 190 // data somewhere, even if we don't use it. |
| 232 // them to the new name. Note that we will be merging any differences | 191 continue; |
| 233 // between the new and old values and sync'ing them back. | |
| 234 sync_pref_name = new_pref_name; | |
| 235 } else { | |
| 236 // We're not syncing this preference locally, ignore the sync data. | |
| 237 // TODO(zea): Eventually we want to be able to have the syncable service | |
| 238 // reconstruct all sync data for its datatype (therefore having | |
| 239 // GetAllSyncData be a complete representation). We should store this | |
| 240 // data somewhere, even if we don't use it. | |
| 241 continue; | |
| 242 } | |
| 243 } else { | |
| 244 remaining_preferences.erase(sync_pref_name); | |
| 245 } | 192 } |
| 246 InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_changes, | 193 |
| 247 &migrated_preference_list); | 194 remaining_preferences.erase(sync_pref_name); |
|
gab
2015/12/02 21:06:51
If I'm reading the old logic correctly, this shoul
sdefresne
2015/12/03 10:02:29
There is no else block now as I changed the code f
gab
2015/12/03 15:25:37
Ah, indeed, had missed that.
| |
| 195 InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_changes); | |
| 248 } | 196 } |
| 249 | 197 |
| 250 // Go through and build sync data for any remaining preferences. | 198 // Go through and build sync data for any remaining preferences. |
| 251 for (std::set<std::string>::iterator pref_name_iter = | 199 for (std::set<std::string>::iterator pref_name_iter = |
| 252 remaining_preferences.begin(); | 200 remaining_preferences.begin(); |
| 253 pref_name_iter != remaining_preferences.end(); | 201 pref_name_iter != remaining_preferences.end(); |
| 254 ++pref_name_iter) { | 202 ++pref_name_iter) { |
| 255 InitPrefAndAssociate(syncer::SyncData(), *pref_name_iter, &new_changes, | 203 InitPrefAndAssociate(syncer::SyncData(), *pref_name_iter, &new_changes); |
| 256 &migrated_preference_list); | |
| 257 } | |
| 258 | |
| 259 // Now go over any migrated preference names and build sync data for them too. | |
| 260 for (SyncDataMap::const_iterator migrated_pref_iter = | |
| 261 migrated_preference_list.begin(); | |
| 262 migrated_pref_iter != migrated_preference_list.end(); | |
| 263 ++migrated_pref_iter) { | |
| 264 syncer::SyncChange::SyncChangeType change_type = | |
| 265 (synced_preferences_.count(migrated_pref_iter->first) == 0) ? | |
| 266 syncer::SyncChange::ACTION_ADD : | |
| 267 syncer::SyncChange::ACTION_UPDATE; | |
| 268 new_changes.push_back( | |
| 269 syncer::SyncChange(FROM_HERE, change_type, migrated_pref_iter->second)); | |
| 270 synced_preferences_.insert(migrated_pref_iter->first); | |
| 271 } | 204 } |
| 272 | 205 |
| 273 // Push updates to sync. | 206 // Push updates to sync. |
| 274 merge_result.set_error( | 207 merge_result.set_error( |
| 275 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); | 208 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); |
| 276 if (merge_result.error().IsSet()) | 209 if (merge_result.error().IsSet()) |
| 277 return merge_result; | 210 return merge_result; |
| 278 | 211 |
| 279 models_associated_ = true; | 212 models_associated_ = true; |
| 280 pref_service_->OnIsSyncingChanged(); | 213 pref_service_->OnIsSyncingChanged(); |
| 281 return merge_result; | 214 return merge_result; |
| 282 } | 215 } |
| 283 | 216 |
| 284 void PrefModelAssociator::StopSyncing(syncer::ModelType type) { | 217 void PrefModelAssociator::StopSyncing(syncer::ModelType type) { |
| 285 DCHECK_EQ(type_, type); | 218 DCHECK_EQ(type_, type); |
| 286 models_associated_ = false; | 219 models_associated_ = false; |
| 287 sync_processor_.reset(); | 220 sync_processor_.reset(); |
| 288 sync_error_factory_.reset(); | 221 sync_error_factory_.reset(); |
| 289 pref_service_->OnIsSyncingChanged(); | 222 pref_service_->OnIsSyncingChanged(); |
| 290 } | 223 } |
| 291 | 224 |
| 292 scoped_ptr<base::Value> PrefModelAssociator::MergePreference( | 225 scoped_ptr<base::Value> PrefModelAssociator::MergePreference( |
| 293 const std::string& name, | 226 const std::string& name, |
| 294 const base::Value& local_value, | 227 const base::Value& local_value, |
| 295 const base::Value& server_value) { | 228 const base::Value& server_value) { |
| 296 // This function special cases preferences individually, so don't attempt | 229 // This function special cases preferences individually, so don't attempt |
| 297 // to merge for all migrated values. | 230 // to merge for all migrated values. |
| 298 if (client_) { | 231 if (client_) { |
| 299 std::string new_pref_name; | 232 std::string new_pref_name; |
| 300 DCHECK(!client_->IsOldMigratedPreference(name, &new_pref_name)); | |
| 301 if (client_->IsMergeableListPreference(name)) | 233 if (client_->IsMergeableListPreference(name)) |
| 302 return make_scoped_ptr(MergeListValues(local_value, server_value)); | 234 return make_scoped_ptr(MergeListValues(local_value, server_value)); |
| 303 if (client_->IsMergeableDictionaryPreference(name)) | 235 if (client_->IsMergeableDictionaryPreference(name)) |
| 304 return make_scoped_ptr(MergeDictionaryValues(local_value, server_value)); | 236 return make_scoped_ptr(MergeDictionaryValues(local_value, server_value)); |
| 305 } | 237 } |
| 306 | 238 |
| 307 // If this is not a specially handled preference, server wins. | 239 // If this is not a specially handled preference, server wins. |
| 308 return make_scoped_ptr(server_value.DeepCopy()); | 240 return make_scoped_ptr(server_value.DeepCopy()); |
| 309 } | 241 } |
| 310 | 242 |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 439 | 371 |
| 440 const sync_pb::PreferenceSpecifics& pref_specifics = | 372 const sync_pb::PreferenceSpecifics& pref_specifics = |
| 441 GetSpecifics(iter->sync_data()); | 373 GetSpecifics(iter->sync_data()); |
| 442 | 374 |
| 443 std::string name = pref_specifics.name(); | 375 std::string name = pref_specifics.name(); |
| 444 // It is possible that we may receive a change to a preference we do not | 376 // It is possible that we may receive a change to a preference we do not |
| 445 // want to sync. For example if the user is syncing a Mac client and a | 377 // want to sync. For example if the user is syncing a Mac client and a |
| 446 // Windows client, the Windows client does not support | 378 // Windows client, the Windows client does not support |
| 447 // kConfirmToQuitEnabled. Ignore updates from these preferences. | 379 // kConfirmToQuitEnabled. Ignore updates from these preferences. |
| 448 std::string pref_name = pref_specifics.name(); | 380 std::string pref_name = pref_specifics.name(); |
| 449 std::string new_pref_name; | |
| 450 // We migrated this preference name, so do as if the name had not changed. | |
| 451 if (client_ && client_->IsOldMigratedPreference(name, &new_pref_name)) { | |
| 452 pref_name = new_pref_name; | |
| 453 } | |
| 454 | |
| 455 if (!IsPrefRegistered(pref_name.c_str())) | 381 if (!IsPrefRegistered(pref_name.c_str())) |
| 456 continue; | 382 continue; |
| 457 | 383 |
| 458 if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) { | 384 if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) { |
| 459 pref_service_->ClearPref(pref_name); | 385 pref_service_->ClearPref(pref_name); |
| 460 continue; | 386 continue; |
| 461 } | 387 } |
| 462 | 388 |
| 463 scoped_ptr<base::Value> value(ReadPreferenceSpecifics(pref_specifics)); | 389 scoped_ptr<base::Value> value(ReadPreferenceSpecifics(pref_specifics)); |
| 464 if (!value.get()) { | 390 if (!value.get()) { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 566 } | 492 } |
| 567 | 493 |
| 568 base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true); | 494 base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true); |
| 569 | 495 |
| 570 NotifySyncedPrefObservers(name, false /*from_sync*/); | 496 NotifySyncedPrefObservers(name, false /*from_sync*/); |
| 571 | 497 |
| 572 if (synced_preferences_.count(name) == 0) { | 498 if (synced_preferences_.count(name) == 0) { |
| 573 // Not in synced_preferences_ means no synced data. InitPrefAndAssociate(..) | 499 // Not in synced_preferences_ means no synced data. InitPrefAndAssociate(..) |
| 574 // will determine if we care about its data (e.g. if it has a default value | 500 // will determine if we care about its data (e.g. if it has a default value |
| 575 // and hasn't been changed yet we don't) and take care syncing any new data. | 501 // and hasn't been changed yet we don't) and take care syncing any new data. |
| 576 InitPrefAndAssociate(syncer::SyncData(), name, &changes, NULL); | 502 InitPrefAndAssociate(syncer::SyncData(), name, &changes); |
| 577 } else { | 503 } else { |
| 578 // We are already syncing this preference, just update it's sync node. | 504 // We are already syncing this preference, just update it's sync node. |
| 579 syncer::SyncData sync_data; | 505 syncer::SyncData sync_data; |
| 580 if (!CreatePrefSyncData(name, *preference->GetValue(), &sync_data)) { | 506 if (!CreatePrefSyncData(name, *preference->GetValue(), &sync_data)) { |
| 581 LOG(ERROR) << "Failed to update preference."; | 507 LOG(ERROR) << "Failed to update preference."; |
| 582 return; | 508 return; |
| 583 } | 509 } |
| 584 changes.push_back( | 510 changes.push_back( |
| 585 syncer::SyncChange(FROM_HERE, | 511 syncer::SyncChange(FROM_HERE, |
| 586 syncer::SyncChange::ACTION_UPDATE, | 512 syncer::SyncChange::ACTION_UPDATE, |
| 587 sync_data)); | 513 sync_data)); |
| 588 // This preference has been migrated from an old version that must be kept | |
| 589 // in sync on older versions of Chrome. | |
| 590 std::string old_pref_name; | |
| 591 if (client_ && client_->IsMigratedPreference(name, &old_pref_name)) { | |
| 592 if (!CreatePrefSyncData(old_pref_name, | |
| 593 *preference->GetValue(), | |
| 594 &sync_data)) { | |
| 595 LOG(ERROR) << "Failed to update preference."; | |
| 596 return; | |
| 597 } | |
| 598 | |
| 599 syncer::SyncChange::SyncChangeType change_type = | |
| 600 (synced_preferences_.count(old_pref_name) == 0) ? | |
| 601 syncer::SyncChange::ACTION_ADD : | |
| 602 syncer::SyncChange::ACTION_UPDATE; | |
| 603 changes.push_back( | |
| 604 syncer::SyncChange(FROM_HERE, change_type, sync_data)); | |
| 605 } | |
| 606 } | 514 } |
| 607 | 515 |
| 608 syncer::SyncError error = | 516 syncer::SyncError error = |
| 609 sync_processor_->ProcessSyncChanges(FROM_HERE, changes); | 517 sync_processor_->ProcessSyncChanges(FROM_HERE, changes); |
| 610 } | 518 } |
| 611 | 519 |
| 612 void PrefModelAssociator::SetPrefService(PrefServiceSyncable* pref_service) { | 520 void PrefModelAssociator::SetPrefService(PrefServiceSyncable* pref_service) { |
| 613 DCHECK(pref_service_ == NULL); | 521 DCHECK(pref_service_ == NULL); |
| 614 pref_service_ = pref_service; | 522 pref_service_ = pref_service; |
| 615 } | 523 } |
| 616 | 524 |
| 617 void PrefModelAssociator::NotifySyncedPrefObservers(const std::string& path, | 525 void PrefModelAssociator::NotifySyncedPrefObservers(const std::string& path, |
| 618 bool from_sync) const { | 526 bool from_sync) const { |
| 619 SyncedPrefObserverMap::const_iterator observer_iter = | 527 SyncedPrefObserverMap::const_iterator observer_iter = |
| 620 synced_pref_observers_.find(path); | 528 synced_pref_observers_.find(path); |
| 621 if (observer_iter == synced_pref_observers_.end()) | 529 if (observer_iter == synced_pref_observers_.end()) |
| 622 return; | 530 return; |
| 623 SyncedPrefObserverList* observers = observer_iter->second; | 531 SyncedPrefObserverList* observers = observer_iter->second; |
| 624 FOR_EACH_OBSERVER(SyncedPrefObserver, *observers, | 532 FOR_EACH_OBSERVER(SyncedPrefObserver, *observers, |
| 625 OnSyncedPrefChanged(path, from_sync)); | 533 OnSyncedPrefChanged(path, from_sync)); |
| 626 } | 534 } |
| 627 | 535 |
| 628 } // namespace syncable_prefs | 536 } // namespace syncable_prefs |
| OLD | NEW |