1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/sync_preferences/pref_service_syncable.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/value_conversions.h"
14 #include "components/pref_registry/pref_registry_syncable.h"
15 #include "components/prefs/default_pref_store.h"
16 #include "components/prefs/in_memory_pref_store.h"
17 #include "components/prefs/overlay_user_pref_store.h"
18 #include "components/prefs/pref_notifier_impl.h"
19 #include "components/prefs/pref_registry.h"
20 #include "components/prefs/pref_value_store.h"
21 #include "components/sync_preferences/pref_model_associator.h"
22 #include "components/sync_preferences/pref_service_syncable_observer.h"
23 #include "components/sync_preferences/synced_pref_observer.h"
24
25 #if defined(OS_CHROMEOS)
26 #include "chromeos/constants/chromeos_features.h"
27 #endif
28
29 namespace sync_preferences {
30
31 // TODO(tschumann): Handing out pointers to this in the constructor is an
32 // anti-pattern. Instead, introduce a factory method which first constructs
33 // the PrefServiceSyncable instance and then the members which need a reference
34 // to the PrefServiceSycnable instance.
PrefServiceSyncable(std::unique_ptr<PrefNotifierImpl> pref_notifier,std::unique_ptr<PrefValueStore> pref_value_store,scoped_refptr<PersistentPrefStore> user_prefs,scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry,const PrefModelAssociatorClient * pref_model_associator_client,base::RepeatingCallback<void (PersistentPrefStore::PrefReadError)> read_error_callback,bool async)35 PrefServiceSyncable::PrefServiceSyncable(
36 std::unique_ptr<PrefNotifierImpl> pref_notifier,
37 std::unique_ptr<PrefValueStore> pref_value_store,
38 scoped_refptr<PersistentPrefStore> user_prefs,
39 scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry,
40 const PrefModelAssociatorClient* pref_model_associator_client,
41 base::RepeatingCallback<void(PersistentPrefStore::PrefReadError)>
42 read_error_callback,
43 bool async)
44 : PrefService(std::move(pref_notifier),
45 std::move(pref_value_store),
46 user_prefs,
47 pref_registry,
48 std::move(read_error_callback),
49 async),
50 pref_service_forked_(false),
51 pref_sync_associator_(pref_model_associator_client,
52 syncer::PREFERENCES,
53 user_prefs.get()),
54 priority_pref_sync_associator_(pref_model_associator_client,
55 syncer::PRIORITY_PREFERENCES,
56 user_prefs.get()),
57 #if defined(OS_CHROMEOS)
58 os_pref_sync_associator_(pref_model_associator_client,
59 syncer::OS_PREFERENCES,
60 user_prefs.get()),
61 os_priority_pref_sync_associator_(pref_model_associator_client,
62 syncer::OS_PRIORITY_PREFERENCES,
63 user_prefs.get()),
64 #endif
65 pref_registry_(std::move(pref_registry)) {
66 pref_sync_associator_.SetPrefService(this);
67 priority_pref_sync_associator_.SetPrefService(this);
68 #if defined(OS_CHROMEOS)
69 os_pref_sync_associator_.SetPrefService(this);
70 os_priority_pref_sync_associator_.SetPrefService(this);
71 #endif
72
73 // Let PrefModelAssociators know about changes to preference values.
74 pref_value_store_->set_callback(base::BindRepeating(
75 &PrefServiceSyncable::ProcessPrefChange, base::Unretained(this)));
76
77 // Add already-registered syncable preferences to PrefModelAssociator.
78 for (const auto& entry : *pref_registry_) {
79 const std::string& path = entry.first;
80 AddRegisteredSyncablePreference(path,
81 pref_registry_->GetRegistrationFlags(path));
82 }
83
84 // Watch for syncable preferences registered after this point.
85 static_cast<user_prefs::PrefRegistrySyncable*>(pref_registry_.get())
86 ->SetSyncableRegistrationCallback(base::BindRepeating(
87 &PrefServiceSyncable::AddRegisteredSyncablePreference,
88 base::Unretained(this)));
89 }
90
~PrefServiceSyncable()91 PrefServiceSyncable::~PrefServiceSyncable() {
92 // Remove our callback from the registry, since it may outlive us.
93 pref_registry_->SetSyncableRegistrationCallback(base::NullCallback());
94 }
95
96 std::unique_ptr<PrefServiceSyncable>
CreateIncognitoPrefService(PrefStore * incognito_extension_pref_store,const std::vector<const char * > & persistent_pref_names)97 PrefServiceSyncable::CreateIncognitoPrefService(
98 PrefStore* incognito_extension_pref_store,
99 const std::vector<const char*>& persistent_pref_names) {
100 pref_service_forked_ = true;
101 auto pref_notifier = std::make_unique<PrefNotifierImpl>();
102
103 scoped_refptr<user_prefs::PrefRegistrySyncable> forked_registry =
104 pref_registry_->ForkForIncognito();
105
106 auto overlay = base::MakeRefCounted<InMemoryPrefStore>();
107 auto incognito_pref_store = base::MakeRefCounted<OverlayUserPrefStore>(
108 overlay.get(), user_pref_store_.get());
109
110 for (const char* persistent_pref_name : persistent_pref_names)
111 incognito_pref_store->RegisterPersistentPref(persistent_pref_name);
112
113 auto pref_value_store = pref_value_store_->CloneAndSpecialize(
114 nullptr, // managed
115 nullptr, // supervised_user
116 incognito_extension_pref_store,
117 nullptr, // command_line_prefs
118 incognito_pref_store.get(),
119 nullptr, // recommended
120 forked_registry->defaults().get(), pref_notifier.get(),
121 /*delegate=*/nullptr);
122 return std::make_unique<PrefServiceSyncable>(
123 std::move(pref_notifier), std::move(pref_value_store),
124 std::move(incognito_pref_store), std::move(forked_registry),
125 pref_sync_associator_.client(), read_error_callback_, false);
126 }
127
IsSyncing()128 bool PrefServiceSyncable::IsSyncing() {
129 if (pref_sync_associator_.models_associated())
130 return true;
131 #if defined(OS_CHROMEOS)
132 if (os_pref_sync_associator_.models_associated())
133 return true;
134 #endif
135 return false;
136 }
137
IsPrioritySyncing()138 bool PrefServiceSyncable::IsPrioritySyncing() {
139 if (priority_pref_sync_associator_.models_associated())
140 return true;
141 #if defined(OS_CHROMEOS)
142 if (os_priority_pref_sync_associator_.models_associated())
143 return true;
144 #endif
145 return false;
146 }
147
AddObserver(PrefServiceSyncableObserver * observer)148 void PrefServiceSyncable::AddObserver(PrefServiceSyncableObserver* observer) {
149 observer_list_.AddObserver(observer);
150 }
151
RemoveObserver(PrefServiceSyncableObserver * observer)152 void PrefServiceSyncable::RemoveObserver(
153 PrefServiceSyncableObserver* observer) {
154 observer_list_.RemoveObserver(observer);
155 }
156
GetSyncableService(const syncer::ModelType & type)157 syncer::SyncableService* PrefServiceSyncable::GetSyncableService(
158 const syncer::ModelType& type) {
159 switch (type) {
160 case syncer::PREFERENCES:
161 return &pref_sync_associator_;
162 case syncer::PRIORITY_PREFERENCES:
163 return &priority_pref_sync_associator_;
164 #if defined(OS_CHROMEOS)
165 case syncer::OS_PREFERENCES:
166 return &os_pref_sync_associator_;
167 case syncer::OS_PRIORITY_PREFERENCES:
168 return &os_priority_pref_sync_associator_;
169 #endif
170 default:
171 NOTREACHED() << "invalid model type: " << type;
172 return nullptr;
173 }
174 }
175
UpdateCommandLinePrefStore(PrefStore * cmd_line_store)176 void PrefServiceSyncable::UpdateCommandLinePrefStore(
177 PrefStore* cmd_line_store) {
178 // If |pref_service_forked_| is true, then this PrefService and the forked
179 // copies will be out of sync.
180 DCHECK(!pref_service_forked_);
181 PrefService::UpdateCommandLinePrefStore(cmd_line_store);
182 }
183
AddSyncedPrefObserver(const std::string & name,SyncedPrefObserver * observer)184 void PrefServiceSyncable::AddSyncedPrefObserver(const std::string& name,
185 SyncedPrefObserver* observer) {
186 pref_sync_associator_.AddSyncedPrefObserver(name, observer);
187 priority_pref_sync_associator_.AddSyncedPrefObserver(name, observer);
188 #if defined(OS_CHROMEOS)
189 os_pref_sync_associator_.AddSyncedPrefObserver(name, observer);
190 os_priority_pref_sync_associator_.AddSyncedPrefObserver(name, observer);
191 #endif
192 }
193
RemoveSyncedPrefObserver(const std::string & name,SyncedPrefObserver * observer)194 void PrefServiceSyncable::RemoveSyncedPrefObserver(
195 const std::string& name,
196 SyncedPrefObserver* observer) {
197 pref_sync_associator_.RemoveSyncedPrefObserver(name, observer);
198 priority_pref_sync_associator_.RemoveSyncedPrefObserver(name, observer);
199 #if defined(OS_CHROMEOS)
200 os_pref_sync_associator_.RemoveSyncedPrefObserver(name, observer);
201 os_priority_pref_sync_associator_.RemoveSyncedPrefObserver(name, observer);
202 #endif
203 }
204
AddRegisteredSyncablePreference(const std::string & path,uint32_t flags)205 void PrefServiceSyncable::AddRegisteredSyncablePreference(
206 const std::string& path,
207 uint32_t flags) {
208 DCHECK(FindPreference(path));
209 if (flags & user_prefs::PrefRegistrySyncable::SYNCABLE_PREF) {
210 pref_sync_associator_.RegisterPref(path);
211 return;
212 }
213 if (flags & user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF) {
214 priority_pref_sync_associator_.RegisterPref(path);
215 return;
216 }
217 #if defined(OS_CHROMEOS)
218 if (flags & user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF) {
219 if (chromeos::features::IsSplitSettingsSyncEnabled()) {
220 // Register the pref under the new ModelType::OS_PREFERENCES.
221 os_pref_sync_associator_.RegisterPref(path);
222 // Also register under the old ModelType::PREFERENCES. This ensures that
223 // local changes to OS prefs are also synced to old clients that have the
224 // pref registered as a browser SYNCABLE_PREF.
225 pref_sync_associator_.RegisterPrefWithLegacyModelType(path);
226 } else {
227 // Behave like an old client and treat this pref like it was registered
228 // as a SYNCABLE_PREF under ModelType::PREFERENCES.
229 pref_sync_associator_.RegisterPref(path);
230 }
231 return;
232 }
233 if (flags & user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PRIORITY_PREF) {
234 // See comments for SYNCABLE_OS_PREF above.
235 if (chromeos::features::IsSplitSettingsSyncEnabled()) {
236 os_priority_pref_sync_associator_.RegisterPref(path);
237 priority_pref_sync_associator_.RegisterPrefWithLegacyModelType(path);
238 } else {
239 priority_pref_sync_associator_.RegisterPref(path);
240 }
241 return;
242 }
243 #endif
244 }
245
OnIsSyncingChanged()246 void PrefServiceSyncable::OnIsSyncingChanged() {
247 for (auto& observer : observer_list_)
248 observer.OnIsSyncingChanged();
249 }
250
ProcessPrefChange(const std::string & name)251 void PrefServiceSyncable::ProcessPrefChange(const std::string& name) {
252 pref_sync_associator_.ProcessPrefChange(name);
253 priority_pref_sync_associator_.ProcessPrefChange(name);
254 #if defined(OS_CHROMEOS)
255 os_pref_sync_associator_.ProcessPrefChange(name);
256 os_priority_pref_sync_associator_.ProcessPrefChange(name);
257 #endif
258 }
259
260 } // namespace sync_preferences
261