modules/libpref/src/Preferences.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:95f0452c04c7
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/ContentChild.h"
9
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/HashFunctions.h"
13
14 #include "nsXULAppAPI.h"
15
16 #include "mozilla/Preferences.h"
17 #include "nsAppDirectoryServiceDefs.h"
18 #include "nsDataHashtable.h"
19 #include "nsDirectoryServiceDefs.h"
20 #include "nsICategoryManager.h"
21 #include "nsCategoryManagerUtils.h"
22 #include "nsNetUtil.h"
23 #include "nsIFile.h"
24 #include "nsIInputStream.h"
25 #include "nsIObserverService.h"
26 #include "nsIStringEnumerator.h"
27 #include "nsIZipReader.h"
28 #include "nsPrefBranch.h"
29 #include "nsXPIDLString.h"
30 #include "nsCRT.h"
31 #include "nsCOMArray.h"
32 #include "nsXPCOMCID.h"
33 #include "nsAutoPtr.h"
34 #include "nsPrintfCString.h"
35
36 #include "nsQuickSort.h"
37 #include "pldhash.h"
38
39 #include "prefapi.h"
40 #include "prefread.h"
41 #include "prefapi_private_data.h"
42
43 #include "mozilla/Omnijar.h"
44 #include "nsZipArchive.h"
45
46 #include "nsTArray.h"
47 #include "nsRefPtrHashtable.h"
48 #include "nsIMemoryReporter.h"
49 #include "nsThreadUtils.h"
50
51 #ifdef DEBUG
52 #define ENSURE_MAIN_PROCESS(message, pref) do { \
53 if (MOZ_UNLIKELY(XRE_GetProcessType() != GeckoProcessType_Default)) { \
54 nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref); \
55 NS_WARNING(msg.get()); \
56 return NS_ERROR_NOT_AVAILABLE; \
57 } \
58 } while (0);
59 #else
60 #define ENSURE_MAIN_PROCESS(message, pref) \
61 if (MOZ_UNLIKELY(XRE_GetProcessType() != GeckoProcessType_Default)) { \
62 return NS_ERROR_NOT_AVAILABLE; \
63 }
64 #endif
65
66 class PrefCallback;
67
68 namespace mozilla {
69
70 // Definitions
71 #define INITIAL_PREF_FILES 10
72 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
73
74 // Prototypes
75 static nsresult openPrefFile(nsIFile* aFile);
76 static nsresult pref_InitInitialObjects(void);
77 static nsresult pref_LoadPrefsInDirList(const char *listId);
78 static nsresult ReadExtensionPrefs(nsIFile *aFile);
79
80 static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
81 static const char kOldTelemetryPref[] = "toolkit.telemetry.enabledPreRelease";
82 static const char kChannelPref[] = "app.update.channel";
83
84 Preferences* Preferences::sPreferences = nullptr;
85 nsIPrefBranch* Preferences::sRootBranch = nullptr;
86 nsIPrefBranch* Preferences::sDefaultRootBranch = nullptr;
87 bool Preferences::sShutdown = false;
88
89 class ValueObserverHashKey : public PLDHashEntryHdr {
90 public:
91 typedef ValueObserverHashKey* KeyType;
92 typedef const ValueObserverHashKey* KeyTypePointer;
93
94 static const ValueObserverHashKey* KeyToPointer(ValueObserverHashKey *aKey)
95 {
96 return aKey;
97 }
98
99 static PLDHashNumber HashKey(const ValueObserverHashKey *aKey)
100 {
101 PLDHashNumber hash = HashString(aKey->mPrefName);
102 return AddToHash(hash, aKey->mCallback);
103 }
104
105 ValueObserverHashKey(const char *aPref, PrefChangedFunc aCallback) :
106 mPrefName(aPref), mCallback(aCallback) { }
107
108 ValueObserverHashKey(const ValueObserverHashKey *aOther) :
109 mPrefName(aOther->mPrefName), mCallback(aOther->mCallback)
110 { }
111
112 bool KeyEquals(const ValueObserverHashKey *aOther) const
113 {
114 return mCallback == aOther->mCallback && mPrefName == aOther->mPrefName;
115 }
116
117 ValueObserverHashKey *GetKey() const
118 {
119 return const_cast<ValueObserverHashKey*>(this);
120 }
121
122 enum { ALLOW_MEMMOVE = true };
123
124 nsCString mPrefName;
125 PrefChangedFunc mCallback;
126 };
127
128 class ValueObserver MOZ_FINAL : public nsIObserver,
129 public ValueObserverHashKey
130 {
131 public:
132 NS_DECL_ISUPPORTS
133 NS_DECL_NSIOBSERVER
134
135 ValueObserver(const char *aPref, PrefChangedFunc aCallback)
136 : ValueObserverHashKey(aPref, aCallback) { }
137
138 ~ValueObserver() {
139 Preferences::RemoveObserver(this, mPrefName.get());
140 }
141
142 void AppendClosure(void *aClosure) {
143 mClosures.AppendElement(aClosure);
144 }
145
146 void RemoveClosure(void *aClosure) {
147 mClosures.RemoveElement(aClosure);
148 }
149
150 bool HasNoClosures() {
151 return mClosures.Length() == 0;
152 }
153
154 nsTArray<void*> mClosures;
155 };
156
157 NS_IMPL_ISUPPORTS(ValueObserver, nsIObserver)
158
159 NS_IMETHODIMP
160 ValueObserver::Observe(nsISupports *aSubject,
161 const char *aTopic,
162 const char16_t *aData)
163 {
164 NS_ASSERTION(!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
165 "invalid topic");
166 NS_ConvertUTF16toUTF8 data(aData);
167 for (uint32_t i = 0; i < mClosures.Length(); i++) {
168 mCallback(data.get(), mClosures.ElementAt(i));
169 }
170
171 return NS_OK;
172 }
173
174 struct CacheData {
175 void* cacheLocation;
176 union {
177 bool defaultValueBool;
178 int32_t defaultValueInt;
179 uint32_t defaultValueUint;
180 float defaultValueFloat;
181 };
182 };
183
184 static nsTArray<nsAutoPtr<CacheData> >* gCacheData = nullptr;
185 static nsRefPtrHashtable<ValueObserverHashKey,
186 ValueObserver>* gObserverTable = nullptr;
187
188 static size_t
189 SizeOfObserverEntryExcludingThis(ValueObserverHashKey* aKey,
190 const nsRefPtr<ValueObserver>& aData,
191 mozilla::MallocSizeOf aMallocSizeOf,
192 void*)
193 {
194 size_t n = 0;
195 n += aKey->mPrefName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
196 n += aData->mClosures.SizeOfExcludingThis(aMallocSizeOf);
197 return n;
198 }
199
200 // Although this is a member of Preferences, it measures sPreferences and
201 // several other global structures.
202 /* static */ int64_t
203 Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf)
204 {
205 NS_ENSURE_TRUE(InitStaticMembers(), 0);
206
207 size_t n = aMallocSizeOf(sPreferences);
208 if (gHashTable.ops) {
209 // pref keys are allocated in a private arena, which we count elsewhere.
210 // pref stringvals are allocated out of the same private arena.
211 n += PL_DHashTableSizeOfExcludingThis(&gHashTable, nullptr, aMallocSizeOf);
212 }
213 if (gCacheData) {
214 n += gCacheData->SizeOfIncludingThis(aMallocSizeOf);
215 for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
216 n += aMallocSizeOf((*gCacheData)[i]);
217 }
218 }
219 if (gObserverTable) {
220 n += aMallocSizeOf(gObserverTable);
221 n += gObserverTable->SizeOfExcludingThis(SizeOfObserverEntryExcludingThis,
222 aMallocSizeOf);
223 }
224 // We don't measure sRootBranch and sDefaultRootBranch here because
225 // DMD indicates they are not significant.
226 n += pref_SizeOfPrivateData(aMallocSizeOf);
227 return n;
228 }
229
230 class PreferenceServiceReporter MOZ_FINAL : public nsIMemoryReporter
231 {
232 public:
233 NS_DECL_ISUPPORTS
234 NS_DECL_NSIMEMORYREPORTER
235
236 protected:
237 static const uint32_t kSuspectReferentCount = 1000;
238 static PLDHashOperator CountReferents(PrefCallback* aKey,
239 nsAutoPtr<PrefCallback>& aCallback,
240 void* aClosure);
241 };
242
243 NS_IMPL_ISUPPORTS(PreferenceServiceReporter, nsIMemoryReporter)
244
245 struct PreferencesReferentCount {
246 PreferencesReferentCount() : numStrong(0), numWeakAlive(0), numWeakDead(0) {}
247 size_t numStrong;
248 size_t numWeakAlive;
249 size_t numWeakDead;
250 nsTArray<nsCString> suspectPreferences;
251 // Count of the number of referents for each preference.
252 nsDataHashtable<nsCStringHashKey, uint32_t> prefCounter;
253 };
254
255 PLDHashOperator
256 PreferenceServiceReporter::CountReferents(PrefCallback* aKey,
257 nsAutoPtr<PrefCallback>& aCallback,
258 void* aClosure)
259 {
260 PreferencesReferentCount* referentCount =
261 static_cast<PreferencesReferentCount*>(aClosure);
262
263 nsPrefBranch* prefBranch = aCallback->GetPrefBranch();
264 const char* pref = prefBranch->getPrefName(aCallback->GetDomain().get());
265
266 if (aCallback->IsWeak()) {
267 nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(aCallback->mWeakRef);
268 if (callbackRef) {
269 referentCount->numWeakAlive++;
270 } else {
271 referentCount->numWeakDead++;
272 }
273 } else {
274 referentCount->numStrong++;
275 }
276
277 nsDependentCString prefString(pref);
278 uint32_t oldCount = 0;
279 referentCount->prefCounter.Get(prefString, &oldCount);
280 uint32_t currentCount = oldCount + 1;
281 referentCount->prefCounter.Put(prefString, currentCount);
282
283 // Keep track of preferences that have a suspiciously large
284 // number of referents (symptom of leak).
285 if (currentCount == kSuspectReferentCount) {
286 referentCount->suspectPreferences.AppendElement(prefString);
287 }
288
289 return PL_DHASH_NEXT;
290 }
291
292 MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)
293
294 NS_IMETHODIMP
295 PreferenceServiceReporter::CollectReports(nsIMemoryReporterCallback* aCb,
296 nsISupports* aClosure)
297 {
298 #define REPORT(_path, _kind, _units, _amount, _desc) \
299 do { \
300 nsresult rv; \
301 rv = aCb->Callback(EmptyCString(), _path, _kind, \
302 _units, _amount, NS_LITERAL_CSTRING(_desc), \
303 aClosure); \
304 NS_ENSURE_SUCCESS(rv, rv); \
305 } while (0)
306
307 REPORT(NS_LITERAL_CSTRING("explicit/preferences"),
308 KIND_HEAP, UNITS_BYTES,
309 Preferences::SizeOfIncludingThisAndOtherStuff(PreferenceServiceMallocSizeOf),
310 "Memory used by the preferences system.");
311
312 nsPrefBranch* rootBranch =
313 static_cast<nsPrefBranch*>(Preferences::GetRootBranch());
314 if (!rootBranch) {
315 return NS_OK;
316 }
317
318 PreferencesReferentCount referentCount;
319 rootBranch->mObservers.Enumerate(&CountReferents, &referentCount);
320
321 for (uint32_t i = 0; i < referentCount.suspectPreferences.Length(); i++) {
322 nsCString& suspect = referentCount.suspectPreferences[i];
323 uint32_t totalReferentCount = 0;
324 referentCount.prefCounter.Get(suspect, &totalReferentCount);
325
326 nsPrintfCString suspectPath("preference-service-suspect/"
327 "referent(pref=%s)", suspect.get());
328
329 REPORT(suspectPath,
330 KIND_OTHER, UNITS_COUNT, totalReferentCount,
331 "A preference with a suspiciously large number "
332 "referents (symptom of a leak).");
333 }
334
335 REPORT(NS_LITERAL_CSTRING("preference-service/referent/strong"),
336 KIND_OTHER, UNITS_COUNT, referentCount.numStrong,
337 "The number of strong referents held by the preference service.");
338
339 REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/alive"),
340 KIND_OTHER, UNITS_COUNT, referentCount.numWeakAlive,
341 "The number of weak referents held by the preference service "
342 "that are still alive.");
343
344 REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/dead"),
345 KIND_OTHER, UNITS_COUNT, referentCount.numWeakDead,
346 "The number of weak referents held by the preference service "
347 "that are dead.");
348
349 #undef REPORT
350
351 return NS_OK;
352 }
353
354 namespace {
355 class AddPreferencesMemoryReporterRunnable : public nsRunnable
356 {
357 NS_IMETHOD Run()
358 {
359 return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
360 }
361 };
362 } // anonymous namespace
363
364 // static
365 Preferences*
366 Preferences::GetInstanceForService()
367 {
368 if (sPreferences) {
369 NS_ADDREF(sPreferences);
370 return sPreferences;
371 }
372
373 NS_ENSURE_TRUE(!sShutdown, nullptr);
374
375 sRootBranch = new nsPrefBranch("", false);
376 NS_ADDREF(sRootBranch);
377 sDefaultRootBranch = new nsPrefBranch("", true);
378 NS_ADDREF(sDefaultRootBranch);
379
380 sPreferences = new Preferences();
381 NS_ADDREF(sPreferences);
382
383 if (NS_FAILED(sPreferences->Init())) {
384 // The singleton instance will delete sRootBranch and sDefaultRootBranch.
385 NS_RELEASE(sPreferences);
386 return nullptr;
387 }
388
389 gCacheData = new nsTArray<nsAutoPtr<CacheData> >();
390
391 gObserverTable = new nsRefPtrHashtable<ValueObserverHashKey, ValueObserver>();
392
393 // Preferences::GetInstanceForService() can be called from GetService(), and
394 // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To
395 // avoid a potential recursive GetService() call, we can't register the
396 // memory reporter here; instead, do it off a runnable.
397 nsRefPtr<AddPreferencesMemoryReporterRunnable> runnable =
398 new AddPreferencesMemoryReporterRunnable();
399 NS_DispatchToMainThread(runnable);
400
401 NS_ADDREF(sPreferences);
402 return sPreferences;
403 }
404
405 // static
406 bool
407 Preferences::InitStaticMembers()
408 {
409 #ifndef MOZ_B2G
410 MOZ_ASSERT(NS_IsMainThread());
411 #endif
412
413 if (!sShutdown && !sPreferences) {
414 nsCOMPtr<nsIPrefService> prefService =
415 do_GetService(NS_PREFSERVICE_CONTRACTID);
416 }
417
418 return sPreferences != nullptr;
419 }
420
421 // static
422 void
423 Preferences::Shutdown()
424 {
425 if (!sShutdown) {
426 sShutdown = true; // Don't create the singleton instance after here.
427
428 // Don't set sPreferences to nullptr here. The instance may be grabbed by
429 // other modules. The utility methods of Preferences should be available
430 // until the singleton instance actually released.
431 if (sPreferences) {
432 sPreferences->Release();
433 }
434 }
435 }
436
437 //-----------------------------------------------------------------------------
438
439 /*
440 * Constructor/Destructor
441 */
442
443 Preferences::Preferences()
444 {
445 }
446
447 Preferences::~Preferences()
448 {
449 NS_ASSERTION(sPreferences == this, "Isn't this the singleton instance?");
450
451 delete gObserverTable;
452 gObserverTable = nullptr;
453
454 delete gCacheData;
455 gCacheData = nullptr;
456
457 NS_RELEASE(sRootBranch);
458 NS_RELEASE(sDefaultRootBranch);
459
460 sPreferences = nullptr;
461
462 PREF_Cleanup();
463 }
464
465
466 /*
467 * nsISupports Implementation
468 */
469
470 NS_IMPL_ADDREF(Preferences)
471 NS_IMPL_RELEASE(Preferences)
472
473 NS_INTERFACE_MAP_BEGIN(Preferences)
474 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefService)
475 NS_INTERFACE_MAP_ENTRY(nsIPrefService)
476 NS_INTERFACE_MAP_ENTRY(nsIObserver)
477 NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
478 NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2)
479 NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)
480 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
481 NS_INTERFACE_MAP_END
482
483
484 /*
485 * nsIPrefService Implementation
486 */
487
488 nsresult
489 Preferences::Init()
490 {
491 nsresult rv;
492
493 rv = PREF_Init();
494 NS_ENSURE_SUCCESS(rv, rv);
495
496 rv = pref_InitInitialObjects();
497 NS_ENSURE_SUCCESS(rv, rv);
498
499 using mozilla::dom::ContentChild;
500 if (XRE_GetProcessType() == GeckoProcessType_Content) {
501 InfallibleTArray<PrefSetting> prefs;
502 ContentChild::GetSingleton()->SendReadPrefsArray(&prefs);
503
504 // Store the array
505 for (uint32_t i = 0; i < prefs.Length(); ++i) {
506 pref_SetPref(prefs[i]);
507 }
508 return NS_OK;
509 }
510
511 nsXPIDLCString lockFileName;
512 /*
513 * The following is a small hack which will allow us to only load the library
514 * which supports the netscape.cfg file if the preference is defined. We
515 * test for the existence of the pref, set in the all.js (mozilla) or
516 * all-ns.js (netscape 6), and if it exists we startup the pref config
517 * category which will do the rest.
518 */
519
520 rv = PREF_CopyCharPref("general.config.filename", getter_Copies(lockFileName), false);
521 if (NS_SUCCEEDED(rv))
522 NS_CreateServicesFromCategory("pref-config-startup",
523 static_cast<nsISupports *>(static_cast<void *>(this)),
524 "pref-config-startup");
525
526 nsCOMPtr<nsIObserverService> observerService =
527 mozilla::services::GetObserverService();
528 if (!observerService)
529 return NS_ERROR_FAILURE;
530
531 rv = observerService->AddObserver(this, "profile-before-change", true);
532
533 observerService->AddObserver(this, "load-extension-defaults", true);
534 observerService->AddObserver(this, "suspend_process_notification", true);
535
536 return(rv);
537 }
538
539 // static
540 nsresult
541 Preferences::ResetAndReadUserPrefs()
542 {
543 sPreferences->ResetUserPrefs();
544 return sPreferences->ReadUserPrefs(nullptr);
545 }
546
547 NS_IMETHODIMP
548 Preferences::Observe(nsISupports *aSubject, const char *aTopic,
549 const char16_t *someData)
550 {
551 if (XRE_GetProcessType() == GeckoProcessType_Content)
552 return NS_ERROR_NOT_AVAILABLE;
553
554 nsresult rv = NS_OK;
555
556 if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
557 if (!nsCRT::strcmp(someData, MOZ_UTF16("shutdown-cleanse"))) {
558 if (mCurrentFile) {
559 mCurrentFile->Remove(false);
560 mCurrentFile = nullptr;
561 }
562 } else {
563 rv = SavePrefFile(nullptr);
564 }
565 } else if (!strcmp(aTopic, "load-extension-defaults")) {
566 pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
567 } else if (!nsCRT::strcmp(aTopic, "reload-default-prefs")) {
568 // Reload the default prefs from file.
569 pref_InitInitialObjects();
570 } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) {
571 // Our process is being suspended. The OS may wake our process later,
572 // or it may kill the process. In case our process is going to be killed
573 // from the suspended state, we save preferences before suspending.
574 rv = SavePrefFile(nullptr);
575 }
576 return rv;
577 }
578
579
580 NS_IMETHODIMP
581 Preferences::ReadUserPrefs(nsIFile *aFile)
582 {
583 if (XRE_GetProcessType() == GeckoProcessType_Content) {
584 NS_ERROR("cannot load prefs from content process");
585 return NS_ERROR_NOT_AVAILABLE;
586 }
587
588 nsresult rv;
589
590 if (nullptr == aFile) {
591 rv = UseDefaultPrefFile();
592 // A user pref file is optional.
593 // Ignore all errors related to it, so we retain 'rv' value :-|
594 (void) UseUserPrefFile();
595
596 // Migrate the old prerelease telemetry pref
597 if (!Preferences::GetBool(kOldTelemetryPref, true)) {
598 Preferences::SetBool(kTelemetryPref, false);
599 Preferences::ClearUser(kOldTelemetryPref);
600 }
601
602 NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);
603 } else {
604 rv = ReadAndOwnUserPrefFile(aFile);
605 }
606
607 return rv;
608 }
609
610 NS_IMETHODIMP
611 Preferences::ResetPrefs()
612 {
613 if (XRE_GetProcessType() == GeckoProcessType_Content) {
614 NS_ERROR("cannot reset prefs from content process");
615 return NS_ERROR_NOT_AVAILABLE;
616 }
617
618 NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
619 PREF_CleanupPrefs();
620
621 nsresult rv = PREF_Init();
622 NS_ENSURE_SUCCESS(rv, rv);
623
624 return pref_InitInitialObjects();
625 }
626
627 NS_IMETHODIMP
628 Preferences::ResetUserPrefs()
629 {
630 if (XRE_GetProcessType() == GeckoProcessType_Content) {
631 NS_ERROR("cannot reset user prefs from content process");
632 return NS_ERROR_NOT_AVAILABLE;
633 }
634
635 PREF_ClearAllUserPrefs();
636 return NS_OK;
637 }
638
639 NS_IMETHODIMP
640 Preferences::SavePrefFile(nsIFile *aFile)
641 {
642 if (XRE_GetProcessType() == GeckoProcessType_Content) {
643 NS_ERROR("cannot save pref file from content process");
644 return NS_ERROR_NOT_AVAILABLE;
645 }
646
647 return SavePrefFileInternal(aFile);
648 }
649
650 static nsresult
651 ReadExtensionPrefs(nsIFile *aFile)
652 {
653 nsresult rv;
654 nsCOMPtr<nsIZipReader> reader = do_CreateInstance(kZipReaderCID, &rv);
655 NS_ENSURE_SUCCESS(rv, rv);
656
657 rv = reader->Open(aFile);
658 NS_ENSURE_SUCCESS(rv, rv);
659
660 nsCOMPtr<nsIUTF8StringEnumerator> files;
661 rv = reader->FindEntries(nsDependentCString("defaults/preferences/*.(J|j)(S|s)$"),
662 getter_AddRefs(files));
663 NS_ENSURE_SUCCESS(rv, rv);
664
665 char buffer[4096];
666
667 bool more;
668 while (NS_SUCCEEDED(rv = files->HasMore(&more)) && more) {
669 nsAutoCString entry;
670 rv = files->GetNext(entry);
671 NS_ENSURE_SUCCESS(rv, rv);
672
673 nsCOMPtr<nsIInputStream> stream;
674 rv = reader->GetInputStream(entry, getter_AddRefs(stream));
675 NS_ENSURE_SUCCESS(rv, rv);
676
677 uint64_t avail;
678 uint32_t read;
679
680 PrefParseState ps;
681 PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
682 while (NS_SUCCEEDED(rv = stream->Available(&avail)) && avail) {
683 rv = stream->Read(buffer, 4096, &read);
684 if (NS_FAILED(rv)) {
685 NS_WARNING("Pref stream read failed");
686 break;
687 }
688
689 PREF_ParseBuf(&ps, buffer, read);
690 }
691 PREF_FinalizeParseState(&ps);
692 }
693 return rv;
694 }
695
696 void
697 Preferences::SetPreference(const PrefSetting& aPref)
698 {
699 pref_SetPref(aPref);
700 }
701
702 void
703 Preferences::GetPreference(PrefSetting* aPref)
704 {
705 PrefHashEntry *entry = pref_HashTableLookup(aPref->name().get());
706 if (!entry)
707 return;
708
709 pref_GetPrefFromEntry(entry, aPref);
710 }
711
712 void
713 Preferences::GetPreferences(InfallibleTArray<PrefSetting>* aPrefs)
714 {
715 aPrefs->SetCapacity(PL_DHASH_TABLE_SIZE(&gHashTable));
716 PL_DHashTableEnumerate(&gHashTable, pref_GetPrefs, aPrefs);
717 }
718
719 NS_IMETHODIMP
720 Preferences::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
721 {
722 nsresult rv;
723
724 if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) {
725 // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
726 nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, false);
727 if (!prefBranch)
728 return NS_ERROR_OUT_OF_MEMORY;
729
730 rv = CallQueryInterface(prefBranch, _retval);
731 } else {
732 // special case caching the default root
733 nsCOMPtr<nsIPrefBranch> root(sRootBranch);
734 root.forget(_retval);
735 rv = NS_OK;
736 }
737 return rv;
738 }
739
740 NS_IMETHODIMP
741 Preferences::GetDefaultBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
742 {
743 if (!aPrefRoot || !aPrefRoot[0]) {
744 nsCOMPtr<nsIPrefBranch> root(sDefaultRootBranch);
745 root.forget(_retval);
746 return NS_OK;
747 }
748
749 // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
750 nsRefPtr<nsPrefBranch> prefBranch = new nsPrefBranch(aPrefRoot, true);
751 if (!prefBranch)
752 return NS_ERROR_OUT_OF_MEMORY;
753
754 prefBranch.forget(_retval);
755 return NS_OK;
756 }
757
758
759 nsresult
760 Preferences::NotifyServiceObservers(const char *aTopic)
761 {
762 nsCOMPtr<nsIObserverService> observerService =
763 mozilla::services::GetObserverService();
764 if (!observerService)
765 return NS_ERROR_FAILURE;
766
767 nsISupports *subject = (nsISupports *)((nsIPrefService *)this);
768 observerService->NotifyObservers(subject, aTopic, nullptr);
769
770 return NS_OK;
771 }
772
773 nsresult
774 Preferences::UseDefaultPrefFile()
775 {
776 nsresult rv;
777 nsCOMPtr<nsIFile> aFile;
778
779 #if defined(XP_WIN) && defined(MOZ_METRO)
780 if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
781 rv = NS_GetSpecialDirectory(NS_METRO_APP_PREFS_50_FILE, getter_AddRefs(aFile));
782 } else
783 #endif
784 {
785 rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE, getter_AddRefs(aFile));
786 }
787
788 if (NS_SUCCEEDED(rv)) {
789 rv = ReadAndOwnUserPrefFile(aFile);
790 // Most likely cause of failure here is that the file didn't
791 // exist, so save a new one. mUserPrefReadFailed will be
792 // used to catch an error in actually reading the file.
793 if (NS_FAILED(rv)) {
794 if (NS_FAILED(SavePrefFileInternal(aFile)))
795 NS_ERROR("Failed to save new shared pref file");
796 else
797 rv = NS_OK;
798 }
799 }
800
801 return rv;
802 }
803
804 nsresult
805 Preferences::UseUserPrefFile()
806 {
807 nsresult rv = NS_OK;
808 nsCOMPtr<nsIFile> aFile;
809 nsDependentCString prefsDirProp(NS_APP_PREFS_50_DIR);
810
811 rv = NS_GetSpecialDirectory(prefsDirProp.get(), getter_AddRefs(aFile));
812 if (NS_SUCCEEDED(rv) && aFile) {
813 rv = aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
814 if (NS_SUCCEEDED(rv)) {
815 bool exists = false;
816 aFile->Exists(&exists);
817 if (exists) {
818 rv = openPrefFile(aFile);
819 } else {
820 rv = NS_ERROR_FILE_NOT_FOUND;
821 }
822 }
823 }
824 return rv;
825 }
826
827 nsresult
828 Preferences::MakeBackupPrefFile(nsIFile *aFile)
829 {
830 // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.
831 // "Invalidprefs.js" is removed if it exists, prior to making the copy.
832 nsAutoString newFilename;
833 nsresult rv = aFile->GetLeafName(newFilename);
834 NS_ENSURE_SUCCESS(rv, rv);
835 newFilename.Insert(NS_LITERAL_STRING("Invalid"), 0);
836 nsCOMPtr<nsIFile> newFile;
837 rv = aFile->GetParent(getter_AddRefs(newFile));
838 NS_ENSURE_SUCCESS(rv, rv);
839 rv = newFile->Append(newFilename);
840 NS_ENSURE_SUCCESS(rv, rv);
841 bool exists = false;
842 newFile->Exists(&exists);
843 if (exists) {
844 rv = newFile->Remove(false);
845 NS_ENSURE_SUCCESS(rv, rv);
846 }
847 rv = aFile->CopyTo(nullptr, newFilename);
848 NS_ENSURE_SUCCESS(rv, rv);
849 return rv;
850 }
851
852 nsresult
853 Preferences::ReadAndOwnUserPrefFile(nsIFile *aFile)
854 {
855 NS_ENSURE_ARG(aFile);
856
857 if (mCurrentFile == aFile)
858 return NS_OK;
859 mCurrentFile = aFile;
860
861 nsresult rv = NS_OK;
862 bool exists = false;
863 mCurrentFile->Exists(&exists);
864 if (exists) {
865 rv = openPrefFile(mCurrentFile);
866 if (NS_FAILED(rv)) {
867 // Save a backup copy of the current (invalid) prefs file, since all prefs
868 // from the error line to the end of the file will be lost (bug 361102).
869 // TODO we should notify the user about it (bug 523725).
870 MakeBackupPrefFile(mCurrentFile);
871 }
872 } else {
873 rv = NS_ERROR_FILE_NOT_FOUND;
874 }
875
876 return rv;
877 }
878
879 nsresult
880 Preferences::SavePrefFileInternal(nsIFile *aFile)
881 {
882 if (nullptr == aFile) {
883 // the gDirty flag tells us if we should write to mCurrentFile
884 // we only check this flag when the caller wants to write to the default
885 if (!gDirty)
886 return NS_OK;
887
888 // It's possible that we never got a prefs file.
889 nsresult rv = NS_OK;
890 if (mCurrentFile)
891 rv = WritePrefFile(mCurrentFile);
892
893 return rv;
894 } else {
895 return WritePrefFile(aFile);
896 }
897 }
898
899 nsresult
900 Preferences::WritePrefFile(nsIFile* aFile)
901 {
902 const char outHeader[] =
903 "# Mozilla User Preferences"
904 NS_LINEBREAK
905 NS_LINEBREAK
906 "/* Do not edit this file."
907 NS_LINEBREAK
908 " *"
909 NS_LINEBREAK
910 " * If you make changes to this file while the application is running,"
911 NS_LINEBREAK
912 " * the changes will be overwritten when the application exits."
913 NS_LINEBREAK
914 " *"
915 NS_LINEBREAK
916 " * To make a manual change to preferences, you can visit the URL about:config"
917 NS_LINEBREAK
918 " */"
919 NS_LINEBREAK
920 NS_LINEBREAK;
921
922 nsCOMPtr<nsIOutputStream> outStreamSink;
923 nsCOMPtr<nsIOutputStream> outStream;
924 uint32_t writeAmount;
925 nsresult rv;
926
927 if (!gHashTable.ops)
928 return NS_ERROR_NOT_INITIALIZED;
929
930 // execute a "safe" save by saving through a tempfile
931 rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink),
932 aFile,
933 -1,
934 0600);
935 if (NS_FAILED(rv))
936 return rv;
937 rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096);
938 if (NS_FAILED(rv))
939 return rv;
940
941 nsAutoArrayPtr<char*> valueArray(new char*[gHashTable.entryCount]);
942 memset(valueArray, 0, gHashTable.entryCount * sizeof(char*));
943 pref_saveArgs saveArgs;
944 saveArgs.prefArray = valueArray;
945 saveArgs.saveTypes = SAVE_ALL;
946
947 // get the lines that we're supposed to be writing to the file
948 PL_DHashTableEnumerate(&gHashTable, pref_savePref, &saveArgs);
949
950 /* Sort the preferences to make a readable file on disk */
951 NS_QuickSort(valueArray, gHashTable.entryCount, sizeof(char *), pref_CompareStrings, nullptr);
952
953 // write out the file header
954 outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount);
955
956 char** walker = valueArray;
957 for (uint32_t valueIdx = 0; valueIdx < gHashTable.entryCount; valueIdx++, walker++) {
958 if (*walker) {
959 outStream->Write(*walker, strlen(*walker), &writeAmount);
960 outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
961 NS_Free(*walker);
962 }
963 }
964
965 // tell the safe output stream to overwrite the real prefs file
966 // (it'll abort if there were any errors during writing)
967 nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
968 NS_ASSERTION(safeStream, "expected a safe output stream!");
969 if (safeStream) {
970 rv = safeStream->Finish();
971 if (NS_FAILED(rv)) {
972 NS_WARNING("failed to save prefs file! possible data loss");
973 return rv;
974 }
975 }
976
977 gDirty = false;
978 return NS_OK;
979 }
980
981 static nsresult openPrefFile(nsIFile* aFile)
982 {
983 nsCOMPtr<nsIInputStream> inStr;
984
985 nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile);
986 if (NS_FAILED(rv))
987 return rv;
988
989 uint64_t fileSize64;
990 rv = inStr->Available(&fileSize64);
991 if (NS_FAILED(rv))
992 return rv;
993 NS_ENSURE_TRUE(fileSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
994
995 uint32_t fileSize = (uint32_t)fileSize64;
996 nsAutoArrayPtr<char> fileBuffer(new char[fileSize]);
997 if (fileBuffer == nullptr)
998 return NS_ERROR_OUT_OF_MEMORY;
999
1000 PrefParseState ps;
1001 PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
1002
1003 // Read is not guaranteed to return a buf the size of fileSize,
1004 // but usually will.
1005 nsresult rv2 = NS_OK;
1006 for (;;) {
1007 uint32_t amtRead = 0;
1008 rv = inStr->Read((char*)fileBuffer, fileSize, &amtRead);
1009 if (NS_FAILED(rv) || amtRead == 0)
1010 break;
1011 if (!PREF_ParseBuf(&ps, fileBuffer, amtRead))
1012 rv2 = NS_ERROR_FILE_CORRUPTED;
1013 }
1014
1015 PREF_FinalizeParseState(&ps);
1016
1017 return NS_FAILED(rv) ? rv : rv2;
1018 }
1019
1020 /*
1021 * some stuff that gets called from Pref_Init()
1022 */
1023
1024 static int
1025 pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2, void* /*unused*/)
1026 {
1027 nsAutoCString filename1, filename2;
1028 aFile1->GetNativeLeafName(filename1);
1029 aFile2->GetNativeLeafName(filename2);
1030
1031 return Compare(filename2, filename1);
1032 }
1033
1034 /**
1035 * Load default pref files from a directory. The files in the
1036 * directory are sorted reverse-alphabetically; a set of "special file
1037 * names" may be specified which are loaded after all the others.
1038 */
1039 static nsresult
1040 pref_LoadPrefsInDir(nsIFile* aDir, char const *const *aSpecialFiles, uint32_t aSpecialFilesCount)
1041 {
1042 nsresult rv, rv2;
1043 bool hasMoreElements;
1044
1045 nsCOMPtr<nsISimpleEnumerator> dirIterator;
1046
1047 // this may fail in some normal cases, such as embedders who do not use a GRE
1048 rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
1049 if (NS_FAILED(rv)) {
1050 // If the directory doesn't exist, then we have no reason to complain. We
1051 // loaded everything (and nothing) successfully.
1052 if (rv == NS_ERROR_FILE_NOT_FOUND || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
1053 rv = NS_OK;
1054 return rv;
1055 }
1056
1057 rv = dirIterator->HasMoreElements(&hasMoreElements);
1058 NS_ENSURE_SUCCESS(rv, rv);
1059
1060 nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES);
1061 nsCOMArray<nsIFile> specialFiles(aSpecialFilesCount);
1062 nsCOMPtr<nsIFile> prefFile;
1063
1064 while (hasMoreElements && NS_SUCCEEDED(rv)) {
1065 nsAutoCString leafName;
1066
1067 nsCOMPtr<nsISupports> supports;
1068 rv = dirIterator->GetNext(getter_AddRefs(supports));
1069 prefFile = do_QueryInterface(supports);
1070 if (NS_FAILED(rv)) {
1071 break;
1072 }
1073
1074 prefFile->GetNativeLeafName(leafName);
1075 NS_ASSERTION(!leafName.IsEmpty(), "Failure in default prefs: directory enumerator returned empty file?");
1076
1077 // Skip non-js files
1078 if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".js"),
1079 nsCaseInsensitiveCStringComparator())) {
1080 bool shouldParse = true;
1081 // separate out special files
1082 for (uint32_t i = 0; i < aSpecialFilesCount; ++i) {
1083 if (leafName.Equals(nsDependentCString(aSpecialFiles[i]))) {
1084 shouldParse = false;
1085 // special files should be process in order; we put them into
1086 // the array by index; this can make the array sparse
1087 specialFiles.ReplaceObjectAt(prefFile, i);
1088 }
1089 }
1090
1091 if (shouldParse) {
1092 prefFiles.AppendObject(prefFile);
1093 }
1094 }
1095
1096 rv = dirIterator->HasMoreElements(&hasMoreElements);
1097 }
1098
1099 if (prefFiles.Count() + specialFiles.Count() == 0) {
1100 NS_WARNING("No default pref files found.");
1101 if (NS_SUCCEEDED(rv)) {
1102 rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY;
1103 }
1104 return rv;
1105 }
1106
1107 prefFiles.Sort(pref_CompareFileNames, nullptr);
1108
1109 uint32_t arrayCount = prefFiles.Count();
1110 uint32_t i;
1111 for (i = 0; i < arrayCount; ++i) {
1112 rv2 = openPrefFile(prefFiles[i]);
1113 if (NS_FAILED(rv2)) {
1114 NS_ERROR("Default pref file not parsed successfully.");
1115 rv = rv2;
1116 }
1117 }
1118
1119 arrayCount = specialFiles.Count();
1120 for (i = 0; i < arrayCount; ++i) {
1121 // this may be a sparse array; test before parsing
1122 nsIFile* file = specialFiles[i];
1123 if (file) {
1124 rv2 = openPrefFile(file);
1125 if (NS_FAILED(rv2)) {
1126 NS_ERROR("Special default pref file not parsed successfully.");
1127 rv = rv2;
1128 }
1129 }
1130 }
1131
1132 return rv;
1133 }
1134
1135 static nsresult pref_LoadPrefsInDirList(const char *listId)
1136 {
1137 nsresult rv;
1138 nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
1139 if (NS_FAILED(rv))
1140 return rv;
1141
1142 nsCOMPtr<nsISimpleEnumerator> list;
1143 dirSvc->Get(listId,
1144 NS_GET_IID(nsISimpleEnumerator),
1145 getter_AddRefs(list));
1146 if (!list)
1147 return NS_OK;
1148
1149 bool hasMore;
1150 while (NS_SUCCEEDED(list->HasMoreElements(&hasMore)) && hasMore) {
1151 nsCOMPtr<nsISupports> elem;
1152 list->GetNext(getter_AddRefs(elem));
1153 if (!elem)
1154 continue;
1155
1156 nsCOMPtr<nsIFile> path = do_QueryInterface(elem);
1157 if (!path)
1158 continue;
1159
1160 nsAutoCString leaf;
1161 path->GetNativeLeafName(leaf);
1162
1163 // Do we care if a file provided by this process fails to load?
1164 if (Substring(leaf, leaf.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi")))
1165 ReadExtensionPrefs(path);
1166 else
1167 pref_LoadPrefsInDir(path, nullptr, 0);
1168 }
1169 return NS_OK;
1170 }
1171
1172 static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
1173 {
1174 nsZipItemPtr<char> manifest(jarReader, name, true);
1175 NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
1176
1177 PrefParseState ps;
1178 PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
1179 PREF_ParseBuf(&ps, manifest, manifest.Length());
1180 PREF_FinalizeParseState(&ps);
1181
1182 return NS_OK;
1183 }
1184
1185 //----------------------------------------------------------------------------------------
1186 // Initialize default preference JavaScript buffers from
1187 // appropriate TEXT resources
1188 //----------------------------------------------------------------------------------------
1189 static nsresult pref_InitInitialObjects()
1190 {
1191 nsresult rv;
1192
1193 // In omni.jar case, we load the following prefs:
1194 // - jar:$gre/omni.jar!/greprefs.js
1195 // - jar:$gre/omni.jar!/defaults/pref/*.js
1196 // In non omni.jar case, we load:
1197 // - $gre/greprefs.js
1198 //
1199 // In both cases, we also load:
1200 // - $gre/defaults/pref/*.js
1201 // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar)
1202 // on $app == $gre case ; we load all files instead of channel-prefs.js only
1203 // to have the same behaviour as $app != $gre, where this is required as
1204 // a supported location for GRE preferences.
1205 //
1206 // When $app != $gre, we additionally load, in omni.jar case:
1207 // - jar:$app/omni.jar!/defaults/preferences/*.js
1208 // - $app/defaults/preferences/*.js
1209 // and in non omni.jar case:
1210 // - $app/defaults/preferences/*.js
1211 // When $app == $gre, we additionally load, in omni.jar case:
1212 // - jar:$gre/omni.jar!/defaults/preferences/*.js
1213 // Thus, in omni.jar case, we always load app-specific default preferences
1214 // from omni.jar, whether or not $app == $gre.
1215
1216 nsZipFind *findPtr;
1217 nsAutoPtr<nsZipFind> find;
1218 nsTArray<nsCString> prefEntries;
1219 const char *entryName;
1220 uint16_t entryNameLen;
1221
1222 nsRefPtr<nsZipArchive> jarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
1223 if (jarReader) {
1224 // Load jar:$gre/omni.jar!/greprefs.js
1225 rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
1226 NS_ENSURE_SUCCESS(rv, rv);
1227
1228 // Load jar:$gre/omni.jar!/defaults/pref/*.js
1229 rv = jarReader->FindInit("defaults/pref/*.js$", &findPtr);
1230 NS_ENSURE_SUCCESS(rv, rv);
1231
1232 find = findPtr;
1233 while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
1234 prefEntries.AppendElement(Substring(entryName, entryNameLen));
1235 }
1236
1237 prefEntries.Sort();
1238 for (uint32_t i = prefEntries.Length(); i--; ) {
1239 rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get());
1240 if (NS_FAILED(rv))
1241 NS_WARNING("Error parsing preferences.");
1242 }
1243 } else {
1244 // Load $gre/greprefs.js
1245 nsCOMPtr<nsIFile> greprefsFile;
1246 rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greprefsFile));
1247 NS_ENSURE_SUCCESS(rv, rv);
1248
1249 rv = greprefsFile->AppendNative(NS_LITERAL_CSTRING("greprefs.js"));
1250 NS_ENSURE_SUCCESS(rv, rv);
1251
1252 rv = openPrefFile(greprefsFile);
1253 if (NS_FAILED(rv))
1254 NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?");
1255 }
1256
1257 // Load $gre/defaults/pref/*.js
1258 nsCOMPtr<nsIFile> defaultPrefDir;
1259
1260 rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(defaultPrefDir));
1261 NS_ENSURE_SUCCESS(rv, rv);
1262
1263 /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
1264 static const char* specialFiles[] = {
1265 #if defined(XP_MACOSX)
1266 "macprefs.js"
1267 #elif defined(XP_WIN)
1268 "winpref.js"
1269 #elif defined(XP_UNIX)
1270 "unix.js"
1271 #if defined(VMS)
1272 , "openvms.js"
1273 #elif defined(_AIX)
1274 , "aix.js"
1275 #endif
1276 #elif defined(XP_BEOS)
1277 "beos.js"
1278 #endif
1279 };
1280
1281 rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles));
1282 if (NS_FAILED(rv))
1283 NS_WARNING("Error parsing application default preferences.");
1284
1285 // Load jar:$app/omni.jar!/defaults/preferences/*.js
1286 // or jar:$gre/omni.jar!/defaults/preferences/*.js.
1287 nsRefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
1288 // GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
1289 // case we look for app-specific default preferences in $gre.
1290 if (!appJarReader)
1291 appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
1292 if (appJarReader) {
1293 rv = appJarReader->FindInit("defaults/preferences/*.js$", &findPtr);
1294 NS_ENSURE_SUCCESS(rv, rv);
1295 find = findPtr;
1296 prefEntries.Clear();
1297 while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
1298 prefEntries.AppendElement(Substring(entryName, entryNameLen));
1299 }
1300 prefEntries.Sort();
1301 for (uint32_t i = prefEntries.Length(); i--; ) {
1302 rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get());
1303 if (NS_FAILED(rv))
1304 NS_WARNING("Error parsing preferences.");
1305 }
1306 }
1307
1308 rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST);
1309 NS_ENSURE_SUCCESS(rv, rv);
1310
1311 // Set up the correct default for toolkit.telemetry.enabled.
1312 // If this build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta
1313 // channel, telemetry is on by default, otherwise not. This is necessary
1314 // so that beta users who are testing final release builds don't flipflop
1315 // defaults.
1316 if (Preferences::GetDefaultType(kTelemetryPref) == PREF_INVALID) {
1317 bool prerelease = false;
1318 #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
1319 prerelease = true;
1320 #else
1321 if (Preferences::GetDefaultCString(kChannelPref).EqualsLiteral("beta")) {
1322 prerelease = true;
1323 }
1324 #endif
1325 PREF_SetBoolPref(kTelemetryPref, prerelease, true);
1326 }
1327
1328 NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID,
1329 nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID);
1330
1331 nsCOMPtr<nsIObserverService> observerService =
1332 mozilla::services::GetObserverService();
1333 if (!observerService)
1334 return NS_ERROR_FAILURE;
1335
1336 observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nullptr);
1337
1338 return pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
1339 }
1340
1341
1342 /******************************************************************************
1343 *
1344 * static utilities
1345 *
1346 ******************************************************************************/
1347
1348 // static
1349 nsresult
1350 Preferences::GetBool(const char* aPref, bool* aResult)
1351 {
1352 NS_PRECONDITION(aResult, "aResult must not be NULL");
1353 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1354 return PREF_GetBoolPref(aPref, aResult, false);
1355 }
1356
1357 // static
1358 nsresult
1359 Preferences::GetInt(const char* aPref, int32_t* aResult)
1360 {
1361 NS_PRECONDITION(aResult, "aResult must not be NULL");
1362 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1363 return PREF_GetIntPref(aPref, aResult, false);
1364 }
1365
1366 // static
1367 nsresult
1368 Preferences::GetFloat(const char* aPref, float* aResult)
1369 {
1370 NS_PRECONDITION(aResult, "aResult must not be NULL");
1371 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1372 nsAutoCString result;
1373 nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
1374 if (NS_SUCCEEDED(rv)) {
1375 *aResult = result.ToFloat(&rv);
1376 }
1377
1378 return rv;
1379 }
1380
1381 // static
1382 nsAdoptingCString
1383 Preferences::GetCString(const char* aPref)
1384 {
1385 nsAdoptingCString result;
1386 PREF_CopyCharPref(aPref, getter_Copies(result), false);
1387 return result;
1388 }
1389
1390 // static
1391 nsAdoptingString
1392 Preferences::GetString(const char* aPref)
1393 {
1394 nsAdoptingString result;
1395 GetString(aPref, &result);
1396 return result;
1397 }
1398
1399 // static
1400 nsresult
1401 Preferences::GetCString(const char* aPref, nsACString* aResult)
1402 {
1403 NS_PRECONDITION(aResult, "aResult must not be NULL");
1404 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1405 nsAutoCString result;
1406 nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
1407 if (NS_SUCCEEDED(rv)) {
1408 *aResult = result;
1409 }
1410 return rv;
1411 }
1412
1413 // static
1414 nsresult
1415 Preferences::GetString(const char* aPref, nsAString* aResult)
1416 {
1417 NS_PRECONDITION(aResult, "aResult must not be NULL");
1418 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1419 nsAutoCString result;
1420 nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
1421 if (NS_SUCCEEDED(rv)) {
1422 CopyUTF8toUTF16(result, *aResult);
1423 }
1424 return rv;
1425 }
1426
1427 // static
1428 nsAdoptingCString
1429 Preferences::GetLocalizedCString(const char* aPref)
1430 {
1431 nsAdoptingCString result;
1432 GetLocalizedCString(aPref, &result);
1433 return result;
1434 }
1435
1436 // static
1437 nsAdoptingString
1438 Preferences::GetLocalizedString(const char* aPref)
1439 {
1440 nsAdoptingString result;
1441 GetLocalizedString(aPref, &result);
1442 return result;
1443 }
1444
1445 // static
1446 nsresult
1447 Preferences::GetLocalizedCString(const char* aPref, nsACString* aResult)
1448 {
1449 NS_PRECONDITION(aResult, "aResult must not be NULL");
1450 nsAutoString result;
1451 nsresult rv = GetLocalizedString(aPref, &result);
1452 if (NS_SUCCEEDED(rv)) {
1453 CopyUTF16toUTF8(result, *aResult);
1454 }
1455 return rv;
1456 }
1457
1458 // static
1459 nsresult
1460 Preferences::GetLocalizedString(const char* aPref, nsAString* aResult)
1461 {
1462 NS_PRECONDITION(aResult, "aResult must not be NULL");
1463 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1464 nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
1465 nsresult rv = sRootBranch->GetComplexValue(aPref,
1466 NS_GET_IID(nsIPrefLocalizedString),
1467 getter_AddRefs(prefLocalString));
1468 if (NS_SUCCEEDED(rv)) {
1469 NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
1470 prefLocalString->GetData(getter_Copies(*aResult));
1471 }
1472 return rv;
1473 }
1474
1475 // static
1476 nsresult
1477 Preferences::GetComplex(const char* aPref, const nsIID &aType, void** aResult)
1478 {
1479 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1480 return sRootBranch->GetComplexValue(aPref, aType, aResult);
1481 }
1482
1483 // static
1484 nsresult
1485 Preferences::SetCString(const char* aPref, const char* aValue)
1486 {
1487 ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
1488 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1489 return PREF_SetCharPref(aPref, aValue, false);
1490 }
1491
1492 // static
1493 nsresult
1494 Preferences::SetCString(const char* aPref, const nsACString &aValue)
1495 {
1496 ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
1497 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1498 return PREF_SetCharPref(aPref, PromiseFlatCString(aValue).get(), false);
1499 }
1500
1501 // static
1502 nsresult
1503 Preferences::SetString(const char* aPref, const char16_t* aValue)
1504 {
1505 ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
1506 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1507 return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
1508 }
1509
1510 // static
1511 nsresult
1512 Preferences::SetString(const char* aPref, const nsAString &aValue)
1513 {
1514 ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
1515 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1516 return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
1517 }
1518
1519 // static
1520 nsresult
1521 Preferences::SetBool(const char* aPref, bool aValue)
1522 {
1523 ENSURE_MAIN_PROCESS("Cannot SetBool from content process:", aPref);
1524 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1525 return PREF_SetBoolPref(aPref, aValue, false);
1526 }
1527
1528 // static
1529 nsresult
1530 Preferences::SetInt(const char* aPref, int32_t aValue)
1531 {
1532 ENSURE_MAIN_PROCESS("Cannot SetInt from content process:", aPref);
1533 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1534 return PREF_SetIntPref(aPref, aValue, false);
1535 }
1536
1537 // static
1538 nsresult
1539 Preferences::SetComplex(const char* aPref, const nsIID &aType,
1540 nsISupports* aValue)
1541 {
1542 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1543 return sRootBranch->SetComplexValue(aPref, aType, aValue);
1544 }
1545
1546 // static
1547 nsresult
1548 Preferences::ClearUser(const char* aPref)
1549 {
1550 ENSURE_MAIN_PROCESS("Cannot ClearUser from content process:", aPref);
1551 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1552 return PREF_ClearUserPref(aPref);
1553 }
1554
1555 // static
1556 bool
1557 Preferences::HasUserValue(const char* aPref)
1558 {
1559 NS_ENSURE_TRUE(InitStaticMembers(), false);
1560 return PREF_HasUserPref(aPref);
1561 }
1562
1563 // static
1564 int32_t
1565 Preferences::GetType(const char* aPref)
1566 {
1567 NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
1568 int32_t result;
1569 return NS_SUCCEEDED(sRootBranch->GetPrefType(aPref, &result)) ?
1570 result : nsIPrefBranch::PREF_INVALID;
1571 }
1572
1573 // static
1574 nsresult
1575 Preferences::AddStrongObserver(nsIObserver* aObserver,
1576 const char* aPref)
1577 {
1578 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1579 return sRootBranch->AddObserver(aPref, aObserver, false);
1580 }
1581
1582 // static
1583 nsresult
1584 Preferences::AddWeakObserver(nsIObserver* aObserver,
1585 const char* aPref)
1586 {
1587 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1588 return sRootBranch->AddObserver(aPref, aObserver, true);
1589 }
1590
1591 // static
1592 nsresult
1593 Preferences::RemoveObserver(nsIObserver* aObserver,
1594 const char* aPref)
1595 {
1596 if (!sPreferences && sShutdown) {
1597 return NS_OK; // Observers have been released automatically.
1598 }
1599 NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
1600 return sRootBranch->RemoveObserver(aPref, aObserver);
1601 }
1602
1603 // static
1604 nsresult
1605 Preferences::AddStrongObservers(nsIObserver* aObserver,
1606 const char** aPrefs)
1607 {
1608 for (uint32_t i = 0; aPrefs[i]; i++) {
1609 nsresult rv = AddStrongObserver(aObserver, aPrefs[i]);
1610 NS_ENSURE_SUCCESS(rv, rv);
1611 }
1612 return NS_OK;
1613 }
1614
1615 // static
1616 nsresult
1617 Preferences::AddWeakObservers(nsIObserver* aObserver,
1618 const char** aPrefs)
1619 {
1620 for (uint32_t i = 0; aPrefs[i]; i++) {
1621 nsresult rv = AddWeakObserver(aObserver, aPrefs[i]);
1622 NS_ENSURE_SUCCESS(rv, rv);
1623 }
1624 return NS_OK;
1625 }
1626
1627 // static
1628 nsresult
1629 Preferences::RemoveObservers(nsIObserver* aObserver,
1630 const char** aPrefs)
1631 {
1632 if (!sPreferences && sShutdown) {
1633 return NS_OK; // Observers have been released automatically.
1634 }
1635 NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
1636
1637 for (uint32_t i = 0; aPrefs[i]; i++) {
1638 nsresult rv = RemoveObserver(aObserver, aPrefs[i]);
1639 NS_ENSURE_SUCCESS(rv, rv);
1640 }
1641 return NS_OK;
1642 }
1643
1644 // static
1645 nsresult
1646 Preferences::RegisterCallback(PrefChangedFunc aCallback,
1647 const char* aPref,
1648 void* aClosure)
1649 {
1650 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1651
1652 ValueObserverHashKey hashKey(aPref, aCallback);
1653 nsRefPtr<ValueObserver> observer;
1654 gObserverTable->Get(&hashKey, getter_AddRefs(observer));
1655 if (observer) {
1656 observer->AppendClosure(aClosure);
1657 return NS_OK;
1658 }
1659
1660 observer = new ValueObserver(aPref, aCallback);
1661 observer->AppendClosure(aClosure);
1662 nsresult rv = AddStrongObserver(observer, aPref);
1663 NS_ENSURE_SUCCESS(rv, rv);
1664 gObserverTable->Put(observer, observer);
1665 return NS_OK;
1666 }
1667
1668 // static
1669 nsresult
1670 Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback,
1671 const char* aPref,
1672 void* aClosure)
1673 {
1674 nsresult rv = RegisterCallback(aCallback, aPref, aClosure);
1675 if (NS_SUCCEEDED(rv)) {
1676 (*aCallback)(aPref, aClosure);
1677 }
1678 return rv;
1679 }
1680
1681 // static
1682 nsresult
1683 Preferences::UnregisterCallback(PrefChangedFunc aCallback,
1684 const char* aPref,
1685 void* aClosure)
1686 {
1687 if (!sPreferences && sShutdown) {
1688 return NS_OK; // Observers have been released automatically.
1689 }
1690 NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
1691
1692 ValueObserverHashKey hashKey(aPref, aCallback);
1693 nsRefPtr<ValueObserver> observer;
1694 gObserverTable->Get(&hashKey, getter_AddRefs(observer));
1695 if (!observer) {
1696 return NS_OK;
1697 }
1698
1699 observer->RemoveClosure(aClosure);
1700 if (observer->HasNoClosures()) {
1701 // Delete the callback since its list of closures is empty.
1702 gObserverTable->Remove(observer);
1703 }
1704 return NS_OK;
1705 }
1706
1707 static void BoolVarChanged(const char* aPref, void* aClosure)
1708 {
1709 CacheData* cache = static_cast<CacheData*>(aClosure);
1710 *((bool*)cache->cacheLocation) =
1711 Preferences::GetBool(aPref, cache->defaultValueBool);
1712 }
1713
1714 // static
1715 nsresult
1716 Preferences::AddBoolVarCache(bool* aCache,
1717 const char* aPref,
1718 bool aDefault)
1719 {
1720 NS_ASSERTION(aCache, "aCache must not be NULL");
1721 *aCache = GetBool(aPref, aDefault);
1722 CacheData* data = new CacheData();
1723 data->cacheLocation = aCache;
1724 data->defaultValueBool = aDefault;
1725 gCacheData->AppendElement(data);
1726 return RegisterCallback(BoolVarChanged, aPref, data);
1727 }
1728
1729 static void IntVarChanged(const char* aPref, void* aClosure)
1730 {
1731 CacheData* cache = static_cast<CacheData*>(aClosure);
1732 *((int32_t*)cache->cacheLocation) =
1733 Preferences::GetInt(aPref, cache->defaultValueInt);
1734 }
1735
1736 // static
1737 nsresult
1738 Preferences::AddIntVarCache(int32_t* aCache,
1739 const char* aPref,
1740 int32_t aDefault)
1741 {
1742 NS_ASSERTION(aCache, "aCache must not be NULL");
1743 *aCache = Preferences::GetInt(aPref, aDefault);
1744 CacheData* data = new CacheData();
1745 data->cacheLocation = aCache;
1746 data->defaultValueInt = aDefault;
1747 gCacheData->AppendElement(data);
1748 return RegisterCallback(IntVarChanged, aPref, data);
1749 }
1750
1751 static void UintVarChanged(const char* aPref, void* aClosure)
1752 {
1753 CacheData* cache = static_cast<CacheData*>(aClosure);
1754 *((uint32_t*)cache->cacheLocation) =
1755 Preferences::GetUint(aPref, cache->defaultValueUint);
1756 }
1757
1758 // static
1759 nsresult
1760 Preferences::AddUintVarCache(uint32_t* aCache,
1761 const char* aPref,
1762 uint32_t aDefault)
1763 {
1764 NS_ASSERTION(aCache, "aCache must not be NULL");
1765 *aCache = Preferences::GetUint(aPref, aDefault);
1766 CacheData* data = new CacheData();
1767 data->cacheLocation = aCache;
1768 data->defaultValueUint = aDefault;
1769 gCacheData->AppendElement(data);
1770 return RegisterCallback(UintVarChanged, aPref, data);
1771 }
1772
1773 static void FloatVarChanged(const char* aPref, void* aClosure)
1774 {
1775 CacheData* cache = static_cast<CacheData*>(aClosure);
1776 *((float*)cache->cacheLocation) =
1777 Preferences::GetFloat(aPref, cache->defaultValueFloat);
1778 }
1779
1780 // static
1781 nsresult
1782 Preferences::AddFloatVarCache(float* aCache,
1783 const char* aPref,
1784 float aDefault)
1785 {
1786 NS_ASSERTION(aCache, "aCache must not be NULL");
1787 *aCache = Preferences::GetFloat(aPref, aDefault);
1788 CacheData* data = new CacheData();
1789 data->cacheLocation = aCache;
1790 data->defaultValueFloat = aDefault;
1791 gCacheData->AppendElement(data);
1792 return RegisterCallback(FloatVarChanged, aPref, data);
1793 }
1794
1795 // static
1796 nsresult
1797 Preferences::GetDefaultBool(const char* aPref, bool* aResult)
1798 {
1799 NS_PRECONDITION(aResult, "aResult must not be NULL");
1800 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1801 return PREF_GetBoolPref(aPref, aResult, true);
1802 }
1803
1804 // static
1805 nsresult
1806 Preferences::GetDefaultInt(const char* aPref, int32_t* aResult)
1807 {
1808 NS_PRECONDITION(aResult, "aResult must not be NULL");
1809 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1810 return PREF_GetIntPref(aPref, aResult, true);
1811 }
1812
1813 // static
1814 nsresult
1815 Preferences::GetDefaultCString(const char* aPref, nsACString* aResult)
1816 {
1817 NS_PRECONDITION(aResult, "aResult must not be NULL");
1818 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1819 nsAutoCString result;
1820 nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
1821 if (NS_SUCCEEDED(rv)) {
1822 *aResult = result;
1823 }
1824 return rv;
1825 }
1826
1827 // static
1828 nsresult
1829 Preferences::GetDefaultString(const char* aPref, nsAString* aResult)
1830 {
1831 NS_PRECONDITION(aResult, "aResult must not be NULL");
1832 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1833 nsAutoCString result;
1834 nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
1835 if (NS_SUCCEEDED(rv)) {
1836 CopyUTF8toUTF16(result, *aResult);
1837 }
1838 return rv;
1839 }
1840
1841 // static
1842 nsresult
1843 Preferences::GetDefaultLocalizedCString(const char* aPref,
1844 nsACString* aResult)
1845 {
1846 nsAutoString result;
1847 nsresult rv = GetDefaultLocalizedString(aPref, &result);
1848 if (NS_SUCCEEDED(rv)) {
1849 CopyUTF16toUTF8(result, *aResult);
1850 }
1851 return rv;
1852 }
1853
1854 // static
1855 nsresult
1856 Preferences::GetDefaultLocalizedString(const char* aPref,
1857 nsAString* aResult)
1858 {
1859 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1860 nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
1861 nsresult rv =
1862 sDefaultRootBranch->GetComplexValue(aPref,
1863 NS_GET_IID(nsIPrefLocalizedString),
1864 getter_AddRefs(prefLocalString));
1865 if (NS_SUCCEEDED(rv)) {
1866 NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
1867 prefLocalString->GetData(getter_Copies(*aResult));
1868 }
1869 return rv;
1870 }
1871
1872 // static
1873 nsAdoptingString
1874 Preferences::GetDefaultString(const char* aPref)
1875 {
1876 nsAdoptingString result;
1877 GetDefaultString(aPref, &result);
1878 return result;
1879 }
1880
1881 // static
1882 nsAdoptingCString
1883 Preferences::GetDefaultCString(const char* aPref)
1884 {
1885 nsAdoptingCString result;
1886 PREF_CopyCharPref(aPref, getter_Copies(result), true);
1887 return result;
1888 }
1889
1890 // static
1891 nsAdoptingString
1892 Preferences::GetDefaultLocalizedString(const char* aPref)
1893 {
1894 nsAdoptingString result;
1895 GetDefaultLocalizedString(aPref, &result);
1896 return result;
1897 }
1898
1899 // static
1900 nsAdoptingCString
1901 Preferences::GetDefaultLocalizedCString(const char* aPref)
1902 {
1903 nsAdoptingCString result;
1904 GetDefaultLocalizedCString(aPref, &result);
1905 return result;
1906 }
1907
1908 // static
1909 nsresult
1910 Preferences::GetDefaultComplex(const char* aPref, const nsIID &aType,
1911 void** aResult)
1912 {
1913 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1914 return sDefaultRootBranch->GetComplexValue(aPref, aType, aResult);
1915 }
1916
1917 // static
1918 int32_t
1919 Preferences::GetDefaultType(const char* aPref)
1920 {
1921 NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
1922 int32_t result;
1923 return NS_SUCCEEDED(sDefaultRootBranch->GetPrefType(aPref, &result)) ?
1924 result : nsIPrefBranch::PREF_INVALID;
1925 }
1926
1927 } // namespace mozilla
1928
1929 #undef ENSURE_MAIN_PROCESS

mercurial