Home | History | Annotate | Download | only in prefs
      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