pref_service.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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, new base::FundamentalValue(value)); 340} 341 342void PrefService::SetInteger(const char* path, int value) { 343 SetUserPrefValue(path, new base::FundamentalValue(value)); 344} 345 346void PrefService::SetDouble(const char* path, double value) { 347 SetUserPrefValue(path, new base::FundamentalValue(value)); 348} 349 350void PrefService::SetString(const char* path, const std::string& value) { 351 SetUserPrefValue(path, new base::StringValue(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, new base::StringValue(base::Int64ToString(value))); 360} 361 362int64 PrefService::GetInt64(const char* path) const { 363 DCHECK(CalledOnValidThread()); 364 365 const base::Value* value = GetPreferenceValue(path); 366 if (!value) { 367 NOTREACHED() << "Trying to read an unregistered pref: " << path; 368 return 0; 369 } 370 std::string result("0"); 371 bool rv = value->GetAsString(&result); 372 DCHECK(rv); 373 374 int64 val; 375 base::StringToInt64(result, &val); 376 return val; 377} 378 379void PrefService::SetUint64(const char* path, uint64 value) { 380 SetUserPrefValue(path, new base::StringValue(base::Uint64ToString(value))); 381} 382 383uint64 PrefService::GetUint64(const char* path) const { 384 DCHECK(CalledOnValidThread()); 385 386 const base::Value* value = GetPreferenceValue(path); 387 if (!value) { 388 NOTREACHED() << "Trying to read an unregistered pref: " << path; 389 return 0; 390 } 391 std::string result("0"); 392 bool rv = value->GetAsString(&result); 393 DCHECK(rv); 394 395 uint64 val; 396 base::StringToUint64(result, &val); 397 return val; 398} 399 400base::Value* PrefService::GetMutableUserPref(const char* path, 401 base::Value::Type type) { 402 CHECK(type == base::Value::TYPE_DICTIONARY || type == base::Value::TYPE_LIST); 403 DCHECK(CalledOnValidThread()); 404 405 const Preference* pref = FindPreference(path); 406 if (!pref) { 407 NOTREACHED() << "Trying to get an unregistered pref: " << path; 408 return NULL; 409 } 410 if (pref->GetType() != type) { 411 NOTREACHED() << "Wrong type for GetMutableValue: " << path; 412 return NULL; 413 } 414 415 // Look for an existing preference in the user store. If it doesn't 416 // exist or isn't the correct type, create a new user preference. 417 base::Value* value = NULL; 418 if (!user_pref_store_->GetMutableValue(path, &value) || 419 !value->IsType(type)) { 420 if (type == base::Value::TYPE_DICTIONARY) { 421 value = new base::DictionaryValue; 422 } else if (type == base::Value::TYPE_LIST) { 423 value = new base::ListValue; 424 } else { 425 NOTREACHED(); 426 } 427 user_pref_store_->SetValueSilently(path, value); 428 } 429 return value; 430} 431 432void PrefService::ReportUserPrefChanged(const std::string& key) { 433 user_pref_store_->ReportValueChanged(key); 434} 435 436void PrefService::SetUserPrefValue(const char* path, base::Value* new_value) { 437 scoped_ptr<base::Value> owned_value(new_value); 438 DCHECK(CalledOnValidThread()); 439 440 const Preference* pref = FindPreference(path); 441 if (!pref) { 442 NOTREACHED() << "Trying to write an unregistered pref: " << path; 443 return; 444 } 445 if (pref->GetType() != new_value->GetType()) { 446 NOTREACHED() << "Trying to set pref " << path 447 << " of type " << pref->GetType() 448 << " to value of type " << new_value->GetType(); 449 return; 450 } 451 452 user_pref_store_->SetValue(path, owned_value.release()); 453} 454 455void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) { 456 pref_value_store_->UpdateCommandLinePrefStore(command_line_store); 457} 458 459/////////////////////////////////////////////////////////////////////////////// 460// PrefService::Preference 461 462PrefService::Preference::Preference(const PrefService* service, 463 const char* name, 464 base::Value::Type type) 465 : name_(name), 466 type_(type), 467 pref_service_(service) { 468 DCHECK(name); 469 DCHECK(service); 470} 471 472const std::string PrefService::Preference::name() const { 473 return name_; 474} 475 476base::Value::Type PrefService::Preference::GetType() const { 477 return type_; 478} 479 480const base::Value* PrefService::Preference::GetValue() const { 481 const base::Value* result= pref_service_->GetPreferenceValue(name_); 482 DCHECK(result) << "Must register pref before getting its value"; 483 return result; 484} 485 486const base::Value* PrefService::Preference::GetRecommendedValue() const { 487 DCHECK(pref_service_->FindPreference(name_.c_str())) << 488 "Must register pref before getting its value"; 489 490 const base::Value* found_value = NULL; 491 if (pref_value_store()->GetRecommendedValue(name_, type_, &found_value)) { 492 DCHECK(found_value->IsType(type_)); 493 return found_value; 494 } 495 496 // The pref has no recommended value. 497 return NULL; 498} 499 500bool PrefService::Preference::IsManaged() const { 501 return pref_value_store()->PrefValueInManagedStore(name_.c_str()); 502} 503 504bool PrefService::Preference::IsRecommended() const { 505 return pref_value_store()->PrefValueFromRecommendedStore(name_.c_str()); 506} 507 508bool PrefService::Preference::HasExtensionSetting() const { 509 return pref_value_store()->PrefValueInExtensionStore(name_.c_str()); 510} 511 512bool PrefService::Preference::HasUserSetting() const { 513 return pref_value_store()->PrefValueInUserStore(name_.c_str()); 514} 515 516bool PrefService::Preference::IsExtensionControlled() const { 517 return pref_value_store()->PrefValueFromExtensionStore(name_.c_str()); 518} 519 520bool PrefService::Preference::IsUserControlled() const { 521 return pref_value_store()->PrefValueFromUserStore(name_.c_str()); 522} 523 524bool PrefService::Preference::IsDefaultValue() const { 525 return pref_value_store()->PrefValueFromDefaultStore(name_.c_str()); 526} 527 528bool PrefService::Preference::IsUserModifiable() const { 529 return pref_value_store()->PrefValueUserModifiable(name_.c_str()); 530} 531 532bool PrefService::Preference::IsExtensionModifiable() const { 533 return pref_value_store()->PrefValueExtensionModifiable(name_.c_str()); 534} 535 536const base::Value* PrefService::GetPreferenceValue( 537 const std::string& path) const { 538 DCHECK(CalledOnValidThread()); 539 const base::Value* default_value = NULL; 540 if (pref_registry_->defaults()->GetValue(path, &default_value)) { 541 const base::Value* found_value = NULL; 542 base::Value::Type default_type = default_value->GetType(); 543 if (pref_value_store_->GetValue(path, default_type, &found_value)) { 544 DCHECK(found_value->IsType(default_type)); 545 return found_value; 546 } else { 547 // Every registered preference has at least a default value. 548 NOTREACHED() << "no valid value found for registered pref " << path; 549 } 550 } 551 552 return NULL; 553} 554