LCOV - code coverage report
Current view: top level - modules/libpref - Preferences.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 531 1006 52.8 %
Date: 2017-07-14 16:53:18 Functions: 87 145 60.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "mozilla/MemoryReporting.h"
       8             : #include "mozilla/dom/PContent.h"
       9             : 
      10             : #include "mozilla/ArrayUtils.h"
      11             : #include "mozilla/Attributes.h"
      12             : #include "mozilla/HashFunctions.h"
      13             : #include "mozilla/ServoStyleSet.h"
      14             : #include "mozilla/Telemetry.h"
      15             : #include "mozilla/UniquePtrExtensions.h"
      16             : 
      17             : #include "nsXULAppAPI.h"
      18             : 
      19             : #include "mozilla/Preferences.h"
      20             : #include "nsAppDirectoryServiceDefs.h"
      21             : #include "nsDataHashtable.h"
      22             : #include "nsDirectoryServiceDefs.h"
      23             : #include "nsICategoryManager.h"
      24             : #include "nsCategoryManagerUtils.h"
      25             : #include "nsNetUtil.h"
      26             : #include "nsIFile.h"
      27             : #include "nsIInputStream.h"
      28             : #include "nsIObserverService.h"
      29             : #include "nsIOutputStream.h"
      30             : #include "nsISafeOutputStream.h"
      31             : #include "nsISimpleEnumerator.h"
      32             : #include "nsIStringEnumerator.h"
      33             : #include "nsIZipReader.h"
      34             : #include "nsPrefBranch.h"
      35             : #include "nsXPIDLString.h"
      36             : #include "nsCRT.h"
      37             : #include "nsCOMArray.h"
      38             : #include "nsXPCOMCID.h"
      39             : #include "nsAutoPtr.h"
      40             : #include "nsPrintfCString.h"
      41             : 
      42             : #include "nsQuickSort.h"
      43             : #include "PLDHashTable.h"
      44             : 
      45             : #include "prefapi.h"
      46             : #include "prefread.h"
      47             : #include "prefapi_private_data.h"
      48             : 
      49             : #include "mozilla/Omnijar.h"
      50             : #include "nsZipArchive.h"
      51             : 
      52             : #include "nsTArray.h"
      53             : #include "nsRefPtrHashtable.h"
      54             : #include "nsIMemoryReporter.h"
      55             : #include "nsThreadUtils.h"
      56             : #include "GeckoProfiler.h"
      57             : 
      58             : using namespace mozilla;
      59             : 
      60             : #ifdef DEBUG
      61             : #define ENSURE_MAIN_PROCESS(message, pref) do {                                \
      62             :   if (MOZ_UNLIKELY(!XRE_IsParentProcess())) {                                  \
      63             :     nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref);   \
      64             :     NS_WARNING(msg.get());                                                     \
      65             :     return NS_ERROR_NOT_AVAILABLE;                                             \
      66             :   }                                                                            \
      67             : } while (0);
      68             : class WatchinPrefRAII {
      69             : public:
      70        2124 :   WatchinPrefRAII() {
      71        2124 :     pref_SetWatchingPref(true);
      72        2124 :   }
      73        2124 :   ~WatchinPrefRAII() {
      74        2124 :     pref_SetWatchingPref(false);
      75        2124 :   }
      76             : };
      77             : #define WATCHING_PREF_RAII() WatchinPrefRAII watchingPrefRAII
      78             : #else
      79             : #define ENSURE_MAIN_PROCESS(message, pref)                                     \
      80             :   if (MOZ_UNLIKELY(!XRE_IsParentProcess())) {                                  \
      81             :     return NS_ERROR_NOT_AVAILABLE;                                             \
      82             :   }
      83             : #define WATCHING_PREF_RAII()
      84             : #endif
      85             : 
      86             : class PrefCallback;
      87             : 
      88             : namespace mozilla {
      89             : 
      90             : // Definitions
      91             : #define INITIAL_PREF_FILES 10
      92             : static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
      93             : 
      94             : void
      95         521 : Preferences::DirtyCallback()
      96             : {
      97         521 :   if (!XRE_IsParentProcess()) {
      98             :     // TODO: this should really assert because you can't set prefs in a
      99             :     // content process. But so much code currently does this that we just
     100             :     // ignore it for now.
     101         338 :     return;
     102             :   }
     103         183 :   if (gHashTable && sPreferences && !sPreferences->mDirty) {
     104           1 :     sPreferences->mDirty = true;
     105             : 
     106           1 :     NS_WARNING_ASSERTION(!sPreferences->mProfileShutdown,
     107             :                          "Setting user pref after profile shutdown.");
     108             :   }
     109             : }
     110             : 
     111             : // Prototypes
     112             : static nsresult openPrefFile(nsIFile* aFile);
     113             : static nsresult pref_InitInitialObjects(void);
     114             : static nsresult pref_LoadPrefsInDirList(const char *listId);
     115             : static nsresult ReadExtensionPrefs(nsIFile *aFile);
     116             : 
     117             : static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
     118             : static const char kOldTelemetryPref[] = "toolkit.telemetry.enabledPreRelease";
     119             : static const char kChannelPref[] = "app.update.channel";
     120             : 
     121             : static const char kPrefFileHeader[] =
     122             :   "# Mozilla User Preferences"
     123             :   NS_LINEBREAK
     124             :   NS_LINEBREAK
     125             :   "/* Do not edit this file."
     126             :   NS_LINEBREAK
     127             :   " *"
     128             :   NS_LINEBREAK
     129             :   " * If you make changes to this file while the application is running,"
     130             :   NS_LINEBREAK
     131             :   " * the changes will be overwritten when the application exits."
     132             :   NS_LINEBREAK
     133             :   " *"
     134             :   NS_LINEBREAK
     135             :   " * To make a manual change to preferences, you can visit the URL about:config"
     136             :   NS_LINEBREAK
     137             :   " */"
     138             :   NS_LINEBREAK
     139             :   NS_LINEBREAK;
     140             : 
     141             : Preferences* Preferences::sPreferences = nullptr;
     142             : nsIPrefBranch* Preferences::sRootBranch = nullptr;
     143             : nsIPrefBranch* Preferences::sDefaultRootBranch = nullptr;
     144             : bool Preferences::sShutdown = false;
     145             : 
     146             : // This globally enables or disables OMT pref writing, both sync and async
     147             : static int32_t sAllowOMTPrefWrite = -1;
     148             : 
     149             : 
     150        2957 : class ValueObserverHashKey : public PLDHashEntryHdr {
     151             : public:
     152             :   typedef ValueObserverHashKey* KeyType;
     153             :   typedef const ValueObserverHashKey* KeyTypePointer;
     154             : 
     155        5062 :   static const ValueObserverHashKey* KeyToPointer(ValueObserverHashKey *aKey)
     156             :   {
     157        5062 :     return aKey;
     158             :   }
     159             : 
     160        5059 :   static PLDHashNumber HashKey(const ValueObserverHashKey *aKey)
     161             :   {
     162        5059 :     PLDHashNumber hash = HashString(aKey->mPrefName);
     163        5059 :     hash = AddToHash(hash, aKey->mMatchKind);
     164        5059 :     return AddToHash(hash, aKey->mCallback);
     165             :   }
     166             : 
     167        5062 :   ValueObserverHashKey(const char *aPref, PrefChangedFunc aCallback, Preferences::MatchKind aMatchKind) :
     168        5062 :     mPrefName(aPref), mCallback(aCallback), mMatchKind(aMatchKind) { }
     169             : 
     170        2105 :   explicit ValueObserverHashKey(const ValueObserverHashKey *aOther) :
     171             :     mPrefName(aOther->mPrefName),
     172        2105 :     mCallback(aOther->mCallback),
     173        4210 :     mMatchKind(aOther->mMatchKind)
     174        2105 :   { }
     175             : 
     176         852 :   bool KeyEquals(const ValueObserverHashKey *aOther) const
     177             :   {
     178        1704 :     return mCallback == aOther->mCallback &&
     179        1704 :            mPrefName == aOther->mPrefName &&
     180        1704 :            mMatchKind == aOther->mMatchKind;
     181             :   }
     182             : 
     183           0 :   ValueObserverHashKey *GetKey() const
     184             :   {
     185           0 :     return const_cast<ValueObserverHashKey*>(this);
     186             :   }
     187             : 
     188             :   enum { ALLOW_MEMMOVE = true };
     189             : 
     190             :   nsCString mPrefName;
     191             :   PrefChangedFunc mCallback;
     192             :   Preferences::MatchKind mMatchKind;
     193             : };
     194             : 
     195             : class ValueObserver final : public nsIObserver,
     196             :                             public ValueObserverHashKey
     197             : {
     198           0 :   ~ValueObserver() {
     199           0 :     Preferences::RemoveObserver(this, mPrefName.get());
     200           0 :   }
     201             : 
     202             : public:
     203             :   NS_DECL_ISUPPORTS
     204             :   NS_DECL_NSIOBSERVER
     205             : 
     206        2105 :   ValueObserver(const char *aPref, PrefChangedFunc aCallback, Preferences::MatchKind aMatchKind)
     207        2105 :     : ValueObserverHashKey(aPref, aCallback, aMatchKind) { }
     208             : 
     209        2957 :   void AppendClosure(void *aClosure) {
     210        2957 :     mClosures.AppendElement(aClosure);
     211        2957 :   }
     212             : 
     213           0 :   void RemoveClosure(void *aClosure) {
     214           0 :     mClosures.RemoveElement(aClosure);
     215           0 :   }
     216             : 
     217           0 :   bool HasNoClosures() {
     218           0 :     return mClosures.Length() == 0;
     219             :   }
     220             : 
     221             :   nsTArray<void*> mClosures;
     222             : };
     223             : 
     224       12066 : NS_IMPL_ISUPPORTS(ValueObserver, nsIObserver)
     225             : 
     226             : NS_IMETHODIMP
     227          11 : ValueObserver::Observe(nsISupports     *aSubject,
     228             :                        const char      *aTopic,
     229             :                        const char16_t *aData)
     230             : {
     231          11 :   NS_ASSERTION(!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
     232             :                "invalid topic");
     233          22 :   NS_ConvertUTF16toUTF8 data(aData);
     234          11 :   if (mMatchKind == Preferences::ExactMatch && !mPrefName.EqualsASCII(data.get())) {
     235           0 :     return NS_OK;
     236             :   }
     237          22 :   for (uint32_t i = 0; i < mClosures.Length(); i++) {
     238          11 :     mCallback(data.get(), mClosures.ElementAt(i));
     239             :   }
     240             : 
     241          11 :   return NS_OK;
     242             : }
     243             : 
     244             : // Write the preference data to a file.
     245             : //
     246             : class PreferencesWriter final
     247             : {
     248             : public:
     249             :   PreferencesWriter()
     250             :   {
     251             :   }
     252             : 
     253             :   static
     254           0 :   nsresult Write(nsIFile* aFile, PrefSaveData& aPrefs)
     255             :   {
     256           0 :     nsCOMPtr<nsIOutputStream> outStreamSink;
     257           0 :     nsCOMPtr<nsIOutputStream> outStream;
     258             :     uint32_t                  writeAmount;
     259             :     nsresult                  rv;
     260             : 
     261             :     // execute a "safe" save by saving through a tempfile
     262           0 :     rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink),
     263             :                                          aFile,
     264             :                                          -1,
     265           0 :                                          0600);
     266           0 :     if (NS_FAILED(rv)) {
     267           0 :       return rv;
     268             :     }
     269             : 
     270           0 :     rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096);
     271           0 :     if (NS_FAILED(rv)) {
     272           0 :       return rv;
     273             :     }
     274             : 
     275             :     struct CharComparator
     276             :     {
     277           0 :       bool LessThan(const mozilla::UniqueFreePtr<char>& a,
     278             :                     const mozilla::UniqueFreePtr<char>& b) const
     279             :       {
     280           0 :         return strcmp(a.get(), b.get()) < 0;
     281             :       }
     282           0 :       bool Equals(const mozilla::UniqueFreePtr<char>& a,
     283             :                   const mozilla::UniqueFreePtr<char>& b) const
     284             :       {
     285           0 :         return strcmp(a.get(), b.get()) == 0;
     286             :       }
     287             :     };
     288             : 
     289             :     /* Sort the preferences to make a readable file on disk */
     290           0 :     aPrefs.Sort(CharComparator());
     291             : 
     292             :     // write out the file header
     293           0 :     outStream->Write(kPrefFileHeader, sizeof(kPrefFileHeader) - 1, &writeAmount);
     294             : 
     295           0 :     for (auto& prefptr : aPrefs) {
     296           0 :       char* pref = prefptr.get();
     297           0 :       MOZ_ASSERT(pref);
     298           0 :       outStream->Write(pref, strlen(pref), &writeAmount);
     299           0 :       outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
     300             :     }
     301             : 
     302             :     // tell the safe output stream to overwrite the real prefs file
     303             :     // (it'll abort if there were any errors during writing)
     304           0 :     nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
     305           0 :     NS_ASSERTION(safeStream, "expected a safe output stream!");
     306           0 :     if (safeStream) {
     307           0 :       rv = safeStream->Finish();
     308             :     }
     309             : 
     310             : #ifdef DEBUG
     311           0 :     if (NS_FAILED(rv)) {
     312           0 :       NS_WARNING("failed to save prefs file! possible data loss");
     313             :     }
     314             : #endif
     315           0 :     return rv;
     316             :   }
     317             : 
     318             :   static
     319           0 :   void Flush()
     320             :   {
     321             :     // This can be further optimized; instead of waiting for
     322             :     // all of the writer thread to be available, we just have
     323             :     // to wait for all the pending writes to be done.
     324           0 :     if (!sPendingWriteData.compareExchange(nullptr, nullptr)) {
     325           0 :       nsresult rv = NS_OK;
     326             :       nsCOMPtr<nsIEventTarget> target =
     327           0 :         do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
     328           0 :       if (NS_SUCCEEDED(rv)) {
     329           0 :         target->Dispatch(NS_NewRunnableFunction("Preferences_dummy", [] {}),
     330           0 :                          nsIEventTarget::DISPATCH_SYNC);
     331             :       }
     332             :     }
     333           0 :   }
     334             : 
     335             :   // This is the data that all of the runnables (see below) will attempt
     336             :   // to write.  It will always have the most up to date version, or be
     337             :   // null, if the up to date information has already been written out.
     338             :   static Atomic<PrefSaveData*> sPendingWriteData;
     339             : };
     340             : Atomic<PrefSaveData*> PreferencesWriter::sPendingWriteData(nullptr);
     341             : 
     342           0 : class PWRunnable : public Runnable
     343             : {
     344             : public:
     345           0 :   explicit PWRunnable(nsIFile* aFile)
     346           0 :     : Runnable("PWRunnable")
     347           0 :     , mFile(aFile)
     348           0 :   {}
     349             : 
     350           0 :   NS_IMETHOD Run() override
     351             :   {
     352           0 :     mozilla::UniquePtr<PrefSaveData> prefs(PreferencesWriter::sPendingWriteData.exchange(nullptr));
     353             :     // If we get a nullptr on the exchange, it means that somebody
     354             :     // else has already processed the request, and we can just return.
     355             : 
     356           0 :     nsresult rv = NS_OK;
     357           0 :     if (prefs) {
     358           0 :       rv = PreferencesWriter::Write(mFile, *prefs);
     359             : 
     360             :       // Make a copy of these so we can have them in runnable lambda.
     361             :       // nsIFile is only there so that we would never release the
     362             :       // ref counted pointer off main thread.
     363           0 :       nsresult rvCopy = rv;
     364           0 :       nsCOMPtr<nsIFile> fileCopy(mFile);
     365           0 :       SystemGroup::Dispatch("Preferences::WriterRunnable",
     366             :                             TaskCategory::Other,
     367           0 :                             NS_NewRunnableFunction("Preferences::WriterRunnable", [fileCopy, rvCopy] {
     368           0 :         MOZ_RELEASE_ASSERT(NS_IsMainThread());
     369           0 :         if (NS_FAILED(rvCopy)) {
     370           0 :           Preferences::DirtyCallback();
     371             :         }
     372           0 :       }));
     373             :     }
     374           0 :     return rv;
     375             :   }
     376             : 
     377             : protected:
     378             :   nsCOMPtr<nsIFile> mFile;
     379             : };
     380             : 
     381             : struct CacheData {
     382             :   void* cacheLocation;
     383             :   union {
     384             :     bool defaultValueBool;
     385             :     int32_t defaultValueInt;
     386             :     uint32_t defaultValueUint;
     387             :     float defaultValueFloat;
     388             :   };
     389             : };
     390             : 
     391             : static nsTArray<nsAutoPtr<CacheData> >* gCacheData = nullptr;
     392             : static nsRefPtrHashtable<ValueObserverHashKey,
     393             :                          ValueObserver>* gObserverTable = nullptr;
     394             : 
     395             : #ifdef DEBUG
     396             : static bool
     397        2014 : HaveExistingCacheFor(void* aPtr)
     398             : {
     399        2014 :   MOZ_ASSERT(NS_IsMainThread());
     400        2014 :   if (gCacheData) {
     401      690036 :     for (size_t i = 0, count = gCacheData->Length(); i < count; ++i) {
     402      688022 :       if ((*gCacheData)[i]->cacheLocation == aPtr) {
     403           0 :         return true;
     404             :       }
     405             :     }
     406             :   }
     407        2014 :   return false;
     408             : }
     409             : 
     410             : static void
     411        2014 : AssertNotAlreadyCached(const char* aPrefType,
     412             :                        const char* aPref,
     413             :                        void* aPtr)
     414             : {
     415        2014 :   if (HaveExistingCacheFor(aPtr)) {
     416             :     fprintf_stderr(stderr,
     417             :       "Attempt to add a %s pref cache for preference '%s' at address '%p'"
     418             :       "was made. However, a pref was already cached at this address.\n",
     419           0 :       aPrefType, aPref, aPtr);
     420           0 :     MOZ_ASSERT(false, "Should not have an existing pref cache for this address");
     421             :   }
     422        2014 : }
     423             : #endif
     424             : 
     425             : static void
     426           0 : ReportToConsole(const char* aMessage, int aLine, bool aError)
     427             : {
     428             :   nsPrintfCString message("** Preference parsing %s (line %d) = %s **\n",
     429           0 :                           (aError ? "error" : "warning"), aLine, aMessage);
     430           0 :   nsPrefBranch::ReportToConsole(NS_ConvertUTF8toUTF16(message.get()));
     431           0 : }
     432             : 
     433             : // Although this is a member of Preferences, it measures sPreferences and
     434             : // several other global structures.
     435             : /* static */ int64_t
     436           0 : Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf)
     437             : {
     438           0 :   NS_ENSURE_TRUE(InitStaticMembers(), 0);
     439             : 
     440           0 :   size_t n = aMallocSizeOf(sPreferences);
     441           0 :   if (gHashTable) {
     442             :     // pref keys are allocated in a private arena, which we count elsewhere.
     443             :     // pref stringvals are allocated out of the same private arena.
     444           0 :     n += gHashTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
     445             :   }
     446           0 :   if (gCacheData) {
     447           0 :     n += gCacheData->ShallowSizeOfIncludingThis(aMallocSizeOf);
     448           0 :     for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
     449           0 :       n += aMallocSizeOf((*gCacheData)[i]);
     450             :     }
     451             :   }
     452           0 :   if (gObserverTable) {
     453           0 :     n += gObserverTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
     454           0 :     for (auto iter = gObserverTable->Iter(); !iter.Done(); iter.Next()) {
     455           0 :       n += iter.Key()->mPrefName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     456           0 :       n += iter.Data()->mClosures.ShallowSizeOfExcludingThis(aMallocSizeOf);
     457             :     }
     458             :   }
     459           0 :   if (sRootBranch) {
     460           0 :     n += reinterpret_cast<nsPrefBranch*>(sRootBranch)->SizeOfIncludingThis(aMallocSizeOf);
     461             :   }
     462           0 :   if (sDefaultRootBranch) {
     463           0 :     n += reinterpret_cast<nsPrefBranch*>(sDefaultRootBranch)->SizeOfIncludingThis(aMallocSizeOf);
     464             :   }
     465           0 :   n += pref_SizeOfPrivateData(aMallocSizeOf);
     466           0 :   return n;
     467             : }
     468             : 
     469           3 : class PreferenceServiceReporter final : public nsIMemoryReporter
     470             : {
     471           0 :   ~PreferenceServiceReporter() {}
     472             : 
     473             : public:
     474             :   NS_DECL_ISUPPORTS
     475             :   NS_DECL_NSIMEMORYREPORTER
     476             : 
     477             : protected:
     478             :   static const uint32_t kSuspectReferentCount = 1000;
     479             : };
     480             : 
     481          39 : NS_IMPL_ISUPPORTS(PreferenceServiceReporter, nsIMemoryReporter)
     482             : 
     483           0 : MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)
     484             : 
     485             : NS_IMETHODIMP
     486           0 : PreferenceServiceReporter::CollectReports(
     487             :   nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
     488             : {
     489           0 :   MOZ_COLLECT_REPORT(
     490             :     "explicit/preferences", KIND_HEAP, UNITS_BYTES,
     491             :     Preferences::SizeOfIncludingThisAndOtherStuff(PreferenceServiceMallocSizeOf),
     492           0 :     "Memory used by the preferences system.");
     493             : 
     494             :   nsPrefBranch* rootBranch =
     495           0 :     static_cast<nsPrefBranch*>(Preferences::GetRootBranch());
     496           0 :   if (!rootBranch) {
     497           0 :     return NS_OK;
     498             :   }
     499             : 
     500           0 :   size_t numStrong = 0;
     501           0 :   size_t numWeakAlive = 0;
     502           0 :   size_t numWeakDead = 0;
     503           0 :   nsTArray<nsCString> suspectPreferences;
     504             :   // Count of the number of referents for each preference.
     505           0 :   nsDataHashtable<nsCStringHashKey, uint32_t> prefCounter;
     506             : 
     507           0 :   for (auto iter = rootBranch->mObservers.Iter(); !iter.Done(); iter.Next()) {
     508           0 :     nsAutoPtr<PrefCallback>& callback = iter.Data();
     509           0 :     nsPrefBranch* prefBranch = callback->GetPrefBranch();
     510           0 :     const auto& pref = prefBranch->getPrefName(callback->GetDomain().get());
     511             : 
     512           0 :     if (callback->IsWeak()) {
     513           0 :       nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(callback->mWeakRef);
     514           0 :       if (callbackRef) {
     515           0 :         numWeakAlive++;
     516             :       } else {
     517           0 :         numWeakDead++;
     518             :       }
     519             :     } else {
     520           0 :       numStrong++;
     521             :     }
     522             : 
     523           0 :     nsDependentCString prefString(pref.get());
     524           0 :     uint32_t oldCount = 0;
     525           0 :     prefCounter.Get(prefString, &oldCount);
     526           0 :     uint32_t currentCount = oldCount + 1;
     527           0 :     prefCounter.Put(prefString, currentCount);
     528             : 
     529             :     // Keep track of preferences that have a suspiciously large number of
     530             :     // referents (a symptom of a leak).
     531           0 :     if (currentCount == kSuspectReferentCount) {
     532           0 :       suspectPreferences.AppendElement(prefString);
     533             :     }
     534             :   }
     535             : 
     536           0 :   for (uint32_t i = 0; i < suspectPreferences.Length(); i++) {
     537           0 :     nsCString& suspect = suspectPreferences[i];
     538           0 :     uint32_t totalReferentCount = 0;
     539           0 :     prefCounter.Get(suspect, &totalReferentCount);
     540             : 
     541             :     nsPrintfCString suspectPath("preference-service-suspect/"
     542           0 :                                 "referent(pref=%s)", suspect.get());
     543             : 
     544           0 :     aHandleReport->Callback(
     545           0 :       /* process = */ EmptyCString(),
     546             :       suspectPath, KIND_OTHER, UNITS_COUNT, totalReferentCount,
     547           0 :       NS_LITERAL_CSTRING(
     548             :         "A preference with a suspiciously large number referents (symptom of a "
     549             :         "leak)."),
     550           0 :       aData);
     551             :   }
     552             : 
     553           0 :   MOZ_COLLECT_REPORT(
     554             :     "preference-service/referent/strong", KIND_OTHER, UNITS_COUNT,
     555             :     numStrong,
     556           0 :     "The number of strong referents held by the preference service.");
     557             : 
     558           0 :   MOZ_COLLECT_REPORT(
     559             :     "preference-service/referent/weak/alive", KIND_OTHER, UNITS_COUNT,
     560             :     numWeakAlive,
     561             :     "The number of weak referents held by the preference service that are "
     562           0 :     "still alive.");
     563             : 
     564           0 :   MOZ_COLLECT_REPORT(
     565             :     "preference-service/referent/weak/dead", KIND_OTHER, UNITS_COUNT,
     566             :     numWeakDead,
     567             :     "The number of weak referents held by the preference service that are "
     568           0 :     "dead.");
     569             : 
     570           0 :   return NS_OK;
     571             : }
     572             : 
     573             : namespace {
     574           9 : class AddPreferencesMemoryReporterRunnable : public Runnable
     575             : {
     576             : public:
     577           3 :   AddPreferencesMemoryReporterRunnable() : Runnable("AddPreferencesMemoryReporterRunnable") {}
     578           3 :   NS_IMETHOD Run() override
     579             :   {
     580           3 :     return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
     581             :   }
     582             : };
     583             : } // namespace
     584             : 
     585             : // static
     586             : Preferences*
     587           3 : Preferences::GetInstanceForService()
     588             : {
     589           3 :   if (sPreferences) {
     590           0 :     NS_ADDREF(sPreferences);
     591           0 :     return sPreferences;
     592             :   }
     593             : 
     594           3 :   NS_ENSURE_TRUE(!sShutdown, nullptr);
     595             : 
     596           3 :   sRootBranch = new nsPrefBranch("", false);
     597           3 :   NS_ADDREF(sRootBranch);
     598           3 :   sDefaultRootBranch = new nsPrefBranch("", true);
     599           3 :   NS_ADDREF(sDefaultRootBranch);
     600             : 
     601           3 :   sPreferences = new Preferences();
     602           3 :   NS_ADDREF(sPreferences);
     603             : 
     604           3 :   if (NS_FAILED(sPreferences->Init())) {
     605             :     // The singleton instance will delete sRootBranch and sDefaultRootBranch.
     606           0 :     NS_RELEASE(sPreferences);
     607           0 :     return nullptr;
     608             :   }
     609             : 
     610           3 :   gCacheData = new nsTArray<nsAutoPtr<CacheData> >();
     611             : 
     612           3 :   gObserverTable = new nsRefPtrHashtable<ValueObserverHashKey, ValueObserver>();
     613             : 
     614             :   // Preferences::GetInstanceForService() can be called from GetService(), and
     615             :   // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter).  To
     616             :   // avoid a potential recursive GetService() call, we can't register the
     617             :   // memory reporter here; instead, do it off a runnable.
     618             :   RefPtr<AddPreferencesMemoryReporterRunnable> runnable =
     619           6 :     new AddPreferencesMemoryReporterRunnable();
     620           3 :   NS_DispatchToMainThread(runnable);
     621             : 
     622           3 :   NS_ADDREF(sPreferences);
     623           3 :   return sPreferences;
     624             : }
     625             : 
     626             : // static
     627             : bool
     628        4355 : Preferences::IsServiceAvailable()
     629             : {
     630        4355 :   return !!sPreferences;
     631             : }
     632             : 
     633             : // static
     634             : bool
     635        7904 : Preferences::InitStaticMembers()
     636             : {
     637             : #ifndef MOZ_B2G
     638        7904 :   MOZ_ASSERT(NS_IsMainThread() || mozilla::ServoStyleSet::IsInServoTraversal());
     639             : #endif
     640             : 
     641        7904 :   if (!sShutdown && !sPreferences) {
     642           2 :     MOZ_ASSERT(NS_IsMainThread());
     643             :     nsCOMPtr<nsIPrefService> prefService =
     644           2 :       do_GetService(NS_PREFSERVICE_CONTRACTID);
     645             :   }
     646             : 
     647        7904 :   return sPreferences != nullptr;
     648             : }
     649             : 
     650             : // static
     651             : void
     652           0 : Preferences::Shutdown()
     653             : {
     654           0 :   if (!sShutdown) {
     655           0 :     sShutdown = true; // Don't create the singleton instance after here.
     656             : 
     657             :     // Don't set sPreferences to nullptr here.  The instance may be grabbed by
     658             :     // other modules.  The utility methods of Preferences should be available
     659             :     // until the singleton instance actually released.
     660           0 :     if (sPreferences) {
     661           0 :       sPreferences->Release();
     662             :     }
     663             :   }
     664           0 : }
     665             : 
     666             : //-----------------------------------------------------------------------------
     667             : 
     668             : /*
     669             :  * Constructor/Destructor
     670             :  */
     671             : 
     672           3 : Preferences::Preferences()
     673             : {
     674           3 : }
     675             : 
     676           0 : Preferences::~Preferences()
     677             : {
     678           0 :   NS_ASSERTION(sPreferences == this, "Isn't this the singleton instance?");
     679             : 
     680           0 :   delete gObserverTable;
     681           0 :   gObserverTable = nullptr;
     682             : 
     683           0 :   delete gCacheData;
     684           0 :   gCacheData = nullptr;
     685             : 
     686           0 :   NS_RELEASE(sRootBranch);
     687           0 :   NS_RELEASE(sDefaultRootBranch);
     688             : 
     689           0 :   sPreferences = nullptr;
     690             : 
     691           0 :   PREF_Cleanup();
     692           0 : }
     693             : 
     694             : 
     695             : /*
     696             :  * nsISupports Implementation
     697             :  */
     698             : 
     699         960 : NS_IMPL_ADDREF(Preferences)
     700         679 : NS_IMPL_RELEASE(Preferences)
     701             : 
     702        2661 : NS_INTERFACE_MAP_BEGIN(Preferences)
     703        2661 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefService)
     704        2082 :     NS_INTERFACE_MAP_ENTRY(nsIPrefService)
     705        2038 :     NS_INTERFACE_MAP_ENTRY(nsIObserver)
     706        2036 :     NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
     707        1902 :     NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2)
     708        1900 :     NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)
     709        1900 :     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     710        1896 : NS_INTERFACE_MAP_END
     711             : 
     712             : /*
     713             :  * nsIPrefService Implementation
     714             :  */
     715             : 
     716             : InfallibleTArray<Preferences::PrefSetting>* gInitPrefs;
     717             : 
     718             : /*static*/
     719             : void
     720           2 : Preferences::SetInitPreferences(nsTArray<PrefSetting>* aPrefs) {
     721           4 :   gInitPrefs = new InfallibleTArray<PrefSetting>(mozilla::Move(*aPrefs));
     722           2 : }
     723             : 
     724             : nsresult
     725           3 : Preferences::Init()
     726             : {
     727             :   nsresult rv;
     728             : 
     729           3 :   PREF_SetDirtyCallback(&DirtyCallback);
     730           3 :   PREF_Init();
     731             : 
     732           3 :   rv = pref_InitInitialObjects();
     733           3 :   NS_ENSURE_SUCCESS(rv, rv);
     734             : 
     735           3 :   if (XRE_IsContentProcess()) {
     736           2 :     MOZ_ASSERT(gInitPrefs);
     737         262 :     for (unsigned int i = 0; i < gInitPrefs->Length(); i++) {
     738         260 :       Preferences::SetPreference(gInitPrefs->ElementAt(i));
     739             :     }
     740           2 :     delete gInitPrefs;
     741           2 :     gInitPrefs = nullptr;
     742           2 :     return NS_OK;
     743             :   }
     744             : 
     745           2 :   nsXPIDLCString lockFileName;
     746             :   /*
     747             :    * The following is a small hack which will allow us to only load the library
     748             :    * which supports the netscape.cfg file if the preference is defined. We
     749             :    * test for the existence of the pref, set in the all.js (mozilla) or
     750             :    * all-ns.js (netscape 6), and if it exists we startup the pref config
     751             :    * category which will do the rest.
     752             :    */
     753             : 
     754           1 :   rv = PREF_CopyCharPref("general.config.filename", getter_Copies(lockFileName), false);
     755           1 :   if (NS_SUCCEEDED(rv))
     756             :     NS_CreateServicesFromCategory("pref-config-startup",
     757             :                                   static_cast<nsISupports *>(static_cast<void *>(this)),
     758           0 :                                   "pref-config-startup");
     759             : 
     760             :   nsCOMPtr<nsIObserverService> observerService =
     761           2 :     mozilla::services::GetObserverService();
     762           1 :   if (!observerService)
     763           0 :     return NS_ERROR_FAILURE;
     764             : 
     765           1 :   observerService->AddObserver(this, "profile-before-change-telemetry", true);
     766           1 :   rv = observerService->AddObserver(this, "profile-before-change", true);
     767             : 
     768           1 :   observerService->AddObserver(this, "load-extension-defaults", true);
     769           1 :   observerService->AddObserver(this, "suspend_process_notification", true);
     770             : 
     771           1 :   return(rv);
     772             : }
     773             : 
     774             : // static
     775             : nsresult
     776           1 : Preferences::ResetAndReadUserPrefs()
     777             : {
     778           1 :   sPreferences->ResetUserPrefs();
     779             : 
     780           1 :   MOZ_ASSERT(!sPreferences->mCurrentFile, "Should only initialize prefs once");
     781             : 
     782           1 :   nsresult rv = sPreferences->UseDefaultPrefFile();
     783           1 :   sPreferences->UseUserPrefFile();
     784             : 
     785             :   // Migrate the old prerelease telemetry pref
     786           1 :   if (!Preferences::GetBool(kOldTelemetryPref, true)) {
     787           0 :     Preferences::SetBool(kTelemetryPref, false);
     788           0 :     Preferences::ClearUser(kOldTelemetryPref);
     789             :   }
     790             : 
     791           1 :   sPreferences->NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);
     792           1 :   return rv;
     793             : }
     794             : 
     795             : NS_IMETHODIMP
     796           1 : Preferences::Observe(nsISupports *aSubject, const char *aTopic,
     797             :                      const char16_t *someData)
     798             : {
     799           1 :   if (MOZ_UNLIKELY(!XRE_IsParentProcess())) {
     800           0 :     return NS_ERROR_NOT_AVAILABLE;
     801             :   }
     802             : 
     803           1 :   nsresult rv = NS_OK;
     804             : 
     805           1 :   if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
     806             :     // Normally prefs aren't written after this point, and so we kick off
     807             :     // an asynchronous pref save so that I/O can be done in parallel with
     808             :     // other shutdown.
     809           0 :     if (AllowOffMainThreadSave()) {
     810           0 :       SavePrefFile(nullptr);
     811             :     }
     812           1 :   } else if (!nsCRT::strcmp(aTopic, "profile-before-change-telemetry")) {
     813             :     // It's possible that a profile-before-change observer after ours
     814             :     // set a pref. A blocking save here re-saves if necessary and also waits
     815             :     // for any pending saves to complete.
     816           0 :     SavePrefFileBlocking();
     817           0 :     MOZ_ASSERT(!mDirty, "Preferences should not be dirty");
     818           0 :     mProfileShutdown = true;
     819           1 :   } else if (!strcmp(aTopic, "load-extension-defaults")) {
     820           1 :     pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
     821           0 :   } else if (!nsCRT::strcmp(aTopic, "reload-default-prefs")) {
     822             :     // Reload the default prefs from file.
     823           0 :     pref_InitInitialObjects();
     824           0 :   } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) {
     825             :     // Our process is being suspended. The OS may wake our process later,
     826             :     // or it may kill the process. In case our process is going to be killed
     827             :     // from the suspended state, we save preferences before suspending.
     828           0 :     rv = SavePrefFileBlocking();
     829             :   }
     830           1 :   return rv;
     831             : }
     832             : 
     833             : 
     834             : NS_IMETHODIMP
     835           0 : Preferences::ReadUserPrefsFromFile(nsIFile *aFile)
     836             : {
     837           0 :   if (MOZ_UNLIKELY(!XRE_IsParentProcess())) {
     838           0 :     NS_ERROR("must load prefs from parent process");
     839           0 :     return NS_ERROR_NOT_AVAILABLE;
     840             :   }
     841             : 
     842           0 :   if (!aFile) {
     843           0 :     NS_ERROR("ReadUserPrefsFromFile requires a parameter");
     844           0 :     return NS_ERROR_INVALID_ARG;
     845             :   }
     846             : 
     847           0 :   return openPrefFile(aFile);
     848             : }
     849             : 
     850             : NS_IMETHODIMP
     851           0 : Preferences::ResetPrefs()
     852             : {
     853           0 :   if (MOZ_UNLIKELY(!XRE_IsParentProcess())) {
     854           0 :     NS_ERROR("must reset prefs from parent process");
     855           0 :     return NS_ERROR_NOT_AVAILABLE;
     856             :   }
     857             : 
     858           0 :   NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
     859           0 :   PREF_CleanupPrefs();
     860             : 
     861           0 :   PREF_Init();
     862             : 
     863           0 :   return pref_InitInitialObjects();
     864             : }
     865             : 
     866             : NS_IMETHODIMP
     867           1 : Preferences::ResetUserPrefs()
     868             : {
     869           1 :   if (MOZ_UNLIKELY(!XRE_IsParentProcess())) {
     870           0 :     NS_ERROR("must reset user prefs from parent process");
     871           0 :     return NS_ERROR_NOT_AVAILABLE;
     872             :   }
     873             : 
     874           1 :   PREF_ClearAllUserPrefs();
     875           1 :   return NS_OK;
     876             : }
     877             : 
     878             : bool
     879           0 : Preferences::AllowOffMainThreadSave()
     880             : {
     881             :   // Put in a preference that allows us to disable
     882             :   // off main thread preference file save.
     883           0 :   if (sAllowOMTPrefWrite < 0) {
     884           0 :     bool value = false;
     885           0 :     Preferences::GetBool("preferences.allow.omt-write", &value);
     886           0 :     sAllowOMTPrefWrite = value ? 1 : 0;
     887             :   }
     888           0 :   return !!sAllowOMTPrefWrite;
     889             : }
     890             : 
     891             : nsresult
     892           0 : Preferences::SavePrefFileBlocking()
     893             : {
     894           0 :   if (mDirty) {
     895           0 :     return SavePrefFileInternal(nullptr, SaveMethod::Blocking);
     896             :   }
     897             : 
     898             :   // If we weren't dirty to start, SavePrefFileInternal will early exit
     899             :   // so there is no guarantee that we don't have oustanding async
     900             :   // saves in the pipe.  Since the contract of SavePrefFileOnMainThread
     901             :   // is that the file on disk matches the preferences, we have to make
     902             :   // sure those requests are completed.
     903             : 
     904           0 :   if (AllowOffMainThreadSave()) {
     905           0 :     PreferencesWriter::Flush();
     906             :   }
     907           0 :   return NS_OK;
     908             : }
     909             : 
     910             : nsresult
     911           0 : Preferences::SavePrefFileAsynchronous()
     912             : {
     913           0 :   return SavePrefFileInternal(nullptr, SaveMethod::Asynchronous);
     914             : }
     915             : 
     916             : NS_IMETHODIMP
     917           0 : Preferences::SavePrefFile(nsIFile *aFile)
     918             : {
     919             :   // This is the method accessible from service API.  Make it off
     920             :   // main thread.
     921           0 :   return SavePrefFileInternal(aFile, SaveMethod::Asynchronous);
     922             : }
     923             : 
     924             : static nsresult
     925           0 : ReadExtensionPrefs(nsIFile *aFile)
     926             : {
     927             :   nsresult rv;
     928           0 :   nsCOMPtr<nsIZipReader> reader = do_CreateInstance(kZipReaderCID, &rv);
     929           0 :   NS_ENSURE_SUCCESS(rv, rv);
     930             : 
     931           0 :   rv = reader->Open(aFile);
     932           0 :   NS_ENSURE_SUCCESS(rv, rv);
     933             : 
     934           0 :   nsCOMPtr<nsIUTF8StringEnumerator> files;
     935           0 :   rv = reader->FindEntries(nsDependentCString("defaults/preferences/*.(J|j)(S|s)$"),
     936           0 :                            getter_AddRefs(files));
     937           0 :   NS_ENSURE_SUCCESS(rv, rv);
     938             : 
     939             :   char buffer[4096];
     940             : 
     941             :   bool more;
     942           0 :   while (NS_SUCCEEDED(rv = files->HasMore(&more)) && more) {
     943           0 :     nsAutoCString entry;
     944           0 :     rv = files->GetNext(entry);
     945           0 :     NS_ENSURE_SUCCESS(rv, rv);
     946             : 
     947           0 :     nsCOMPtr<nsIInputStream> stream;
     948           0 :     rv = reader->GetInputStream(entry, getter_AddRefs(stream));
     949           0 :     NS_ENSURE_SUCCESS(rv, rv);
     950             : 
     951             :     uint64_t avail;
     952             :     uint32_t read;
     953             : 
     954             :     PrefParseState ps;
     955           0 :     PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
     956           0 :     while (NS_SUCCEEDED(rv = stream->Available(&avail)) && avail) {
     957           0 :       rv = stream->Read(buffer, 4096, &read);
     958           0 :       if (NS_FAILED(rv)) {
     959           0 :         NS_WARNING("Pref stream read failed");
     960           0 :         break;
     961             :       }
     962             : 
     963           0 :       PREF_ParseBuf(&ps, buffer, read);
     964             :     }
     965           0 :     PREF_FinalizeParseState(&ps);
     966             :   }
     967           0 :   return rv;
     968             : }
     969             : 
     970             : void
     971        6348 : Preferences::SetPreference(const PrefSetting& aPref)
     972             : {
     973        6348 :   pref_SetPref(aPref);
     974        6348 : }
     975             : 
     976             : void
     977          23 : Preferences::GetPreference(PrefSetting* aPref)
     978             : {
     979          23 :   PrefHashEntry *entry = pref_HashTableLookup(aPref->name().get());
     980          23 :   if (!entry)
     981           0 :     return;
     982             : 
     983          23 :   if (pref_EntryHasAdvisablySizedValues(entry)) {
     984          23 :     pref_GetPrefFromEntry(entry, aPref);
     985             :   }
     986             : }
     987             : 
     988             : void
     989           2 : Preferences::GetPreferences(InfallibleTArray<PrefSetting>* aPrefs)
     990             : {
     991           2 :   aPrefs->SetCapacity(gHashTable->Capacity());
     992        6067 :   for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
     993        6065 :     auto entry = static_cast<PrefHashEntry*>(iter.Get());
     994             : 
     995        6065 :     if (!pref_EntryHasAdvisablySizedValues(entry)) {
     996           0 :       continue;
     997             :     }
     998             : 
     999        6065 :     dom::PrefSetting *pref = aPrefs->AppendElement();
    1000        6065 :     pref_GetPrefFromEntry(entry, pref);
    1001             :   }
    1002           2 : }
    1003             : 
    1004             : #ifdef DEBUG
    1005             : void
    1006          16 : Preferences::SetInitPhase(pref_initPhase phase)
    1007             : {
    1008          16 :   pref_SetInitPhase(phase);
    1009          16 : }
    1010             : 
    1011             : pref_initPhase
    1012        2504 : Preferences::InitPhase()
    1013             : {
    1014        2504 :   return pref_GetInitPhase();
    1015             : }
    1016             : #endif
    1017             : 
    1018             : NS_IMETHODIMP
    1019          35 : Preferences::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
    1020             : {
    1021             :   nsresult rv;
    1022             : 
    1023          35 :   if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) {
    1024             :     // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
    1025          62 :     RefPtr<nsPrefBranch> prefBranch = new nsPrefBranch(aPrefRoot, false);
    1026          31 :     prefBranch.forget(_retval);
    1027          62 :     rv = NS_OK;
    1028             :   } else {
    1029             :     // special case caching the default root
    1030           8 :     nsCOMPtr<nsIPrefBranch> root(sRootBranch);
    1031           4 :     root.forget(_retval);
    1032           4 :     rv = NS_OK;
    1033             :   }
    1034          35 :   return rv;
    1035             : }
    1036             : 
    1037             : NS_IMETHODIMP
    1038          10 : Preferences::GetDefaultBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
    1039             : {
    1040          10 :   if (!aPrefRoot || !aPrefRoot[0]) {
    1041          12 :     nsCOMPtr<nsIPrefBranch> root(sDefaultRootBranch);
    1042           6 :     root.forget(_retval);
    1043           6 :     return NS_OK;
    1044             :   }
    1045             : 
    1046             :   // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
    1047           8 :   RefPtr<nsPrefBranch> prefBranch = new nsPrefBranch(aPrefRoot, true);
    1048           4 :   if (!prefBranch)
    1049           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1050             : 
    1051           4 :   prefBranch.forget(_retval);
    1052           4 :   return NS_OK;
    1053             : }
    1054             : 
    1055             : NS_IMETHODIMP
    1056           0 : Preferences::GetDirty(bool *_retval) {
    1057           0 :   *_retval = mDirty;
    1058           0 :   return NS_OK;
    1059             : }
    1060             : 
    1061             : nsresult
    1062           1 : Preferences::NotifyServiceObservers(const char *aTopic)
    1063             : {
    1064             :   nsCOMPtr<nsIObserverService> observerService =
    1065           2 :     mozilla::services::GetObserverService();
    1066           1 :   if (!observerService)
    1067           0 :     return NS_ERROR_FAILURE;
    1068             : 
    1069           1 :   nsISupports *subject = (nsISupports *)((nsIPrefService *)this);
    1070           1 :   observerService->NotifyObservers(subject, aTopic, nullptr);
    1071             : 
    1072           1 :   return NS_OK;
    1073             : }
    1074             : 
    1075             : nsresult
    1076           1 : Preferences::UseDefaultPrefFile()
    1077             : {
    1078           2 :   nsCOMPtr<nsIFile> file;
    1079           1 :   nsresult rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE,
    1080           2 :                                        getter_AddRefs(file));
    1081           1 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1082           0 :     return rv;
    1083             :   }
    1084             : 
    1085           1 :   mCurrentFile = file;
    1086             : 
    1087           1 :   rv = openPrefFile(file);
    1088           1 :   if (rv == NS_ERROR_FILE_NOT_FOUND) {
    1089             :     // this is a normal case for new users
    1090           0 :     Telemetry::ScalarSet(Telemetry::ScalarID::PREFERENCES_CREATED_NEW_USER_PREFS_FILE, true);
    1091           0 :     rv = NS_OK;
    1092           1 :   } else if (NS_FAILED(rv)) {
    1093             :     // Save a backup copy of the current (invalid) prefs file, since all prefs
    1094             :     // from the error line to the end of the file will be lost (bug 361102).
    1095             :     // TODO we should notify the user about it (bug 523725).
    1096           0 :     Telemetry::ScalarSet(Telemetry::ScalarID::PREFERENCES_PREFS_FILE_WAS_INVALID, true);
    1097           0 :     MakeBackupPrefFile(file);
    1098             :   }
    1099             : 
    1100           1 :   return rv;
    1101             : }
    1102             : 
    1103             : void
    1104           1 : Preferences::UseUserPrefFile()
    1105             : {
    1106           2 :   nsCOMPtr<nsIFile> aFile;
    1107           1 :   nsresult rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_DIR,
    1108           2 :                                        getter_AddRefs(aFile));
    1109           1 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1110           0 :     return;
    1111             :   }
    1112             : 
    1113           1 :   aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
    1114           1 :   rv = openPrefFile(aFile);
    1115           1 :   if (rv != NS_ERROR_FILE_NOT_FOUND) {
    1116             :     // If the file exists and was at least partially read, record that
    1117             :     // in telemetry as it may be a sign of pref injection.
    1118           1 :     Telemetry::ScalarSet(Telemetry::ScalarID::PREFERENCES_READ_USER_JS, true);
    1119             :   }
    1120             : }
    1121             : 
    1122             : nsresult
    1123           0 : Preferences::MakeBackupPrefFile(nsIFile *aFile)
    1124             : {
    1125             :   // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.
    1126             :   // "Invalidprefs.js" is removed if it exists, prior to making the copy.
    1127           0 :   nsAutoString newFilename;
    1128           0 :   nsresult rv = aFile->GetLeafName(newFilename);
    1129           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1130           0 :   newFilename.Insert(NS_LITERAL_STRING("Invalid"), 0);
    1131           0 :   nsCOMPtr<nsIFile> newFile;
    1132           0 :   rv = aFile->GetParent(getter_AddRefs(newFile));
    1133           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1134           0 :   rv = newFile->Append(newFilename);
    1135           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1136           0 :   bool exists = false;
    1137           0 :   newFile->Exists(&exists);
    1138           0 :   if (exists) {
    1139           0 :     rv = newFile->Remove(false);
    1140           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1141             :   }
    1142           0 :   rv = aFile->CopyTo(nullptr, newFilename);
    1143           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1144           0 :   return rv;
    1145             : }
    1146             : 
    1147             : nsresult
    1148           0 : Preferences::SavePrefFileInternal(nsIFile *aFile, SaveMethod aSaveMethod)
    1149             : {
    1150           0 :   if (MOZ_UNLIKELY(!XRE_IsParentProcess())) {
    1151           0 :     NS_ERROR("must save pref file from parent process");
    1152           0 :     return NS_ERROR_NOT_AVAILABLE;
    1153             :   }
    1154             : 
    1155             :   // We allow different behavior here when aFile argument is not null,
    1156             :   // but it happens to be the same as the current file.  It is not
    1157             :   // clear that we should, but it does give us a "force" save on the
    1158             :   // unmodified pref file (see the original bug 160377 when we added this.)
    1159             : 
    1160           0 :   if (nullptr == aFile) {
    1161             :     // Off main thread writing only if allowed
    1162           0 :     if (!AllowOffMainThreadSave()) {
    1163           0 :       aSaveMethod = SaveMethod::Blocking;
    1164             :     }
    1165             : 
    1166             :     // the mDirty flag tells us if we should write to mCurrentFile
    1167             :     // we only check this flag when the caller wants to write to the default
    1168           0 :     if (!mDirty) {
    1169           0 :       return NS_OK;
    1170             :     }
    1171             : 
    1172             :     // check for profile shutdown after mDirty because the runnables from
    1173             :     // DirtyCallback can still be pending
    1174           0 :     if (mProfileShutdown) {
    1175           0 :       NS_WARNING("Cannot save pref file after profile shutdown.");
    1176           0 :       return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
    1177             :     }
    1178             : 
    1179             :     // It's possible that we never got a prefs file.
    1180           0 :     nsresult rv = NS_OK;
    1181           0 :     if (mCurrentFile) {
    1182           0 :       rv = WritePrefFile(mCurrentFile, aSaveMethod);
    1183             :     }
    1184             : 
    1185             :     // If we succeeded writing to mCurrentFile, reset the dirty flag
    1186           0 :     if (NS_SUCCEEDED(rv)) {
    1187           0 :       mDirty = false;
    1188             :     }
    1189           0 :     return rv;
    1190             :   } else {
    1191             :     // We only allow off main thread writes on mCurrentFile
    1192           0 :     return WritePrefFile(aFile, SaveMethod::Blocking);
    1193             :   }
    1194             : }
    1195             : 
    1196             : nsresult
    1197           0 : Preferences::WritePrefFile(nsIFile* aFile, SaveMethod aSaveMethod)
    1198             : {
    1199           0 :   if (!gHashTable) {
    1200           0 :     return NS_ERROR_NOT_INITIALIZED;
    1201             :   }
    1202             : 
    1203           0 :   AUTO_PROFILER_LABEL("Preferences::WritePrefFile", OTHER);
    1204             : 
    1205           0 :   if (AllowOffMainThreadSave()) {
    1206             : 
    1207           0 :     nsresult rv = NS_OK;
    1208             :     mozilla::UniquePtr<PrefSaveData> prefs =
    1209           0 :       MakeUnique<PrefSaveData>(pref_savePrefs(gHashTable));
    1210             : 
    1211             :     // Put the newly constructed preference data into sPendingWriteData
    1212             :     // for the next request to pick up
    1213           0 :     prefs.reset(PreferencesWriter::sPendingWriteData.exchange(prefs.release()));
    1214           0 :     if (prefs) {
    1215             :       // There was a previous request that hasn't been processed,
    1216             :       // and this is the data it had.
    1217           0 :       return rv;
    1218             :     } else {
    1219             :       // There were no previous requests, dispatch one since
    1220             :       // sPendingWriteData has the up to date information.
    1221             :       nsCOMPtr<nsIEventTarget> target =
    1222           0 :         do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
    1223           0 :       if (NS_SUCCEEDED(rv)) {
    1224           0 :         bool async = aSaveMethod == SaveMethod::Asynchronous;
    1225           0 :         rv = target->Dispatch(new PWRunnable(aFile),
    1226             :                               async ? nsIEventTarget::DISPATCH_NORMAL :
    1227             :                                       nsIEventTarget::DISPATCH_SYNC);
    1228           0 :         return rv;
    1229             :       }
    1230             :     }
    1231             : 
    1232             :     // If we can't get the thread for writing, for whatever reason, do the
    1233             :     // main thread write after making some noise:
    1234           0 :     MOZ_ASSERT(false,"failed to get the target thread for OMT pref write");
    1235             :   }
    1236             : 
    1237             :   // This will do a main thread write.  It is safe to do it this way
    1238             :   // as AllowOffMainThreadSave() returns a consistent value for the
    1239             :   // lifetime of the parent process.
    1240           0 :   PrefSaveData prefsData = pref_savePrefs(gHashTable);
    1241           0 :   return PreferencesWriter::Write(aFile, prefsData);
    1242             : }
    1243             : 
    1244          35 : static nsresult openPrefFile(nsIFile* aFile)
    1245             : {
    1246          70 :   nsCOMPtr<nsIInputStream> inStr;
    1247             : 
    1248          35 :   nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile);
    1249          35 :   if (NS_FAILED(rv))
    1250           0 :     return rv;
    1251             : 
    1252             :   int64_t fileSize64;
    1253          35 :   rv = aFile->GetFileSize(&fileSize64);
    1254          35 :   if (NS_FAILED(rv))
    1255           0 :     return rv;
    1256          35 :   NS_ENSURE_TRUE(fileSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
    1257             : 
    1258          35 :   uint32_t fileSize = (uint32_t)fileSize64;
    1259          70 :   auto fileBuffer = MakeUniqueFallible<char[]>(fileSize);
    1260          35 :   if (fileBuffer == nullptr)
    1261           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1262             : 
    1263             :   PrefParseState ps;
    1264          35 :   PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
    1265             : 
    1266             :   // Read is not guaranteed to return a buf the size of fileSize,
    1267             :   // but usually will.
    1268          35 :   nsresult rv2 = NS_OK;
    1269          35 :   uint32_t offset = 0;
    1270             :   for (;;) {
    1271          35 :     uint32_t amtRead = 0;
    1272          35 :     rv = inStr->Read(fileBuffer.get(), fileSize, &amtRead);
    1273          35 :     if (NS_FAILED(rv) || amtRead == 0)
    1274          35 :       break;
    1275          35 :     if (!PREF_ParseBuf(&ps, fileBuffer.get(), amtRead))
    1276           0 :       rv2 = NS_ERROR_FILE_CORRUPTED;
    1277          35 :     offset += amtRead;
    1278          35 :     if (offset == fileSize) {
    1279          35 :       break;
    1280             :     }
    1281           0 :   }
    1282             : 
    1283          35 :   PREF_FinalizeParseState(&ps);
    1284             : 
    1285          35 :   return NS_FAILED(rv) ? rv : rv2;
    1286             : }
    1287             : 
    1288             : /*
    1289             :  * some stuff that gets called from Pref_Init()
    1290             :  */
    1291             : 
    1292             : static int
    1293          54 : pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2, void* /*unused*/)
    1294             : {
    1295         108 :   nsAutoCString filename1, filename2;
    1296          54 :   aFile1->GetNativeLeafName(filename1);
    1297          54 :   aFile2->GetNativeLeafName(filename2);
    1298             : 
    1299         108 :   return Compare(filename2, filename1);
    1300             : }
    1301             : 
    1302             : /**
    1303             :  * Load default pref files from a directory. The files in the
    1304             :  * directory are sorted reverse-alphabetically; a set of "special file
    1305             :  * names" may be specified which are loaded after all the others.
    1306             :  */
    1307             : static nsresult
    1308           6 : pref_LoadPrefsInDir(nsIFile* aDir, char const *const *aSpecialFiles, uint32_t aSpecialFilesCount)
    1309             : {
    1310             :   nsresult rv, rv2;
    1311             :   bool hasMoreElements;
    1312             : 
    1313          12 :   nsCOMPtr<nsISimpleEnumerator> dirIterator;
    1314             : 
    1315             :   // this may fail in some normal cases, such as embedders who do not use a GRE
    1316           6 :   rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
    1317           6 :   if (NS_FAILED(rv)) {
    1318             :     // If the directory doesn't exist, then we have no reason to complain.  We
    1319             :     // loaded everything (and nothing) successfully.
    1320           0 :     if (rv == NS_ERROR_FILE_NOT_FOUND || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
    1321           0 :       rv = NS_OK;
    1322           0 :     return rv;
    1323             :   }
    1324             : 
    1325           6 :   rv = dirIterator->HasMoreElements(&hasMoreElements);
    1326           6 :   NS_ENSURE_SUCCESS(rv, rv);
    1327             : 
    1328          12 :   nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES);
    1329          12 :   nsCOMArray<nsIFile> specialFiles(aSpecialFilesCount);
    1330          12 :   nsCOMPtr<nsIFile> prefFile;
    1331             : 
    1332          66 :   while (hasMoreElements && NS_SUCCEEDED(rv)) {
    1333          60 :     nsAutoCString leafName;
    1334             : 
    1335          60 :     nsCOMPtr<nsISupports> supports;
    1336          30 :     rv = dirIterator->GetNext(getter_AddRefs(supports));
    1337          30 :     prefFile = do_QueryInterface(supports);
    1338          30 :     if (NS_FAILED(rv)) {
    1339           0 :       break;
    1340             :     }
    1341             : 
    1342          30 :     prefFile->GetNativeLeafName(leafName);
    1343          30 :     NS_ASSERTION(!leafName.IsEmpty(), "Failure in default prefs: directory enumerator returned empty file?");
    1344             : 
    1345             :     // Skip non-js files
    1346          90 :     if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".js"),
    1347          90 :                        nsCaseInsensitiveCStringComparator())) {
    1348          30 :       bool shouldParse = true;
    1349             :       // separate out special files
    1350          42 :       for (uint32_t i = 0; i < aSpecialFilesCount; ++i) {
    1351          12 :         if (leafName.Equals(nsDependentCString(aSpecialFiles[i]))) {
    1352           0 :           shouldParse = false;
    1353             :           // special files should be process in order; we put them into
    1354             :           // the array by index; this can make the array sparse
    1355           0 :           specialFiles.ReplaceObjectAt(prefFile, i);
    1356             :         }
    1357             :       }
    1358             : 
    1359          30 :       if (shouldParse) {
    1360          30 :         prefFiles.AppendObject(prefFile);
    1361             :       }
    1362             :     }
    1363             : 
    1364          30 :     rv = dirIterator->HasMoreElements(&hasMoreElements);
    1365             :   }
    1366             : 
    1367           6 :   if (prefFiles.Count() + specialFiles.Count() == 0) {
    1368           0 :     NS_WARNING("No default pref files found.");
    1369           0 :     if (NS_SUCCEEDED(rv)) {
    1370           0 :       rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY;
    1371             :     }
    1372           0 :     return rv;
    1373             :   }
    1374             : 
    1375           6 :   prefFiles.Sort(pref_CompareFileNames, nullptr);
    1376             : 
    1377           6 :   uint32_t arrayCount = prefFiles.Count();
    1378             :   uint32_t i;
    1379          36 :   for (i = 0; i < arrayCount; ++i) {
    1380          30 :     rv2 = openPrefFile(prefFiles[i]);
    1381          30 :     if (NS_FAILED(rv2)) {
    1382           0 :       NS_ERROR("Default pref file not parsed successfully.");
    1383           0 :       rv = rv2;
    1384             :     }
    1385             :   }
    1386             : 
    1387           6 :   arrayCount = specialFiles.Count();
    1388           6 :   for (i = 0; i < arrayCount; ++i) {
    1389             :     // this may be a sparse array; test before parsing
    1390           0 :     nsIFile* file = specialFiles[i];
    1391           0 :     if (file) {
    1392           0 :       rv2 = openPrefFile(file);
    1393           0 :       if (NS_FAILED(rv2)) {
    1394           0 :         NS_ERROR("Special default pref file not parsed successfully.");
    1395           0 :         rv = rv2;
    1396             :       }
    1397             :     }
    1398             :   }
    1399             : 
    1400           6 :   return rv;
    1401             : }
    1402             : 
    1403           7 : static nsresult pref_LoadPrefsInDirList(const char *listId)
    1404             : {
    1405             :   nsresult rv;
    1406          14 :   nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
    1407           7 :   if (NS_FAILED(rv))
    1408           0 :     return rv;
    1409             : 
    1410          14 :   nsCOMPtr<nsISimpleEnumerator> list;
    1411          14 :   dirSvc->Get(listId,
    1412             :               NS_GET_IID(nsISimpleEnumerator),
    1413          14 :               getter_AddRefs(list));
    1414           7 :   if (!list)
    1415           0 :     return NS_OK;
    1416             : 
    1417             :   bool hasMore;
    1418          13 :   while (NS_SUCCEEDED(list->HasMoreElements(&hasMore)) && hasMore) {
    1419           6 :     nsCOMPtr<nsISupports> elem;
    1420           3 :     list->GetNext(getter_AddRefs(elem));
    1421           3 :     if (!elem)
    1422           0 :       continue;
    1423             : 
    1424           6 :     nsCOMPtr<nsIFile> path = do_QueryInterface(elem);
    1425           3 :     if (!path)
    1426           0 :       continue;
    1427             : 
    1428           6 :     nsAutoCString leaf;
    1429           3 :     path->GetNativeLeafName(leaf);
    1430             : 
    1431             :     // Do we care if a file provided by this process fails to load?
    1432           3 :     if (Substring(leaf, leaf.Length() - 4).EqualsLiteral(".xpi"))
    1433           0 :       ReadExtensionPrefs(path);
    1434             :     else
    1435           3 :       pref_LoadPrefsInDir(path, nullptr, 0);
    1436             :   }
    1437           7 :   return NS_OK;
    1438             : }
    1439             : 
    1440           0 : static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
    1441             : {
    1442           0 :   nsZipItemPtr<char> manifest(jarReader, name, true);
    1443           0 :   NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
    1444             : 
    1445             :   PrefParseState ps;
    1446           0 :   PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
    1447           0 :   PREF_ParseBuf(&ps, manifest, manifest.Length());
    1448           0 :   PREF_FinalizeParseState(&ps);
    1449             : 
    1450           0 :   return NS_OK;
    1451             : }
    1452             : 
    1453             : //----------------------------------------------------------------------------------------
    1454             : // Initialize default preference JavaScript buffers from
    1455             : // appropriate TEXT resources
    1456             : //----------------------------------------------------------------------------------------
    1457           3 : static nsresult pref_InitInitialObjects()
    1458             : {
    1459             :   nsresult rv;
    1460             : 
    1461             :   // In omni.jar case, we load the following prefs:
    1462             :   // - jar:$gre/omni.jar!/greprefs.js
    1463             :   // - jar:$gre/omni.jar!/defaults/pref/*.js
    1464             :   // In non omni.jar case, we load:
    1465             :   // - $gre/greprefs.js
    1466             :   //
    1467             :   // In both cases, we also load:
    1468             :   // - $gre/defaults/pref/*.js
    1469             :   // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar)
    1470             :   // on $app == $gre case ; we load all files instead of channel-prefs.js only
    1471             :   // to have the same behaviour as $app != $gre, where this is required as
    1472             :   // a supported location for GRE preferences.
    1473             :   //
    1474             :   // When $app != $gre, we additionally load, in omni.jar case:
    1475             :   // - jar:$app/omni.jar!/defaults/preferences/*.js
    1476             :   // - $app/defaults/preferences/*.js
    1477             :   // and in non omni.jar case:
    1478             :   // - $app/defaults/preferences/*.js
    1479             :   // When $app == $gre, we additionally load, in omni.jar case:
    1480             :   // - jar:$gre/omni.jar!/defaults/preferences/*.js
    1481             :   // Thus, in omni.jar case, we always load app-specific default preferences
    1482             :   // from omni.jar, whether or not $app == $gre.
    1483             : 
    1484             :   nsZipFind *findPtr;
    1485           6 :   nsAutoPtr<nsZipFind> find;
    1486           6 :   nsTArray<nsCString> prefEntries;
    1487             :   const char *entryName;
    1488             :   uint16_t entryNameLen;
    1489             : 
    1490           6 :   RefPtr<nsZipArchive> jarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
    1491           3 :   if (jarReader) {
    1492             :     // Load jar:$gre/omni.jar!/greprefs.js
    1493           0 :     rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
    1494           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1495             : 
    1496             :     // Load jar:$gre/omni.jar!/defaults/pref/*.js
    1497           0 :     rv = jarReader->FindInit("defaults/pref/*.js$", &findPtr);
    1498           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1499             : 
    1500           0 :     find = findPtr;
    1501           0 :     while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
    1502           0 :       prefEntries.AppendElement(Substring(entryName, entryNameLen));
    1503             :     }
    1504             : 
    1505           0 :     prefEntries.Sort();
    1506           0 :     for (uint32_t i = prefEntries.Length(); i--; ) {
    1507           0 :       rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get());
    1508           0 :       if (NS_FAILED(rv))
    1509           0 :         NS_WARNING("Error parsing preferences.");
    1510             :     }
    1511             :   } else {
    1512             :     // Load $gre/greprefs.js
    1513           6 :     nsCOMPtr<nsIFile> greprefsFile;
    1514           3 :     rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greprefsFile));
    1515           3 :     NS_ENSURE_SUCCESS(rv, rv);
    1516             : 
    1517           3 :     rv = greprefsFile->AppendNative(NS_LITERAL_CSTRING("greprefs.js"));
    1518           3 :     NS_ENSURE_SUCCESS(rv, rv);
    1519             : 
    1520           3 :     rv = openPrefFile(greprefsFile);
    1521           3 :     if (NS_FAILED(rv))
    1522           0 :       NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?");
    1523             :   }
    1524             : 
    1525             :   // Load $gre/defaults/pref/*.js
    1526           6 :   nsCOMPtr<nsIFile> defaultPrefDir;
    1527             : 
    1528           3 :   rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(defaultPrefDir));
    1529           3 :   NS_ENSURE_SUCCESS(rv, rv);
    1530             : 
    1531             :   /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
    1532             :   static const char* specialFiles[] = {
    1533             : #if defined(XP_MACOSX)
    1534             :     "macprefs.js"
    1535             : #elif defined(XP_WIN)
    1536             :     "winpref.js"
    1537             : #elif defined(XP_UNIX)
    1538             :     "unix.js"
    1539             : #if defined(_AIX)
    1540             :     , "aix.js"
    1541             : #endif
    1542             : #elif defined(XP_BEOS)
    1543             :     "beos.js"
    1544             : #endif
    1545             :   };
    1546             : 
    1547           3 :   rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles));
    1548           3 :   if (NS_FAILED(rv))
    1549           0 :     NS_WARNING("Error parsing application default preferences.");
    1550             : 
    1551             :   // Load jar:$app/omni.jar!/defaults/preferences/*.js
    1552             :   // or jar:$gre/omni.jar!/defaults/preferences/*.js.
    1553           6 :   RefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
    1554             :   // GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
    1555             :   // case we look for app-specific default preferences in $gre.
    1556           3 :   if (!appJarReader)
    1557           3 :     appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
    1558           3 :   if (appJarReader) {
    1559           0 :     rv = appJarReader->FindInit("defaults/preferences/*.js$", &findPtr);
    1560           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1561           0 :     find = findPtr;
    1562           0 :     prefEntries.Clear();
    1563           0 :     while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
    1564           0 :       prefEntries.AppendElement(Substring(entryName, entryNameLen));
    1565             :     }
    1566           0 :     prefEntries.Sort();
    1567           0 :     for (uint32_t i = prefEntries.Length(); i--; ) {
    1568           0 :       rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get());
    1569           0 :       if (NS_FAILED(rv))
    1570           0 :         NS_WARNING("Error parsing preferences.");
    1571             :     }
    1572             :   }
    1573             : 
    1574           3 :   rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST);
    1575           3 :   NS_ENSURE_SUCCESS(rv, rv);
    1576             : 
    1577             :   // Set up the correct default for toolkit.telemetry.enabled.
    1578             :   // If this build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta
    1579             :   // channel, telemetry is on by default, otherwise not. This is necessary
    1580             :   // so that beta users who are testing final release builds don't flipflop
    1581             :   // defaults.
    1582           3 :   if (Preferences::GetDefaultType(kTelemetryPref) == nsIPrefBranch::PREF_INVALID) {
    1583           3 :     bool prerelease = false;
    1584             : #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
    1585             :     prerelease = true;
    1586             : #else
    1587           3 :     if (Preferences::GetDefaultCString(kChannelPref).EqualsLiteral("beta")) {
    1588           0 :       prerelease = true;
    1589             :     }
    1590             : #endif
    1591           3 :     PREF_SetBoolPref(kTelemetryPref, prerelease, true);
    1592             :   }
    1593             : 
    1594             :   NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID,
    1595           3 :                                 nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID);
    1596             : 
    1597             :   nsCOMPtr<nsIObserverService> observerService =
    1598           6 :     mozilla::services::GetObserverService();
    1599           3 :   if (!observerService)
    1600           0 :     return NS_ERROR_FAILURE;
    1601             : 
    1602           3 :   observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nullptr);
    1603             : 
    1604           3 :   return pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
    1605             : }
    1606             : 
    1607             : 
    1608             : /******************************************************************************
    1609             :  *
    1610             :  * static utilities
    1611             :  *
    1612             :  ******************************************************************************/
    1613             : 
    1614             : // static
    1615             : nsresult
    1616        3668 : Preferences::GetBool(const char* aPref, bool* aResult)
    1617             : {
    1618        3668 :   NS_PRECONDITION(aResult, "aResult must not be NULL");
    1619        3668 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1620        3668 :   return PREF_GetBoolPref(aPref, aResult, false);
    1621             : }
    1622             : 
    1623             : // static
    1624             : nsresult
    1625        1516 : Preferences::GetInt(const char* aPref, int32_t* aResult)
    1626             : {
    1627        1516 :   NS_PRECONDITION(aResult, "aResult must not be NULL");
    1628        1516 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1629        1516 :   return PREF_GetIntPref(aPref, aResult, false);
    1630             : }
    1631             : 
    1632             : // static
    1633             : nsresult
    1634         142 : Preferences::GetFloat(const char* aPref, float* aResult)
    1635             : {
    1636         142 :   NS_PRECONDITION(aResult, "aResult must not be NULL");
    1637         142 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1638         284 :   nsAutoCString result;
    1639         142 :   nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
    1640         142 :   if (NS_SUCCEEDED(rv)) {
    1641         126 :     *aResult = result.ToFloat(&rv);
    1642             :   }
    1643             : 
    1644         142 :   return rv;
    1645             : }
    1646             : 
    1647             : // static
    1648             : nsAdoptingCString
    1649         219 : Preferences::GetCString(const char* aPref)
    1650             : {
    1651         219 :   nsAdoptingCString result;
    1652         219 :   PREF_CopyCharPref(aPref, getter_Copies(result), false);
    1653         219 :   return result;
    1654             : }
    1655             : 
    1656             : // static
    1657             : nsAdoptingString
    1658         197 : Preferences::GetString(const char* aPref)
    1659             : {
    1660         197 :   nsAdoptingString result;
    1661         197 :   GetString(aPref, &result);
    1662         197 :   return result;
    1663             : }
    1664             : 
    1665             : // static
    1666             : nsresult
    1667          35 : Preferences::GetCString(const char* aPref, nsACString* aResult)
    1668             : {
    1669          35 :   NS_PRECONDITION(aResult, "aResult must not be NULL");
    1670          35 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1671          70 :   nsAutoCString result;
    1672          35 :   nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
    1673          35 :   if (NS_SUCCEEDED(rv)) {
    1674          35 :     *aResult = result;
    1675             :   }
    1676          35 :   return rv;
    1677             : }
    1678             : 
    1679             : // static
    1680             : nsresult
    1681         388 : Preferences::GetString(const char* aPref, nsAString* aResult)
    1682             : {
    1683         388 :   NS_PRECONDITION(aResult, "aResult must not be NULL");
    1684         388 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1685         776 :   nsAutoCString result;
    1686         388 :   nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
    1687         388 :   if (NS_SUCCEEDED(rv)) {
    1688         186 :     CopyUTF8toUTF16(result, *aResult);
    1689             :   }
    1690         388 :   return rv;
    1691             : }
    1692             : 
    1693             : // static
    1694             : nsAdoptingCString
    1695           5 : Preferences::GetLocalizedCString(const char* aPref)
    1696             : {
    1697           5 :   nsAdoptingCString result;
    1698           5 :   GetLocalizedCString(aPref, &result);
    1699           5 :   return result;
    1700             : }
    1701             : 
    1702             : // static
    1703             : nsAdoptingString
    1704           4 : Preferences::GetLocalizedString(const char* aPref)
    1705             : {
    1706           4 :   nsAdoptingString result;
    1707           4 :   GetLocalizedString(aPref, &result);
    1708           4 :   return result;
    1709             : }
    1710             : 
    1711             : // static
    1712             : nsresult
    1713           5 : Preferences::GetLocalizedCString(const char* aPref, nsACString* aResult)
    1714             : {
    1715           5 :   NS_PRECONDITION(aResult, "aResult must not be NULL");
    1716          10 :   nsAutoString result;
    1717           5 :   nsresult rv = GetLocalizedString(aPref, &result);
    1718           5 :   if (NS_SUCCEEDED(rv)) {
    1719           5 :     CopyUTF16toUTF8(result, *aResult);
    1720             :   }
    1721          10 :   return rv;
    1722             : }
    1723             : 
    1724             : // static
    1725             : nsresult
    1726           9 : Preferences::GetLocalizedString(const char* aPref, nsAString* aResult)
    1727             : {
    1728           9 :   NS_PRECONDITION(aResult, "aResult must not be NULL");
    1729           9 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1730          18 :   nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
    1731          18 :   nsresult rv = sRootBranch->GetComplexValue(aPref,
    1732             :                                              NS_GET_IID(nsIPrefLocalizedString),
    1733          18 :                                              getter_AddRefs(prefLocalString));
    1734           9 :   if (NS_SUCCEEDED(rv)) {
    1735           9 :     NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
    1736           9 :     prefLocalString->GetData(getter_Copies(*aResult));
    1737             :   }
    1738           9 :   return rv;
    1739             : }
    1740             : 
    1741             : // static
    1742             : nsresult
    1743           1 : Preferences::GetComplex(const char* aPref, const nsIID &aType, void** aResult)
    1744             : {
    1745           1 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1746           1 :   return sRootBranch->GetComplexValue(aPref, aType, aResult);
    1747             : }
    1748             : 
    1749             : // static
    1750             : nsresult
    1751           0 : Preferences::SetCString(const char* aPref, const char* aValue)
    1752             : {
    1753           0 :   ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
    1754           0 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1755           0 :   return PREF_SetCharPref(aPref, aValue, false);
    1756             : }
    1757             : 
    1758             : // static
    1759             : nsresult
    1760           0 : Preferences::SetCString(const char* aPref, const nsACString &aValue)
    1761             : {
    1762           0 :   ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
    1763           0 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1764           0 :   return PREF_SetCharPref(aPref, PromiseFlatCString(aValue).get(), false);
    1765             : }
    1766             : 
    1767             : // static
    1768             : nsresult
    1769           0 : Preferences::SetString(const char* aPref, const char16ptr_t aValue)
    1770             : {
    1771           0 :   ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
    1772           0 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1773           0 :   return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
    1774             : }
    1775             : 
    1776             : // static
    1777             : nsresult
    1778           0 : Preferences::SetString(const char* aPref, const nsAString &aValue)
    1779             : {
    1780           0 :   ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
    1781           0 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1782           0 :   return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
    1783             : }
    1784             : 
    1785             : // static
    1786             : nsresult
    1787           1 : Preferences::SetBool(const char* aPref, bool aValue)
    1788             : {
    1789           1 :   ENSURE_MAIN_PROCESS("Cannot SetBool from content process:", aPref);
    1790           1 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1791           1 :   return PREF_SetBoolPref(aPref, aValue, false);
    1792             : }
    1793             : 
    1794             : // static
    1795             : nsresult
    1796           1 : Preferences::SetInt(const char* aPref, int32_t aValue)
    1797             : {
    1798           1 :   ENSURE_MAIN_PROCESS("Cannot SetInt from content process:", aPref);
    1799           1 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1800           1 :   return PREF_SetIntPref(aPref, aValue, false);
    1801             : }
    1802             : 
    1803             : // static
    1804             : nsresult
    1805           0 : Preferences::SetFloat(const char* aPref, float aValue)
    1806             : {
    1807           0 :   return SetCString(aPref, nsPrintfCString("%f", aValue).get());
    1808             : }
    1809             : 
    1810             : // static
    1811             : nsresult
    1812           0 : Preferences::SetComplex(const char* aPref, const nsIID &aType,
    1813             :                         nsISupports* aValue)
    1814             : {
    1815           0 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1816           0 :   return sRootBranch->SetComplexValue(aPref, aType, aValue);
    1817             : }
    1818             : 
    1819             : // static
    1820             : nsresult
    1821           1 : Preferences::ClearUser(const char* aPref)
    1822             : {
    1823           1 :   ENSURE_MAIN_PROCESS("Cannot ClearUser from content process:", aPref);
    1824           1 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1825           1 :   return PREF_ClearUserPref(aPref);
    1826             : }
    1827             : 
    1828             : // static
    1829             : bool
    1830          21 : Preferences::HasUserValue(const char* aPref)
    1831             : {
    1832          21 :   NS_ENSURE_TRUE(InitStaticMembers(), false);
    1833          21 :   return PREF_HasUserPref(aPref);
    1834             : }
    1835             : 
    1836             : // static
    1837             : int32_t
    1838         484 : Preferences::GetType(const char* aPref)
    1839             : {
    1840         484 :   NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
    1841             :   int32_t result;
    1842         484 :   return NS_SUCCEEDED(sRootBranch->GetPrefType(aPref, &result)) ?
    1843         484 :     result : nsIPrefBranch::PREF_INVALID;
    1844             : }
    1845             : 
    1846             : // static
    1847             : nsresult
    1848         623 : Preferences::AddStrongObserver(nsIObserver* aObserver,
    1849             :                                const char* aPref)
    1850             : {
    1851         623 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1852         623 :   return sRootBranch->AddObserver(aPref, aObserver, false);
    1853             : }
    1854             : 
    1855             : // static
    1856             : nsresult
    1857          40 : Preferences::AddWeakObserver(nsIObserver* aObserver,
    1858             :                              const char* aPref)
    1859             : {
    1860          40 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1861          40 :   return sRootBranch->AddObserver(aPref, aObserver, true);
    1862             : }
    1863             : 
    1864             : // static
    1865             : nsresult
    1866           3 : Preferences::RemoveObserver(nsIObserver* aObserver,
    1867             :                             const char* aPref)
    1868             : {
    1869           3 :   if (!sPreferences && sShutdown) {
    1870           0 :     return NS_OK; // Observers have been released automatically.
    1871             :   }
    1872           3 :   NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
    1873           3 :   return sRootBranch->RemoveObserver(aPref, aObserver);
    1874             : }
    1875             : 
    1876             : // static
    1877             : nsresult
    1878          16 : Preferences::AddStrongObservers(nsIObserver* aObserver,
    1879             :                                 const char** aPrefs)
    1880             : {
    1881          58 :   for (uint32_t i = 0; aPrefs[i]; i++) {
    1882          42 :     nsresult rv = AddStrongObserver(aObserver, aPrefs[i]);
    1883          42 :     NS_ENSURE_SUCCESS(rv, rv);
    1884             :   }
    1885          16 :   return NS_OK;
    1886             : }
    1887             : 
    1888             : // static
    1889             : nsresult
    1890           4 : Preferences::AddWeakObservers(nsIObserver* aObserver,
    1891             :                               const char** aPrefs)
    1892             : {
    1893          39 :   for (uint32_t i = 0; aPrefs[i]; i++) {
    1894          35 :     nsresult rv = AddWeakObserver(aObserver, aPrefs[i]);
    1895          35 :     NS_ENSURE_SUCCESS(rv, rv);
    1896             :   }
    1897           4 :   return NS_OK;
    1898             : }
    1899             : 
    1900             : // static
    1901             : nsresult
    1902           0 : Preferences::RemoveObservers(nsIObserver* aObserver,
    1903             :                              const char** aPrefs)
    1904             : {
    1905           0 :   if (!sPreferences && sShutdown) {
    1906           0 :     return NS_OK; // Observers have been released automatically.
    1907             :   }
    1908           0 :   NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
    1909             : 
    1910           0 :   for (uint32_t i = 0; aPrefs[i]; i++) {
    1911           0 :     nsresult rv = RemoveObserver(aObserver, aPrefs[i]);
    1912           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1913             :   }
    1914           0 :   return NS_OK;
    1915             : }
    1916             : 
    1917          10 : static void NotifyObserver(const char* aPref, void* aClosure)
    1918             : {
    1919          20 :   nsCOMPtr<nsIObserver> observer = static_cast<nsIObserver*>(aClosure);
    1920          20 :   observer->Observe(nullptr, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID,
    1921          20 :                     NS_ConvertASCIItoUTF16(aPref).get());
    1922          10 : }
    1923             : 
    1924        2014 : static void RegisterPriorityCallback(PrefChangedFunc aCallback,
    1925             :                                      const char* aPref,
    1926             :                                      void* aClosure)
    1927             : {
    1928        2014 :   MOZ_ASSERT(Preferences::IsServiceAvailable());
    1929             : 
    1930        3620 :   ValueObserverHashKey hashKey(aPref, aCallback, Preferences::ExactMatch);
    1931        3620 :   RefPtr<ValueObserver> observer;
    1932        2014 :   gObserverTable->Get(&hashKey, getter_AddRefs(observer));
    1933        2014 :   if (observer) {
    1934         408 :     observer->AppendClosure(aClosure);
    1935         408 :     return;
    1936             :   }
    1937             : 
    1938        1606 :   observer = new ValueObserver(aPref, aCallback, Preferences::ExactMatch);
    1939        1606 :   observer->AppendClosure(aClosure);
    1940             :   PREF_RegisterPriorityCallback(aPref, NotifyObserver,
    1941        1606 :                                 static_cast<nsIObserver*>(observer));
    1942        1606 :   gObserverTable->Put(observer, observer);
    1943             : }
    1944             : 
    1945             : // static
    1946             : nsresult
    1947         943 : Preferences::RegisterCallback(PrefChangedFunc aCallback,
    1948             :                               const char* aPref,
    1949             :                               void* aClosure,
    1950             :                               MatchKind aMatchKind)
    1951             : {
    1952         943 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    1953             : 
    1954        1886 :   ValueObserverHashKey hashKey(aPref, aCallback, aMatchKind);
    1955        1886 :   RefPtr<ValueObserver> observer;
    1956         943 :   gObserverTable->Get(&hashKey, getter_AddRefs(observer));
    1957         943 :   if (observer) {
    1958         444 :     observer->AppendClosure(aClosure);
    1959         444 :     return NS_OK;
    1960             :   }
    1961             : 
    1962         499 :   observer = new ValueObserver(aPref, aCallback, aMatchKind);
    1963         499 :   observer->AppendClosure(aClosure);
    1964         499 :   nsresult rv = AddStrongObserver(observer, aPref);
    1965         499 :   NS_ENSURE_SUCCESS(rv, rv);
    1966         499 :   gObserverTable->Put(observer, observer);
    1967         499 :   return NS_OK;
    1968             : }
    1969             : 
    1970             : // static
    1971             : nsresult
    1972         110 : Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback,
    1973             :                                      const char* aPref,
    1974             :                                      void* aClosure,
    1975             :                                      MatchKind aMatchKind)
    1976             : {
    1977         220 :   WATCHING_PREF_RAII();
    1978         110 :   nsresult rv = RegisterCallback(aCallback, aPref, aClosure, aMatchKind);
    1979         110 :   if (NS_SUCCEEDED(rv)) {
    1980         110 :     (*aCallback)(aPref, aClosure);
    1981             :   }
    1982         220 :   return rv;
    1983             : }
    1984             : 
    1985             : // static
    1986             : nsresult
    1987           0 : Preferences::UnregisterCallback(PrefChangedFunc aCallback,
    1988             :                                 const char* aPref,
    1989             :                                 void* aClosure,
    1990             :                                 MatchKind aMatchKind)
    1991             : {
    1992           0 :   if (!sPreferences && sShutdown) {
    1993           0 :     return NS_OK; // Observers have been released automatically.
    1994             :   }
    1995           0 :   NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
    1996             : 
    1997           0 :   ValueObserverHashKey hashKey(aPref, aCallback, aMatchKind);
    1998           0 :   RefPtr<ValueObserver> observer;
    1999           0 :   gObserverTable->Get(&hashKey, getter_AddRefs(observer));
    2000           0 :   if (!observer) {
    2001           0 :     return NS_OK;
    2002             :   }
    2003             : 
    2004           0 :   observer->RemoveClosure(aClosure);
    2005           0 :   if (observer->HasNoClosures()) {
    2006             :     // Delete the callback since its list of closures is empty.
    2007           0 :     gObserverTable->Remove(observer);
    2008             :   }
    2009           0 :   return NS_OK;
    2010             : }
    2011             : 
    2012             : // We insert cache observers using RegisterPriorityCallback to ensure they
    2013             : // are called prior to ordinary pref observers.  Doing this ensures that
    2014             : // ordinary observers will never get stale values from cache variables.
    2015             : 
    2016          10 : static void BoolVarChanged(const char* aPref, void* aClosure)
    2017             : {
    2018          10 :   CacheData* cache = static_cast<CacheData*>(aClosure);
    2019          20 :   *((bool*)cache->cacheLocation) =
    2020          10 :     Preferences::GetBool(aPref, cache->defaultValueBool);
    2021          10 : }
    2022             : 
    2023             : // static
    2024             : nsresult
    2025        1371 : Preferences::AddBoolVarCache(bool* aCache,
    2026             :                              const char* aPref,
    2027             :                              bool aDefault)
    2028             : {
    2029        2742 :   WATCHING_PREF_RAII();
    2030        1371 :   NS_ASSERTION(aCache, "aCache must not be NULL");
    2031             : #ifdef DEBUG
    2032        1371 :   AssertNotAlreadyCached("bool", aPref, aCache);
    2033             : #endif
    2034        1371 :   *aCache = GetBool(aPref, aDefault);
    2035        1371 :   CacheData* data = new CacheData();
    2036        1371 :   data->cacheLocation = aCache;
    2037        1371 :   data->defaultValueBool = aDefault;
    2038        1371 :   gCacheData->AppendElement(data);
    2039        1371 :   RegisterPriorityCallback(BoolVarChanged, aPref, data);
    2040        2742 :   return NS_OK;
    2041             : }
    2042             : 
    2043           0 : static void IntVarChanged(const char* aPref, void* aClosure)
    2044             : {
    2045           0 :   CacheData* cache = static_cast<CacheData*>(aClosure);
    2046           0 :   *((int32_t*)cache->cacheLocation) =
    2047           0 :     Preferences::GetInt(aPref, cache->defaultValueInt);
    2048           0 : }
    2049             : 
    2050             : // static
    2051             : nsresult
    2052         344 : Preferences::AddIntVarCache(int32_t* aCache,
    2053             :                             const char* aPref,
    2054             :                             int32_t aDefault)
    2055             : {
    2056         688 :   WATCHING_PREF_RAII();
    2057         344 :   NS_ASSERTION(aCache, "aCache must not be NULL");
    2058             : #ifdef DEBUG
    2059         344 :   AssertNotAlreadyCached("int", aPref, aCache);
    2060             : #endif
    2061         344 :   *aCache = Preferences::GetInt(aPref, aDefault);
    2062         344 :   CacheData* data = new CacheData();
    2063         344 :   data->cacheLocation = aCache;
    2064         344 :   data->defaultValueInt = aDefault;
    2065         344 :   gCacheData->AppendElement(data);
    2066         344 :   RegisterPriorityCallback(IntVarChanged, aPref, data);
    2067         688 :   return NS_OK;
    2068             : }
    2069             : 
    2070           0 : static void UintVarChanged(const char* aPref, void* aClosure)
    2071             : {
    2072           0 :   CacheData* cache = static_cast<CacheData*>(aClosure);
    2073           0 :   *((uint32_t*)cache->cacheLocation) =
    2074           0 :     Preferences::GetUint(aPref, cache->defaultValueUint);
    2075           0 : }
    2076             : 
    2077             : // static
    2078             : nsresult
    2079         165 : Preferences::AddUintVarCache(uint32_t* aCache,
    2080             :                              const char* aPref,
    2081             :                              uint32_t aDefault)
    2082             : {
    2083         330 :   WATCHING_PREF_RAII();
    2084         165 :   NS_ASSERTION(aCache, "aCache must not be NULL");
    2085             : #ifdef DEBUG
    2086         165 :   AssertNotAlreadyCached("uint", aPref, aCache);
    2087             : #endif
    2088         165 :   *aCache = Preferences::GetUint(aPref, aDefault);
    2089         165 :   CacheData* data = new CacheData();
    2090         165 :   data->cacheLocation = aCache;
    2091         165 :   data->defaultValueUint = aDefault;
    2092         165 :   gCacheData->AppendElement(data);
    2093         165 :   RegisterPriorityCallback(UintVarChanged, aPref, data);
    2094         330 :   return NS_OK;
    2095             : }
    2096             : 
    2097             : template <MemoryOrdering Order>
    2098           0 : static void AtomicUintVarChanged(const char* aPref, void* aClosure)
    2099             : {
    2100           0 :   CacheData* cache = static_cast<CacheData*>(aClosure);
    2101           0 :   *((Atomic<uint32_t, Order>*)cache->cacheLocation) =
    2102             :     Preferences::GetUint(aPref, cache->defaultValueUint);
    2103           0 : }
    2104             : 
    2105             : template <MemoryOrdering Order>
    2106             : // static
    2107             : nsresult
    2108           5 : Preferences::AddAtomicUintVarCache(Atomic<uint32_t, Order>* aCache,
    2109             :                                    const char* aPref,
    2110             :                                    uint32_t aDefault)
    2111             : {
    2112          10 :   WATCHING_PREF_RAII();
    2113           5 :   NS_ASSERTION(aCache, "aCache must not be NULL");
    2114             : #ifdef DEBUG
    2115           5 :   AssertNotAlreadyCached("uint", aPref, aCache);
    2116             : #endif
    2117           5 :   *aCache = Preferences::GetUint(aPref, aDefault);
    2118           5 :   CacheData* data = new CacheData();
    2119           5 :   data->cacheLocation = aCache;
    2120           5 :   data->defaultValueUint = aDefault;
    2121           5 :   gCacheData->AppendElement(data);
    2122           5 :   RegisterPriorityCallback(AtomicUintVarChanged<Order>, aPref, data);
    2123          10 :   return NS_OK;
    2124             : }
    2125             : 
    2126             : // Since the definition of this template function is not in a header file,
    2127             : // we need to explicitly specify the instantiations that are required.
    2128             : // Currently only the order=Relaxed variant is needed.
    2129             : template
    2130             : nsresult Preferences::AddAtomicUintVarCache(Atomic<uint32_t,Relaxed>*,
    2131             :                                             const char*, uint32_t);
    2132             : 
    2133           0 : static void FloatVarChanged(const char* aPref, void* aClosure)
    2134             : {
    2135           0 :   CacheData* cache = static_cast<CacheData*>(aClosure);
    2136           0 :   *((float*)cache->cacheLocation) =
    2137           0 :     Preferences::GetFloat(aPref, cache->defaultValueFloat);
    2138           0 : }
    2139             : 
    2140             : // static
    2141             : nsresult
    2142         129 : Preferences::AddFloatVarCache(float* aCache,
    2143             :                              const char* aPref,
    2144             :                              float aDefault)
    2145             : {
    2146         258 :   WATCHING_PREF_RAII();
    2147         129 :   NS_ASSERTION(aCache, "aCache must not be NULL");
    2148             : #ifdef DEBUG
    2149         129 :   AssertNotAlreadyCached("float", aPref, aCache);
    2150             : #endif
    2151         129 :   *aCache = Preferences::GetFloat(aPref, aDefault);
    2152         129 :   CacheData* data = new CacheData();
    2153         129 :   data->cacheLocation = aCache;
    2154         129 :   data->defaultValueFloat = aDefault;
    2155         129 :   gCacheData->AppendElement(data);
    2156         129 :   RegisterPriorityCallback(FloatVarChanged, aPref, data);
    2157         258 :   return NS_OK;
    2158             : }
    2159             : 
    2160             : // static
    2161             : nsresult
    2162           0 : Preferences::GetDefaultBool(const char* aPref, bool* aResult)
    2163             : {
    2164           0 :   NS_PRECONDITION(aResult, "aResult must not be NULL");
    2165           0 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    2166           0 :   return PREF_GetBoolPref(aPref, aResult, true);
    2167             : }
    2168             : 
    2169             : // static
    2170             : nsresult
    2171           4 : Preferences::GetDefaultInt(const char* aPref, int32_t* aResult)
    2172             : {
    2173           4 :   NS_PRECONDITION(aResult, "aResult must not be NULL");
    2174           4 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    2175           4 :   return PREF_GetIntPref(aPref, aResult, true);
    2176             : }
    2177             : 
    2178             : // static
    2179             : nsresult
    2180           0 : Preferences::GetDefaultCString(const char* aPref, nsACString* aResult)
    2181             : {
    2182           0 :   NS_PRECONDITION(aResult, "aResult must not be NULL");
    2183           0 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    2184           0 :   nsAutoCString result;
    2185           0 :   nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
    2186           0 :   if (NS_SUCCEEDED(rv)) {
    2187           0 :     *aResult = result;
    2188             :   }
    2189           0 :   return rv;
    2190             : }
    2191             : 
    2192             : // static
    2193             : nsresult
    2194           0 : Preferences::GetDefaultString(const char* aPref, nsAString* aResult)
    2195             : {
    2196           0 :   NS_PRECONDITION(aResult, "aResult must not be NULL");
    2197           0 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    2198           0 :   nsAutoCString result;
    2199           0 :   nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
    2200           0 :   if (NS_SUCCEEDED(rv)) {
    2201           0 :     CopyUTF8toUTF16(result, *aResult);
    2202             :   }
    2203           0 :   return rv;
    2204             : }
    2205             : 
    2206             : // static
    2207             : nsresult
    2208           0 : Preferences::GetDefaultLocalizedCString(const char* aPref,
    2209             :                                         nsACString* aResult)
    2210             : {
    2211           0 :   nsAutoString result;
    2212           0 :   nsresult rv = GetDefaultLocalizedString(aPref, &result);
    2213           0 :   if (NS_SUCCEEDED(rv)) {
    2214           0 :     CopyUTF16toUTF8(result, *aResult);
    2215             :   }
    2216           0 :   return rv;
    2217             : }
    2218             : 
    2219             : // static
    2220             : nsresult
    2221           0 : Preferences::GetDefaultLocalizedString(const char* aPref,
    2222             :                                        nsAString* aResult)
    2223             : {
    2224           0 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    2225           0 :   nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
    2226             :   nsresult rv =
    2227           0 :     sDefaultRootBranch->GetComplexValue(aPref,
    2228             :                                         NS_GET_IID(nsIPrefLocalizedString),
    2229           0 :                                         getter_AddRefs(prefLocalString));
    2230           0 :   if (NS_SUCCEEDED(rv)) {
    2231           0 :     NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
    2232           0 :     prefLocalString->GetData(getter_Copies(*aResult));
    2233             :   }
    2234           0 :   return rv;
    2235             : }
    2236             : 
    2237             : // static
    2238             : nsAdoptingString
    2239           0 : Preferences::GetDefaultString(const char* aPref)
    2240             : {
    2241           0 :   nsAdoptingString result;
    2242           0 :   GetDefaultString(aPref, &result);
    2243           0 :   return result;
    2244             : }
    2245             : 
    2246             : // static
    2247             : nsAdoptingCString
    2248           3 : Preferences::GetDefaultCString(const char* aPref)
    2249             : {
    2250           3 :   nsAdoptingCString result;
    2251           3 :   PREF_CopyCharPref(aPref, getter_Copies(result), true);
    2252           3 :   return result;
    2253             : }
    2254             : 
    2255             : // static
    2256             : nsAdoptingString
    2257           0 : Preferences::GetDefaultLocalizedString(const char* aPref)
    2258             : {
    2259           0 :   nsAdoptingString result;
    2260           0 :   GetDefaultLocalizedString(aPref, &result);
    2261           0 :   return result;
    2262             : }
    2263             : 
    2264             : // static
    2265             : nsAdoptingCString
    2266           0 : Preferences::GetDefaultLocalizedCString(const char* aPref)
    2267             : {
    2268           0 :   nsAdoptingCString result;
    2269           0 :   GetDefaultLocalizedCString(aPref, &result);
    2270           0 :   return result;
    2271             : }
    2272             : 
    2273             : // static
    2274             : nsresult
    2275           0 : Preferences::GetDefaultComplex(const char* aPref, const nsIID &aType,
    2276             :                                void** aResult)
    2277             : {
    2278           0 :   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
    2279           0 :   return sDefaultRootBranch->GetComplexValue(aPref, aType, aResult);
    2280             : }
    2281             : 
    2282             : // static
    2283             : int32_t
    2284           3 : Preferences::GetDefaultType(const char* aPref)
    2285             : {
    2286           3 :   NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
    2287             :   int32_t result;
    2288           3 :   return NS_SUCCEEDED(sDefaultRootBranch->GetPrefType(aPref, &result)) ?
    2289           3 :     result : nsIPrefBranch::PREF_INVALID;
    2290             : }
    2291             : 
    2292             : } // namespace mozilla
    2293             : 
    2294             : #undef ENSURE_MAIN_PROCESS

Generated by: LCOV version 1.13