// Copyright 2014 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/prefs/segregated_pref_store.h" #include #include #include "base/barrier_closure.h" #include "base/check_op.h" #include "base/containers/contains.h" #include "base/notreached.h" #include "base/observer_list.h" #include "base/strings/string_piece.h" #include "base/values.h" #include "components/prefs/pref_name_set.h" SegregatedPrefStore::UnderlyingPrefStoreObserver::UnderlyingPrefStoreObserver( SegregatedPrefStore* outer) : outer_(outer) { DCHECK(outer_); } void SegregatedPrefStore::UnderlyingPrefStoreObserver::OnPrefValueChanged( const std::string& key) { // Notify Observers only after all underlying PrefStores of the outer // SegregatedPrefStore are initialized. if (!outer_->IsInitializationComplete()) return; for (auto& observer : outer_->observers_) observer.OnPrefValueChanged(key); } void SegregatedPrefStore::UnderlyingPrefStoreObserver:: OnInitializationCompleted(bool succeeded) { initialization_succeeded_ = succeeded; // Notify Observers only after all underlying PrefStores of the outer // SegregatedPrefStore are initialized. if (!outer_->IsInitializationComplete()) return; if (outer_->read_error_delegate_) { PersistentPrefStore::PrefReadError read_error = outer_->GetReadError(); if (read_error != PersistentPrefStore::PREF_READ_ERROR_NONE) outer_->read_error_delegate_->OnError(read_error); } for (auto& observer : outer_->observers_) observer.OnInitializationCompleted(outer_->IsInitializationSuccessful()); } SegregatedPrefStore::SegregatedPrefStore( scoped_refptr default_pref_store, scoped_refptr selected_pref_store, PrefNameSet selected_pref_names) : default_pref_store_(std::move(default_pref_store)), selected_pref_store_(std::move(selected_pref_store)), selected_preference_names_(std::move(selected_pref_names)), default_observer_(this), selected_observer_(this) { default_pref_store_->AddObserver(&default_observer_); selected_pref_store_->AddObserver(&selected_observer_); } void SegregatedPrefStore::AddObserver(Observer* observer) { observers_.AddObserver(observer); } void SegregatedPrefStore::RemoveObserver(Observer* observer) { observers_.RemoveObserver(observer); } bool SegregatedPrefStore::HasObservers() const { return !observers_.empty(); } bool SegregatedPrefStore::IsInitializationComplete() const { return default_pref_store_->IsInitializationComplete() && selected_pref_store_->IsInitializationComplete(); } bool SegregatedPrefStore::IsInitializationSuccessful() const { return default_observer_.initialization_succeeded() && selected_observer_.initialization_succeeded(); } bool SegregatedPrefStore::GetValue(base::StringPiece key, const base::Value** result) const { return StoreForKey(key)->GetValue(key, result); } base::Value::Dict SegregatedPrefStore::GetValues() const { base::Value::Dict values = default_pref_store_->GetValues(); base::Value::Dict selected_pref_store_values = selected_pref_store_->GetValues(); for (const auto& key : selected_preference_names_) { if (base::Value* value = selected_pref_store_values.FindByDottedPath(key)) { values.SetByDottedPath(key, std::move(*value)); } else { values.Remove(key); } } return values; } void SegregatedPrefStore::SetValue(const std::string& key, base::Value value, uint32_t flags) { StoreForKey(key)->SetValue(key, std::move(value), flags); } void SegregatedPrefStore::RemoveValue(const std::string& key, uint32_t flags) { StoreForKey(key)->RemoveValue(key, flags); } void SegregatedPrefStore::RemoveValuesByPrefixSilently( const std::string& prefix) { // Since we can't guarantee to have all the prefs in one the pref stores, we // have to push the removal command down to both of them. default_pref_store_->RemoveValuesByPrefixSilently(prefix); selected_pref_store_->RemoveValuesByPrefixSilently(prefix); } bool SegregatedPrefStore::GetMutableValue(const std::string& key, base::Value** result) { return StoreForKey(key)->GetMutableValue(key, result); } void SegregatedPrefStore::ReportValueChanged(const std::string& key, uint32_t flags) { StoreForKey(key)->ReportValueChanged(key, flags); } void SegregatedPrefStore::SetValueSilently(const std::string& key, base::Value value, uint32_t flags) { StoreForKey(key)->SetValueSilently(key, std::move(value), flags); } bool SegregatedPrefStore::ReadOnly() const { return selected_pref_store_->ReadOnly() || default_pref_store_->ReadOnly(); } PersistentPrefStore::PrefReadError SegregatedPrefStore::GetReadError() const { PersistentPrefStore::PrefReadError read_error = default_pref_store_->GetReadError(); if (read_error == PersistentPrefStore::PREF_READ_ERROR_NONE) { read_error = selected_pref_store_->GetReadError(); // Ignore NO_FILE from selected_pref_store_. if (read_error == PersistentPrefStore::PREF_READ_ERROR_NO_FILE) read_error = PersistentPrefStore::PREF_READ_ERROR_NONE; } return read_error; } PersistentPrefStore::PrefReadError SegregatedPrefStore::ReadPrefs() { // Note: Both of these stores own PrefFilters which makes ReadPrefs // asynchronous. This is okay in this case as only the first call will be // truly asynchronous, the second call will then unblock the migration in // TrackedPreferencesMigrator and complete synchronously. default_pref_store_->ReadPrefs(); PersistentPrefStore::PrefReadError selected_store_read_error = selected_pref_store_->ReadPrefs(); DCHECK_NE(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE, selected_store_read_error); return GetReadError(); } void SegregatedPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) { read_error_delegate_.reset(error_delegate); default_pref_store_->ReadPrefsAsync(NULL); selected_pref_store_->ReadPrefsAsync(NULL); } void SegregatedPrefStore::CommitPendingWrite( base::OnceClosure reply_callback, base::OnceClosure synchronous_done_callback) { // A BarrierClosure will run its callback wherever the last instance of the // returned wrapper is invoked. As such it is guaranteed to respect the reply // vs synchronous semantics assuming |default_pref_store_| and // |selected_pref_store_| honor it. base::RepeatingClosure reply_callback_wrapper = reply_callback ? base::BarrierClosure(2, std::move(reply_callback)) : base::RepeatingClosure(); base::RepeatingClosure synchronous_callback_wrapper = synchronous_done_callback ? base::BarrierClosure(2, std::move(synchronous_done_callback)) : base::RepeatingClosure(); default_pref_store_->CommitPendingWrite(reply_callback_wrapper, synchronous_callback_wrapper); selected_pref_store_->CommitPendingWrite(reply_callback_wrapper, synchronous_callback_wrapper); } void SegregatedPrefStore::SchedulePendingLossyWrites() { default_pref_store_->SchedulePendingLossyWrites(); selected_pref_store_->SchedulePendingLossyWrites(); } void SegregatedPrefStore::OnStoreDeletionFromDisk() { default_pref_store_->OnStoreDeletionFromDisk(); selected_pref_store_->OnStoreDeletionFromDisk(); } SegregatedPrefStore::~SegregatedPrefStore() { default_pref_store_->RemoveObserver(&default_observer_); selected_pref_store_->RemoveObserver(&selected_observer_); } PersistentPrefStore* SegregatedPrefStore::StoreForKey(base::StringPiece key) { return (base::Contains(selected_preference_names_, key) ? selected_pref_store_ : default_pref_store_) .get(); } const PersistentPrefStore* SegregatedPrefStore::StoreForKey( base::StringPiece key) const { return (base::Contains(selected_preference_names_, key) ? selected_pref_store_ : default_pref_store_) .get(); }