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
|