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