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 24namespace { 25 26class 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 41PrefService::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 59PrefService::~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 69void PrefService::InitFromStorage(bool async) { 70 if (!async) { 71 read_error_callback_.Run(user_pref_store_->ReadPrefs()); 72 } else { 73 // Guarantee that initialization happens after this function returned. 74 base::MessageLoop::current()->PostTask( 75 FROM_HERE, 76 base::Bind(&PersistentPrefStore::ReadPrefsAsync, 77 user_pref_store_.get(), 78 new ReadErrorHandler(read_error_callback_))); 79 } 80} 81 82void PrefService::CommitPendingWrite() { 83 DCHECK(CalledOnValidThread()); 84 user_pref_store_->CommitPendingWrite(); 85} 86 87bool PrefService::GetBoolean(const char* path) const { 88 DCHECK(CalledOnValidThread()); 89 90 bool result = false; 91 92 const base::Value* value = GetPreferenceValue(path); 93 if (!value) { 94 NOTREACHED() << "Trying to read an unregistered pref: " << path; 95 return result; 96 } 97 bool rv = value->GetAsBoolean(&result); 98 DCHECK(rv); 99 return result; 100} 101 102int PrefService::GetInteger(const char* path) const { 103 DCHECK(CalledOnValidThread()); 104 105 int result = 0; 106 107 const base::Value* value = GetPreferenceValue(path); 108 if (!value) { 109 NOTREACHED() << "Trying to read an unregistered pref: " << path; 110 return result; 111 } 112 bool rv = value->GetAsInteger(&result); 113 DCHECK(rv); 114 return result; 115} 116 117double PrefService::GetDouble(const char* path) const { 118 DCHECK(CalledOnValidThread()); 119 120 double result = 0.0; 121 122 const base::Value* value = GetPreferenceValue(path); 123 if (!value) { 124 NOTREACHED() << "Trying to read an unregistered pref: " << path; 125 return result; 126 } 127 bool rv = value->GetAsDouble(&result); 128 DCHECK(rv); 129 return result; 130} 131 132std::string PrefService::GetString(const char* path) const { 133 DCHECK(CalledOnValidThread()); 134 135 std::string result; 136 137 const base::Value* value = GetPreferenceValue(path); 138 if (!value) { 139 NOTREACHED() << "Trying to read an unregistered pref: " << path; 140 return result; 141 } 142 bool rv = value->GetAsString(&result); 143 DCHECK(rv); 144 return result; 145} 146 147base::FilePath PrefService::GetFilePath(const char* path) const { 148 DCHECK(CalledOnValidThread()); 149 150 base::FilePath result; 151 152 const base::Value* value = GetPreferenceValue(path); 153 if (!value) { 154 NOTREACHED() << "Trying to read an unregistered pref: " << path; 155 return base::FilePath(result); 156 } 157 bool rv = base::GetValueAsFilePath(*value, &result); 158 DCHECK(rv); 159 return result; 160} 161 162bool PrefService::HasPrefPath(const char* path) const { 163 const Preference* pref = FindPreference(path); 164 return pref && !pref->IsDefaultValue(); 165} 166 167scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValues() const { 168 DCHECK(CalledOnValidThread()); 169 scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue); 170 PrefRegistry::const_iterator i = pref_registry_->begin(); 171 for (; i != pref_registry_->end(); ++i) { 172 const base::Value* value = GetPreferenceValue(i->first); 173 DCHECK(value); 174 out->Set(i->first, value->DeepCopy()); 175 } 176 return out.Pass(); 177} 178 179scoped_ptr<base::DictionaryValue> 180PrefService::GetPreferenceValuesWithoutPathExpansion() const { 181 DCHECK(CalledOnValidThread()); 182 scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue); 183 PrefRegistry::const_iterator i = pref_registry_->begin(); 184 for (; i != pref_registry_->end(); ++i) { 185 const base::Value* value = GetPreferenceValue(i->first); 186 DCHECK(value); 187 out->SetWithoutPathExpansion(i->first, value->DeepCopy()); 188 } 189 return out.Pass(); 190} 191 192const PrefService::Preference* PrefService::FindPreference( 193 const char* pref_name) const { 194 DCHECK(CalledOnValidThread()); 195 PreferenceMap::iterator it = prefs_map_.find(pref_name); 196 if (it != prefs_map_.end()) 197 return &(it->second); 198 const base::Value* default_value = NULL; 199 if (!pref_registry_->defaults()->GetValue(pref_name, &default_value)) 200 return NULL; 201 it = prefs_map_.insert( 202 std::make_pair(pref_name, Preference( 203 this, pref_name, default_value->GetType()))).first; 204 return &(it->second); 205} 206 207bool PrefService::ReadOnly() const { 208 return user_pref_store_->ReadOnly(); 209} 210 211PrefService::PrefInitializationStatus PrefService::GetInitializationStatus() 212 const { 213 if (!user_pref_store_->IsInitializationComplete()) 214 return INITIALIZATION_STATUS_WAITING; 215 216 switch (user_pref_store_->GetReadError()) { 217 case PersistentPrefStore::PREF_READ_ERROR_NONE: 218 return INITIALIZATION_STATUS_SUCCESS; 219 case PersistentPrefStore::PREF_READ_ERROR_NO_FILE: 220 return INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE; 221 default: 222 return INITIALIZATION_STATUS_ERROR; 223 } 224} 225 226bool PrefService::IsManagedPreference(const char* pref_name) const { 227 const Preference* pref = FindPreference(pref_name); 228 return pref && pref->IsManaged(); 229} 230 231bool PrefService::IsUserModifiablePreference(const char* pref_name) const { 232 const Preference* pref = FindPreference(pref_name); 233 return pref && pref->IsUserModifiable(); 234} 235 236const base::DictionaryValue* PrefService::GetDictionary( 237 const char* path) const { 238 DCHECK(CalledOnValidThread()); 239 240 const base::Value* value = GetPreferenceValue(path); 241 if (!value) { 242 NOTREACHED() << "Trying to read an unregistered pref: " << path; 243 return NULL; 244 } 245 if (value->GetType() != base::Value::TYPE_DICTIONARY) { 246 NOTREACHED(); 247 return NULL; 248 } 249 return static_cast<const base::DictionaryValue*>(value); 250} 251 252const base::Value* PrefService::GetUserPrefValue(const char* path) const { 253 DCHECK(CalledOnValidThread()); 254 255 const Preference* pref = FindPreference(path); 256 if (!pref) { 257 NOTREACHED() << "Trying to get an unregistered pref: " << path; 258 return NULL; 259 } 260 261 // Look for an existing preference in the user store. If it doesn't 262 // exist, return NULL. 263 base::Value* value = NULL; 264 if (!user_pref_store_->GetMutableValue(path, &value)) 265 return NULL; 266 267 if (!value->IsType(pref->GetType())) { 268 NOTREACHED() << "Pref value type doesn't match registered type."; 269 return NULL; 270 } 271 272 return value; 273} 274 275void PrefService::SetDefaultPrefValue(const char* path, 276 base::Value* value) { 277 DCHECK(CalledOnValidThread()); 278 pref_registry_->SetDefaultPrefValue(path, value); 279} 280 281const base::Value* PrefService::GetDefaultPrefValue(const char* path) const { 282 DCHECK(CalledOnValidThread()); 283 // Lookup the preference in the default store. 284 const base::Value* value = NULL; 285 if (!pref_registry_->defaults()->GetValue(path, &value)) { 286 NOTREACHED() << "Default value missing for pref: " << path; 287 return NULL; 288 } 289 return value; 290} 291 292const base::ListValue* PrefService::GetList(const char* path) const { 293 DCHECK(CalledOnValidThread()); 294 295 const base::Value* value = GetPreferenceValue(path); 296 if (!value) { 297 NOTREACHED() << "Trying to read an unregistered pref: " << path; 298 return NULL; 299 } 300 if (value->GetType() != base::Value::TYPE_LIST) { 301 NOTREACHED(); 302 return NULL; 303 } 304 return static_cast<const base::ListValue*>(value); 305} 306 307void PrefService::AddPrefObserver(const char* path, PrefObserver* obs) { 308 pref_notifier_->AddPrefObserver(path, obs); 309} 310 311void PrefService::RemovePrefObserver(const char* path, PrefObserver* obs) { 312 pref_notifier_->RemovePrefObserver(path, obs); 313} 314 315void PrefService::AddPrefInitObserver(base::Callback<void(bool)> obs) { 316 pref_notifier_->AddInitObserver(obs); 317} 318 319PrefRegistry* PrefService::DeprecatedGetPrefRegistry() { 320 return pref_registry_.get(); 321} 322 323void PrefService::ClearPref(const char* path) { 324 DCHECK(CalledOnValidThread()); 325 326 const Preference* pref = FindPreference(path); 327 if (!pref) { 328 NOTREACHED() << "Trying to clear an unregistered pref: " << path; 329 return; 330 } 331 user_pref_store_->RemoveValue(path); 332} 333 334void PrefService::Set(const char* path, const base::Value& value) { 335 SetUserPrefValue(path, value.DeepCopy()); 336} 337 338void PrefService::SetBoolean(const char* path, bool value) { 339 SetUserPrefValue(path, base::Value::CreateBooleanValue(value)); 340} 341 342void PrefService::SetInteger(const char* path, int value) { 343 SetUserPrefValue(path, base::Value::CreateIntegerValue(value)); 344} 345 346void PrefService::SetDouble(const char* path, double value) { 347 SetUserPrefValue(path, base::Value::CreateDoubleValue(value)); 348} 349 350void PrefService::SetString(const char* path, const std::string& value) { 351 SetUserPrefValue(path, base::Value::CreateStringValue(value)); 352} 353 354void PrefService::SetFilePath(const char* path, const base::FilePath& value) { 355 SetUserPrefValue(path, base::CreateFilePathValue(value)); 356} 357 358void PrefService::SetInt64(const char* path, int64 value) { 359 SetUserPrefValue(path, 360 base::Value::CreateStringValue(base::Int64ToString(value))); 361} 362 363int64 PrefService::GetInt64(const char* path) const { 364 DCHECK(CalledOnValidThread()); 365 366 const base::Value* value = GetPreferenceValue(path); 367 if (!value) { 368 NOTREACHED() << "Trying to read an unregistered pref: " << path; 369 return 0; 370 } 371 std::string result("0"); 372 bool rv = value->GetAsString(&result); 373 DCHECK(rv); 374 375 int64 val; 376 base::StringToInt64(result, &val); 377 return val; 378} 379 380void PrefService::SetUint64(const char* path, uint64 value) { 381 SetUserPrefValue(path, 382 base::Value::CreateStringValue(base::Uint64ToString(value))); 383} 384 385uint64 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 402base::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 434void PrefService::ReportUserPrefChanged(const std::string& key) { 435 user_pref_store_->ReportValueChanged(key); 436} 437 438void 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 457void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) { 458 pref_value_store_->UpdateCommandLinePrefStore(command_line_store); 459} 460 461/////////////////////////////////////////////////////////////////////////////// 462// PrefService::Preference 463 464PrefService::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 474const std::string PrefService::Preference::name() const { 475 return name_; 476} 477 478base::Value::Type PrefService::Preference::GetType() const { 479 return type_; 480} 481 482const 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 488const 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 502bool PrefService::Preference::IsManaged() const { 503 return pref_value_store()->PrefValueInManagedStore(name_.c_str()); 504} 505 506bool PrefService::Preference::IsRecommended() const { 507 return pref_value_store()->PrefValueFromRecommendedStore(name_.c_str()); 508} 509 510bool PrefService::Preference::HasExtensionSetting() const { 511 return pref_value_store()->PrefValueInExtensionStore(name_.c_str()); 512} 513 514bool PrefService::Preference::HasUserSetting() const { 515 return pref_value_store()->PrefValueInUserStore(name_.c_str()); 516} 517 518bool PrefService::Preference::IsExtensionControlled() const { 519 return pref_value_store()->PrefValueFromExtensionStore(name_.c_str()); 520} 521 522bool PrefService::Preference::IsUserControlled() const { 523 return pref_value_store()->PrefValueFromUserStore(name_.c_str()); 524} 525 526bool PrefService::Preference::IsDefaultValue() const { 527 return pref_value_store()->PrefValueFromDefaultStore(name_.c_str()); 528} 529 530bool PrefService::Preference::IsUserModifiable() const { 531 return pref_value_store()->PrefValueUserModifiable(name_.c_str()); 532} 533 534bool PrefService::Preference::IsExtensionModifiable() const { 535 return pref_value_store()->PrefValueExtensionModifiable(name_.c_str()); 536} 537 538const 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