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. 4 // 5 // A helper class that stays in sync with a preference (bool, int, real, 6 // string or filepath). For example: 7 // 8 // class MyClass { 9 // public: 10 // MyClass(PrefService* prefs) { 11 // my_string_.Init(prefs::kHomePage, prefs); 12 // } 13 // private: 14 // StringPrefMember my_string_; 15 // }; 16 // 17 // my_string_ should stay in sync with the prefs::kHomePage pref and will 18 // update if either the pref changes or if my_string_.SetValue is called. 19 // 20 // An optional observer can be passed into the Init method which can be used to 21 // notify MyClass of changes. Note that if you use SetValue(), the observer 22 // will not be notified. 23 24 #ifndef COMPONENTS_PREFS_PREF_MEMBER_H_ 25 #define COMPONENTS_PREFS_PREF_MEMBER_H_ 26 27 #include <string> 28 #include <vector> 29 30 #include "base/check.h" 31 #include "base/files/file_path.h" 32 #include "base/functional/bind.h" 33 #include "base/functional/callback_forward.h" 34 #include "base/memory/raw_ptr.h" 35 #include "base/memory/ref_counted.h" 36 #include "base/task/sequenced_task_runner.h" 37 #include "base/values.h" 38 #include "components/prefs/pref_observer.h" 39 #include "components/prefs/prefs_export.h" 40 41 class PrefService; 42 43 namespace subtle { 44 45 class COMPONENTS_PREFS_EXPORT PrefMemberBase : public PrefObserver { 46 public: 47 // Type of callback you can register if you need to know the name of 48 // the pref that is changing. 49 using NamedChangeCallback = base::RepeatingCallback<void(const std::string&)>; 50 prefs()51 PrefService* prefs() { return prefs_; } prefs()52 const PrefService* prefs() const { return prefs_; } 53 54 protected: 55 class COMPONENTS_PREFS_EXPORT Internal 56 : public base::RefCountedThreadSafe<Internal> { 57 public: 58 Internal(); 59 60 Internal(const Internal&) = delete; 61 Internal& operator=(const Internal&) = delete; 62 63 // Update the value, either by calling |UpdateValueInternal| directly 64 // or by dispatching to the right sequence. 65 // Takes ownership of |value|. 66 void UpdateValue(base::Value* value, 67 bool is_managed, 68 bool is_user_modifiable, 69 bool is_default_value, 70 base::OnceClosure callback) const; 71 72 void MoveToSequence(scoped_refptr<base::SequencedTaskRunner> task_runner); 73 74 // See PrefMember<> for description. IsManaged()75 bool IsManaged() const { return is_managed_; } IsUserModifiable()76 bool IsUserModifiable() const { return is_user_modifiable_; } IsDefaultValue()77 bool IsDefaultValue() const { return is_default_value_; } 78 79 protected: 80 friend class base::RefCountedThreadSafe<Internal>; 81 virtual ~Internal(); 82 CheckOnCorrectSequence()83 void CheckOnCorrectSequence() const { DCHECK(IsOnCorrectSequence()); } 84 85 private: 86 // This method actually updates the value. It should only be called from 87 // the sequence the PrefMember is on. 88 virtual bool UpdateValueInternal(const base::Value& value) const = 0; 89 90 bool IsOnCorrectSequence() const; 91 92 scoped_refptr<base::SequencedTaskRunner> owning_task_runner_; 93 mutable bool is_managed_ = false; 94 mutable bool is_user_modifiable_ = false; 95 mutable bool is_default_value_ = false; 96 }; 97 98 PrefMemberBase(); 99 virtual ~PrefMemberBase(); 100 101 // See PrefMember<> for description. 102 void Init(const std::string& pref_name, 103 PrefService* prefs, 104 const NamedChangeCallback& observer); 105 void Init(const std::string& pref_name, PrefService* prefs); 106 107 virtual void CreateInternal() const = 0; 108 109 // See PrefMember<> for description. 110 void Destroy(); 111 112 void MoveToSequence(scoped_refptr<base::SequencedTaskRunner> task_runner); 113 114 // PrefObserver 115 void OnPreferenceChanged(PrefService* service, 116 const std::string& pref_name) override; 117 VerifyValuePrefName()118 void VerifyValuePrefName() const { 119 DCHECK(!pref_name_.empty()); 120 } 121 122 // This method is used to do the actual sync with the preference. 123 // Note: it is logically const, because it doesn't modify the state 124 // seen by the outside world. It is just doing a lazy load behind the scenes. 125 void UpdateValueFromPref(base::OnceClosure callback) const; 126 127 // Verifies the preference name, and lazily loads the preference value if 128 // it hasn't been loaded yet. 129 void VerifyPref() const; 130 pref_name()131 const std::string& pref_name() const { return pref_name_; } 132 133 virtual Internal* internal() const = 0; 134 135 // Used to allow registering plain base::RepeatingClosure callbacks. 136 static void InvokeUnnamedCallback(const base::RepeatingClosure& callback, 137 const std::string& pref_name); 138 139 private: 140 // Ordered the members to compact the class instance. 141 std::string pref_name_; 142 NamedChangeCallback observer_; 143 raw_ptr<PrefService> prefs_; 144 145 protected: 146 bool setting_value_; 147 }; 148 149 // This function implements StringListPrefMember::UpdateValue(). 150 // It is exposed here for testing purposes. 151 bool COMPONENTS_PREFS_EXPORT PrefMemberVectorStringUpdate( 152 const base::Value& value, 153 std::vector<std::string>* string_vector); 154 155 } // namespace subtle 156 157 template <typename ValueType> 158 class PrefMember : public subtle::PrefMemberBase { 159 public: 160 // Defer initialization to an Init method so it's easy to make this class be 161 // a member variable. PrefMember()162 PrefMember() {} 163 164 PrefMember(const PrefMember&) = delete; 165 PrefMember& operator=(const PrefMember&) = delete; 166 ~PrefMember()167 virtual ~PrefMember() {} 168 169 // Do the actual initialization of the class. Use the two-parameter 170 // version if you don't want any notifications of changes. This 171 // method should only be called on the UI thread. Init(const std::string & pref_name,PrefService * prefs,const NamedChangeCallback & observer)172 void Init(const std::string& pref_name, 173 PrefService* prefs, 174 const NamedChangeCallback& observer) { 175 subtle::PrefMemberBase::Init(pref_name, prefs, observer); 176 } Init(const std::string & pref_name,PrefService * prefs,const base::RepeatingClosure & observer)177 void Init(const std::string& pref_name, 178 PrefService* prefs, 179 const base::RepeatingClosure& observer) { 180 subtle::PrefMemberBase::Init( 181 pref_name, prefs, 182 base::BindRepeating(&PrefMemberBase::InvokeUnnamedCallback, observer)); 183 } Init(const std::string & pref_name,PrefService * prefs)184 void Init(const std::string& pref_name, PrefService* prefs) { 185 subtle::PrefMemberBase::Init(pref_name, prefs); 186 } 187 188 // Unsubscribes the PrefMember from the PrefService. After calling this 189 // function, the PrefMember may not be used any more on the UI thread. 190 // Assuming |MoveToSequence| was previously called, |GetValue|, |IsManaged|, 191 // and |IsUserModifiable| can still be called from the other sequence but 192 // the results will no longer update from the PrefService. 193 // This method should only be called on the UI thread. Destroy()194 void Destroy() { 195 subtle::PrefMemberBase::Destroy(); 196 } 197 198 // Moves the PrefMember to another sequence, allowing read accesses from 199 // there. Changes from the PrefService will be propagated asynchronously 200 // via PostTask. 201 // This method should only be used from the sequence the PrefMember is 202 // currently on, which is the UI thread by default. MoveToSequence(scoped_refptr<base::SequencedTaskRunner> task_runner)203 void MoveToSequence(scoped_refptr<base::SequencedTaskRunner> task_runner) { 204 subtle::PrefMemberBase::MoveToSequence(task_runner); 205 } 206 207 // Check whether the pref is managed, i.e. controlled externally through 208 // enterprise configuration management (e.g. windows group policy). Returns 209 // false for unknown prefs. 210 // This method should only be used from the sequence the PrefMember is 211 // currently on, which is the UI thread unless changed by |MoveToSequence|. IsManaged()212 bool IsManaged() const { 213 VerifyPref(); 214 return internal_->IsManaged(); 215 } 216 217 // Checks whether the pref can be modified by the user. This returns false 218 // when the pref is managed by a policy or an extension, and when a command 219 // line flag overrides the pref. 220 // This method should only be used from the sequence the PrefMember is 221 // currently on, which is the UI thread unless changed by |MoveToSequence|. IsUserModifiable()222 bool IsUserModifiable() const { 223 VerifyPref(); 224 return internal_->IsUserModifiable(); 225 } 226 227 // Checks whether the pref is currently using its default value, and has not 228 // been set by any higher-priority source (even with the same value). This 229 // method should only be used from the sequence the PrefMember is currently 230 // on, which is the UI thread unless changed by |MoveToSequence|. IsDefaultValue()231 bool IsDefaultValue() const { 232 VerifyPref(); 233 return internal_->IsDefaultValue(); 234 } 235 236 // Retrieve the value of the member variable. 237 // This method should only be used from the sequence the PrefMember is 238 // currently on, which is the UI thread unless changed by |MoveToSequence|. GetValue()239 ValueType GetValue() const { 240 VerifyPref(); 241 return internal_->value(); 242 } 243 244 // Provided as a convenience. 245 ValueType operator*() const { 246 return GetValue(); 247 } 248 249 // Set the value of the member variable. 250 // This method should only be called on the UI thread. SetValue(const ValueType & value)251 void SetValue(const ValueType& value) { 252 VerifyValuePrefName(); 253 setting_value_ = true; 254 UpdatePref(value); 255 setting_value_ = false; 256 } 257 258 // Returns the pref name. GetPrefName()259 const std::string& GetPrefName() const { 260 return pref_name(); 261 } 262 263 private: 264 class Internal : public subtle::PrefMemberBase::Internal { 265 public: Internal()266 Internal() : value_(ValueType()) {} 267 268 Internal(const Internal&) = delete; 269 Internal& operator=(const Internal&) = delete; 270 value()271 ValueType value() { 272 CheckOnCorrectSequence(); 273 return value_; 274 } 275 276 protected: ~Internal()277 ~Internal() override {} 278 279 COMPONENTS_PREFS_EXPORT bool UpdateValueInternal( 280 const base::Value& value) const override; 281 282 // We cache the value of the pref so we don't have to keep walking the pref 283 // tree. 284 mutable ValueType value_; 285 }; 286 internal()287 Internal* internal() const override { return internal_.get(); } CreateInternal()288 void CreateInternal() const override { internal_ = new Internal(); } 289 290 // This method is used to do the actual sync with pref of the specified type. 291 void COMPONENTS_PREFS_EXPORT UpdatePref(const ValueType& value); 292 293 mutable scoped_refptr<Internal> internal_; 294 }; 295 296 // Declaration of template specialization need to be repeated here 297 // specifically for each specialization (rather than just once above) 298 // or at least one of our compilers won't be happy in all cases. 299 // Specifically, it was failing on ChromeOS with a complaint about 300 // PrefMember<FilePath>::UpdateValueInternal not being defined when 301 // built in a chroot with the following parameters: 302 // 303 // FEATURES="noclean nostrip" USE="-chrome_debug -chrome_remoting 304 // -chrome_internal -chrome_pdf component_build" 305 // ~/trunk/goma/goma-wrapper cros_chrome_make --board=${BOARD} 306 // --install --runhooks 307 308 template <> 309 COMPONENTS_PREFS_EXPORT void PrefMember<bool>::UpdatePref(const bool& value); 310 311 template <> 312 COMPONENTS_PREFS_EXPORT bool PrefMember<bool>::Internal::UpdateValueInternal( 313 const base::Value& value) const; 314 315 template <> 316 COMPONENTS_PREFS_EXPORT void PrefMember<int>::UpdatePref(const int& value); 317 318 template <> 319 COMPONENTS_PREFS_EXPORT bool PrefMember<int>::Internal::UpdateValueInternal( 320 const base::Value& value) const; 321 322 template <> 323 COMPONENTS_PREFS_EXPORT void 324 PrefMember<double>::UpdatePref(const double& value); 325 326 template <> 327 COMPONENTS_PREFS_EXPORT bool PrefMember<double>::Internal::UpdateValueInternal( 328 const base::Value& value) const; 329 330 template <> 331 COMPONENTS_PREFS_EXPORT void PrefMember<std::string>::UpdatePref( 332 const std::string& value); 333 334 template <> 335 COMPONENTS_PREFS_EXPORT bool 336 PrefMember<std::string>::Internal::UpdateValueInternal( 337 const base::Value& value) const; 338 339 template <> 340 COMPONENTS_PREFS_EXPORT void PrefMember<base::FilePath>::UpdatePref( 341 const base::FilePath& value); 342 343 template <> 344 COMPONENTS_PREFS_EXPORT bool 345 PrefMember<base::FilePath>::Internal::UpdateValueInternal( 346 const base::Value& value) const; 347 348 template <> 349 COMPONENTS_PREFS_EXPORT void PrefMember<std::vector<std::string>>::UpdatePref( 350 const std::vector<std::string>& value); 351 352 template <> 353 COMPONENTS_PREFS_EXPORT bool 354 PrefMember<std::vector<std::string>>::Internal::UpdateValueInternal( 355 const base::Value& value) const; 356 357 typedef PrefMember<bool> BooleanPrefMember; 358 typedef PrefMember<int> IntegerPrefMember; 359 typedef PrefMember<double> DoublePrefMember; 360 typedef PrefMember<std::string> StringPrefMember; 361 typedef PrefMember<base::FilePath> FilePathPrefMember; 362 // This preference member is expensive for large string arrays. 363 typedef PrefMember<std::vector<std::string>> StringListPrefMember; 364 365 #endif // COMPONENTS_PREFS_PREF_MEMBER_H_ 366