1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef COMPONENTS_SYNC_PREFERENCES_PREF_MODEL_ASSOCIATOR_H_
6 #define COMPONENTS_SYNC_PREFERENCES_PREF_MODEL_ASSOCIATOR_H_
11 #include <unordered_map>
13 #include "base/callback_forward.h"
14 #include "base/compiler_specific.h"
15 #include "base/memory/raw_ptr.h"
16 #include "base/observer_list.h"
17 #include "base/sequence_checker.h"
18 #include "components/sync/model/sync_data.h"
19 #include "components/sync/model/syncable_service.h"
20 #include "components/sync_preferences/synced_pref_observer.h"
22 class PersistentPrefStore;
29 class EntitySpecifics;
30 class PreferenceSpecifics;
31 } // namespace sync_pb
33 namespace sync_preferences {
35 class PrefModelAssociatorClient;
36 class PrefServiceSyncable;
38 // Contains all preference sync related logic.
39 // TODO(sync): Merge this into PrefService once we separate the profile
40 // PrefService from the local state PrefService.
41 class PrefModelAssociator : public syncer::SyncableService {
43 // Constructs a PrefModelAssociator initializing the |client_| and |type_|
44 // instance variable. The |client| and |user_pref_store| are not owned by this
45 // object and they must outlive the PrefModelAssociator.
46 PrefModelAssociator(const PrefModelAssociatorClient* client,
47 syncer::ModelType type,
48 PersistentPrefStore* user_pref_store);
50 PrefModelAssociator(const PrefModelAssociator&) = delete;
51 PrefModelAssociator& operator=(const PrefModelAssociator&) = delete;
53 ~PrefModelAssociator() override;
55 // See description above field for details.
56 bool models_associated() const { return models_associated_; }
58 // Returns the mutable preference from |specifics| for a given model |type|.
59 // Exposed for testing.
60 static sync_pb::PreferenceSpecifics* GetMutableSpecifics(
61 syncer::ModelType type,
62 sync_pb::EntitySpecifics* specifics);
64 // syncer::SyncableService implementation.
65 void WaitUntilReadyToSync(base::OnceClosure done) override;
66 absl::optional<syncer::ModelError> MergeDataAndStartSyncing(
67 syncer::ModelType type,
68 const syncer::SyncDataList& initial_sync_data,
69 std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
70 std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) override;
71 void StopSyncing(syncer::ModelType type) override;
72 absl::optional<syncer::ModelError> ProcessSyncChanges(
73 const base::Location& from_here,
74 const syncer::SyncChangeList& change_list) override;
75 // Note for GetAllSyncDataForTesting: This will build a model of all
76 // preferences registered as syncable with user controlled data. We do not
77 // track any information for preferences not registered locally as syncable
78 // and do not inform the syncer of non-user controlled preferences.
79 syncer::SyncDataList GetAllSyncDataForTesting(syncer::ModelType type) const;
81 // Register a preference with the specified name for syncing. We do not care
82 // about the type at registration time, but when changes arrive from the
83 // syncer, we check if they can be applied and if not drop them.
84 // Note: This should only be called at profile startup time (before sync
86 void RegisterPref(const std::string& name);
88 // See |legacy_model_type_preferences_|.
89 void RegisterPrefWithLegacyModelType(const std::string& name);
91 // Process a local preference change. This can trigger new SyncChanges being
92 // sent to the syncer.
93 void ProcessPrefChange(const std::string& name);
95 void SetPrefService(PrefServiceSyncable* pref_service);
97 // Merges the local_value into the supplied server_value and returns
98 // the result (caller takes ownership). If there is a conflict, the server
99 // value always takes precedence. Note that only certain preferences will
100 // actually be merged, all others will return a copy of the server value. See
101 // the method's implementation for details.
102 base::Value MergePreference(const std::string& name,
103 const base::Value& local_value,
104 const base::Value& server_value);
106 // Fills |sync_data| with a sync representation of the preference data
108 bool CreatePrefSyncData(const std::string& name,
109 const base::Value& value,
110 syncer::SyncData* sync_data) const;
112 // Returns true if the specified preference is registered for syncing.
113 bool IsPrefRegistered(const std::string& name) const;
115 // See |legacy_model_type_preferences_|.
116 // Exposed for testing.
117 bool IsLegacyModelTypePref(const std::string& name) const;
119 // Adds a SyncedPrefObserver to watch for changes to a specific pref.
120 void AddSyncedPrefObserver(const std::string& name,
121 SyncedPrefObserver* observer);
123 // Removes a SyncedPrefObserver from a pref's list of observers.
124 void RemoveSyncedPrefObserver(const std::string& name,
125 SyncedPrefObserver* observer);
127 // Returns the PrefModelAssociatorClient for this object.
128 const PrefModelAssociatorClient* client() const { return client_; }
130 // Returns true if the pref under the given name is pulled down from sync.
131 // Note this does not refer to SYNCABLE_PREF.
132 bool IsPrefSyncedForTesting(const std::string& name) const;
135 // Create an association for a given preference. If |sync_pref| is valid,
136 // signifying that sync has data for this preference, we reconcile their data
137 // with ours and append a new UPDATE SyncChange to |sync_changes|. If
138 // sync_pref is not set, we append an ADD SyncChange to |sync_changes| with
139 // the current preference data.
140 // Note: We do not modify the sync data for preferences that are either
141 // controlled by policy (are not user modifiable) or have their default value
142 // (are not user controlled).
143 void InitPrefAndAssociate(const syncer::SyncData& sync_pref,
144 const std::string& pref_name,
145 syncer::SyncChangeList* sync_changes);
147 static std::unique_ptr<base::Value> MergeListValues(
148 const base::Value& from_value,
149 const base::Value& to_value);
151 static base::Value MergeDictionaryValues(const base::Value& from_value,
152 const base::Value& to_value);
154 // Extract preference value from sync specifics.
155 static absl::optional<base::Value> ReadPreferenceSpecifics(
156 const sync_pb::PreferenceSpecifics& specifics);
158 void NotifySyncedPrefObservers(const std::string& path, bool from_sync) const;
160 // Sets |pref_name| to |new_value| if |new_value| has an appropriate type for
161 // this preference. Otherwise records metrics and logs a warning.
162 void SetPrefWithTypeCheck(const std::string& pref_name,
163 const base::Value& new_value);
165 // Returns true if the |new_value| for |pref_name| has the same type as the
166 // existing value in the user's local pref store. If the types don't match,
167 // records metrics and logs a warning.
168 bool TypeMatchesUserPrefStore(const std::string& pref_name,
169 const base::Value& new_value) const;
171 // Verifies that the type which preference |pref_name| was registered with
172 // matches the type of any persisted value. On mismatch, the persisted value
174 void EnforceRegisteredTypeInStore(const std::string& pref_name);
176 // Notifies the synced pref observers that the pref for the given |path| is
178 void NotifyStartedSyncing(const std::string& path) const;
180 // Do we have an active association between the preferences and sync models?
181 // Set when start syncing, reset in StopSyncing. While this is not set, we
182 // ignore any local preference changes (when we start syncing we will look
183 // up the most recent values anyways).
184 bool models_associated_ = false;
186 // Whether we're currently processing changes from the syncer. While this is
187 // true, we ignore any local preference changes, since we triggered them.
188 bool processing_syncer_changes_ = false;
190 // A set of preference names.
191 typedef std::set<std::string> PreferenceSet;
193 // All preferences that have registered as being syncable with this profile.
194 PreferenceSet registered_preferences_;
196 // The preferences that are currently synced (excludes those preferences
197 // that have never had sync data and currently have default values or are
198 // policy controlled).
199 // Note: this set never decreases, only grows to eventually match
200 // registered_preferences_ as more preferences are synced. It determines
201 // whether a preference change should update an existing sync node or create
203 PreferenceSet synced_preferences_;
205 // Preferences that have migrated to a new ModelType. They are included here
206 // so updates can be sent back to older clients with this old ModelType.
207 // Updates received from older clients will be ignored. The common case is
208 // migration from PREFERENCES to OS_PREFERENCES. This field can be removed
210 PreferenceSet legacy_model_type_preferences_;
212 // The PrefService we are syncing to.
213 raw_ptr<PrefServiceSyncable> pref_service_ = nullptr;
215 // Sync's syncer::SyncChange handler. We push all our changes through this.
216 std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;
218 // Sync's error handler. We use this to create sync errors.
219 std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory_;
221 // The datatype that this associator is responible for, either PREFERENCES or
222 // PRIORITY_PREFERENCES or OS_PREFERENCES or OS_PRIORITY_PREFERENCES.
223 syncer::ModelType type_;
225 // Map prefs to lists of observers. Observers will receive notification when
226 // a pref changes, including the detail of whether or not the change came
228 using SyncedPrefObserverList =
229 base::ObserverList<SyncedPrefObserver>::Unchecked;
230 std::unordered_map<std::string, std::unique_ptr<SyncedPrefObserverList>>
231 synced_pref_observers_;
232 raw_ptr<const PrefModelAssociatorClient> client_; // Weak.
234 const raw_ptr<PersistentPrefStore> user_pref_store_;
236 SEQUENCE_CHECKER(sequence_checker_);
239 } // namespace sync_preferences
241 #endif // COMPONENTS_SYNC_PREFERENCES_PREF_MODEL_ASSOCIATOR_H_