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 (!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 
     82 void PrefService::CommitPendingWrite() {
     83   DCHECK(CalledOnValidThread());
     84   user_pref_store_->CommitPendingWrite();
     85 }
     86 
     87 bool 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 
    102 int 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 
    117 double 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 
    132 std::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 
    147 base::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 
    162 bool PrefService::HasPrefPath(const char* path) const {
    163   const Preference* pref = FindPreference(path);
    164   return pref && !pref->IsDefaultValue();
    165 }
    166 
    167 scoped_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 
    179 scoped_ptr<base::DictionaryValue>
    180 PrefService::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 
    192 const 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 
    207 bool PrefService::ReadOnly() const {
    208   return user_pref_store_->ReadOnly();
    209 }
    210 
    211 PrefService::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 
    226 bool PrefService::IsManagedPreference(const char* pref_name) const {
    227   const Preference* pref = FindPreference(pref_name);
    228   return pref && pref->IsManaged();
    229 }
    230 
    231 bool PrefService::IsUserModifiablePreference(const char* pref_name) const {
    232   const Preference* pref = FindPreference(pref_name);
    233   return pref && pref->IsUserModifiable();
    234 }
    235 
    236 const 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 
    252 const 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 
    275 void PrefService::SetDefaultPrefValue(const char* path,
    276                                       base::Value* value) {
    277   DCHECK(CalledOnValidThread());
    278   pref_registry_->SetDefaultPrefValue(path, value);
    279 }
    280 
    281 const 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 
    292 const 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 
    307 void PrefService::AddPrefObserver(const char* path, PrefObserver* obs) {
    308   pref_notifier_->AddPrefObserver(path, obs);
    309 }
    310 
    311 void PrefService::RemovePrefObserver(const char* path, PrefObserver* obs) {
    312   pref_notifier_->RemovePrefObserver(path, obs);
    313 }
    314 
    315 void PrefService::AddPrefInitObserver(base::Callback<void(bool)> obs) {
    316   pref_notifier_->AddInitObserver(obs);
    317 }
    318 
    319 PrefRegistry* PrefService::DeprecatedGetPrefRegistry() {
    320   return pref_registry_.get();
    321 }
    322 
    323 void 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 
    334 void PrefService::Set(const char* path, const base::Value& value) {
    335   SetUserPrefValue(path, value.DeepCopy());
    336 }
    337 
    338 void PrefService::SetBoolean(const char* path, bool value) {
    339   SetUserPrefValue(path, base::Value::CreateBooleanValue(value));
    340 }
    341 
    342 void PrefService::SetInteger(const char* path, int value) {
    343   SetUserPrefValue(path, base::Value::CreateIntegerValue(value));
    344 }
    345 
    346 void PrefService::SetDouble(const char* path, double value) {
    347   SetUserPrefValue(path, base::Value::CreateDoubleValue(value));
    348 }
    349 
    350 void PrefService::SetString(const char* path, const std::string& value) {
    351   SetUserPrefValue(path, base::Value::CreateStringValue(value));
    352 }
    353 
    354 void PrefService::SetFilePath(const char* path, const base::FilePath& value) {
    355   SetUserPrefValue(path, base::CreateFilePathValue(value));
    356 }
    357 
    358 void PrefService::SetInt64(const char* path, int64 value) {
    359   SetUserPrefValue(path,
    360                    base::Value::CreateStringValue(base::Int64ToString(value)));
    361 }
    362 
    363 int64 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 
    380 void PrefService::SetUint64(const char* path, uint64 value) {
    381   SetUserPrefValue(path,
    382                    base::Value::CreateStringValue(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