blob: 023c58bd45414becfe487f652d4d3e0c18405b49 [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 <string_view>
#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 "components/prefs/persistent_pref_store.h"
#include "components/prefs/value_map_pref_store.h"
#include "components/sync/base/data_type.h"
#include "components/sync/service/sync_service_observer.h"
namespace syncer {
class SyncService;
} // namespace syncer
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 syncer::SyncServiceObserver {
public:
DualLayerUserPrefStore(
scoped_refptr<PersistentPrefStore> local_pref_store,
scoped_refptr<PersistentPrefStore> account_pref_store,
scoped_refptr<PrefModelAssociatorClient> pref_model_associator_client);
DualLayerUserPrefStore(const DualLayerUserPrefStore&) = delete;
DualLayerUserPrefStore& operator=(const DualLayerUserPrefStore&) = delete;
// Marks `data_type` as enabled for account storage. This should be called
// when a data type starts syncing.
void EnableType(syncer::DataType data_type);
// Unmarks `data_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::DataType data_type);
// Sets value for preference `key` only in the account store. This is meant
// for use by sync components (specifically PrefModelAssociator) to insert
// value in the account store directly but only leads to notifications for
// DualLayerUserPrefStore observers if the effective value changes.
// Note: This does not do any merge/unmerge and does not check whether the
// pref `key` is syncable.
// TODO(crbug.com/40277783): Implement a better way to handle this usage by
// the sync components.
void SetValueInAccountStoreOnly(std::string_view key,
base::Value value,
uint32_t flags);
void OnSyncServiceInitialized(syncer::SyncService* sync_service);
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(std::string_view key,
const base::Value** result) const override;
base::Value::Dict GetValues() const override;
// WriteablePrefStore implementation.
void SetValue(std::string_view key,
base::Value value,
uint32_t flags) override;
void RemoveValue(std::string_view key, uint32_t flags) override;
bool GetMutableValue(std::string_view key, base::Value** result) override;
void ReportValueChanged(std::string_view key, uint32_t flags) override;
void SetValueSilently(std::string_view key,
base::Value value,
uint32_t flags) override;
void RemoveValuesByPrefixSilently(std::string_view 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;
bool HasReadErrorDelegate() const override;
// SyncServiceObserver implementation
void OnStateChanged(syncer::SyncService* sync_service) override;
void OnSyncShutdown(syncer::SyncService* sync_service) override;
// Return the set of active pref types.
base::flat_set<syncer::DataType> GetActiveTypesForTest() const;
bool IsHistorySyncEnabledForTest() const;
void SetIsHistorySyncEnabledForTest(bool is_history_sync_enabled);
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(std::string_view 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 inserted into the
// account pref store. Note that the account store keeps in sync with the
// account.
bool ShouldSetValueInAccountStore(std::string_view key) const;
// Returns whether the pref with the given `key` should be queried from the
// account pref store. Note that the account store keeps in sync with the
// account.
bool ShouldGetValueFromAccountStore(std::string_view key) const;
// Returns whether the pref with the given `key` is mergeable.
bool IsPrefKeyMergeable(std::string_view 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(std::string_view pref_name,
const base::Value& local_value,
const base::Value& account_value) const;
base::Value* MaybeMerge(std::string_view 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(std::string_view pref_name,
base::Value value,
uint32_t flags) const;
// Get all prefs currently present in the account store.
// Note that this will also return prefs which can not be queried from the
// account store. For example, this method will return prefs requiring history
// opt-in even if history sync is disabled. A GetValue() call for such a pref
// will not query the account store. Thus it is the role of the callers to
// check the history opt-in.
std::vector<std::string> GetPrefNamesInAccountStore() const;
// Returns whether the user has history sync turned on.
bool IsHistorySyncEnabled() 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_;
// Optional so we can differentiate `nullopt` from `nullptr`.
std::optional<std::unique_ptr<PersistentPrefStore::ReadErrorDelegate>>
read_error_delegate_;
// List of preference types currently syncing.
base::flat_set<syncer::DataType> 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;
bool is_history_sync_enabled_ = false;
base::ObserverList<PrefStore::Observer, true> observers_;
const scoped_refptr<PrefModelAssociatorClient> pref_model_associator_client_;
};
} // namespace sync_preferences
#endif // COMPONENTS_SYNC_PREFERENCES_DUAL_LAYER_USER_PREF_STORE_H_