summaryrefslogtreecommitdiffstats
path: root/modules/libpref/Preferences.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--modules/libpref/Preferences.h551
1 files changed, 551 insertions, 0 deletions
diff --git a/modules/libpref/Preferences.h b/modules/libpref/Preferences.h
new file mode 100644
index 0000000000..7540755422
--- /dev/null
+++ b/modules/libpref/Preferences.h
@@ -0,0 +1,551 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Documentation for libpref is in modules/libpref/docs/index.rst.
+
+#ifndef mozilla_Preferences_h
+#define mozilla_Preferences_h
+
+#ifndef MOZILLA_INTERNAL_API
+# error "This header is only usable from within libxul (MOZILLA_INTERNAL_API)."
+#endif
+
+#include "mozilla/Atomics.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/StaticPtr.h"
+#include "nsCOMPtr.h"
+#include "nsIObserver.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefService.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nsWeakReference.h"
+#include "nsXULAppAPI.h"
+#include <atomic>
+#include <functional>
+
+class nsIFile;
+
+// The callback function will get passed the pref name which triggered the call
+// and the void* data which was passed to the registered callback function.
+typedef void (*PrefChangedFunc)(const char* aPref, void* aData);
+
+class nsPrefBranch;
+
+namespace mozilla {
+
+struct RegisterCallbacksInternal;
+
+void UnloadPrefsModule();
+
+class PreferenceServiceReporter;
+
+namespace dom {
+class Pref;
+class PrefValue;
+} // namespace dom
+
+namespace ipc {
+class FileDescriptor;
+} // namespace ipc
+
+struct PrefsSizes;
+
+// Xlib.h defines Bool as a macro constant. Don't try to define this enum if
+// it's already been included.
+#ifndef Bool
+
+// Keep this in sync with PrefType in parser/src/lib.rs.
+enum class PrefType : uint8_t {
+ None = 0, // only used when neither the default nor user value is set
+ String = 1,
+ Int = 2,
+ Bool = 3,
+};
+
+#endif
+
+#ifdef XP_UNIX
+// We need to send two shared memory descriptors to every child process:
+//
+// 1) A read-only/write-protected snapshot of the initial state of the
+// preference database. This memory is shared between all processes, and
+// therefore cannot be modified once it has been created.
+//
+// 2) A set of changes on top of the snapshot, containing the current values of
+// all preferences which have changed since it was created.
+//
+// Since the second set will be different for every process, and the first set
+// cannot be modified, it is unfortunately not possible to combine them into a
+// single file descriptor.
+//
+// XXX: bug 1440207 is about improving how fixed fds such as this are used.
+static const int kPrefsFileDescriptor = 8;
+static const int kPrefMapFileDescriptor = 9;
+#endif
+
+// Keep this in sync with PrefType in parser/src/lib.rs.
+enum class PrefValueKind : uint8_t { Default, User };
+
+class Preferences final : public nsIPrefService,
+ public nsIObserver,
+ public nsIPrefBranch,
+ public nsSupportsWeakReference {
+ friend class ::nsPrefBranch;
+
+ public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIPREFSERVICE
+ NS_FORWARD_NSIPREFBRANCH(mRootBranch->)
+ NS_DECL_NSIOBSERVER
+
+ Preferences();
+
+ // Returns true if the Preferences service is available, false otherwise.
+ static bool IsServiceAvailable();
+
+ // Initialize user prefs from prefs.js/user.js
+ static void InitializeUserPrefs();
+ static void FinishInitializingUserPrefs();
+
+ // Returns the singleton instance which is addreffed.
+ static already_AddRefed<Preferences> GetInstanceForService();
+
+ // Finallizes global members.
+ static void Shutdown();
+
+ // Returns shared pref service instance NOTE: not addreffed.
+ static nsIPrefService* GetService() {
+ NS_ENSURE_TRUE(InitStaticMembers(), nullptr);
+ return sPreferences;
+ }
+
+ // Returns shared pref branch instance. NOTE: not addreffed.
+ static nsIPrefBranch* GetRootBranch(
+ PrefValueKind aKind = PrefValueKind::User) {
+ NS_ENSURE_TRUE(InitStaticMembers(), nullptr);
+ return (aKind == PrefValueKind::Default) ? sPreferences->mDefaultRootBranch
+ : sPreferences->mRootBranch;
+ }
+
+ // Gets the type of the pref.
+ static int32_t GetType(const char* aPrefName);
+
+ // Fallible value getters. When `aKind` is `User` they will get the user
+ // value if possible, and fall back to the default value otherwise.
+ static nsresult GetBool(const char* aPrefName, bool* aResult,
+ PrefValueKind aKind = PrefValueKind::User);
+ static nsresult GetInt(const char* aPrefName, int32_t* aResult,
+ PrefValueKind aKind = PrefValueKind::User);
+ static nsresult GetUint(const char* aPrefName, uint32_t* aResult,
+ PrefValueKind aKind = PrefValueKind::User) {
+ return GetInt(aPrefName, reinterpret_cast<int32_t*>(aResult), aKind);
+ }
+ static nsresult GetFloat(const char* aPrefName, float* aResult,
+ PrefValueKind aKind = PrefValueKind::User);
+ static nsresult GetCString(const char* aPrefName, nsACString& aResult,
+ PrefValueKind aKind = PrefValueKind::User);
+ static nsresult GetString(const char* aPrefName, nsAString& aResult,
+ PrefValueKind aKind = PrefValueKind::User);
+ static nsresult GetLocalizedCString(
+ const char* aPrefName, nsACString& aResult,
+ PrefValueKind aKind = PrefValueKind::User);
+ static nsresult GetLocalizedString(const char* aPrefName, nsAString& aResult,
+ PrefValueKind aKind = PrefValueKind::User);
+ static nsresult GetComplex(const char* aPrefName, const nsIID& aType,
+ void** aResult,
+ PrefValueKind aKind = PrefValueKind::User);
+
+ // Infallible getters of user or default values, with fallback results on
+ // failure. When `aKind` is `User` they will get the user value if possible,
+ // and fall back to the default value otherwise.
+ static bool GetBool(const char* aPrefName, bool aFallback = false,
+ PrefValueKind aKind = PrefValueKind::User);
+ static int32_t GetInt(const char* aPrefName, int32_t aFallback = 0,
+ PrefValueKind aKind = PrefValueKind::User);
+ static uint32_t GetUint(const char* aPrefName, uint32_t aFallback = 0,
+ PrefValueKind aKind = PrefValueKind::User);
+ static float GetFloat(const char* aPrefName, float aFallback = 0.0f,
+ PrefValueKind aKind = PrefValueKind::User);
+
+ // Value setters. These fail if run outside the parent process.
+
+ static nsresult SetBool(const char* aPrefName, bool aValue,
+ PrefValueKind aKind = PrefValueKind::User);
+ static nsresult SetInt(const char* aPrefName, int32_t aValue,
+ PrefValueKind aKind = PrefValueKind::User);
+ static nsresult SetCString(const char* aPrefName, const nsACString& aValue,
+ PrefValueKind aKind = PrefValueKind::User);
+
+ static nsresult SetUint(const char* aPrefName, uint32_t aValue,
+ PrefValueKind aKind = PrefValueKind::User) {
+ return SetInt(aPrefName, static_cast<int32_t>(aValue), aKind);
+ }
+
+ static nsresult SetFloat(const char* aPrefName, float aValue,
+ PrefValueKind aKind = PrefValueKind::User) {
+ nsAutoCString value;
+ value.AppendFloat(aValue);
+ return SetCString(aPrefName, value, aKind);
+ }
+
+ static nsresult SetCString(const char* aPrefName, const char* aValue,
+ PrefValueKind aKind = PrefValueKind::User) {
+ return Preferences::SetCString(aPrefName, nsDependentCString(aValue),
+ aKind);
+ }
+
+ static nsresult SetString(const char* aPrefName, const char16ptr_t aValue,
+ PrefValueKind aKind = PrefValueKind::User) {
+ return Preferences::SetCString(aPrefName, NS_ConvertUTF16toUTF8(aValue),
+ aKind);
+ }
+
+ static nsresult SetString(const char* aPrefName, const nsAString& aValue,
+ PrefValueKind aKind = PrefValueKind::User) {
+ return Preferences::SetCString(aPrefName, NS_ConvertUTF16toUTF8(aValue),
+ aKind);
+ }
+
+ static nsresult SetComplex(const char* aPrefName, const nsIID& aType,
+ nsISupports* aValue,
+ PrefValueKind aKind = PrefValueKind::User);
+
+ static nsresult Lock(const char* aPrefName);
+ static nsresult Unlock(const char* aPrefName);
+ static bool IsLocked(const char* aPrefName);
+ static bool IsSanitized(const char* aPrefName);
+
+ // Clears user set pref. Fails if run outside the parent process.
+ static nsresult ClearUser(const char* aPrefName);
+
+ // Whether the pref has a user value or not.
+ static bool HasUserValue(const char* aPref);
+
+ // Whether the pref has a user value or not.
+ static bool HasDefaultValue(const char* aPref);
+
+ // Adds/Removes the observer for the root pref branch. See nsIPrefBranch.idl
+ // for details.
+ static nsresult AddStrongObserver(nsIObserver* aObserver,
+ const nsACString& aPref);
+ static nsresult AddWeakObserver(nsIObserver* aObserver,
+ const nsACString& aPref);
+ static nsresult RemoveObserver(nsIObserver* aObserver,
+ const nsACString& aPref);
+
+ template <int N>
+ static nsresult AddStrongObserver(nsIObserver* aObserver,
+ const char (&aPref)[N]) {
+ return AddStrongObserver(aObserver, nsLiteralCString(aPref));
+ }
+ template <int N>
+ static nsresult AddWeakObserver(nsIObserver* aObserver,
+ const char (&aPref)[N]) {
+ return AddWeakObserver(aObserver, nsLiteralCString(aPref));
+ }
+ template <int N>
+ static nsresult RemoveObserver(nsIObserver* aObserver,
+ const char (&aPref)[N]) {
+ return RemoveObserver(aObserver, nsLiteralCString(aPref));
+ }
+
+ // Adds/Removes two or more observers for the root pref branch. Pass to
+ // aPrefs an array of const char* whose last item is nullptr.
+ // Note: All preference strings *must* be statically-allocated string
+ // literals.
+ static nsresult AddStrongObservers(nsIObserver* aObserver,
+ const char** aPrefs);
+ static nsresult AddWeakObservers(nsIObserver* aObserver, const char** aPrefs);
+ static nsresult RemoveObservers(nsIObserver* aObserver, const char** aPrefs);
+
+ // Registers/Unregisters the callback function for the aPref.
+ template <typename T = void>
+ static nsresult RegisterCallback(PrefChangedFunc aCallback,
+ const nsACString& aPref,
+ T* aClosure = nullptr) {
+ return RegisterCallback(aCallback, aPref, aClosure, ExactMatch);
+ }
+
+ template <typename T = void>
+ static nsresult UnregisterCallback(PrefChangedFunc aCallback,
+ const nsACString& aPref,
+ T* aClosure = nullptr) {
+ return UnregisterCallback(aCallback, aPref, aClosure, ExactMatch);
+ }
+
+ // Like RegisterCallback, but also calls the callback immediately for
+ // initialization.
+ template <typename T = void>
+ static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback,
+ const nsACString& aPref,
+ T* aClosure = nullptr) {
+ return RegisterCallbackAndCall(aCallback, aPref, aClosure, ExactMatch);
+ }
+
+ // Like RegisterCallback, but registers a callback for a prefix of multiple
+ // pref names, not a single pref name.
+ template <typename T = void>
+ static nsresult RegisterPrefixCallback(PrefChangedFunc aCallback,
+ const nsACString& aPref,
+ T* aClosure = nullptr) {
+ return RegisterCallback(aCallback, aPref, aClosure, PrefixMatch);
+ }
+
+ // Like RegisterPrefixCallback, but also calls the callback immediately for
+ // initialization.
+ template <typename T = void>
+ static nsresult RegisterPrefixCallbackAndCall(PrefChangedFunc aCallback,
+ const nsACString& aPref,
+ T* aClosure = nullptr) {
+ return RegisterCallbackAndCall(aCallback, aPref, aClosure, PrefixMatch);
+ }
+
+ // Unregister a callback registered with RegisterPrefixCallback or
+ // RegisterPrefixCallbackAndCall.
+ template <typename T = void>
+ static nsresult UnregisterPrefixCallback(PrefChangedFunc aCallback,
+ const nsACString& aPref,
+ T* aClosure = nullptr) {
+ return UnregisterCallback(aCallback, aPref, aClosure, PrefixMatch);
+ }
+
+ // Variants of the above which register a single callback to handle multiple
+ // preferences.
+ //
+ // The array of preference names must be null terminated. It may be
+ // dynamically allocated, but the caller is responsible for keeping it alive
+ // until the callback is unregistered.
+ //
+ // Also note that the exact same aPrefs pointer must be passed to the
+ // Unregister call as was passed to the Register call.
+ template <typename T = void>
+ static nsresult RegisterCallbacks(PrefChangedFunc aCallback,
+ const char** aPrefs,
+ T* aClosure = nullptr) {
+ return RegisterCallbacks(aCallback, aPrefs, aClosure, ExactMatch);
+ }
+ static nsresult RegisterCallbacksAndCall(PrefChangedFunc aCallback,
+ const char** aPrefs,
+ void* aClosure = nullptr);
+ template <typename T = void>
+ static nsresult UnregisterCallbacks(PrefChangedFunc aCallback,
+ const char** aPrefs,
+ T* aClosure = nullptr) {
+ return UnregisterCallbacks(aCallback, aPrefs, aClosure, ExactMatch);
+ }
+ template <typename T = void>
+ static nsresult RegisterPrefixCallbacks(PrefChangedFunc aCallback,
+ const char** aPrefs,
+ T* aClosure = nullptr) {
+ return RegisterCallbacks(aCallback, aPrefs, aClosure, PrefixMatch);
+ }
+ template <typename T = void>
+ static nsresult UnregisterPrefixCallbacks(PrefChangedFunc aCallback,
+ const char** aPrefs,
+ T* aClosure = nullptr) {
+ return UnregisterCallbacks(aCallback, aPrefs, aClosure, PrefixMatch);
+ }
+
+ template <int N, typename T = void>
+ static nsresult RegisterCallback(PrefChangedFunc aCallback,
+ const char (&aPref)[N],
+ T* aClosure = nullptr) {
+ return RegisterCallback(aCallback, nsLiteralCString(aPref), aClosure,
+ ExactMatch);
+ }
+
+ template <int N, typename T = void>
+ static nsresult UnregisterCallback(PrefChangedFunc aCallback,
+ const char (&aPref)[N],
+ T* aClosure = nullptr) {
+ return UnregisterCallback(aCallback, nsLiteralCString(aPref), aClosure,
+ ExactMatch);
+ }
+
+ template <int N, typename T = void>
+ static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback,
+ const char (&aPref)[N],
+ T* aClosure = nullptr) {
+ return RegisterCallbackAndCall(aCallback, nsLiteralCString(aPref), aClosure,
+ ExactMatch);
+ }
+
+ template <int N, typename T = void>
+ static nsresult RegisterPrefixCallback(PrefChangedFunc aCallback,
+ const char (&aPref)[N],
+ T* aClosure = nullptr) {
+ return RegisterCallback(aCallback, nsLiteralCString(aPref), aClosure,
+ PrefixMatch);
+ }
+
+ template <int N, typename T = void>
+ static nsresult RegisterPrefixCallbackAndCall(PrefChangedFunc aCallback,
+ const char (&aPref)[N],
+ T* aClosure = nullptr) {
+ return RegisterCallbackAndCall(aCallback, nsLiteralCString(aPref), aClosure,
+ PrefixMatch);
+ }
+
+ template <int N, typename T = void>
+ static nsresult UnregisterPrefixCallback(PrefChangedFunc aCallback,
+ const char (&aPref)[N],
+ T* aClosure = nullptr) {
+ return UnregisterCallback(aCallback, nsLiteralCString(aPref), aClosure,
+ PrefixMatch);
+ }
+
+ // When a content process is created these methods are used to pass changed
+ // prefs in bulk from the parent process, via shared memory.
+ static void SerializePreferences(nsCString& aStr,
+ bool aIsDestinationWebContentProcess);
+ static void DeserializePreferences(char* aStr, size_t aPrefsLen);
+
+ static mozilla::ipc::FileDescriptor EnsureSnapshot(size_t* aSize);
+ static void InitSnapshot(const mozilla::ipc::FileDescriptor&, size_t aSize);
+
+ // When a single pref is changed in the parent process, these methods are
+ // used to pass the update to content processes.
+ static void GetPreference(dom::Pref* aPref,
+ const GeckoProcessType aDestinationProcessType,
+ const nsACString& aDestinationRemoteType);
+ static void SetPreference(const dom::Pref& aPref);
+
+#ifdef DEBUG
+ static bool ArePrefsInitedInContentProcess();
+#endif
+
+ static void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+ PrefsSizes& aSizes);
+
+ static void HandleDirty();
+
+ // Explicitly choosing synchronous or asynchronous (if allowed) preferences
+ // file write. Only for the default file. The guarantee for the "blocking"
+ // is that when it returns, the file on disk reflect the current state of
+ // preferences.
+ nsresult SavePrefFileBlocking();
+ nsresult SavePrefFileAsynchronous();
+
+ // If this is false, only blocking writes, on main thread are allowed.
+ bool AllowOffMainThreadSave();
+
+ private:
+ virtual ~Preferences();
+
+ nsresult NotifyServiceObservers(const char* aSubject);
+
+ // Loads the prefs.js file from the profile, or creates a new one. Returns
+ // the prefs file if successful, or nullptr on failure.
+ already_AddRefed<nsIFile> ReadSavedPrefs();
+
+ // Loads the user.js file from the profile if present.
+ void ReadUserOverridePrefs();
+
+ nsresult MakeBackupPrefFile(nsIFile* aFile);
+
+ // Default pref file save can be blocking or not.
+ enum class SaveMethod { Blocking, Asynchronous };
+
+ // Off main thread is only respected for the default aFile value (nullptr).
+ nsresult SavePrefFileInternal(nsIFile* aFile, SaveMethod aSaveMethod);
+ nsresult WritePrefFile(nsIFile* aFile, SaveMethod aSaveMethod);
+
+ nsresult ResetUserPrefs();
+
+ // Helpers for implementing
+ // Register(Prefix)Callback/Unregister(Prefix)Callback.
+ public:
+ // Public so the ValueObserver classes can use it.
+ enum MatchKind {
+ PrefixMatch,
+ ExactMatch,
+ };
+
+ private:
+ static void SetupTelemetryPref();
+ static nsresult InitInitialObjects(bool aIsStartup);
+
+ friend struct Internals;
+
+ static nsresult RegisterCallback(PrefChangedFunc aCallback,
+ const nsACString& aPref, void* aClosure,
+ MatchKind aMatchKind,
+ bool aIsPriority = false);
+ static nsresult UnregisterCallback(PrefChangedFunc aCallback,
+ const nsACString& aPref, void* aClosure,
+ MatchKind aMatchKind);
+ static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback,
+ const nsACString& aPref,
+ void* aClosure, MatchKind aMatchKind);
+
+ static nsresult RegisterCallbacks(PrefChangedFunc aCallback,
+ const char** aPrefs, void* aClosure,
+ MatchKind aMatchKind);
+ static nsresult UnregisterCallbacks(PrefChangedFunc aCallback,
+ const char** aPrefs, void* aClosure,
+ MatchKind aMatchKind);
+
+ template <typename T>
+ static nsresult RegisterCallbackImpl(PrefChangedFunc aCallback, T& aPref,
+ void* aClosure, MatchKind aMatchKind,
+ bool aIsPriority = false);
+ template <typename T>
+ static nsresult UnregisterCallbackImpl(PrefChangedFunc aCallback, T& aPref,
+ void* aClosure, MatchKind aMatchKind);
+
+ static nsresult RegisterCallback(PrefChangedFunc aCallback, const char* aPref,
+ void* aClosure, MatchKind aMatchKind,
+ bool aIsPriority = false) {
+ return RegisterCallback(aCallback, nsDependentCString(aPref), aClosure,
+ aMatchKind, aIsPriority);
+ }
+ static nsresult UnregisterCallback(PrefChangedFunc aCallback,
+ const char* aPref, void* aClosure,
+ MatchKind aMatchKind) {
+ return UnregisterCallback(aCallback, nsDependentCString(aPref), aClosure,
+ aMatchKind);
+ }
+ static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback,
+ const char* aPref, void* aClosure,
+ MatchKind aMatchKind) {
+ return RegisterCallbackAndCall(aCallback, nsDependentCString(aPref),
+ aClosure, aMatchKind);
+ }
+
+ private:
+ nsCOMPtr<nsIFile> mCurrentFile;
+ bool mDirty = false;
+ bool mProfileShutdown = false;
+ // We wait a bit after prefs are dirty before writing them. In this period,
+ // mDirty and mSavePending will both be true.
+ bool mSavePending = false;
+
+ nsCOMPtr<nsIPrefBranch> mRootBranch;
+ nsCOMPtr<nsIPrefBranch> mDefaultRootBranch;
+
+ static StaticRefPtr<Preferences> sPreferences;
+ static bool sShutdown;
+
+ // Init static members. Returns true on success.
+ static bool InitStaticMembers();
+};
+
+extern Atomic<bool, Relaxed> sOmitBlocklistedPrefValues;
+extern Atomic<bool, Relaxed> sCrashOnBlocklistedPref;
+
+bool IsPreferenceSanitized(const char* aPref);
+
+const char kFissionEnforceBlockList[] =
+ "fission.enforceBlocklistedPrefsInSubprocesses";
+const char kFissionOmitBlockListValues[] =
+ "fission.omitBlocklistedPrefsInSubprocesses";
+
+void OnFissionBlocklistPrefChange(const char* aPref, void* aData);
+
+} // namespace mozilla
+
+#endif // mozilla_Preferences_h