blob: 1f3ccc52fcb7731fbc514fb903014847755fcbf7 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 <utility>
#include "base/barrier_closure.h"
#include "base/check_op.h"
#include "base/containers/contains.h"
#include "base/notreached.h"
#include "base/values.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<PersistentPrefStore> default_pref_store,
scoped_refptr<PersistentPrefStore> selected_pref_store,
std::set<std::string> 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(const std::string& key,
const base::Value** result) const {
return StoreForKey(key)->GetValue(key, result);
}
std::unique_ptr<base::DictionaryValue> SegregatedPrefStore::GetValues() const {
auto values = default_pref_store_->GetValues();
auto selected_pref_store_values = selected_pref_store_->GetValues();
for (const auto& key : selected_preference_names_) {
const base::Value* value = nullptr;
if (selected_pref_store_values->Get(key, &value)) {
values->SetPath(key, value->Clone());
} else {
values->RemoveKey(key);
}
}
return values;
}
void SegregatedPrefStore::SetValue(const std::string& key,
std::unique_ptr<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,
std::unique_ptr<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::ClearMutableValues() {
NOTIMPLEMENTED();
}
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(const std::string& key) {
return (base::Contains(selected_preference_names_, key) ? selected_pref_store_
: default_pref_store_)
.get();
}
const PersistentPrefStore* SegregatedPrefStore::StoreForKey(
const std::string& key) const {
return (base::Contains(selected_preference_names_, key) ? selected_pref_store_
: default_pref_store_)
.get();
}