Push API: Fix unsubscribing from GCM on Android
[chromium-blink-merge.git] / base / prefs / pref_service.cc
blob5afb5ea7c67496fcbc22148af7f77d51fd702ca9
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.
5 #include "base/prefs/pref_service.h"
7 #include <algorithm>
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"
24 namespace {
26 class ReadErrorHandler : public PersistentPrefStore::ReadErrorDelegate {
27 public:
28 ReadErrorHandler(base::Callback<void(PersistentPrefStore::PrefReadError)> cb)
29 : callback_(cb) {}
31 void OnError(PersistentPrefStore::PrefReadError error) override {
32 callback_.Run(error);
35 private:
36 base::Callback<void(PersistentPrefStore::PrefReadError)> callback_;
39 } // namespace
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);
56 // TODO(battre): This is a check for crbug.com/435208 to make sure that
57 // access violations are caused by a use-after-free bug and not by an
58 // initialization bug.
59 CHECK(pref_registry_);
60 CHECK(pref_value_store_);
62 InitFromStorage(async);
65 PrefService::~PrefService() {
66 DCHECK(CalledOnValidThread());
68 // Reset pointers so accesses after destruction reliably crash.
69 pref_value_store_.reset();
70 pref_registry_ = NULL;
71 user_pref_store_ = NULL;
72 pref_notifier_.reset();
75 void PrefService::InitFromStorage(bool async) {
76 if (user_pref_store_->IsInitializationComplete()) {
77 read_error_callback_.Run(user_pref_store_->GetReadError());
78 } else 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_)));
90 void PrefService::CommitPendingWrite() {
91 DCHECK(CalledOnValidThread());
92 user_pref_store_->CommitPendingWrite();
95 bool PrefService::GetBoolean(const std::string& path) const {
96 DCHECK(CalledOnValidThread());
98 bool result = false;
100 const base::Value* value = GetPreferenceValue(path);
101 if (!value) {
102 NOTREACHED() << "Trying to read an unregistered pref: " << path;
103 return result;
105 bool rv = value->GetAsBoolean(&result);
106 DCHECK(rv);
107 return result;
110 int PrefService::GetInteger(const std::string& path) const {
111 DCHECK(CalledOnValidThread());
113 int result = 0;
115 const base::Value* value = GetPreferenceValue(path);
116 if (!value) {
117 NOTREACHED() << "Trying to read an unregistered pref: " << path;
118 return result;
120 bool rv = value->GetAsInteger(&result);
121 DCHECK(rv);
122 return result;
125 double PrefService::GetDouble(const std::string& path) const {
126 DCHECK(CalledOnValidThread());
128 double result = 0.0;
130 const base::Value* value = GetPreferenceValue(path);
131 if (!value) {
132 NOTREACHED() << "Trying to read an unregistered pref: " << path;
133 return result;
135 bool rv = value->GetAsDouble(&result);
136 DCHECK(rv);
137 return result;
140 std::string PrefService::GetString(const std::string& path) const {
141 DCHECK(CalledOnValidThread());
143 std::string result;
145 const base::Value* value = GetPreferenceValue(path);
146 if (!value) {
147 NOTREACHED() << "Trying to read an unregistered pref: " << path;
148 return result;
150 bool rv = value->GetAsString(&result);
151 DCHECK(rv);
152 return result;
155 base::FilePath PrefService::GetFilePath(const std::string& path) const {
156 DCHECK(CalledOnValidThread());
158 base::FilePath result;
160 const base::Value* value = GetPreferenceValue(path);
161 if (!value) {
162 NOTREACHED() << "Trying to read an unregistered pref: " << path;
163 return base::FilePath(result);
165 bool rv = base::GetValueAsFilePath(*value, &result);
166 DCHECK(rv);
167 return result;
170 bool PrefService::HasPrefPath(const std::string& path) const {
171 const Preference* pref = FindPreference(path);
172 return pref && !pref->IsDefaultValue();
175 scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValues() const {
176 DCHECK(CalledOnValidThread());
177 scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
178 for (const auto& it : *pref_registry_) {
179 const base::Value* value = GetPreferenceValue(it.first);
180 out->Set(it.first, value->DeepCopy());
182 return out.Pass();
185 scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValuesOmitDefaults()
186 const {
187 DCHECK(CalledOnValidThread());
188 scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
189 for (const auto& it : *pref_registry_) {
190 const Preference* pref = FindPreference(it.first);
191 if (pref->IsDefaultValue())
192 continue;
193 out->Set(it.first, pref->GetValue()->DeepCopy());
195 return out.Pass();
198 scoped_ptr<base::DictionaryValue>
199 PrefService::GetPreferenceValuesWithoutPathExpansion() const {
200 DCHECK(CalledOnValidThread());
201 scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
202 for (const auto& it : *pref_registry_) {
203 const base::Value* value = GetPreferenceValue(it.first);
204 DCHECK(value);
205 out->SetWithoutPathExpansion(it.first, value->DeepCopy());
207 return out.Pass();
210 const PrefService::Preference* PrefService::FindPreference(
211 const std::string& pref_name) const {
212 DCHECK(CalledOnValidThread());
213 PreferenceMap::iterator it = prefs_map_.find(pref_name);
214 if (it != prefs_map_.end())
215 return &(it->second);
216 const base::Value* default_value = NULL;
217 if (!pref_registry_->defaults()->GetValue(pref_name, &default_value))
218 return NULL;
219 it = prefs_map_.insert(
220 std::make_pair(pref_name, Preference(
221 this, pref_name, default_value->GetType()))).first;
222 return &(it->second);
225 bool PrefService::ReadOnly() const {
226 return user_pref_store_->ReadOnly();
229 PrefService::PrefInitializationStatus PrefService::GetInitializationStatus()
230 const {
231 if (!user_pref_store_->IsInitializationComplete())
232 return INITIALIZATION_STATUS_WAITING;
234 switch (user_pref_store_->GetReadError()) {
235 case PersistentPrefStore::PREF_READ_ERROR_NONE:
236 return INITIALIZATION_STATUS_SUCCESS;
237 case PersistentPrefStore::PREF_READ_ERROR_NO_FILE:
238 return INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE;
239 default:
240 return INITIALIZATION_STATUS_ERROR;
244 bool PrefService::IsManagedPreference(const std::string& pref_name) const {
245 const Preference* pref = FindPreference(pref_name);
246 return pref && pref->IsManaged();
249 bool PrefService::IsPreferenceManagedByCustodian(
250 const std::string& pref_name) const {
251 const Preference* pref = FindPreference(pref_name);
252 return pref && pref->IsManagedByCustodian();
255 bool PrefService::IsUserModifiablePreference(
256 const std::string& pref_name) const {
257 const Preference* pref = FindPreference(pref_name);
258 return pref && pref->IsUserModifiable();
261 const base::DictionaryValue* PrefService::GetDictionary(
262 const std::string& path) const {
263 DCHECK(CalledOnValidThread());
265 const base::Value* value = GetPreferenceValue(path);
266 if (!value) {
267 NOTREACHED() << "Trying to read an unregistered pref: " << path;
268 return NULL;
270 if (value->GetType() != base::Value::TYPE_DICTIONARY) {
271 NOTREACHED();
272 return NULL;
274 return static_cast<const base::DictionaryValue*>(value);
277 const base::Value* PrefService::GetUserPrefValue(
278 const std::string& path) const {
279 DCHECK(CalledOnValidThread());
281 const Preference* pref = FindPreference(path);
282 if (!pref) {
283 NOTREACHED() << "Trying to get an unregistered pref: " << path;
284 return NULL;
287 // Look for an existing preference in the user store. If it doesn't
288 // exist, return NULL.
289 base::Value* value = NULL;
290 if (!user_pref_store_->GetMutableValue(path, &value))
291 return NULL;
293 if (!value->IsType(pref->GetType())) {
294 NOTREACHED() << "Pref value type doesn't match registered type.";
295 return NULL;
298 return value;
301 void PrefService::SetDefaultPrefValue(const std::string& path,
302 base::Value* value) {
303 DCHECK(CalledOnValidThread());
304 pref_registry_->SetDefaultPrefValue(path, value);
307 const base::Value* PrefService::GetDefaultPrefValue(
308 const std::string& path) const {
309 DCHECK(CalledOnValidThread());
310 // Lookup the preference in the default store.
311 const base::Value* value = NULL;
312 if (!pref_registry_->defaults()->GetValue(path, &value)) {
313 NOTREACHED() << "Default value missing for pref: " << path;
314 return NULL;
316 return value;
319 const base::ListValue* PrefService::GetList(const std::string& path) const {
320 DCHECK(CalledOnValidThread());
322 const base::Value* value = GetPreferenceValue(path);
323 if (!value) {
324 NOTREACHED() << "Trying to read an unregistered pref: " << path;
325 return NULL;
327 if (value->GetType() != base::Value::TYPE_LIST) {
328 NOTREACHED();
329 return NULL;
331 return static_cast<const base::ListValue*>(value);
334 void PrefService::AddPrefObserver(const std::string& path, PrefObserver* obs) {
335 pref_notifier_->AddPrefObserver(path, obs);
338 void PrefService::RemovePrefObserver(const std::string& path,
339 PrefObserver* obs) {
340 pref_notifier_->RemovePrefObserver(path, obs);
343 void PrefService::AddPrefInitObserver(base::Callback<void(bool)> obs) {
344 pref_notifier_->AddInitObserver(obs);
347 PrefRegistry* PrefService::DeprecatedGetPrefRegistry() {
348 return pref_registry_.get();
351 void PrefService::ClearPref(const std::string& path) {
352 DCHECK(CalledOnValidThread());
354 const Preference* pref = FindPreference(path);
355 if (!pref) {
356 NOTREACHED() << "Trying to clear an unregistered pref: " << path;
357 return;
359 user_pref_store_->RemoveValue(path);
362 void PrefService::Set(const std::string& path, const base::Value& value) {
363 SetUserPrefValue(path, value.DeepCopy());
366 void PrefService::SetBoolean(const std::string& path, bool value) {
367 SetUserPrefValue(path, new base::FundamentalValue(value));
370 void PrefService::SetInteger(const std::string& path, int value) {
371 SetUserPrefValue(path, new base::FundamentalValue(value));
374 void PrefService::SetDouble(const std::string& path, double value) {
375 SetUserPrefValue(path, new base::FundamentalValue(value));
378 void PrefService::SetString(const std::string& path, const std::string& value) {
379 SetUserPrefValue(path, new base::StringValue(value));
382 void PrefService::SetFilePath(const std::string& path,
383 const base::FilePath& value) {
384 SetUserPrefValue(path, base::CreateFilePathValue(value));
387 void PrefService::SetInt64(const std::string& path, int64 value) {
388 SetUserPrefValue(path, new base::StringValue(base::Int64ToString(value)));
391 int64 PrefService::GetInt64(const std::string& path) const {
392 DCHECK(CalledOnValidThread());
394 const base::Value* value = GetPreferenceValue(path);
395 if (!value) {
396 NOTREACHED() << "Trying to read an unregistered pref: " << path;
397 return 0;
399 std::string result("0");
400 bool rv = value->GetAsString(&result);
401 DCHECK(rv);
403 int64 val;
404 base::StringToInt64(result, &val);
405 return val;
408 void PrefService::SetUint64(const std::string& path, uint64 value) {
409 SetUserPrefValue(path, new base::StringValue(base::Uint64ToString(value)));
412 uint64 PrefService::GetUint64(const std::string& path) const {
413 DCHECK(CalledOnValidThread());
415 const base::Value* value = GetPreferenceValue(path);
416 if (!value) {
417 NOTREACHED() << "Trying to read an unregistered pref: " << path;
418 return 0;
420 std::string result("0");
421 bool rv = value->GetAsString(&result);
422 DCHECK(rv);
424 uint64 val;
425 base::StringToUint64(result, &val);
426 return val;
429 base::Value* PrefService::GetMutableUserPref(const std::string& path,
430 base::Value::Type type) {
431 CHECK(type == base::Value::TYPE_DICTIONARY || type == base::Value::TYPE_LIST);
432 DCHECK(CalledOnValidThread());
434 const Preference* pref = FindPreference(path);
435 if (!pref) {
436 NOTREACHED() << "Trying to get an unregistered pref: " << path;
437 return NULL;
439 if (pref->GetType() != type) {
440 NOTREACHED() << "Wrong type for GetMutableValue: " << path;
441 return NULL;
444 // Look for an existing preference in the user store. If it doesn't
445 // exist or isn't the correct type, create a new user preference.
446 base::Value* value = NULL;
447 if (!user_pref_store_->GetMutableValue(path, &value) ||
448 !value->IsType(type)) {
449 if (type == base::Value::TYPE_DICTIONARY) {
450 value = new base::DictionaryValue;
451 } else if (type == base::Value::TYPE_LIST) {
452 value = new base::ListValue;
453 } else {
454 NOTREACHED();
456 user_pref_store_->SetValueSilently(path, value);
458 return value;
461 void PrefService::ReportUserPrefChanged(const std::string& key) {
462 DCHECK(CalledOnValidThread());
463 user_pref_store_->ReportValueChanged(key);
466 void PrefService::SetUserPrefValue(const std::string& path,
467 base::Value* new_value) {
468 scoped_ptr<base::Value> owned_value(new_value);
469 DCHECK(CalledOnValidThread());
471 const Preference* pref = FindPreference(path);
472 if (!pref) {
473 NOTREACHED() << "Trying to write an unregistered pref: " << path;
474 return;
476 if (pref->GetType() != new_value->GetType()) {
477 NOTREACHED() << "Trying to set pref " << path
478 << " of type " << pref->GetType()
479 << " to value of type " << new_value->GetType();
480 return;
483 user_pref_store_->SetValue(path, owned_value.release());
486 void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) {
487 pref_value_store_->UpdateCommandLinePrefStore(command_line_store);
490 ///////////////////////////////////////////////////////////////////////////////
491 // PrefService::Preference
493 PrefService::Preference::Preference(const PrefService* service,
494 const std::string& name,
495 base::Value::Type type)
496 : name_(name), type_(type), pref_service_(service) {
497 DCHECK(service);
500 const std::string PrefService::Preference::name() const {
501 return name_;
504 base::Value::Type PrefService::Preference::GetType() const {
505 return type_;
508 const base::Value* PrefService::Preference::GetValue() const {
509 const base::Value* result= pref_service_->GetPreferenceValue(name_);
510 DCHECK(result) << "Must register pref before getting its value";
511 return result;
514 const base::Value* PrefService::Preference::GetRecommendedValue() const {
515 DCHECK(pref_service_->FindPreference(name_))
516 << "Must register pref before getting its value";
518 const base::Value* found_value = NULL;
519 if (pref_value_store()->GetRecommendedValue(name_, type_, &found_value)) {
520 DCHECK(found_value->IsType(type_));
521 return found_value;
524 // The pref has no recommended value.
525 return NULL;
528 bool PrefService::Preference::IsManaged() const {
529 return pref_value_store()->PrefValueInManagedStore(name_);
532 bool PrefService::Preference::IsManagedByCustodian() const {
533 return pref_value_store()->PrefValueInSupervisedStore(name_.c_str());
536 bool PrefService::Preference::IsRecommended() const {
537 return pref_value_store()->PrefValueFromRecommendedStore(name_);
540 bool PrefService::Preference::HasExtensionSetting() const {
541 return pref_value_store()->PrefValueInExtensionStore(name_);
544 bool PrefService::Preference::HasUserSetting() const {
545 return pref_value_store()->PrefValueInUserStore(name_);
548 bool PrefService::Preference::IsExtensionControlled() const {
549 return pref_value_store()->PrefValueFromExtensionStore(name_);
552 bool PrefService::Preference::IsUserControlled() const {
553 return pref_value_store()->PrefValueFromUserStore(name_);
556 bool PrefService::Preference::IsDefaultValue() const {
557 return pref_value_store()->PrefValueFromDefaultStore(name_);
560 bool PrefService::Preference::IsUserModifiable() const {
561 return pref_value_store()->PrefValueUserModifiable(name_);
564 bool PrefService::Preference::IsExtensionModifiable() const {
565 return pref_value_store()->PrefValueExtensionModifiable(name_);
568 const base::Value* PrefService::GetPreferenceValue(
569 const std::string& path) const {
570 DCHECK(CalledOnValidThread());
572 // TODO(battre): This is a check for crbug.com/435208. After analyzing some
573 // crash dumps it looks like the PrefService is accessed even though it has
574 // been cleared already.
575 CHECK(pref_registry_);
576 CHECK(pref_registry_->defaults());
577 CHECK(pref_value_store_);
579 const base::Value* default_value = NULL;
580 if (pref_registry_->defaults()->GetValue(path, &default_value)) {
581 const base::Value* found_value = NULL;
582 base::Value::Type default_type = default_value->GetType();
583 if (pref_value_store_->GetValue(path, default_type, &found_value)) {
584 DCHECK(found_value->IsType(default_type));
585 return found_value;
586 } else {
587 // Every registered preference has at least a default value.
588 NOTREACHED() << "no valid value found for registered pref " << path;
592 return NULL;