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