 Chromium Code Reviews
 Chromium Code Reviews Issue 12033093:
  sync: Implementation of Priority Preferences.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 12033093:
  sync: Implementation of Priority Preferences.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| 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/prefs/pref_model_associator.h" | 5 #include "chrome/browser/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" | 
| 11 #include "base/logging.h" | 11 #include "base/logging.h" | 
| 12 #include "base/prefs/pref_service.h" | 12 #include "base/prefs/pref_service.h" | 
| 13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" | 
| 14 #include "base/values.h" | 14 #include "base/values.h" | 
| 15 #include "chrome/browser/prefs/pref_service_syncable.h" | 15 #include "chrome/browser/prefs/pref_service_syncable.h" | 
| 16 #include "chrome/common/chrome_notification_types.h" | 16 #include "chrome/common/chrome_notification_types.h" | 
| 17 #include "chrome/common/pref_names.h" | 17 #include "chrome/common/pref_names.h" | 
| 18 #include "sync/api/sync_change.h" | 18 #include "sync/api/sync_change.h" | 
| 19 #include "sync/api/sync_error_factory.h" | 19 #include "sync/api/sync_error_factory.h" | 
| 20 #include "sync/protocol/preference_specifics.pb.h" | 20 #include "sync/protocol/preference_specifics.pb.h" | 
| 21 #include "sync/protocol/sync.pb.h" | 21 #include "sync/protocol/sync.pb.h" | 
| 22 | 22 | 
| 23 using syncer::PREFERENCES; | 23 using syncer::PREFERENCES; | 
| 24 using syncer::PRIORITY_PREFERENCES; | |
| 24 | 25 | 
| 25 PrefModelAssociator::PrefModelAssociator() | 26 PrefModelAssociator::PrefModelAssociator(syncer::ModelType type) | 
| 26 : models_associated_(false), | 27 : models_associated_(false), | 
| 27 processing_syncer_changes_(false), | 28 processing_syncer_changes_(false), | 
| 28 pref_service_(NULL) { | 29 pref_service_(NULL), | 
| 30 type_(type) { | |
| 29 DCHECK(CalledOnValidThread()); | 31 DCHECK(CalledOnValidThread()); | 
| 32 DCHECK(type_ == PREFERENCES || type_ == PRIORITY_PREFERENCES); | |
| 30 } | 33 } | 
| 31 | 34 | 
| 32 PrefModelAssociator::~PrefModelAssociator() { | 35 PrefModelAssociator::~PrefModelAssociator() { | 
| 33 DCHECK(CalledOnValidThread()); | 36 DCHECK(CalledOnValidThread()); | 
| 34 pref_service_ = NULL; | 37 pref_service_ = NULL; | 
| 35 } | 38 } | 
| 36 | 39 | 
| 37 void PrefModelAssociator::InitPrefAndAssociate( | 40 void PrefModelAssociator::InitPrefAndAssociate( | 
| 38 const syncer::SyncData& sync_pref, | 41 const syncer::SyncData& sync_pref, | 
| 39 const std::string& pref_name, | 42 const std::string& pref_name, | 
| 40 syncer::SyncChangeList* sync_changes) { | 43 syncer::SyncChangeList* sync_changes) { | 
| 41 const Value* user_pref_value = pref_service_->GetUserPrefValue( | 44 const Value* user_pref_value = pref_service_->GetUserPrefValue( | 
| 42 pref_name.c_str()); | 45 pref_name.c_str()); | 
| 43 VLOG(1) << "Associating preference " << pref_name; | 46 VLOG(1) << "Associating preference " << pref_name; | 
| 44 | 47 | 
| 45 if (sync_pref.IsValid()) { | 48 if (sync_pref.IsValid()) { | 
| 46 const sync_pb::PreferenceSpecifics& preference = | 49 const sync_pb::PreferenceSpecifics* preference; | 
| 47 sync_pref.GetSpecifics().preference(); | 50 | 
| 48 DCHECK_EQ(pref_name, preference.name()); | 51 if (type_ == PREFERENCES) { | 
| 
Nicolas Zea
2013/02/25 23:47:47
Yeah, I think an anon namespace helper function wo
 
albertb
2013/03/01 22:01:56
Done.
 | |
| 52 preference = &sync_pref.GetSpecifics().preference(); | |
| 53 } else { | |
| 54 preference = &sync_pref.GetSpecifics().priority_preference().preference(); | |
| 55 } | |
| 56 DCHECK_EQ(pref_name, preference->name()); | |
| 49 | 57 | 
| 50 base::JSONReader reader; | 58 base::JSONReader reader; | 
| 51 scoped_ptr<Value> sync_value(reader.ReadToValue(preference.value())); | 59 scoped_ptr<Value> sync_value(reader.ReadToValue(preference->value())); | 
| 52 if (!sync_value.get()) { | 60 if (!sync_value.get()) { | 
| 53 LOG(ERROR) << "Failed to deserialize preference value: " | 61 LOG(ERROR) << "Failed to deserialize preference value: " | 
| 54 << reader.GetErrorMessage(); | 62 << reader.GetErrorMessage(); | 
| 55 return; | 63 return; | 
| 56 } | 64 } | 
| 57 | 65 | 
| 58 if (user_pref_value) { | 66 if (user_pref_value) { | 
| 59 // We have both server and local values. Merge them. | 67 // We have both server and local values. Merge them. | 
| 60 scoped_ptr<Value> new_value( | 68 scoped_ptr<Value> new_value( | 
| 61 MergePreference(pref_name, *user_pref_value, *sync_value)); | 69 MergePreference(pref_name, *user_pref_value, *sync_value)); | 
| 62 | 70 | 
| 63 // Update the local preference based on what we got from the | 71 // Update the local preference based on what we got from the | 
| 64 // sync server. Note: this only updates the user value store, which is | 72 // sync server. Note: this only updates the user value store, which is | 
| 65 // ignored if the preference is policy controlled. | 73 // ignored if the preference is policy controlled. | 
| 66 if (new_value->IsType(Value::TYPE_NULL)) { | 74 if (new_value->IsType(Value::TYPE_NULL)) { | 
| 67 LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str(); | 75 LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str(); | 
| 68 pref_service_->ClearPref(pref_name.c_str()); | 76 pref_service_->ClearPref(pref_name.c_str()); | 
| 69 } else if (!new_value->IsType(user_pref_value->GetType())) { | 77 } else if (!new_value->IsType(user_pref_value->GetType())) { | 
| 70 LOG(WARNING) << "Synced value for " << preference.name() | 78 LOG(WARNING) << "Synced value for " << preference->name() | 
| 71 << " is of type " << new_value->GetType() | 79 << " is of type " << new_value->GetType() | 
| 72 << " which doesn't match pref type " | 80 << " which doesn't match pref type " | 
| 73 << user_pref_value->GetType(); | 81 << user_pref_value->GetType(); | 
| 74 } else if (!user_pref_value->Equals(new_value.get())) { | 82 } else if (!user_pref_value->Equals(new_value.get())) { | 
| 75 pref_service_->Set(pref_name.c_str(), *new_value); | 83 pref_service_->Set(pref_name.c_str(), *new_value); | 
| 76 } | 84 } | 
| 77 | 85 | 
| 78 // If the merge resulted in an updated value, inform the syncer. | 86 // If the merge resulted in an updated value, inform the syncer. | 
| 79 if (!sync_value->Equals(new_value.get())) { | 87 if (!sync_value->Equals(new_value.get())) { | 
| 80 syncer::SyncData sync_data; | 88 syncer::SyncData sync_data; | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 117 // the server is aware of. | 125 // the server is aware of. | 
| 118 synced_preferences_.insert(pref_name); | 126 synced_preferences_.insert(pref_name); | 
| 119 return; | 127 return; | 
| 120 } | 128 } | 
| 121 | 129 | 
| 122 syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing( | 130 syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing( | 
| 123 syncer::ModelType type, | 131 syncer::ModelType type, | 
| 124 const syncer::SyncDataList& initial_sync_data, | 132 const syncer::SyncDataList& initial_sync_data, | 
| 125 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, | 133 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, | 
| 126 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { | 134 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { | 
| 127 DCHECK_EQ(type, PREFERENCES); | 135 DCHECK_EQ(type_, type); | 
| 128 DCHECK(CalledOnValidThread()); | 136 DCHECK(CalledOnValidThread()); | 
| 129 DCHECK(pref_service_); | 137 DCHECK(pref_service_); | 
| 130 DCHECK(!sync_processor_.get()); | 138 DCHECK(!sync_processor_.get()); | 
| 131 DCHECK(sync_processor.get()); | 139 DCHECK(sync_processor.get()); | 
| 132 DCHECK(sync_error_factory.get()); | 140 DCHECK(sync_error_factory.get()); | 
| 133 syncer::SyncMergeResult merge_result(type); | 141 syncer::SyncMergeResult merge_result(type); | 
| 134 sync_processor_ = sync_processor.Pass(); | 142 sync_processor_ = sync_processor.Pass(); | 
| 135 sync_error_factory_ = sync_error_factory.Pass(); | 143 sync_error_factory_ = sync_error_factory.Pass(); | 
| 136 | 144 | 
| 137 syncer::SyncChangeList new_changes; | 145 syncer::SyncChangeList new_changes; | 
| 138 std::set<std::string> remaining_preferences = registered_preferences_; | 146 std::set<std::string> remaining_preferences = registered_preferences_; | 
| 139 | 147 | 
| 140 // Go through and check for all preferences we care about that sync already | 148 // Go through and check for all preferences we care about that sync already | 
| 141 // knows about. | 149 // knows about. | 
| 142 for (syncer::SyncDataList::const_iterator sync_iter = | 150 for (syncer::SyncDataList::const_iterator sync_iter = | 
| 143 initial_sync_data.begin(); | 151 initial_sync_data.begin(); | 
| 144 sync_iter != initial_sync_data.end(); | 152 sync_iter != initial_sync_data.end(); | 
| 145 ++sync_iter) { | 153 ++sync_iter) { | 
| 146 DCHECK_EQ(PREFERENCES, sync_iter->GetDataType()); | 154 DCHECK_EQ(type_, sync_iter->GetDataType()); | 
| 147 std::string sync_pref_name = sync_iter->GetSpecifics().preference().name(); | 155 std::string sync_pref_name; | 
| 156 | |
| 157 if (type_ == PREFERENCES) { | |
| 158 sync_pref_name = sync_iter->GetSpecifics().preference().name(); | |
| 159 } else { | |
| 160 sync_pref_name = | |
| 161 sync_iter->GetSpecifics().priority_preference().preference().name(); | |
| 162 } | |
| 148 if (remaining_preferences.count(sync_pref_name) == 0) { | 163 if (remaining_preferences.count(sync_pref_name) == 0) { | 
| 149 // We're not syncing this preference locally, ignore the sync data. | 164 // We're not syncing this preference locally, ignore the sync data. | 
| 150 // TODO(zea): Eventually we want to be able to have the syncable service | 165 // TODO(zea): Eventually we want to be able to have the syncable service | 
| 151 // reconstruct all sync data for it's datatype (therefore having | 166 // reconstruct all sync data for it's datatype (therefore having | 
| 152 // GetAllSyncData be a complete representation). We should store this data | 167 // GetAllSyncData be a complete representation). We should store this data | 
| 153 // somewhere, even if we don't use it. | 168 // somewhere, even if we don't use it. | 
| 154 continue; | 169 continue; | 
| 155 } | 170 } | 
| 156 | 171 | 
| 157 remaining_preferences.erase(sync_pref_name); | 172 remaining_preferences.erase(sync_pref_name); | 
| (...skipping 13 matching lines...) Expand all Loading... | |
| 171 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); | 186 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); | 
| 172 if (merge_result.error().IsSet()) | 187 if (merge_result.error().IsSet()) | 
| 173 return merge_result; | 188 return merge_result; | 
| 174 | 189 | 
| 175 models_associated_ = true; | 190 models_associated_ = true; | 
| 176 pref_service_->OnIsSyncingChanged(); | 191 pref_service_->OnIsSyncingChanged(); | 
| 177 return merge_result; | 192 return merge_result; | 
| 178 } | 193 } | 
| 179 | 194 | 
| 180 void PrefModelAssociator::StopSyncing(syncer::ModelType type) { | 195 void PrefModelAssociator::StopSyncing(syncer::ModelType type) { | 
| 181 DCHECK_EQ(type, PREFERENCES); | 196 DCHECK_EQ(type_, type); | 
| 182 models_associated_ = false; | 197 models_associated_ = false; | 
| 183 sync_processor_.reset(); | 198 sync_processor_.reset(); | 
| 184 sync_error_factory_.reset(); | 199 sync_error_factory_.reset(); | 
| 185 pref_service_->OnIsSyncingChanged(); | 200 pref_service_->OnIsSyncingChanged(); | 
| 186 } | 201 } | 
| 187 | 202 | 
| 188 scoped_ptr<Value> PrefModelAssociator::MergePreference( | 203 scoped_ptr<Value> PrefModelAssociator::MergePreference( | 
| 189 const std::string& name, | 204 const std::string& name, | 
| 190 const Value& local_value, | 205 const Value& local_value, | 
| 191 const Value& server_value) { | 206 const Value& server_value) { | 
| 192 if (name == prefs::kURLsToRestoreOnStartup) { | 207 if (name == prefs::kURLsToRestoreOnStartup) { | 
| 193 return scoped_ptr<Value>(MergeListValues(local_value, server_value)).Pass(); | 208 return scoped_ptr<Value>(MergeListValues(local_value, server_value)).Pass(); | 
| 194 } | 209 } | 
| 195 | 210 | 
| 196 if (name == prefs::kContentSettingsPatternPairs) { | 211 if (name == prefs::kContentSettingsPatternPairs) { | 
| 197 return scoped_ptr<Value>( | 212 return scoped_ptr<Value>( | 
| 198 MergeDictionaryValues(local_value, server_value)).Pass(); | 213 MergeDictionaryValues(local_value, server_value)).Pass(); | 
| 199 } | 214 } | 
| 200 | 215 | 
| 201 // If this is not a specially handled preference, server wins. | 216 // If this is not a specially handled preference, server wins. | 
| 202 return scoped_ptr<Value>(server_value.DeepCopy()).Pass(); | 217 return scoped_ptr<Value>(server_value.DeepCopy()).Pass(); | 
| 203 } | 218 } | 
| 204 | 219 | 
| 205 bool PrefModelAssociator::CreatePrefSyncData( | 220 bool PrefModelAssociator::CreatePrefSyncData( | 
| 206 const std::string& name, | 221 const std::string& name, | 
| 207 const Value& value, | 222 const Value& value, | 
| 208 syncer::SyncData* sync_data) { | 223 syncer::SyncData* sync_data) const { | 
| 209 if (value.IsType(Value::TYPE_NULL)) { | 224 if (value.IsType(Value::TYPE_NULL)) { | 
| 210 LOG(ERROR) << "Attempting to sync a null pref value for " << name; | 225 LOG(ERROR) << "Attempting to sync a null pref value for " << name; | 
| 211 return false; | 226 return false; | 
| 212 } | 227 } | 
| 213 | 228 | 
| 214 std::string serialized; | 229 std::string serialized; | 
| 215 // TODO(zea): consider JSONWriter::Write since you don't have to check | 230 // TODO(zea): consider JSONWriter::Write since you don't have to check | 
| 216 // failures to deserialize. | 231 // failures to deserialize. | 
| 217 JSONStringValueSerializer json(&serialized); | 232 JSONStringValueSerializer json(&serialized); | 
| 218 if (!json.Serialize(value)) { | 233 if (!json.Serialize(value)) { | 
| 219 LOG(ERROR) << "Failed to serialize preference value."; | 234 LOG(ERROR) << "Failed to serialize preference value."; | 
| 220 return false; | 235 return false; | 
| 221 } | 236 } | 
| 222 | 237 | 
| 223 sync_pb::EntitySpecifics specifics; | 238 sync_pb::EntitySpecifics specifics; | 
| 224 sync_pb::PreferenceSpecifics* pref_specifics = specifics.mutable_preference(); | 239 sync_pb::PreferenceSpecifics* pref_specifics; | 
| 240 | |
| 241 if (type_ == PREFERENCES) { | |
| 242 pref_specifics = specifics.mutable_preference(); | |
| 243 } else { | |
| 244 pref_specifics = | |
| 245 specifics.mutable_priority_preference()->mutable_preference(); | |
| 246 } | |
| 247 | |
| 225 pref_specifics->set_name(name); | 248 pref_specifics->set_name(name); | 
| 226 pref_specifics->set_value(serialized); | 249 pref_specifics->set_value(serialized); | 
| 250 | |
| 227 *sync_data = syncer::SyncData::CreateLocalData(name, name, specifics); | 251 *sync_data = syncer::SyncData::CreateLocalData(name, name, specifics); | 
| 228 return true; | 252 return true; | 
| 229 } | 253 } | 
| 230 | 254 | 
| 231 Value* PrefModelAssociator::MergeListValues(const Value& from_value, | 255 Value* PrefModelAssociator::MergeListValues(const Value& from_value, | 
| 232 const Value& to_value) { | 256 const Value& to_value) { | 
| 233 if (from_value.GetType() == Value::TYPE_NULL) | 257 if (from_value.GetType() == Value::TYPE_NULL) | 
| 234 return to_value.DeepCopy(); | 258 return to_value.DeepCopy(); | 
| 235 if (to_value.GetType() == Value::TYPE_NULL) | 259 if (to_value.GetType() == Value::TYPE_NULL) | 
| 236 return from_value.DeepCopy(); | 260 return from_value.DeepCopy(); | 
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 286 return result; | 310 return result; | 
| 287 } | 311 } | 
| 288 | 312 | 
| 289 // Note: This will build a model of all preferences registered as syncable | 313 // Note: This will build a model of all preferences registered as syncable | 
| 290 // with user controlled data. We do not track any information for preferences | 314 // with user controlled data. We do not track any information for preferences | 
| 291 // not registered locally as syncable and do not inform the syncer of | 315 // not registered locally as syncable and do not inform the syncer of | 
| 292 // non-user controlled preferences. | 316 // non-user controlled preferences. | 
| 293 syncer::SyncDataList PrefModelAssociator::GetAllSyncData( | 317 syncer::SyncDataList PrefModelAssociator::GetAllSyncData( | 
| 294 syncer::ModelType type) | 318 syncer::ModelType type) | 
| 295 const { | 319 const { | 
| 296 DCHECK_EQ(PREFERENCES, type); | 320 DCHECK_EQ(type_, type); | 
| 297 syncer::SyncDataList current_data; | 321 syncer::SyncDataList current_data; | 
| 298 for (PreferenceSet::const_iterator iter = synced_preferences_.begin(); | 322 for (PreferenceSet::const_iterator iter = synced_preferences_.begin(); | 
| 299 iter != synced_preferences_.end(); | 323 iter != synced_preferences_.end(); | 
| 300 ++iter) { | 324 ++iter) { | 
| 301 std::string name = *iter; | 325 std::string name = *iter; | 
| 302 const PrefService::Preference* pref = | 326 const PrefService::Preference* pref = | 
| 303 pref_service_->FindPreference(name.c_str()); | 327 pref_service_->FindPreference(name.c_str()); | 
| 304 DCHECK(pref); | 328 DCHECK(pref); | 
| 305 if (!pref->IsUserControlled() || pref->IsDefaultValue()) | 329 if (!pref->IsUserControlled() || pref->IsDefaultValue()) | 
| 306 continue; // This is not data we care about. | 330 continue; // This is not data we care about. | 
| (...skipping 11 matching lines...) Expand all Loading... | |
| 318 const syncer::SyncChangeList& change_list) { | 342 const syncer::SyncChangeList& change_list) { | 
| 319 if (!models_associated_) { | 343 if (!models_associated_) { | 
| 320 syncer::SyncError error(FROM_HERE, | 344 syncer::SyncError error(FROM_HERE, | 
| 321 "Models not yet associated.", | 345 "Models not yet associated.", | 
| 322 PREFERENCES); | 346 PREFERENCES); | 
| 323 return error; | 347 return error; | 
| 324 } | 348 } | 
| 325 base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true); | 349 base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true); | 
| 326 syncer::SyncChangeList::const_iterator iter; | 350 syncer::SyncChangeList::const_iterator iter; | 
| 327 for (iter = change_list.begin(); iter != change_list.end(); ++iter) { | 351 for (iter = change_list.begin(); iter != change_list.end(); ++iter) { | 
| 328 DCHECK_EQ(PREFERENCES, iter->sync_data().GetDataType()); | 352 DCHECK_EQ(type_, iter->sync_data().GetDataType()); | 
| 329 | 353 | 
| 330 std::string name; | 354 std::string name; | 
| 331 sync_pb::PreferenceSpecifics pref_specifics = | 355 sync_pb::PreferenceSpecifics pref_specifics; | 
| 332 iter->sync_data().GetSpecifics().preference(); | 356 if (type_ == PREFERENCES) { | 
| 357 pref_specifics = iter->sync_data().GetSpecifics().preference(); | |
| 358 } else { | |
| 359 pref_specifics = | |
| 360 iter->sync_data().GetSpecifics().priority_preference().preference(); | |
| 361 } | |
| 333 scoped_ptr<Value> value(ReadPreferenceSpecifics(pref_specifics, | 362 scoped_ptr<Value> value(ReadPreferenceSpecifics(pref_specifics, | 
| 334 &name)); | 363 &name)); | 
| 335 | 364 | 
| 336 if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) { | 365 if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) { | 
| 337 // We never delete preferences. | 366 // We never delete preferences. | 
| 338 NOTREACHED() << "Attempted to process sync delete change for " << name | 367 NOTREACHED() << "Attempted to process sync delete change for " << name | 
| 339 << ". Skipping."; | 368 << ". Skipping."; | 
| 340 continue; | 369 continue; | 
| 341 } | 370 } | 
| 342 | 371 | 
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 446 } | 475 } | 
| 447 | 476 | 
| 448 syncer::SyncError error = | 477 syncer::SyncError error = | 
| 449 sync_processor_->ProcessSyncChanges(FROM_HERE, changes); | 478 sync_processor_->ProcessSyncChanges(FROM_HERE, changes); | 
| 450 } | 479 } | 
| 451 | 480 | 
| 452 void PrefModelAssociator::SetPrefService(PrefServiceSyncable* pref_service) { | 481 void PrefModelAssociator::SetPrefService(PrefServiceSyncable* pref_service) { | 
| 453 DCHECK(pref_service_ == NULL); | 482 DCHECK(pref_service_ == NULL); | 
| 454 pref_service_ = pref_service; | 483 pref_service_ = pref_service; | 
| 455 } | 484 } | 
| OLD | NEW |