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 "base/prefs/pref_service.h" 6 7 #include <algorithm> 8 9 #include "base/bind.h" 10 #include "base/files/file_path.h" 11 #include "base/logging.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/metrics/histogram.h" 14 #include "base/prefs/default_pref_store.h" 15 #include "base/prefs/pref_notifier_impl.h" 16 #include "base/prefs/pref_registry.h" 17 #include "base/prefs/pref_value_store.h" 18 #include "base/stl_util.h" 19 #include "base/strings/string_number_conversions.h" 20 #include "base/strings/string_util.h" 21 #include "base/value_conversions.h" 22 #include "build/build_config.h" 23 24 namespace { 25 26 class ReadErrorHandler : public PersistentPrefStore::ReadErrorDelegate { 27 public: 28 ReadErrorHandler(base::Callback<void(PersistentPrefStore::PrefReadError)> cb) 29 : callback_(cb) {} 30 31 virtual void OnError(PersistentPrefStore::PrefReadError error) OVERRIDE { 32 callback_.Run(error); 33 } 34 35 private: 36 base::Callback<void(PersistentPrefStore::PrefReadError)> callback_; 37 }; 38 39 } // namespace 40 41 PrefService::PrefService( 42 PrefNotifierImpl* pref_notifier, 43 PrefValueStore* pref_value_store, 44 PersistentPrefStore* user_prefs, 45 PrefRegistry* pref_registry, 46 base::Callback<void(PersistentPrefStore::PrefReadError)> 47 read_error_callback, 48 bool async) 49 : pref_notifier_(pref_notifier), 50 pref_value_store_(pref_value_store), 51 pref_registry_(pref_registry), 52 user_pref_store_(user_prefs), 53 read_error_callback_(read_error_callback) { 54 pref_notifier_->SetPrefService(this); 55 56 InitFromStorage(async); 57 } 58 59 PrefService::~PrefService() { 60 DCHECK(CalledOnValidThread()); 61 62 // Reset pointers so accesses after destruction reliably crash. 63 pref_value_store_.reset(); 64 pref_registry_ = NULL; 65 user_pref_store_ = NULL; 66 pref_notifier_.reset(); 67 } 68 69 void PrefService::InitFromStorage(bool async) { 70 if (user_pref_store_->IsInitializationComplete()) { 71 read_error_callback_.Run(user_pref_store_->GetReadError()); 72 } else if (!async) { 73 read_error_callback_.Run(user_pref_store_->ReadPrefs()); 74 } else { 75 // Guarantee that initialization happens after this function returned. 76 base::MessageLoop::current()->PostTask( 77 FROM_HERE, 78 base::Bind(&PersistentPrefStore::ReadPrefsAsync, 79 user_pref_store_.get(), 80 new ReadErrorHandler(read_error_callback_))); 81 } 82 } 83 84 void PrefService::CommitPendingWrite() { 85 DCHECK(CalledOnValidThread()); 86 user_pref_store_->CommitPendingWrite(); 87 } 88 89 bool PrefService::GetBoolean(const char* path) const { 90 DCHECK(CalledOnValidThread()); 91 92 bool result = false; 93 94 const base::Value* value = GetPreferenceValue(path); 95 if (!value) { 96 NOTREACHED() << "Trying to read an unregistered pref: " << path; 97 return result; 98 } 99 bool rv = value->GetAsBoolean(&result); 100 DCHECK(rv); 101 return result; 102 } 103 104 int PrefService::GetInteger(const char* path) const { 105 DCHECK(CalledOnValidThread()); 106 107 int result = 0; 108 109 const base::Value* value = GetPreferenceValue(path); 110 if (!value) { 111 NOTREACHED() << "Trying to read an unregistered pref: " << path; 112 return result; 113 } 114 bool rv = value->GetAsInteger(&result); 115 DCHECK(rv); 116 return result; 117 } 118 119 double PrefService::GetDouble(const char* path) const { 120 DCHECK(CalledOnValidThread()); 121 122 double result = 0.0; 123 124 const base::Value* value = GetPreferenceValue(path); 125 if (!value) { 126 NOTREACHED() << "Trying to read an unregistered pref: " << path; 127 return result; 128 } 129 bool rv = value->GetAsDouble(&result); 130 DCHECK(rv); 131 return result; 132 } 133 134 std::string PrefService::GetString(const char* path) const { 135 DCHECK(CalledOnValidThread()); 136 137 std::string result; 138 139 const base::Value* value = GetPreferenceValue(path); 140 if (!value) { 141 NOTREACHED() << "Trying to read an unregistered pref: " << path; 142 return result; 143 } 144 bool rv = value->GetAsString(&result); 145 DCHECK(rv); 146 return result; 147 } 148 149 base::FilePath PrefService::GetFilePath(const char* path) const { 150 DCHECK(CalledOnValidThread()); 151 152 base::FilePath result; 153 154 const base::Value* value = GetPreferenceValue(path); 155 if (!value) { 156 NOTREACHED() << "Trying to read an unregistered pref: " << path; 157 return base::FilePath(result); 158 } 159 bool rv = base::GetValueAsFilePath(*value, &result); 160 DCHECK(rv); 161 return result; 162 } 163 164 bool PrefService::HasPrefPath(const char* path) const { 165 const Preference* pref = FindPreference(path); 166 return pref && !pref->IsDefaultValue(); 167 } 168 169 scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValues() const { 170 DCHECK(CalledOnValidThread()); 171 scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue); 172 PrefRegistry::const_iterator i = pref_registry_->begin(); 173 for (; i != pref_registry_->end(); ++i) { 174 const base::Value* value = GetPreferenceValue(i->first); 175 DCHECK(value); 176 out->Set(i->first, value->DeepCopy()); 177 } 178 return out.Pass(); 179 } 180 181 scoped_ptr<base::DictionaryValue> 182 PrefService::GetPreferenceValuesWithoutPathExpansion() const { 183 DCHECK(CalledOnValidThread()); 184 scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue); 185 PrefRegistry::const_iterator i = pref_registry_->begin(); 186 for (; i != pref_registry_->end(); ++i) { 187 const base::Value* value = GetPreferenceValue(i->first); 188 DCHECK(value); 189 out->SetWithoutPathExpansion(i->first, value->DeepCopy()); 190 } 191 return out.Pass(); 192 } 193 194 const PrefService::Preference* PrefService::FindPreference( 195 const char* pref_name) const { 196 DCHECK(CalledOnValidThread()); 197 PreferenceMap::iterator it = prefs_map_.find(pref_name); 198 if (it != prefs_map_.end()) 199 return &(it->second); 200 const base::Value* default_value = NULL; 201 if (!pref_registry_->defaults()->GetValue(pref_name, &default_value)) 202 return NULL; 203 it = prefs_map_.insert( 204 std::make_pair(pref_name, Preference( 205 this, pref_name, default_value->GetType()))).first; 206 return &(it->second); 207 } 208 209 bool PrefService::ReadOnly() const { 210 return user_pref_store_->ReadOnly(); 211 } 212 213 PrefService::PrefInitializationStatus PrefService::GetInitializationStatus() 214 const { 215 if (!user_pref_store_->IsInitializationComplete()) 216 return INITIALIZATION_STATUS_WAITING; 217 218 switch (user_pref_store_->GetReadError()) { 219 case PersistentPrefStore::PREF_READ_ERROR_NONE: 220 return INITIALIZATION_STATUS_SUCCESS; 221 case PersistentPrefStore::PREF_READ_ERROR_NO_FILE: 222 return INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE; 223 default: 224 return INITIALIZATION_STATUS_ERROR; 225 } 226 } 227 228 bool PrefService::IsManagedPreference(const char* pref_name) const { 229 const Preference* pref = FindPreference(pref_name); 230 return pref && pref->IsManaged(); 231 } 232 233 bool PrefService::IsUserModifiablePreference(const char* pref_name) const { 234 const Preference* pref = FindPreference(pref_name); 235 return pref && pref->IsUserModifiable(); 236 } 237 238 const base::DictionaryValue* PrefService::GetDictionary( 239 const char* path) const { 240 DCHECK(CalledOnValidThread()); 241 242 const base::Value* value = GetPreferenceValue(path); 243 if (!value) { 244 NOTREACHED() << "Trying to read an unregistered pref: " << path; 245 return NULL; 246 } 247 if (value->GetType() != base::Value::TYPE_DICTIONARY) { 248 NOTREACHED(); 249 return NULL; 250 } 251 return static_cast<const base::DictionaryValue*>(value); 252 } 253 254 const base::Value* PrefService::GetUserPrefValue(const char* path) const { 255 DCHECK(CalledOnValidThread()); 256 257 const Preference* pref = FindPreference(path); 258 if (!pref) { 259 NOTREACHED() << "Trying to get an unregistered pref: " << path; 260 return NULL; 261 } 262 263 // Look for an existing preference in the user store. If it doesn't 264 // exist, return NULL. 265 base::Value* value = NULL; 266 if (!user_pref_store_->GetMutableValue(path, &value)) 267 return NULL; 268 269 if (!value->IsType(pref->GetType())) { 270 NOTREACHED() << "Pref value type doesn't match registered type."; 271 return NULL; 272 } 273 274 return value; 275 } 276 277 void PrefService::SetDefaultPrefValue(const char* path, 278 base::Value* value) { 279 DCHECK(CalledOnValidThread()); 280 pref_registry_->SetDefaultPrefValue(path, value); 281 } 282 283 const base::Value* PrefService::GetDefaultPrefValue(const char* path) const { 284 DCHECK(CalledOnValidThread()); 285 // Lookup the preference in the default store. 286 const base::Value* value = NULL; 287 if (!pref_registry_->defaults()->GetValue(path, &value)) { 288 NOTREACHED() << "Default value missing for pref: " << path; 289 return NULL; 290 } 291 return value; 292 } 293 294 const base::ListValue* PrefService::GetList(const char* path) const { 295 DCHECK(CalledOnValidThread()); 296 297 const base::Value* value = GetPreferenceValue(path); 298 if (!value) { 299 NOTREACHED() << "Trying to read an unregistered pref: " << path; 300 return NULL; 301 } 302 if (value->GetType() != base::Value::TYPE_LIST) { 303 NOTREACHED(); 304 return NULL; 305 } 306 return static_cast<const base::ListValue*>(value); 307 } 308 309 void PrefService::AddPrefObserver(const char* path, PrefObserver* obs) { 310 pref_notifier_->AddPrefObserver(path, obs); 311 } 312 313 void PrefService::RemovePrefObserver(const char* path, PrefObserver* obs) { 314 pref_notifier_->RemovePrefObserver(path, obs); 315 } 316 317 void PrefService::AddPrefInitObserver(base::Callback<void(bool)> obs) { 318 pref_notifier_->AddInitObserver(obs); 319 } 320 321 PrefRegistry* PrefService::DeprecatedGetPrefRegistry() { 322 return pref_registry_.get(); 323 } 324 325 void PrefService::ClearPref(const char* path) { 326 DCHECK(CalledOnValidThread()); 327 328 const Preference* pref = FindPreference(path); 329 if (!pref) { 330 NOTREACHED() << "Trying to clear an unregistered pref: " << path; 331 return; 332 } 333 user_pref_store_->RemoveValue(path); 334 } 335 336 void PrefService::Set(const char* path, const base::Value& value) { 337 SetUserPrefValue(path, value.DeepCopy()); 338 } 339 340 void PrefService::SetBoolean(const char* path, bool value) { 341 SetUserPrefValue(path, new base::FundamentalValue(value)); 342 } 343 344 void PrefService::SetInteger(const char* path, int value) { 345 SetUserPrefValue(path, new base::FundamentalValue(value)); 346 } 347 348 void PrefService::SetDouble(const char* path, double value) { 349 SetUserPrefValue(path, new base::FundamentalValue(value)); 350 } 351 352 void PrefService::SetString(const char* path, const std::string& value) { 353 SetUserPrefValue(path, new base::StringValue(value)); 354 } 355 356 void PrefService::SetFilePath(const char* path, const base::FilePath& value) { 357 SetUserPrefValue(path, base::CreateFilePathValue(value)); 358 } 359 360 void PrefService::SetInt64(const char* path, int64 value) { 361 SetUserPrefValue(path, new base::StringValue(base::Int64ToString(value))); 362 } 363 364 int64 PrefService::GetInt64(const char* path) const { 365 DCHECK(CalledOnValidThread()); 366 367 const base::Value* value = GetPreferenceValue(path); 368 if (!value) { 369 NOTREACHED() << "Trying to read an unregistered pref: " << path; 370 return 0; 371 } 372 std::string result("0"); 373 bool rv = value->GetAsString(&result); 374 DCHECK(rv); 375 376 int64 val; 377 base::StringToInt64(result, &val); 378 return val; 379 } 380 381 void PrefService::SetUint64(const char* path, uint64 value) { 382 SetUserPrefValue(path, new base::StringValue(base::Uint64ToString(value))); 383 } 384 385 uint64 PrefService::GetUint64(const char* path) const { 386 DCHECK(CalledOnValidThread()); 387 388 const base::Value* value = GetPreferenceValue(path); 389 if (!value) { 390 NOTREACHED() << "Trying to read an unregistered pref: " << path; 391 return 0; 392 } 393 std::string result("0"); 394 bool rv = value->GetAsString(&result); 395 DCHECK(rv); 396 397 uint64 val; 398 base::StringToUint64(result, &val); 399 return val; 400 } 401 402 base::Value* PrefService::GetMutableUserPref(const char* path, 403 base::Value::Type type) { 404 CHECK(type == base::Value::TYPE_DICTIONARY || type == base::Value::TYPE_LIST); 405 DCHECK(CalledOnValidThread()); 406 407 const Preference* pref = FindPreference(path); 408 if (!pref) { 409 NOTREACHED() << "Trying to get an unregistered pref: " << path; 410 return NULL; 411 } 412 if (pref->GetType() != type) { 413 NOTREACHED() << "Wrong type for GetMutableValue: " << path; 414 return NULL; 415 } 416 417 // Look for an existing preference in the user store. If it doesn't 418 // exist or isn't the correct type, create a new user preference. 419 base::Value* value = NULL; 420 if (!user_pref_store_->GetMutableValue(path, &value) || 421 !value->IsType(type)) { 422 if (type == base::Value::TYPE_DICTIONARY) { 423 value = new base::DictionaryValue; 424 } else if (type == base::Value::TYPE_LIST) { 425 value = new base::ListValue; 426 } else { 427 NOTREACHED(); 428 } 429 user_pref_store_->SetValueSilently(path, value); 430 } 431 return value; 432 } 433 434 void PrefService::ReportUserPrefChanged(const std::string& key) { 435 user_pref_store_->ReportValueChanged(key); 436 } 437 438 void PrefService::SetUserPrefValue(const char* path, base::Value* new_value) { 439 scoped_ptr<base::Value> owned_value(new_value); 440 DCHECK(CalledOnValidThread()); 441 442 const Preference* pref = FindPreference(path); 443 if (!pref) { 444 NOTREACHED() << "Trying to write an unregistered pref: " << path; 445 return; 446 } 447 if (pref->GetType() != new_value->GetType()) { 448 NOTREACHED() << "Trying to set pref " << path 449 << " of type " << pref->GetType() 450 << " to value of type " << new_value->GetType(); 451 return; 452 } 453 454 user_pref_store_->SetValue(path, owned_value.release()); 455 } 456 457 void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) { 458 pref_value_store_->UpdateCommandLinePrefStore(command_line_store); 459 } 460 461 /////////////////////////////////////////////////////////////////////////////// 462 // PrefService::Preference 463 464 PrefService::Preference::Preference(const PrefService* service, 465 const char* name, 466 base::Value::Type type) 467 : name_(name), 468 type_(type), 469 pref_service_(service) { 470 DCHECK(name); 471 DCHECK(service); 472 } 473 474 const std::string PrefService::Preference::name() const { 475 return name_; 476 } 477 478 base::Value::Type PrefService::Preference::GetType() const { 479 return type_; 480 } 481 482 const base::Value* PrefService::Preference::GetValue() const { 483 const base::Value* result= pref_service_->GetPreferenceValue(name_); 484 DCHECK(result) << "Must register pref before getting its value"; 485 return result; 486 } 487 488 const base::Value* PrefService::Preference::GetRecommendedValue() const { 489 DCHECK(pref_service_->FindPreference(name_.c_str())) << 490 "Must register pref before getting its value"; 491 492 const base::Value* found_value = NULL; 493 if (pref_value_store()->GetRecommendedValue(name_, type_, &found_value)) { 494 DCHECK(found_value->IsType(type_)); 495 return found_value; 496 } 497 498 // The pref has no recommended value. 499 return NULL; 500 } 501 502 bool PrefService::Preference::IsManaged() const { 503 return pref_value_store()->PrefValueInManagedStore(name_.c_str()); 504 } 505 506 bool PrefService::Preference::IsRecommended() const { 507 return pref_value_store()->PrefValueFromRecommendedStore(name_.c_str()); 508 } 509 510 bool PrefService::Preference::HasExtensionSetting() const { 511 return pref_value_store()->PrefValueInExtensionStore(name_.c_str()); 512 } 513 514 bool PrefService::Preference::HasUserSetting() const { 515 return pref_value_store()->PrefValueInUserStore(name_.c_str()); 516 } 517 518 bool PrefService::Preference::IsExtensionControlled() const { 519 return pref_value_store()->PrefValueFromExtensionStore(name_.c_str()); 520 } 521 522 bool PrefService::Preference::IsUserControlled() const { 523 return pref_value_store()->PrefValueFromUserStore(name_.c_str()); 524 } 525 526 bool PrefService::Preference::IsDefaultValue() const { 527 return pref_value_store()->PrefValueFromDefaultStore(name_.c_str()); 528 } 529 530 bool PrefService::Preference::IsUserModifiable() const { 531 return pref_value_store()->PrefValueUserModifiable(name_.c_str()); 532 } 533 534 bool PrefService::Preference::IsExtensionModifiable() const { 535 return pref_value_store()->PrefValueExtensionModifiable(name_.c_str()); 536 } 537 538 const base::Value* PrefService::GetPreferenceValue( 539 const std::string& path) const { 540 DCHECK(CalledOnValidThread()); 541 const base::Value* default_value = NULL; 542 if (pref_registry_->defaults()->GetValue(path, &default_value)) { 543 const base::Value* found_value = NULL; 544 base::Value::Type default_type = default_value->GetType(); 545 if (pref_value_store_->GetValue(path, default_type, &found_value)) { 546 DCHECK(found_value->IsType(default_type)); 547 return found_value; 548 } else { 549 // Every registered preference has at least a default value. 550 NOTREACHED() << "no valid value found for registered pref " << path; 551 } 552 } 553 554 return NULL; 555 } 556