Preferences.h (23485B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 // Documentation for libpref is in modules/libpref/docs/index.rst. 8 9 #ifndef mozilla_Preferences_h 10 #define mozilla_Preferences_h 11 12 #ifndef MOZILLA_INTERNAL_API 13 # error "This header is only usable from within libxul (MOZILLA_INTERNAL_API)." 14 #endif 15 16 #include "mozilla/Atomics.h" 17 #include "mozilla/MemoryReporting.h" 18 #include "mozilla/MozPromise.h" 19 #include "mozilla/StaticPtr.h" 20 #include "mozilla/ipc/SharedMemoryHandle.h" 21 #include "nsCOMPtr.h" 22 #include "nsIObserver.h" 23 #include "nsIPrefBranch.h" 24 #include "nsIPrefService.h" 25 #include "nsString.h" 26 #include "nsTArray.h" 27 #include "nsWeakReference.h" 28 #include "nsXULAppAPI.h" 29 #include <atomic> 30 #include <functional> 31 32 class nsIFile; 33 class nsIPrefOverrideMap; 34 35 // The callback function will get passed the pref name which triggered the call 36 // and the void* data which was passed to the registered callback function. 37 typedef void (*PrefChangedFunc)(const char* aPref, void* aData); 38 39 class nsPrefBranch; 40 41 namespace mozilla { 42 43 struct RegisterCallbacksInternal; 44 45 void UnloadPrefsModule(); 46 47 class PreferenceServiceReporter; 48 49 namespace dom { 50 class Pref; 51 class PrefValue; 52 } // namespace dom 53 54 namespace ipc { 55 class FileDescriptor; 56 } // namespace ipc 57 58 struct PrefsSizes; 59 60 // Xlib.h defines Bool as a macro constant. Don't try to define this enum if 61 // it's already been included. 62 #ifndef Bool 63 64 // Keep this in sync with PrefType in parser/src/lib.rs. 65 enum class PrefType : uint8_t { 66 None = 0, // only used when neither the default nor user value is set 67 String = 1, 68 Int = 2, 69 Bool = 3, 70 }; 71 72 #endif 73 74 #ifdef XP_UNIX 75 // We need to send two shared memory descriptors to every child process: 76 // 77 // 1) A read-only/write-protected snapshot of the initial state of the 78 // preference database. This memory is shared between all processes, and 79 // therefore cannot be modified once it has been created. 80 // 81 // 2) A set of changes on top of the snapshot, containing the current values of 82 // all preferences which have changed since it was created. 83 // 84 // Since the second set will be different for every process, and the first set 85 // cannot be modified, it is unfortunately not possible to combine them into a 86 // single file descriptor. 87 // 88 // XXX: bug 1440207 is about improving how fixed fds such as this are used. 89 static const int kPrefsFileDescriptor = 8; 90 static const int kPrefMapFileDescriptor = 9; 91 #endif 92 93 // Keep this in sync with PrefType in parser/src/lib.rs. 94 enum class PrefValueKind : uint8_t { Default, User }; 95 96 class Preferences final : public nsIPrefService, 97 public nsIObserver, 98 public nsIPrefBranch, 99 public nsSupportsWeakReference { 100 friend class ::nsPrefBranch; 101 102 public: 103 using WritePrefFilePromise = MozPromise<bool, nsresult, false>; 104 105 NS_DECL_THREADSAFE_ISUPPORTS 106 NS_DECL_NSIPREFSERVICE 107 NS_FORWARD_NSIPREFBRANCH(mRootBranch->) 108 NS_DECL_NSIOBSERVER 109 110 Preferences(); 111 112 // Returns true if the Preferences service is available, false otherwise. 113 static bool IsServiceAvailable(); 114 115 // Initialize user prefs from prefs.js/user.js 116 static void InitializeUserPrefs(); 117 static void FinishInitializingUserPrefs(); 118 119 // Returns the singleton instance which is addreffed. 120 static already_AddRefed<Preferences> GetInstanceForService(); 121 122 // Finallizes global members. 123 static void Shutdown(); 124 125 // Returns shared pref service instance NOTE: not addreffed. 126 static nsIPrefService* GetService() { 127 NS_ENSURE_TRUE(InitStaticMembers(), nullptr); 128 return sPreferences; 129 } 130 131 // Returns shared pref branch instance. NOTE: not addreffed. 132 static nsIPrefBranch* GetRootBranch( 133 PrefValueKind aKind = PrefValueKind::User) { 134 NS_ENSURE_TRUE(InitStaticMembers(), nullptr); 135 return (aKind == PrefValueKind::Default) ? sPreferences->mDefaultRootBranch 136 : sPreferences->mRootBranch; 137 } 138 139 // Gets the type of the pref. 140 static int32_t GetType(const char* aPrefName); 141 142 // Fallible value getters. When `aKind` is `User` they will get the user 143 // value if possible, and fall back to the default value otherwise. 144 static nsresult GetBool(const char* aPrefName, bool* aResult, 145 PrefValueKind aKind = PrefValueKind::User); 146 static nsresult GetInt(const char* aPrefName, int32_t* aResult, 147 PrefValueKind aKind = PrefValueKind::User); 148 static nsresult GetUint(const char* aPrefName, uint32_t* aResult, 149 PrefValueKind aKind = PrefValueKind::User) { 150 return GetInt(aPrefName, reinterpret_cast<int32_t*>(aResult), aKind); 151 } 152 static nsresult GetFloat(const char* aPrefName, float* aResult, 153 PrefValueKind aKind = PrefValueKind::User); 154 static nsresult GetCString(const char* aPrefName, nsACString& aResult, 155 PrefValueKind aKind = PrefValueKind::User); 156 static nsresult GetString(const char* aPrefName, nsAString& aResult, 157 PrefValueKind aKind = PrefValueKind::User); 158 static nsresult GetLocalizedCString( 159 const char* aPrefName, nsACString& aResult, 160 PrefValueKind aKind = PrefValueKind::User); 161 static nsresult GetLocalizedString(const char* aPrefName, nsAString& aResult, 162 PrefValueKind aKind = PrefValueKind::User); 163 static nsresult GetComplex(const char* aPrefName, const nsIID& aType, 164 void** aResult, 165 PrefValueKind aKind = PrefValueKind::User); 166 167 // Infallible getters of user or default values, with fallback results on 168 // failure. When `aKind` is `User` they will get the user value if possible, 169 // and fall back to the default value otherwise. 170 static bool GetBool(const char* aPrefName, bool aFallback = false, 171 PrefValueKind aKind = PrefValueKind::User); 172 static int32_t GetInt(const char* aPrefName, int32_t aFallback = 0, 173 PrefValueKind aKind = PrefValueKind::User); 174 static uint32_t GetUint(const char* aPrefName, uint32_t aFallback = 0, 175 PrefValueKind aKind = PrefValueKind::User); 176 static float GetFloat(const char* aPrefName, float aFallback = 0.0f, 177 PrefValueKind aKind = PrefValueKind::User); 178 179 // Value setters. These fail if run outside the parent process. 180 181 static nsresult SetBool(const char* aPrefName, bool aValue, 182 PrefValueKind aKind = PrefValueKind::User); 183 static nsresult SetInt(const char* aPrefName, int32_t aValue, 184 PrefValueKind aKind = PrefValueKind::User); 185 static nsresult SetCString(const char* aPrefName, const nsACString& aValue, 186 PrefValueKind aKind = PrefValueKind::User); 187 188 static nsresult SetUint(const char* aPrefName, uint32_t aValue, 189 PrefValueKind aKind = PrefValueKind::User) { 190 return SetInt(aPrefName, static_cast<int32_t>(aValue), aKind); 191 } 192 193 static nsresult SetFloat(const char* aPrefName, float aValue, 194 PrefValueKind aKind = PrefValueKind::User) { 195 nsAutoCString value; 196 value.AppendFloat(aValue); 197 return SetCString(aPrefName, value, aKind); 198 } 199 200 static nsresult SetCString(const char* aPrefName, const char* aValue, 201 PrefValueKind aKind = PrefValueKind::User) { 202 return Preferences::SetCString(aPrefName, nsDependentCString(aValue), 203 aKind); 204 } 205 206 static nsresult SetString(const char* aPrefName, const char16ptr_t aValue, 207 PrefValueKind aKind = PrefValueKind::User) { 208 return Preferences::SetCString(aPrefName, NS_ConvertUTF16toUTF8(aValue), 209 aKind); 210 } 211 212 static nsresult SetString(const char* aPrefName, const nsAString& aValue, 213 PrefValueKind aKind = PrefValueKind::User) { 214 return Preferences::SetCString(aPrefName, NS_ConvertUTF16toUTF8(aValue), 215 aKind); 216 } 217 218 static nsresult SetComplex(const char* aPrefName, const nsIID& aType, 219 nsISupports* aValue, 220 PrefValueKind aKind = PrefValueKind::User); 221 222 static nsresult Lock(const char* aPrefName); 223 static nsresult Unlock(const char* aPrefName); 224 static bool IsLocked(const char* aPrefName); 225 static bool IsSanitized(const char* aPrefName); 226 227 // Clears user set pref. Fails if run outside the parent process. 228 static nsresult ClearUser(const char* aPrefName); 229 230 // Whether the pref has a user value or not. 231 static bool HasUserValue(const char* aPref); 232 233 // Whether the pref has a user value or not. 234 static bool HasDefaultValue(const char* aPref); 235 236 // Adds/Removes the observer for the root pref branch. See nsIPrefBranch.idl 237 // for details. 238 static nsresult AddStrongObserver(nsIObserver* aObserver, 239 const nsACString& aPref); 240 static nsresult AddWeakObserver(nsIObserver* aObserver, 241 const nsACString& aPref); 242 static nsresult RemoveObserver(nsIObserver* aObserver, 243 const nsACString& aPref); 244 245 template <int N> 246 static nsresult AddStrongObserver(nsIObserver* aObserver, 247 const char (&aPref)[N]) { 248 return AddStrongObserver(aObserver, nsLiteralCString(aPref)); 249 } 250 template <int N> 251 static nsresult AddWeakObserver(nsIObserver* aObserver, 252 const char (&aPref)[N]) { 253 return AddWeakObserver(aObserver, nsLiteralCString(aPref)); 254 } 255 template <int N> 256 static nsresult RemoveObserver(nsIObserver* aObserver, 257 const char (&aPref)[N]) { 258 return RemoveObserver(aObserver, nsLiteralCString(aPref)); 259 } 260 261 // Adds/Removes two or more observers for the root pref branch. Pass to 262 // aPrefs an array of const char* whose last item is nullptr. 263 // Note: All preference strings *must* be statically-allocated string 264 // literals. 265 static nsresult AddStrongObservers(nsIObserver* aObserver, 266 const char* const* aPrefs); 267 static nsresult AddWeakObservers(nsIObserver* aObserver, 268 const char* const* aPrefs); 269 static nsresult RemoveObservers(nsIObserver* aObserver, 270 const char* const* aPrefs); 271 272 // Registers/Unregisters the callback function for the aPref. 273 template <typename T = void> 274 static nsresult RegisterCallback(PrefChangedFunc aCallback, 275 const nsACString& aPref, 276 T* aClosure = nullptr) { 277 return RegisterCallback(aCallback, aPref, aClosure, ExactMatch); 278 } 279 280 template <typename T = void> 281 static nsresult UnregisterCallback(PrefChangedFunc aCallback, 282 const nsACString& aPref, 283 T* aClosure = nullptr) { 284 return UnregisterCallback(aCallback, aPref, aClosure, ExactMatch); 285 } 286 287 // Like RegisterCallback, but also calls the callback immediately for 288 // initialization. 289 template <typename T = void> 290 static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback, 291 const nsACString& aPref, 292 T* aClosure = nullptr) { 293 return RegisterCallbackAndCall(aCallback, aPref, aClosure, ExactMatch); 294 } 295 296 // Like RegisterCallback, but registers a callback for a prefix of multiple 297 // pref names, not a single pref name. 298 template <typename T = void> 299 static nsresult RegisterPrefixCallback(PrefChangedFunc aCallback, 300 const nsACString& aPref, 301 T* aClosure = nullptr) { 302 return RegisterCallback(aCallback, aPref, aClosure, PrefixMatch); 303 } 304 305 // Like RegisterPrefixCallback, but also calls the callback immediately for 306 // initialization. 307 template <typename T = void> 308 static nsresult RegisterPrefixCallbackAndCall(PrefChangedFunc aCallback, 309 const nsACString& aPref, 310 T* aClosure = nullptr) { 311 return RegisterCallbackAndCall(aCallback, aPref, aClosure, PrefixMatch); 312 } 313 314 // Unregister a callback registered with RegisterPrefixCallback or 315 // RegisterPrefixCallbackAndCall. 316 template <typename T = void> 317 static nsresult UnregisterPrefixCallback(PrefChangedFunc aCallback, 318 const nsACString& aPref, 319 T* aClosure = nullptr) { 320 return UnregisterCallback(aCallback, aPref, aClosure, PrefixMatch); 321 } 322 323 // Variants of the above which register a single callback to handle multiple 324 // preferences. 325 // 326 // The array of preference names must be null terminated. It may be 327 // dynamically allocated, but the caller is responsible for keeping it alive 328 // until the callback is unregistered. 329 // 330 // Also note that the exact same aPrefs pointer must be passed to the 331 // Unregister call as was passed to the Register call. 332 template <typename T = void> 333 static nsresult RegisterCallbacks(PrefChangedFunc aCallback, 334 const char* const* aPrefs, 335 T* aClosure = nullptr) { 336 return RegisterCallbacks(aCallback, aPrefs, aClosure, ExactMatch); 337 } 338 static nsresult RegisterCallbacksAndCall(PrefChangedFunc aCallback, 339 const char* const* aPrefs, 340 void* aClosure = nullptr); 341 template <typename T = void> 342 static nsresult UnregisterCallbacks(PrefChangedFunc aCallback, 343 const char* const* aPrefs, 344 T* aClosure = nullptr) { 345 return UnregisterCallbacks(aCallback, aPrefs, aClosure, ExactMatch); 346 } 347 template <typename T = void> 348 static nsresult RegisterPrefixCallbacks(PrefChangedFunc aCallback, 349 const char* const* aPrefs, 350 T* aClosure = nullptr) { 351 return RegisterCallbacks(aCallback, aPrefs, aClosure, PrefixMatch); 352 } 353 template <typename T = void> 354 static nsresult UnregisterPrefixCallbacks(PrefChangedFunc aCallback, 355 const char* const* aPrefs, 356 T* aClosure = nullptr) { 357 return UnregisterCallbacks(aCallback, aPrefs, aClosure, PrefixMatch); 358 } 359 360 template <int N, typename T = void> 361 static nsresult RegisterCallback(PrefChangedFunc aCallback, 362 const char (&aPref)[N], 363 T* aClosure = nullptr) { 364 return RegisterCallback(aCallback, nsLiteralCString(aPref), aClosure, 365 ExactMatch); 366 } 367 368 template <int N, typename T = void> 369 static nsresult UnregisterCallback(PrefChangedFunc aCallback, 370 const char (&aPref)[N], 371 T* aClosure = nullptr) { 372 return UnregisterCallback(aCallback, nsLiteralCString(aPref), aClosure, 373 ExactMatch); 374 } 375 376 template <int N, typename T = void> 377 static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback, 378 const char (&aPref)[N], 379 T* aClosure = nullptr) { 380 return RegisterCallbackAndCall(aCallback, nsLiteralCString(aPref), aClosure, 381 ExactMatch); 382 } 383 384 template <int N, typename T = void> 385 static nsresult RegisterPrefixCallback(PrefChangedFunc aCallback, 386 const char (&aPref)[N], 387 T* aClosure = nullptr) { 388 return RegisterCallback(aCallback, nsLiteralCString(aPref), aClosure, 389 PrefixMatch); 390 } 391 392 template <int N, typename T = void> 393 static nsresult RegisterPrefixCallbackAndCall(PrefChangedFunc aCallback, 394 const char (&aPref)[N], 395 T* aClosure = nullptr) { 396 return RegisterCallbackAndCall(aCallback, nsLiteralCString(aPref), aClosure, 397 PrefixMatch); 398 } 399 400 template <int N, typename T = void> 401 static nsresult UnregisterPrefixCallback(PrefChangedFunc aCallback, 402 const char (&aPref)[N], 403 T* aClosure = nullptr) { 404 return UnregisterCallback(aCallback, nsLiteralCString(aPref), aClosure, 405 PrefixMatch); 406 } 407 408 // When a content process is created these methods are used to pass changed 409 // prefs in bulk from the parent process, via shared memory. 410 static void SerializePreferences(nsCString& aStr, 411 bool aIsDestinationWebContentProcess); 412 static void DeserializePreferences(const char* aStr, size_t aPrefsLen); 413 414 static mozilla::ipc::ReadOnlySharedMemoryHandle EnsureSnapshot(); 415 static void InitSnapshot(const mozilla::ipc::ReadOnlySharedMemoryHandle&); 416 417 // When a single pref is changed in the parent process, these methods are 418 // used to pass the update to content processes. 419 static void GetPreference(dom::Pref* aPref, 420 const GeckoProcessType aDestinationProcessType, 421 const nsACString& aDestinationRemoteType); 422 static void SetPreference(const dom::Pref& aPref); 423 424 #ifdef DEBUG 425 static bool ArePrefsInitedInContentProcess(); 426 #endif 427 428 static void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, 429 PrefsSizes& aSizes); 430 431 static void HandleDirty(); 432 433 // Explicitly choosing synchronous or asynchronous (if allowed) preferences 434 // file write. Only for the default file. The guarantee for the "blocking" 435 // is that when it returns, the file on disk reflect the current state of 436 // preferences. 437 nsresult SavePrefFileBlocking(); 438 nsresult SavePrefFileAsynchronous(); 439 440 // If this is false, only blocking writes, on main thread are allowed. 441 bool AllowOffMainThreadSave(); 442 443 private: 444 ~Preferences(); 445 446 nsresult NotifyServiceObservers(const char* aSubject); 447 448 // Loads the prefs.js file from the profile, or creates a new one. Returns 449 // the prefs file if successful, or nullptr on failure. 450 already_AddRefed<nsIFile> ReadSavedPrefs(); 451 452 // Loads the user.js file from the profile if present. 453 void ReadUserOverridePrefs(); 454 455 nsresult MakeBackupPrefFile(nsIFile* aFile); 456 457 // Default pref file save can be blocking or not. 458 enum class SaveMethod { Blocking, Asynchronous }; 459 460 // Off main thread is only respected for the default aFile value (nullptr). 461 nsresult SavePrefFileInternal(nsIFile* aFile, SaveMethod aSaveMethod); 462 463 nsresult WritePrefFile( 464 nsIFile* aFile, SaveMethod aSaveMethod, 465 UniquePtr<MozPromiseHolder<WritePrefFilePromise>> aPromise = nullptr, 466 const nsIPrefOverrideMap* aPrefOverrideMap = nullptr); 467 468 nsresult ResetUserPrefs(); 469 470 // Helpers for implementing 471 // Register(Prefix)Callback/Unregister(Prefix)Callback. 472 public: 473 // Public so the ValueObserver classes can use it. 474 enum MatchKind { 475 PrefixMatch, 476 ExactMatch, 477 }; 478 479 private: 480 static void SetupTelemetryPref(); 481 static nsresult InitInitialObjects(bool aIsStartup); 482 483 friend struct Internals; 484 485 static nsresult RegisterCallback(PrefChangedFunc aCallback, 486 const nsACString& aPref, void* aClosure, 487 MatchKind aMatchKind, 488 bool aIsPriority = false); 489 static nsresult UnregisterCallback(PrefChangedFunc aCallback, 490 const nsACString& aPref, void* aClosure, 491 MatchKind aMatchKind); 492 static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback, 493 const nsACString& aPref, 494 void* aClosure, MatchKind aMatchKind); 495 496 static nsresult RegisterCallbacks(PrefChangedFunc aCallback, 497 const char* const* aPrefs, void* aClosure, 498 MatchKind aMatchKind); 499 static nsresult UnregisterCallbacks(PrefChangedFunc aCallback, 500 const char* const* aPrefs, void* aClosure, 501 MatchKind aMatchKind); 502 503 template <typename T> 504 static nsresult RegisterCallbackImpl(PrefChangedFunc aCallback, T& aPref, 505 void* aClosure, MatchKind aMatchKind, 506 bool aIsPriority = false); 507 template <typename T> 508 static nsresult UnregisterCallbackImpl(PrefChangedFunc aCallback, T& aPref, 509 void* aClosure, MatchKind aMatchKind); 510 511 static nsresult RegisterCallback(PrefChangedFunc aCallback, const char* aPref, 512 void* aClosure, MatchKind aMatchKind, 513 bool aIsPriority = false) { 514 return RegisterCallback(aCallback, nsDependentCString(aPref), aClosure, 515 aMatchKind, aIsPriority); 516 } 517 static nsresult UnregisterCallback(PrefChangedFunc aCallback, 518 const char* aPref, void* aClosure, 519 MatchKind aMatchKind) { 520 return UnregisterCallback(aCallback, nsDependentCString(aPref), aClosure, 521 aMatchKind); 522 } 523 static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback, 524 const char* aPref, void* aClosure, 525 MatchKind aMatchKind) { 526 return RegisterCallbackAndCall(aCallback, nsDependentCString(aPref), 527 aClosure, aMatchKind); 528 } 529 530 private: 531 nsCOMPtr<nsIFile> mCurrentFile; 532 // Time since unix epoch in ms (JS Date compatible) 533 PRTime mUserPrefsFileLastModifiedAtStartup = 0; 534 bool mDirty = false; 535 bool mProfileShutdown = false; 536 // We wait a bit after prefs are dirty before writing them. In this period, 537 // mDirty and mSavePending will both be true. 538 bool mSavePending = false; 539 540 nsCOMPtr<nsIPrefBranch> mRootBranch; 541 nsCOMPtr<nsIPrefBranch> mDefaultRootBranch; 542 543 static StaticRefPtr<Preferences> sPreferences; 544 static bool sShutdown; 545 546 // Init static members. Returns true on success. 547 static bool InitStaticMembers(); 548 }; 549 550 extern Atomic<bool, Relaxed> sOmitBlocklistedPrefValues; 551 extern Atomic<bool, Relaxed> sCrashOnBlocklistedPref; 552 553 bool IsPreferenceSanitized(const char* aPref); 554 555 const char kFissionEnforceBlockList[] = 556 "fission.enforceBlocklistedPrefsInSubprocesses"; 557 const char kFissionOmitBlockListValues[] = 558 "fission.omitBlocklistedPrefsInSubprocesses"; 559 560 void OnFissionBlocklistPrefChange(const char* aPref, void* aData); 561 562 } // namespace mozilla 563 564 #endif // mozilla_Preferences_h