blob: 8a85501118e191a4ac45ee9a6daf41a6ef5689a3 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_SYNC_PREFERENCES_DUAL_LAYER_USER_PREF_STORE_H_
#define COMPONENTS_SYNC_PREFERENCES_DUAL_LAYER_USER_PREF_STORE_H_
#include <memory>
#include <set>
#include <string>
#include <utility>
#include "base/containers/flat_set.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string_piece.h"
#include "components/prefs/persistent_pref_store.h"
#include "components/prefs/value_map_pref_store.h"
#include "components/sync/base/model_type.h"
namespace sync_preferences {
class PrefModelAssociatorClient;
// A two-layer user PrefStore that combines local preferences (scoped to this
// profile) with account-scoped preferences (scoped to the user's signed-in
// account).
// * Account takes precedence: If a pref has a value in both stores, then
// typically the account-scoped one takes precedence. However, for some prefs,
// the two values may be merged.
// * Dual writes: Any changes made to prefs *on this device* are written to both
// stores. However, incoming changes made on other devices only go into the
// account store.
class DualLayerUserPrefStore : public PersistentPrefStore {
public:
DualLayerUserPrefStore(
scoped_refptr<PersistentPrefStore> local_pref_store,
scoped_refptr<PersistentPrefStore> account_pref_store,
const PrefModelAssociatorClient* pref_model_associator_client);
DualLayerUserPrefStore(const DualLayerUserPrefStore&) = delete;
DualLayerUserPrefStore& operator=(const DualLayerUserPrefStore&) = delete;
// Marks `model_type` as enabled for account storage. This should be called
// when a data type starts syncing.
void EnableType(syncer::ModelType model_type);
// Unmarks `model_type` as enabled for account storage and removes all
// corresponding preference entries(belonging to this type) from account
// storage. This should be called when a data type stops syncing.
void DisableTypeAndClearAccountStore(syncer::ModelType model_type);
scoped_refptr<PersistentPrefStore> GetLocalPrefStore();
scoped_refptr<WriteablePrefStore> GetAccountPrefStore();
// PrefStore implementation.
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
bool HasObservers() const override;
bool IsInitializationComplete() const override;
bool GetValue(base::StringPiece key,
const base::Value** result) const override;
base::Value::Dict GetValues() const override;
// WriteablePrefStore implementation.
void SetValue(const std::string& key,
base::Value value,
uint32_t flags) override;
void RemoveValue(const std::string& key, uint32_t flags) override;
bool GetMutableValue(const std::string& key, base::Value** result) override;
void ReportValueChanged(const std::string& key, uint32_t flags) override;
void SetValueSilently(const std::string& key,
base::Value value,
uint32_t flags) override;
void RemoveValuesByPrefixSilently(const std::string& prefix) override;
// PersistentPrefStore implementation.
bool ReadOnly() const override;
PrefReadError GetReadError() const override;
PrefReadError ReadPrefs() override;
void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
void CommitPendingWrite(
base::OnceClosure reply_callback = base::OnceClosure(),
base::OnceClosure synchronous_done_callback =
base::OnceClosure()) override;
void SchedulePendingLossyWrites() override;
void OnStoreDeletionFromDisk() override;
// Return the set of active pref types.
base::flat_set<syncer::ModelType> GetActiveTypesForTest() const;
protected:
~DualLayerUserPrefStore() override;
private:
// Forwards events from the underlying stores to the provided "outer"
// `DualLayerUserPrefStore` to synthesize external events via `observers_`.
class UnderlyingPrefStoreObserver : public PrefStore::Observer {
public:
explicit UnderlyingPrefStoreObserver(DualLayerUserPrefStore* outer,
bool is_account_store);
UnderlyingPrefStoreObserver(const UnderlyingPrefStoreObserver&) = delete;
UnderlyingPrefStoreObserver& operator=(const UnderlyingPrefStoreObserver&) =
delete;
// PrefStore::Observer implementation.
void OnPrefValueChanged(const std::string& key) override;
void OnInitializationCompleted(bool succeeded) override;
bool initialization_succeeded() const;
private:
const raw_ptr<DualLayerUserPrefStore> outer_;
const bool is_account_store_;
// Start with `initialization_succeeded_` as true as some persistent
// stores do not issue OnInitializationCompleted().
bool initialization_succeeded_ = true;
};
bool IsInitializationSuccessful() const;
// Returns whether the pref with the given `key` should be synced.
bool ShouldSyncPref(const std::string& key) const;
// Returns whether the pref with the given `key` is mergeable.
// TODO(crbug.com/1416479): This does not cover prefs with custom merge logic
// yet.
bool IsPrefKeyMergeable(const std::string& key) const;
// Produces a "merged" view of `account_value` and `local_value`. In case
// `pref_name` is a mergeable pref, a new merged pref is returned, which is
// owned by `merged_prefs_`. Else, it returns a pointer to the account value,
// given that in this case the account value overrides the local value.
const base::Value* MaybeMerge(const std::string& pref_name,
const base::Value& local_value,
const base::Value& account_value) const;
base::Value* MaybeMerge(const std::string& pref_name,
base::Value& local_value,
base::Value& account_value);
// Unmerges `value` and returns the new local value and the account value (in
// that order).
std::pair<base::Value, base::Value> UnmergeValue(const std::string& pref_name,
base::Value value,
uint32_t flags) const;
// Get all prefs currently present in the account store.
std::vector<std::string> GetPrefNamesInAccountStore() const;
// The two underlying pref stores, scoped to this device/profile and to the
// user's signed-in account, respectively.
const scoped_refptr<PersistentPrefStore> local_pref_store_;
const scoped_refptr<PersistentPrefStore> account_pref_store_;
// This stores the merged value of a mergeable pref, if required - i.e. if the
// pref is queried while it exists on both the stores. This is needed to
// tackle the issue regarding the ownership of the newly created merged values
// on calls to GetValue().
// Note: Marked as mutable to allow update by GetValue() method which is
// const.
mutable PrefValueMap merged_prefs_;
// Observers for the two underlying pref stores, used to propagate pref-change
// notifications the this class's own observers.
UnderlyingPrefStoreObserver local_pref_store_observer_;
UnderlyingPrefStoreObserver account_pref_store_observer_;
std::unique_ptr<PersistentPrefStore::ReadErrorDelegate> read_error_delegate_;
// List of preference types currently syncing.
base::flat_set<syncer::ModelType> active_types_;
// Set to true while this store is setting prefs in the underlying stores.
// Used to avoid self-notifications.
bool is_setting_prefs_ = false;
base::ObserverList<PrefStore::Observer, true>::Unchecked observers_;
const raw_ptr<const PrefModelAssociatorClient> pref_model_associator_client_ =
nullptr;
};
} // namespace sync_preferences
#endif // COMPONENTS_SYNC_PREFERENCES_DUAL_LAYER_USER_PREF_STORE_H_