229 lines
8.3 KiB
C++
229 lines
8.3 KiB
C++
// 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 <string>
|
|
#include <utility>
|
|
|
|
#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<PersistentPrefStore> default_pref_store,
|
|
scoped_refptr<PersistentPrefStore> 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();
|
|
}
|