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