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 "components/prefs/pref_service.h"
11 #include "base/bind.h"
12 #include "base/check_op.h"
13 #include "base/debug/alias.h"
14 #include "base/debug/dump_without_crashing.h"
15 #include "base/files/file_path.h"
16 #include "base/json/values_util.h"
17 #include "base/location.h"
18 #include "base/memory/ptr_util.h"
19 #include "base/metrics/histogram.h"
20 #include "base/notreached.h"
21 #include "base/single_thread_task_runner.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_util.h"
24 #include "base/threading/thread_task_runner_handle.h"
25 #include "base/values.h"
26 #include "build/build_config.h"
27 #include "components/prefs/default_pref_store.h"
28 #include "components/prefs/pref_notifier_impl.h"
29 #include "components/prefs/pref_registry.h"
31 #if defined(OS_ANDROID)
32 #include "components/prefs/android/pref_service_android.h"
37 class ReadErrorHandler : public PersistentPrefStore::ReadErrorDelegate {
40 base::RepeatingCallback<void(PersistentPrefStore::PrefReadError)>;
41 explicit ReadErrorHandler(ErrorCallback cb) : callback_(cb) {}
43 void OnError(PersistentPrefStore::PrefReadError error) override {
48 ErrorCallback callback_;
50 DISALLOW_COPY_AND_ASSIGN(ReadErrorHandler);
53 // Returns the WriteablePrefStore::PrefWriteFlags for the pref with the given
55 uint32_t GetWriteFlags(const PrefService::Preference* pref) {
56 uint32_t write_flags = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
61 if (pref->registration_flags() & PrefRegistry::LOSSY_PREF)
62 write_flags |= WriteablePrefStore::LOSSY_PREF_WRITE_FLAG;
66 // For prefs names in |pref_store| that are not presented in |pref_changed_map|,
67 // check if their values differ from those in pref_service->FindPreference() and
68 // add the result into |pref_changed_map|.
69 void CheckForNewPrefChangesInPrefStore(
70 std::map<std::string, bool>* pref_changed_map,
71 PrefStore* pref_store,
72 PrefService* pref_service) {
75 auto values = pref_store->GetValues();
76 for (auto item : values->DictItems()) {
77 // If the key already presents, skip it as a store with higher precedence
78 // already sets the entry.
79 if (pref_changed_map->find(item.first) != pref_changed_map->end())
81 const PrefService::Preference* pref =
82 pref_service->FindPreference(item.first);
85 pref_changed_map->emplace(item.first, *(pref->GetValue()) != item.second);
91 PrefService::PrefService(
92 std::unique_ptr<PrefNotifierImpl> pref_notifier,
93 std::unique_ptr<PrefValueStore> pref_value_store,
94 scoped_refptr<PersistentPrefStore> user_prefs,
95 scoped_refptr<PrefRegistry> pref_registry,
96 base::RepeatingCallback<void(PersistentPrefStore::PrefReadError)>
99 : pref_notifier_(std::move(pref_notifier)),
100 pref_value_store_(std::move(pref_value_store)),
101 user_pref_store_(std::move(user_prefs)),
102 read_error_callback_(std::move(read_error_callback)),
103 pref_registry_(std::move(pref_registry)) {
104 pref_notifier_->SetPrefService(this);
106 DCHECK(pref_registry_);
107 DCHECK(pref_value_store_);
109 InitFromStorage(async);
112 PrefService::~PrefService() {
113 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
115 // TODO(crbug.com/942491, 946668, 945772) The following code collects
116 // augments stack dumps created by ~PrefNotifierImpl() with information
117 // whether the profile owning the PrefService is an incognito profile.
118 // Delete this, once the bugs are closed.
119 const bool is_incognito_profile = user_pref_store_->IsInMemoryPrefStore();
120 base::debug::Alias(&is_incognito_profile);
121 // Export value of is_incognito_profile to a string so that `grep`
122 // is a sufficient tool to analyze crashdumps.
123 char is_incognito_profile_string[32];
124 strncpy(is_incognito_profile_string,
125 is_incognito_profile ? "is_incognito: yes" : "is_incognito: no",
126 sizeof(is_incognito_profile_string));
127 base::debug::Alias(&is_incognito_profile_string);
130 void PrefService::InitFromStorage(bool async) {
131 if (user_pref_store_->IsInitializationComplete()) {
132 read_error_callback_.Run(user_pref_store_->GetReadError());
134 read_error_callback_.Run(user_pref_store_->ReadPrefs());
136 // Guarantee that initialization happens after this function returned.
137 base::ThreadTaskRunnerHandle::Get()->PostTask(
139 base::BindOnce(&PersistentPrefStore::ReadPrefsAsync, user_pref_store_,
140 new ReadErrorHandler(read_error_callback_)));
144 void PrefService::CommitPendingWrite(
145 base::OnceClosure reply_callback,
146 base::OnceClosure synchronous_done_callback) {
147 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
148 user_pref_store_->CommitPendingWrite(std::move(reply_callback),
149 std::move(synchronous_done_callback));
152 void PrefService::SchedulePendingLossyWrites() {
153 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
154 user_pref_store_->SchedulePendingLossyWrites();
157 bool PrefService::GetBoolean(const std::string& path) const {
158 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
160 const base::Value* value = GetPreferenceValueChecked(path);
161 if (!value || !value->is_bool())
163 return value->GetBool();
166 int PrefService::GetInteger(const std::string& path) const {
167 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
169 const base::Value* value = GetPreferenceValueChecked(path);
170 if (!value || !value->is_int())
172 return value->GetInt();
175 double PrefService::GetDouble(const std::string& path) const {
176 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
178 const base::Value* value = GetPreferenceValueChecked(path);
179 if (!value || !value->is_double())
181 return value->GetDouble();
184 std::string PrefService::GetString(const std::string& path) const {
185 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
187 const base::Value* value = GetPreferenceValueChecked(path);
188 if (!value || !value->is_string())
189 return std::string();
190 return value->GetString();
193 base::FilePath PrefService::GetFilePath(const std::string& path) const {
194 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
196 const base::Value* value = GetPreferenceValueChecked(path);
198 return base::FilePath();
199 absl::optional<base::FilePath> result = base::ValueToFilePath(*value);
204 bool PrefService::HasPrefPath(const std::string& path) const {
205 const Preference* pref = FindPreference(path);
206 return pref && !pref->IsDefaultValue();
209 void PrefService::IteratePreferenceValues(
210 base::RepeatingCallback<void(const std::string& key,
211 const base::Value& value)> callback) const {
212 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
213 for (const auto& it : *pref_registry_)
214 callback.Run(it.first, *GetPreferenceValue(it.first));
217 base::Value PrefService::GetPreferenceValues(
218 IncludeDefaults include_defaults) const {
219 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
221 base::Value out(base::Value::Type::DICTIONARY);
222 for (const auto& it : *pref_registry_) {
223 if (include_defaults == INCLUDE_DEFAULTS) {
224 out.SetPath(it.first, GetPreferenceValue(it.first)->Clone());
226 const Preference* pref = FindPreference(it.first);
227 if (pref->IsDefaultValue())
229 out.SetPath(it.first, pref->GetValue()->Clone());
235 const PrefService::Preference* PrefService::FindPreference(
236 const std::string& pref_name) const {
237 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
238 auto it = prefs_map_.find(pref_name);
239 if (it != prefs_map_.end())
240 return &(it->second);
241 const base::Value* default_value = nullptr;
242 if (!pref_registry_->defaults()->GetValue(pref_name, &default_value))
245 .insert(std::make_pair(
246 pref_name, Preference(this, pref_name, default_value->type())))
248 return &(it->second);
251 bool PrefService::ReadOnly() const {
252 return user_pref_store_->ReadOnly();
255 PrefService::PrefInitializationStatus PrefService::GetInitializationStatus()
257 if (!user_pref_store_->IsInitializationComplete())
258 return INITIALIZATION_STATUS_WAITING;
260 switch (user_pref_store_->GetReadError()) {
261 case PersistentPrefStore::PREF_READ_ERROR_NONE:
262 return INITIALIZATION_STATUS_SUCCESS;
263 case PersistentPrefStore::PREF_READ_ERROR_NO_FILE:
264 return INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE;
266 return INITIALIZATION_STATUS_ERROR;
270 PrefService::PrefInitializationStatus
271 PrefService::GetAllPrefStoresInitializationStatus() const {
272 if (!pref_value_store_->IsInitializationComplete())
273 return INITIALIZATION_STATUS_WAITING;
275 return GetInitializationStatus();
278 bool PrefService::IsManagedPreference(const std::string& pref_name) const {
279 const Preference* pref = FindPreference(pref_name);
280 return pref && pref->IsManaged();
283 bool PrefService::IsPreferenceManagedByCustodian(
284 const std::string& pref_name) const {
285 const Preference* pref = FindPreference(pref_name);
286 return pref && pref->IsManagedByCustodian();
289 bool PrefService::IsUserModifiablePreference(
290 const std::string& pref_name) const {
291 const Preference* pref = FindPreference(pref_name);
292 return pref && pref->IsUserModifiable();
295 const base::Value* PrefService::Get(const std::string& path) const {
296 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
297 return GetPreferenceValueChecked(path);
300 const base::DictionaryValue* PrefService::GetDictionary(
301 const std::string& path) const {
302 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
304 const base::Value* value = GetPreferenceValueChecked(path);
307 if (value->type() != base::Value::Type::DICTIONARY) {
311 return static_cast<const base::DictionaryValue*>(value);
314 const base::Value* PrefService::GetUserPrefValue(
315 const std::string& path) const {
316 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
318 const Preference* pref = FindPreference(path);
320 NOTREACHED() << "Trying to get an unregistered pref: " << path;
324 // Look for an existing preference in the user store. If it doesn't
325 // exist, return NULL.
326 base::Value* value = nullptr;
327 if (!user_pref_store_->GetMutableValue(path, &value))
330 if (value->type() != pref->GetType()) {
331 NOTREACHED() << "Pref value type doesn't match registered type.";
338 void PrefService::SetDefaultPrefValue(const std::string& path,
340 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
341 pref_registry_->SetDefaultPrefValue(path, std::move(value));
344 const base::Value* PrefService::GetDefaultPrefValue(
345 const std::string& path) const {
346 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
347 // Lookup the preference in the default store.
348 const base::Value* value = nullptr;
349 bool has_value = pref_registry_->defaults()->GetValue(path, &value);
350 DCHECK(has_value) << "Default value missing for pref: " << path;
354 const base::ListValue* PrefService::GetList(const std::string& path) const {
355 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
357 const base::Value* value = GetPreferenceValueChecked(path);
360 if (value->type() != base::Value::Type::LIST) {
364 return static_cast<const base::ListValue*>(value);
367 void PrefService::AddPrefObserver(const std::string& path, PrefObserver* obs) {
368 pref_notifier_->AddPrefObserver(path, obs);
371 void PrefService::RemovePrefObserver(const std::string& path,
373 pref_notifier_->RemovePrefObserver(path, obs);
376 void PrefService::AddPrefInitObserver(base::OnceCallback<void(bool)> obs) {
377 pref_notifier_->AddInitObserver(std::move(obs));
380 PrefRegistry* PrefService::DeprecatedGetPrefRegistry() {
381 return pref_registry_.get();
384 void PrefService::ClearPref(const std::string& path) {
385 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
387 const Preference* pref = FindPreference(path);
389 NOTREACHED() << "Trying to clear an unregistered pref: " << path;
392 user_pref_store_->RemoveValue(path, GetWriteFlags(pref));
395 void PrefService::ClearPrefsWithPrefixSilently(const std::string& prefix) {
396 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
397 user_pref_store_->RemoveValuesByPrefixSilently(prefix);
400 void PrefService::ClearMutableValues() {
401 user_pref_store_->ClearMutableValues();
404 void PrefService::OnStoreDeletionFromDisk() {
405 user_pref_store_->OnStoreDeletionFromDisk();
408 void PrefService::ChangePrefValueStore(
409 PrefStore* managed_prefs,
410 PrefStore* supervised_user_prefs,
411 PrefStore* extension_prefs,
412 PrefStore* recommended_prefs,
413 std::unique_ptr<PrefValueStore::Delegate> delegate) {
414 // Only adding new pref stores are supported.
415 DCHECK(!pref_value_store_->HasPrefStore(PrefValueStore::MANAGED_STORE) ||
418 !pref_value_store_->HasPrefStore(PrefValueStore::SUPERVISED_USER_STORE) ||
419 !supervised_user_prefs);
420 DCHECK(!pref_value_store_->HasPrefStore(PrefValueStore::EXTENSION_STORE) ||
422 DCHECK(!pref_value_store_->HasPrefStore(PrefValueStore::RECOMMENDED_STORE) ||
425 // If some of the stores are already initialized, check for pref value changes
426 // according to store precedence.
427 std::map<std::string, bool> pref_changed_map;
428 CheckForNewPrefChangesInPrefStore(&pref_changed_map, managed_prefs, this);
429 CheckForNewPrefChangesInPrefStore(&pref_changed_map, supervised_user_prefs,
431 CheckForNewPrefChangesInPrefStore(&pref_changed_map, extension_prefs, this);
432 CheckForNewPrefChangesInPrefStore(&pref_changed_map, recommended_prefs, this);
434 pref_value_store_ = pref_value_store_->CloneAndSpecialize(
435 managed_prefs, supervised_user_prefs, extension_prefs,
436 nullptr /* command_line_prefs */, nullptr /* user_prefs */,
437 recommended_prefs, nullptr /* default_prefs */, pref_notifier_.get(),
438 std::move(delegate));
440 // Notify |pref_notifier_| on all changed values.
441 for (const auto& kv : pref_changed_map) {
443 pref_notifier_.get()->OnPreferenceChanged(kv.first);
447 void PrefService::AddPrefObserverAllPrefs(PrefObserver* obs) {
448 pref_notifier_->AddPrefObserverAllPrefs(obs);
451 void PrefService::RemovePrefObserverAllPrefs(PrefObserver* obs) {
452 pref_notifier_->RemovePrefObserverAllPrefs(obs);
455 #if defined(OS_ANDROID)
456 base::android::ScopedJavaLocalRef<jobject> PrefService::GetJavaObject() {
457 if (!pref_service_android_) {
458 pref_service_android_ = std::make_unique<PrefServiceAndroid>(this);
460 return pref_service_android_->GetJavaObject();
464 void PrefService::Set(const std::string& path, const base::Value& value) {
465 SetUserPrefValue(path, value.Clone());
468 void PrefService::SetBoolean(const std::string& path, bool value) {
469 SetUserPrefValue(path, base::Value(value));
472 void PrefService::SetInteger(const std::string& path, int value) {
473 SetUserPrefValue(path, base::Value(value));
476 void PrefService::SetDouble(const std::string& path, double value) {
477 SetUserPrefValue(path, base::Value(value));
480 void PrefService::SetString(const std::string& path, const std::string& value) {
481 SetUserPrefValue(path, base::Value(value));
484 void PrefService::SetFilePath(const std::string& path,
485 const base::FilePath& value) {
486 SetUserPrefValue(path, base::FilePathToValue(value));
489 void PrefService::SetInt64(const std::string& path, int64_t value) {
490 SetUserPrefValue(path, base::Int64ToValue(value));
493 int64_t PrefService::GetInt64(const std::string& path) const {
494 const base::Value* value = GetPreferenceValueChecked(path);
495 absl::optional<int64_t> integer = base::ValueToInt64(value);
497 return integer.value_or(0);
500 void PrefService::SetUint64(const std::string& path, uint64_t value) {
501 SetUserPrefValue(path, base::Value(base::NumberToString(value)));
504 uint64_t PrefService::GetUint64(const std::string& path) const {
505 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
507 const base::Value* value = GetPreferenceValueChecked(path);
508 if (!value || !value->is_string())
512 base::StringToUint64(value->GetString(), &result);
516 void PrefService::SetTime(const std::string& path, base::Time value) {
517 SetUserPrefValue(path, base::TimeToValue(value));
520 base::Time PrefService::GetTime(const std::string& path) const {
521 const base::Value* value = GetPreferenceValueChecked(path);
522 absl::optional<base::Time> time = base::ValueToTime(value);
524 return time.value_or(base::Time());
527 void PrefService::SetTimeDelta(const std::string& path, base::TimeDelta value) {
528 SetUserPrefValue(path, base::TimeDeltaToValue(value));
531 base::TimeDelta PrefService::GetTimeDelta(const std::string& path) const {
532 const base::Value* value = GetPreferenceValueChecked(path);
533 absl::optional<base::TimeDelta> time_delta = base::ValueToTimeDelta(value);
535 return time_delta.value_or(base::TimeDelta());
538 base::Value* PrefService::GetMutableUserPref(const std::string& path,
539 base::Value::Type type) {
540 CHECK(type == base::Value::Type::DICTIONARY ||
541 type == base::Value::Type::LIST);
542 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
544 const Preference* pref = FindPreference(path);
546 NOTREACHED() << "Trying to get an unregistered pref: " << path;
549 if (pref->GetType() != type) {
550 NOTREACHED() << "Wrong type for GetMutableValue: " << path;
554 // Look for an existing preference in the user store. Return it in case it
555 // exists and has the correct type.
556 base::Value* value = nullptr;
557 if (user_pref_store_->GetMutableValue(path, &value) &&
558 value->type() == type) {
562 // If no user preference of the correct type exists, clone default value.
563 const base::Value* default_value = nullptr;
564 pref_registry_->defaults()->GetValue(path, &default_value);
565 DCHECK_EQ(default_value->type(), type);
566 user_pref_store_->SetValueSilently(
567 path, base::Value::ToUniquePtrValue(default_value->Clone()),
568 GetWriteFlags(pref));
569 user_pref_store_->GetMutableValue(path, &value);
573 void PrefService::ReportUserPrefChanged(const std::string& key) {
574 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
575 user_pref_store_->ReportValueChanged(key, GetWriteFlags(FindPreference(key)));
578 void PrefService::ReportUserPrefChanged(
579 const std::string& key,
580 std::set<std::vector<std::string>> path_components) {
581 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
582 user_pref_store_->ReportSubValuesChanged(key, std::move(path_components),
583 GetWriteFlags(FindPreference(key)));
586 void PrefService::SetUserPrefValue(const std::string& path,
587 base::Value new_value) {
588 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
590 const Preference* pref = FindPreference(path);
592 NOTREACHED() << "Trying to write an unregistered pref: " << path;
595 if (pref->GetType() != new_value.type()) {
596 NOTREACHED() << "Trying to set pref " << path << " of type "
597 << pref->GetType() << " to value of type " << new_value.type();
601 user_pref_store_->SetValue(
602 path, base::Value::ToUniquePtrValue(std::move(new_value)),
603 GetWriteFlags(pref));
606 void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) {
607 pref_value_store_->UpdateCommandLinePrefStore(command_line_store);
610 ///////////////////////////////////////////////////////////////////////////////
611 // PrefService::Preference
613 PrefService::Preference::Preference(const PrefService* service,
615 base::Value::Type type)
616 : name_(std::move(name)),
618 // Cache the registration flags at creation time to avoid multiple map
620 registration_flags_(service->pref_registry_->GetRegistrationFlags(name_)),
621 pref_service_(service) {}
623 const base::Value* PrefService::Preference::GetValue() const {
624 return pref_service_->GetPreferenceValueChecked(name_);
627 const base::Value* PrefService::Preference::GetRecommendedValue() const {
628 DCHECK(pref_service_->FindPreference(name_))
629 << "Must register pref before getting its value";
631 const base::Value* found_value = nullptr;
632 if (pref_value_store()->GetRecommendedValue(name_, type_, &found_value)) {
633 DCHECK(found_value->type() == type_);
637 // The pref has no recommended value.
641 bool PrefService::Preference::IsManaged() const {
642 return pref_value_store()->PrefValueInManagedStore(name_);
645 bool PrefService::Preference::IsManagedByCustodian() const {
646 return pref_value_store()->PrefValueInSupervisedStore(name_);
649 bool PrefService::Preference::IsRecommended() const {
650 return pref_value_store()->PrefValueFromRecommendedStore(name_);
653 bool PrefService::Preference::HasExtensionSetting() const {
654 return pref_value_store()->PrefValueInExtensionStore(name_);
657 bool PrefService::Preference::HasUserSetting() const {
658 return pref_value_store()->PrefValueInUserStore(name_);
661 bool PrefService::Preference::IsExtensionControlled() const {
662 return pref_value_store()->PrefValueFromExtensionStore(name_);
665 bool PrefService::Preference::IsUserControlled() const {
666 return pref_value_store()->PrefValueFromUserStore(name_);
669 bool PrefService::Preference::IsDefaultValue() const {
670 return pref_value_store()->PrefValueFromDefaultStore(name_);
673 bool PrefService::Preference::IsUserModifiable() const {
674 return pref_value_store()->PrefValueUserModifiable(name_);
677 bool PrefService::Preference::IsExtensionModifiable() const {
678 return pref_value_store()->PrefValueExtensionModifiable(name_);
681 const base::Value* PrefService::GetPreferenceValue(
682 const std::string& path) const {
683 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
685 // TODO(battre): This is a check for crbug.com/435208. After analyzing some
686 // crash dumps it looks like the PrefService is accessed even though it has
687 // been cleared already.
688 CHECK(pref_registry_);
689 CHECK(pref_registry_->defaults());
690 CHECK(pref_value_store_);
692 const base::Value* default_value = nullptr;
693 if (!pref_registry_->defaults()->GetValue(path, &default_value))
696 const base::Value* found_value = nullptr;
697 base::Value::Type default_type = default_value->type();
698 if (!pref_value_store_->GetValue(path, default_type, &found_value)) {
699 // Every registered preference has at least a default value.
700 NOTREACHED() << "no valid value found for registered pref " << path;
704 DCHECK_EQ(found_value->type(), default_type);
708 const base::Value* PrefService::GetPreferenceValueChecked(
709 const std::string& path) const {
710 const base::Value* value = GetPreferenceValue(path);
711 DCHECK(value) << "Trying to read an unregistered pref: " << path;
715 void PrefService::CommitPendingWriteSynchronously() {
716 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
717 user_pref_store_->CommitPendingWriteSynchronously();