1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/MemoryReporting.h"
8 #include "mozilla/dom/ContentChild.h"
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/HashFunctions.h"
14 #include "nsXULAppAPI.h"
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"
24 #include "nsIInputStream.h"
25 #include "nsIObserverService.h"
26 #include "nsIStringEnumerator.h"
27 #include "nsIZipReader.h"
28 #include "nsPrefBranch.h"
29 #include "nsXPIDLString.h"
31 #include "nsCOMArray.h"
32 #include "nsXPCOMCID.h"
33 #include "nsAutoPtr.h"
34 #include "nsPrintfCString.h"
36 #include "nsQuickSort.h"
41 #include "prefapi_private_data.h"
43 #include "mozilla/Omnijar.h"
44 #include "nsZipArchive.h"
47 #include "nsRefPtrHashtable.h"
48 #include "nsIMemoryReporter.h"
49 #include "nsThreadUtils.h"
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; \
60 #define ENSURE_MAIN_PROCESS(message, pref) \
61 if (MOZ_UNLIKELY(XRE_GetProcessType() != GeckoProcessType_Default)) { \
62 return NS_ERROR_NOT_AVAILABLE; \
71 #define INITIAL_PREF_FILES 10
72 static NS_DEFINE_CID(kZipReaderCID
, NS_ZIPREADER_CID
);
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
);
80 static const char kTelemetryPref
[] = "toolkit.telemetry.enabled";
81 static const char kOldTelemetryPref
[] = "toolkit.telemetry.enabledPreRelease";
82 static const char kChannelPref
[] = "app.update.channel";
84 Preferences
* Preferences::sPreferences
= nullptr;
85 nsIPrefBranch
* Preferences::sRootBranch
= nullptr;
86 nsIPrefBranch
* Preferences::sDefaultRootBranch
= nullptr;
87 bool Preferences::sShutdown
= false;
89 class ValueObserverHashKey
: public PLDHashEntryHdr
{
91 typedef ValueObserverHashKey
* KeyType
;
92 typedef const ValueObserverHashKey
* KeyTypePointer
;
94 static const ValueObserverHashKey
* KeyToPointer(ValueObserverHashKey
*aKey
)
99 static PLDHashNumber
HashKey(const ValueObserverHashKey
*aKey
)
101 PLDHashNumber hash
= HashString(aKey
->mPrefName
);
102 return AddToHash(hash
, aKey
->mCallback
);
105 ValueObserverHashKey(const char *aPref
, PrefChangedFunc aCallback
) :
106 mPrefName(aPref
), mCallback(aCallback
) { }
108 explicit ValueObserverHashKey(const ValueObserverHashKey
*aOther
) :
109 mPrefName(aOther
->mPrefName
), mCallback(aOther
->mCallback
)
112 bool KeyEquals(const ValueObserverHashKey
*aOther
) const
114 return mCallback
== aOther
->mCallback
&& mPrefName
== aOther
->mPrefName
;
117 ValueObserverHashKey
*GetKey() const
119 return const_cast<ValueObserverHashKey
*>(this);
122 enum { ALLOW_MEMMOVE
= true };
125 PrefChangedFunc mCallback
;
128 class ValueObserver MOZ_FINAL
: public nsIObserver
,
129 public ValueObserverHashKey
132 Preferences::RemoveObserver(this, mPrefName
.get());
139 ValueObserver(const char *aPref
, PrefChangedFunc aCallback
)
140 : ValueObserverHashKey(aPref
, aCallback
) { }
142 void AppendClosure(void *aClosure
) {
143 mClosures
.AppendElement(aClosure
);
146 void RemoveClosure(void *aClosure
) {
147 mClosures
.RemoveElement(aClosure
);
150 bool HasNoClosures() {
151 return mClosures
.Length() == 0;
154 nsTArray
<void*> mClosures
;
157 NS_IMPL_ISUPPORTS(ValueObserver
, nsIObserver
)
160 ValueObserver::Observe(nsISupports
*aSubject
,
162 const char16_t
*aData
)
164 NS_ASSERTION(!nsCRT::strcmp(aTopic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
),
166 NS_ConvertUTF16toUTF8
data(aData
);
167 for (uint32_t i
= 0; i
< mClosures
.Length(); i
++) {
168 mCallback(data
.get(), mClosures
.ElementAt(i
));
177 bool defaultValueBool
;
178 int32_t defaultValueInt
;
179 uint32_t defaultValueUint
;
180 float defaultValueFloat
;
184 static nsTArray
<nsAutoPtr
<CacheData
> >* gCacheData
= nullptr;
185 static nsRefPtrHashtable
<ValueObserverHashKey
,
186 ValueObserver
>* gObserverTable
= nullptr;
190 HaveExistingCacheFor(void* aPtr
)
192 MOZ_ASSERT(NS_IsMainThread());
194 for (size_t i
= 0, count
= gCacheData
->Length(); i
< count
; ++i
) {
195 if ((*gCacheData
)[i
]->cacheLocation
== aPtr
) {
204 AssertNotAlreadyCached(const char* aPrefType
,
208 if (HaveExistingCacheFor(aPtr
)) {
209 fprintf_stderr(stderr
,
210 "Attempt to add a %s pref cache for preference '%s' at address '%p'"
211 "was made. However, a pref was already cached at this address.\n",
212 aPrefType
, aPref
, aPtr
);
213 MOZ_ASSERT(false, "Should not have an existing pref cache for this address");
219 SizeOfObserverEntryExcludingThis(ValueObserverHashKey
* aKey
,
220 const nsRefPtr
<ValueObserver
>& aData
,
221 mozilla::MallocSizeOf aMallocSizeOf
,
225 n
+= aKey
->mPrefName
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
226 n
+= aData
->mClosures
.SizeOfExcludingThis(aMallocSizeOf
);
230 // Although this is a member of Preferences, it measures sPreferences and
231 // several other global structures.
233 Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf
)
235 NS_ENSURE_TRUE(InitStaticMembers(), 0);
237 size_t n
= aMallocSizeOf(sPreferences
);
238 if (gHashTable
.ops
) {
239 // pref keys are allocated in a private arena, which we count elsewhere.
240 // pref stringvals are allocated out of the same private arena.
241 n
+= PL_DHashTableSizeOfExcludingThis(&gHashTable
, nullptr, aMallocSizeOf
);
244 n
+= gCacheData
->SizeOfIncludingThis(aMallocSizeOf
);
245 for (uint32_t i
= 0, count
= gCacheData
->Length(); i
< count
; ++i
) {
246 n
+= aMallocSizeOf((*gCacheData
)[i
]);
249 if (gObserverTable
) {
250 n
+= aMallocSizeOf(gObserverTable
);
251 n
+= gObserverTable
->SizeOfExcludingThis(SizeOfObserverEntryExcludingThis
,
254 // We don't measure sRootBranch and sDefaultRootBranch here because
255 // DMD indicates they are not significant.
256 n
+= pref_SizeOfPrivateData(aMallocSizeOf
);
260 class PreferenceServiceReporter MOZ_FINAL
: public nsIMemoryReporter
262 ~PreferenceServiceReporter() {}
266 NS_DECL_NSIMEMORYREPORTER
269 static const uint32_t kSuspectReferentCount
= 1000;
270 static PLDHashOperator
CountReferents(PrefCallback
* aKey
,
271 nsAutoPtr
<PrefCallback
>& aCallback
,
275 NS_IMPL_ISUPPORTS(PreferenceServiceReporter
, nsIMemoryReporter
)
277 struct PreferencesReferentCount
{
278 PreferencesReferentCount() : numStrong(0), numWeakAlive(0), numWeakDead(0) {}
282 nsTArray
<nsCString
> suspectPreferences
;
283 // Count of the number of referents for each preference.
284 nsDataHashtable
<nsCStringHashKey
, uint32_t> prefCounter
;
288 PreferenceServiceReporter::CountReferents(PrefCallback
* aKey
,
289 nsAutoPtr
<PrefCallback
>& aCallback
,
292 PreferencesReferentCount
* referentCount
=
293 static_cast<PreferencesReferentCount
*>(aClosure
);
295 nsPrefBranch
* prefBranch
= aCallback
->GetPrefBranch();
296 const char* pref
= prefBranch
->getPrefName(aCallback
->GetDomain().get());
298 if (aCallback
->IsWeak()) {
299 nsCOMPtr
<nsIObserver
> callbackRef
= do_QueryReferent(aCallback
->mWeakRef
);
301 referentCount
->numWeakAlive
++;
303 referentCount
->numWeakDead
++;
306 referentCount
->numStrong
++;
309 nsDependentCString
prefString(pref
);
310 uint32_t oldCount
= 0;
311 referentCount
->prefCounter
.Get(prefString
, &oldCount
);
312 uint32_t currentCount
= oldCount
+ 1;
313 referentCount
->prefCounter
.Put(prefString
, currentCount
);
315 // Keep track of preferences that have a suspiciously large
316 // number of referents (symptom of leak).
317 if (currentCount
== kSuspectReferentCount
) {
318 referentCount
->suspectPreferences
.AppendElement(prefString
);
321 return PL_DHASH_NEXT
;
324 MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf
)
327 PreferenceServiceReporter::CollectReports(nsIMemoryReporterCallback
* aCb
,
328 nsISupports
* aClosure
,
331 #define REPORT(_path, _kind, _units, _amount, _desc) \
334 rv = aCb->Callback(EmptyCString(), _path, _kind, \
335 _units, _amount, NS_LITERAL_CSTRING(_desc), \
337 NS_ENSURE_SUCCESS(rv, rv); \
340 REPORT(NS_LITERAL_CSTRING("explicit/preferences"),
341 KIND_HEAP
, UNITS_BYTES
,
342 Preferences::SizeOfIncludingThisAndOtherStuff(PreferenceServiceMallocSizeOf
),
343 "Memory used by the preferences system.");
345 nsPrefBranch
* rootBranch
=
346 static_cast<nsPrefBranch
*>(Preferences::GetRootBranch());
351 PreferencesReferentCount referentCount
;
352 rootBranch
->mObservers
.Enumerate(&CountReferents
, &referentCount
);
354 for (uint32_t i
= 0; i
< referentCount
.suspectPreferences
.Length(); i
++) {
355 nsCString
& suspect
= referentCount
.suspectPreferences
[i
];
356 uint32_t totalReferentCount
= 0;
357 referentCount
.prefCounter
.Get(suspect
, &totalReferentCount
);
359 nsPrintfCString
suspectPath("preference-service-suspect/"
360 "referent(pref=%s)", suspect
.get());
363 KIND_OTHER
, UNITS_COUNT
, totalReferentCount
,
364 "A preference with a suspiciously large number "
365 "referents (symptom of a leak).");
368 REPORT(NS_LITERAL_CSTRING("preference-service/referent/strong"),
369 KIND_OTHER
, UNITS_COUNT
, referentCount
.numStrong
,
370 "The number of strong referents held by the preference service.");
372 REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/alive"),
373 KIND_OTHER
, UNITS_COUNT
, referentCount
.numWeakAlive
,
374 "The number of weak referents held by the preference service "
375 "that are still alive.");
377 REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/dead"),
378 KIND_OTHER
, UNITS_COUNT
, referentCount
.numWeakDead
,
379 "The number of weak referents held by the preference service "
388 class AddPreferencesMemoryReporterRunnable
: public nsRunnable
392 return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
395 } // anonymous namespace
399 Preferences::GetInstanceForService()
402 NS_ADDREF(sPreferences
);
406 NS_ENSURE_TRUE(!sShutdown
, nullptr);
408 sRootBranch
= new nsPrefBranch("", false);
409 NS_ADDREF(sRootBranch
);
410 sDefaultRootBranch
= new nsPrefBranch("", true);
411 NS_ADDREF(sDefaultRootBranch
);
413 sPreferences
= new Preferences();
414 NS_ADDREF(sPreferences
);
416 if (NS_FAILED(sPreferences
->Init())) {
417 // The singleton instance will delete sRootBranch and sDefaultRootBranch.
418 NS_RELEASE(sPreferences
);
422 gCacheData
= new nsTArray
<nsAutoPtr
<CacheData
> >();
424 gObserverTable
= new nsRefPtrHashtable
<ValueObserverHashKey
, ValueObserver
>();
426 // Preferences::GetInstanceForService() can be called from GetService(), and
427 // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To
428 // avoid a potential recursive GetService() call, we can't register the
429 // memory reporter here; instead, do it off a runnable.
430 nsRefPtr
<AddPreferencesMemoryReporterRunnable
> runnable
=
431 new AddPreferencesMemoryReporterRunnable();
432 NS_DispatchToMainThread(runnable
);
434 NS_ADDREF(sPreferences
);
440 Preferences::InitStaticMembers()
443 MOZ_ASSERT(NS_IsMainThread());
446 if (!sShutdown
&& !sPreferences
) {
447 nsCOMPtr
<nsIPrefService
> prefService
=
448 do_GetService(NS_PREFSERVICE_CONTRACTID
);
451 return sPreferences
!= nullptr;
456 Preferences::Shutdown()
459 sShutdown
= true; // Don't create the singleton instance after here.
461 // Don't set sPreferences to nullptr here. The instance may be grabbed by
462 // other modules. The utility methods of Preferences should be available
463 // until the singleton instance actually released.
465 sPreferences
->Release();
470 //-----------------------------------------------------------------------------
473 * Constructor/Destructor
476 Preferences::Preferences()
480 Preferences::~Preferences()
482 NS_ASSERTION(sPreferences
== this, "Isn't this the singleton instance?");
484 delete gObserverTable
;
485 gObserverTable
= nullptr;
488 gCacheData
= nullptr;
490 NS_RELEASE(sRootBranch
);
491 NS_RELEASE(sDefaultRootBranch
);
493 sPreferences
= nullptr;
500 * nsISupports Implementation
503 NS_IMPL_ADDREF(Preferences
)
504 NS_IMPL_RELEASE(Preferences
)
506 NS_INTERFACE_MAP_BEGIN(Preferences
)
507 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIPrefService
)
508 NS_INTERFACE_MAP_ENTRY(nsIPrefService
)
509 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
510 NS_INTERFACE_MAP_ENTRY(nsIPrefBranch
)
511 NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2
)
512 NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal
)
513 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
518 * nsIPrefService Implementation
527 NS_ENSURE_SUCCESS(rv
, rv
);
529 rv
= pref_InitInitialObjects();
530 NS_ENSURE_SUCCESS(rv
, rv
);
532 using mozilla::dom::ContentChild
;
533 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
534 InfallibleTArray
<PrefSetting
> prefs
;
535 ContentChild::GetSingleton()->SendReadPrefsArray(&prefs
);
538 for (uint32_t i
= 0; i
< prefs
.Length(); ++i
) {
539 pref_SetPref(prefs
[i
]);
544 nsXPIDLCString lockFileName
;
546 * The following is a small hack which will allow us to only load the library
547 * which supports the netscape.cfg file if the preference is defined. We
548 * test for the existence of the pref, set in the all.js (mozilla) or
549 * all-ns.js (netscape 6), and if it exists we startup the pref config
550 * category which will do the rest.
553 rv
= PREF_CopyCharPref("general.config.filename", getter_Copies(lockFileName
), false);
554 if (NS_SUCCEEDED(rv
))
555 NS_CreateServicesFromCategory("pref-config-startup",
556 static_cast<nsISupports
*>(static_cast<void *>(this)),
557 "pref-config-startup");
559 nsCOMPtr
<nsIObserverService
> observerService
=
560 mozilla::services::GetObserverService();
561 if (!observerService
)
562 return NS_ERROR_FAILURE
;
564 rv
= observerService
->AddObserver(this, "profile-before-change", true);
566 observerService
->AddObserver(this, "load-extension-defaults", true);
567 observerService
->AddObserver(this, "suspend_process_notification", true);
574 Preferences::ResetAndReadUserPrefs()
576 sPreferences
->ResetUserPrefs();
577 return sPreferences
->ReadUserPrefs(nullptr);
581 Preferences::Observe(nsISupports
*aSubject
, const char *aTopic
,
582 const char16_t
*someData
)
584 if (XRE_GetProcessType() == GeckoProcessType_Content
)
585 return NS_ERROR_NOT_AVAILABLE
;
589 if (!nsCRT::strcmp(aTopic
, "profile-before-change")) {
590 rv
= SavePrefFile(nullptr);
591 } else if (!strcmp(aTopic
, "load-extension-defaults")) {
592 pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST
);
593 } else if (!nsCRT::strcmp(aTopic
, "reload-default-prefs")) {
594 // Reload the default prefs from file.
595 pref_InitInitialObjects();
596 } else if (!nsCRT::strcmp(aTopic
, "suspend_process_notification")) {
597 // Our process is being suspended. The OS may wake our process later,
598 // or it may kill the process. In case our process is going to be killed
599 // from the suspended state, we save preferences before suspending.
600 rv
= SavePrefFile(nullptr);
607 Preferences::ReadUserPrefs(nsIFile
*aFile
)
609 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
610 NS_ERROR("cannot load prefs from content process");
611 return NS_ERROR_NOT_AVAILABLE
;
616 if (nullptr == aFile
) {
617 rv
= UseDefaultPrefFile();
618 // A user pref file is optional.
619 // Ignore all errors related to it, so we retain 'rv' value :-|
620 (void) UseUserPrefFile();
622 // Migrate the old prerelease telemetry pref
623 if (!Preferences::GetBool(kOldTelemetryPref
, true)) {
624 Preferences::SetBool(kTelemetryPref
, false);
625 Preferences::ClearUser(kOldTelemetryPref
);
628 NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID
);
630 rv
= ReadAndOwnUserPrefFile(aFile
);
637 Preferences::ResetPrefs()
639 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
640 NS_ERROR("cannot reset prefs from content process");
641 return NS_ERROR_NOT_AVAILABLE
;
644 NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID
);
647 nsresult rv
= PREF_Init();
648 NS_ENSURE_SUCCESS(rv
, rv
);
650 return pref_InitInitialObjects();
654 Preferences::ResetUserPrefs()
656 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
657 NS_ERROR("cannot reset user prefs from content process");
658 return NS_ERROR_NOT_AVAILABLE
;
661 PREF_ClearAllUserPrefs();
666 Preferences::SavePrefFile(nsIFile
*aFile
)
668 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
669 NS_ERROR("cannot save pref file from content process");
670 return NS_ERROR_NOT_AVAILABLE
;
673 return SavePrefFileInternal(aFile
);
677 ReadExtensionPrefs(nsIFile
*aFile
)
680 nsCOMPtr
<nsIZipReader
> reader
= do_CreateInstance(kZipReaderCID
, &rv
);
681 NS_ENSURE_SUCCESS(rv
, rv
);
683 rv
= reader
->Open(aFile
);
684 NS_ENSURE_SUCCESS(rv
, rv
);
686 nsCOMPtr
<nsIUTF8StringEnumerator
> files
;
687 rv
= reader
->FindEntries(nsDependentCString("defaults/preferences/*.(J|j)(S|s)$"),
688 getter_AddRefs(files
));
689 NS_ENSURE_SUCCESS(rv
, rv
);
694 while (NS_SUCCEEDED(rv
= files
->HasMore(&more
)) && more
) {
696 rv
= files
->GetNext(entry
);
697 NS_ENSURE_SUCCESS(rv
, rv
);
699 nsCOMPtr
<nsIInputStream
> stream
;
700 rv
= reader
->GetInputStream(entry
, getter_AddRefs(stream
));
701 NS_ENSURE_SUCCESS(rv
, rv
);
707 PREF_InitParseState(&ps
, PREF_ReaderCallback
, nullptr);
708 while (NS_SUCCEEDED(rv
= stream
->Available(&avail
)) && avail
) {
709 rv
= stream
->Read(buffer
, 4096, &read
);
711 NS_WARNING("Pref stream read failed");
715 PREF_ParseBuf(&ps
, buffer
, read
);
717 PREF_FinalizeParseState(&ps
);
723 Preferences::SetPreference(const PrefSetting
& aPref
)
729 Preferences::GetPreference(PrefSetting
* aPref
)
731 PrefHashEntry
*entry
= pref_HashTableLookup(aPref
->name().get());
735 pref_GetPrefFromEntry(entry
, aPref
);
739 Preferences::GetPreferences(InfallibleTArray
<PrefSetting
>* aPrefs
)
741 aPrefs
->SetCapacity(gHashTable
.Capacity());
742 PL_DHashTableEnumerate(&gHashTable
, pref_GetPrefs
, aPrefs
);
746 Preferences::GetBranch(const char *aPrefRoot
, nsIPrefBranch
**_retval
)
750 if ((nullptr != aPrefRoot
) && (*aPrefRoot
!= '\0')) {
751 // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
752 nsPrefBranch
* prefBranch
= new nsPrefBranch(aPrefRoot
, false);
754 return NS_ERROR_OUT_OF_MEMORY
;
756 rv
= CallQueryInterface(prefBranch
, _retval
);
758 // special case caching the default root
759 nsCOMPtr
<nsIPrefBranch
> root(sRootBranch
);
760 root
.forget(_retval
);
767 Preferences::GetDefaultBranch(const char *aPrefRoot
, nsIPrefBranch
**_retval
)
769 if (!aPrefRoot
|| !aPrefRoot
[0]) {
770 nsCOMPtr
<nsIPrefBranch
> root(sDefaultRootBranch
);
771 root
.forget(_retval
);
775 // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
776 nsRefPtr
<nsPrefBranch
> prefBranch
= new nsPrefBranch(aPrefRoot
, true);
778 return NS_ERROR_OUT_OF_MEMORY
;
780 prefBranch
.forget(_retval
);
785 Preferences::GetDirty(bool *_retval
) {
791 Preferences::NotifyServiceObservers(const char *aTopic
)
793 nsCOMPtr
<nsIObserverService
> observerService
=
794 mozilla::services::GetObserverService();
795 if (!observerService
)
796 return NS_ERROR_FAILURE
;
798 nsISupports
*subject
= (nsISupports
*)((nsIPrefService
*)this);
799 observerService
->NotifyObservers(subject
, aTopic
, nullptr);
805 Preferences::UseDefaultPrefFile()
808 nsCOMPtr
<nsIFile
> aFile
;
810 #if defined(XP_WIN) && defined(MOZ_METRO)
811 if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro
) {
812 rv
= NS_GetSpecialDirectory(NS_METRO_APP_PREFS_50_FILE
, getter_AddRefs(aFile
));
816 rv
= NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE
, getter_AddRefs(aFile
));
819 if (NS_SUCCEEDED(rv
)) {
820 rv
= ReadAndOwnUserPrefFile(aFile
);
821 // Most likely cause of failure here is that the file didn't
822 // exist, so save a new one. mUserPrefReadFailed will be
823 // used to catch an error in actually reading the file.
825 if (NS_FAILED(SavePrefFileInternal(aFile
)))
826 NS_ERROR("Failed to save new shared pref file");
836 Preferences::UseUserPrefFile()
839 nsCOMPtr
<nsIFile
> aFile
;
840 nsDependentCString
prefsDirProp(NS_APP_PREFS_50_DIR
);
842 rv
= NS_GetSpecialDirectory(prefsDirProp
.get(), getter_AddRefs(aFile
));
843 if (NS_SUCCEEDED(rv
) && aFile
) {
844 rv
= aFile
->AppendNative(NS_LITERAL_CSTRING("user.js"));
845 if (NS_SUCCEEDED(rv
)) {
847 aFile
->Exists(&exists
);
849 rv
= openPrefFile(aFile
);
851 rv
= NS_ERROR_FILE_NOT_FOUND
;
859 Preferences::MakeBackupPrefFile(nsIFile
*aFile
)
861 // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.
862 // "Invalidprefs.js" is removed if it exists, prior to making the copy.
863 nsAutoString newFilename
;
864 nsresult rv
= aFile
->GetLeafName(newFilename
);
865 NS_ENSURE_SUCCESS(rv
, rv
);
866 newFilename
.Insert(NS_LITERAL_STRING("Invalid"), 0);
867 nsCOMPtr
<nsIFile
> newFile
;
868 rv
= aFile
->GetParent(getter_AddRefs(newFile
));
869 NS_ENSURE_SUCCESS(rv
, rv
);
870 rv
= newFile
->Append(newFilename
);
871 NS_ENSURE_SUCCESS(rv
, rv
);
873 newFile
->Exists(&exists
);
875 rv
= newFile
->Remove(false);
876 NS_ENSURE_SUCCESS(rv
, rv
);
878 rv
= aFile
->CopyTo(nullptr, newFilename
);
879 NS_ENSURE_SUCCESS(rv
, rv
);
884 Preferences::ReadAndOwnUserPrefFile(nsIFile
*aFile
)
886 NS_ENSURE_ARG(aFile
);
888 if (mCurrentFile
== aFile
)
890 mCurrentFile
= aFile
;
894 mCurrentFile
->Exists(&exists
);
896 rv
= openPrefFile(mCurrentFile
);
898 // Save a backup copy of the current (invalid) prefs file, since all prefs
899 // from the error line to the end of the file will be lost (bug 361102).
900 // TODO we should notify the user about it (bug 523725).
901 MakeBackupPrefFile(mCurrentFile
);
904 rv
= NS_ERROR_FILE_NOT_FOUND
;
911 Preferences::SavePrefFileInternal(nsIFile
*aFile
)
913 if (nullptr == aFile
) {
914 // the gDirty flag tells us if we should write to mCurrentFile
915 // we only check this flag when the caller wants to write to the default
919 // It's possible that we never got a prefs file.
922 rv
= WritePrefFile(mCurrentFile
);
926 return WritePrefFile(aFile
);
931 Preferences::WritePrefFile(nsIFile
* aFile
)
933 const char outHeader
[] =
934 "# Mozilla User Preferences"
937 "/* Do not edit this file."
941 " * If you make changes to this file while the application is running,"
943 " * the changes will be overwritten when the application exits."
947 " * To make a manual change to preferences, you can visit the URL about:config"
953 nsCOMPtr
<nsIOutputStream
> outStreamSink
;
954 nsCOMPtr
<nsIOutputStream
> outStream
;
955 uint32_t writeAmount
;
959 return NS_ERROR_NOT_INITIALIZED
;
961 // execute a "safe" save by saving through a tempfile
962 rv
= NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink
),
968 rv
= NS_NewBufferedOutputStream(getter_AddRefs(outStream
), outStreamSink
, 4096);
972 nsAutoArrayPtr
<char*> valueArray(new char*[gHashTable
.EntryCount()]);
973 memset(valueArray
, 0, gHashTable
.EntryCount() * sizeof(char*));
974 pref_saveArgs saveArgs
;
975 saveArgs
.prefArray
= valueArray
;
976 saveArgs
.saveTypes
= SAVE_ALL
;
978 // get the lines that we're supposed to be writing to the file
979 PL_DHashTableEnumerate(&gHashTable
, pref_savePref
, &saveArgs
);
981 /* Sort the preferences to make a readable file on disk */
982 NS_QuickSort(valueArray
, gHashTable
.EntryCount(), sizeof(char *), pref_CompareStrings
, nullptr);
984 // write out the file header
985 outStream
->Write(outHeader
, sizeof(outHeader
) - 1, &writeAmount
);
987 char** walker
= valueArray
;
988 for (uint32_t valueIdx
= 0; valueIdx
< gHashTable
.EntryCount(); valueIdx
++, walker
++) {
990 outStream
->Write(*walker
, strlen(*walker
), &writeAmount
);
991 outStream
->Write(NS_LINEBREAK
, NS_LINEBREAK_LEN
, &writeAmount
);
996 // tell the safe output stream to overwrite the real prefs file
997 // (it'll abort if there were any errors during writing)
998 nsCOMPtr
<nsISafeOutputStream
> safeStream
= do_QueryInterface(outStream
);
999 NS_ASSERTION(safeStream
, "expected a safe output stream!");
1001 rv
= safeStream
->Finish();
1002 if (NS_FAILED(rv
)) {
1003 NS_WARNING("failed to save prefs file! possible data loss");
1012 static nsresult
openPrefFile(nsIFile
* aFile
)
1014 nsCOMPtr
<nsIInputStream
> inStr
;
1016 nsresult rv
= NS_NewLocalFileInputStream(getter_AddRefs(inStr
), aFile
);
1020 uint64_t fileSize64
;
1021 rv
= inStr
->Available(&fileSize64
);
1024 NS_ENSURE_TRUE(fileSize64
<= UINT32_MAX
, NS_ERROR_FILE_TOO_BIG
);
1026 uint32_t fileSize
= (uint32_t)fileSize64
;
1027 nsAutoArrayPtr
<char> fileBuffer(new char[fileSize
]);
1028 if (fileBuffer
== nullptr)
1029 return NS_ERROR_OUT_OF_MEMORY
;
1032 PREF_InitParseState(&ps
, PREF_ReaderCallback
, nullptr);
1034 // Read is not guaranteed to return a buf the size of fileSize,
1035 // but usually will.
1036 nsresult rv2
= NS_OK
;
1038 uint32_t amtRead
= 0;
1039 rv
= inStr
->Read((char*)fileBuffer
, fileSize
, &amtRead
);
1040 if (NS_FAILED(rv
) || amtRead
== 0)
1042 if (!PREF_ParseBuf(&ps
, fileBuffer
, amtRead
))
1043 rv2
= NS_ERROR_FILE_CORRUPTED
;
1046 PREF_FinalizeParseState(&ps
);
1048 return NS_FAILED(rv
) ? rv
: rv2
;
1052 * some stuff that gets called from Pref_Init()
1056 pref_CompareFileNames(nsIFile
* aFile1
, nsIFile
* aFile2
, void* /*unused*/)
1058 nsAutoCString filename1
, filename2
;
1059 aFile1
->GetNativeLeafName(filename1
);
1060 aFile2
->GetNativeLeafName(filename2
);
1062 return Compare(filename2
, filename1
);
1066 * Load default pref files from a directory. The files in the
1067 * directory are sorted reverse-alphabetically; a set of "special file
1068 * names" may be specified which are loaded after all the others.
1071 pref_LoadPrefsInDir(nsIFile
* aDir
, char const *const *aSpecialFiles
, uint32_t aSpecialFilesCount
)
1074 bool hasMoreElements
;
1076 nsCOMPtr
<nsISimpleEnumerator
> dirIterator
;
1078 // this may fail in some normal cases, such as embedders who do not use a GRE
1079 rv
= aDir
->GetDirectoryEntries(getter_AddRefs(dirIterator
));
1080 if (NS_FAILED(rv
)) {
1081 // If the directory doesn't exist, then we have no reason to complain. We
1082 // loaded everything (and nothing) successfully.
1083 if (rv
== NS_ERROR_FILE_NOT_FOUND
|| rv
== NS_ERROR_FILE_TARGET_DOES_NOT_EXIST
)
1088 rv
= dirIterator
->HasMoreElements(&hasMoreElements
);
1089 NS_ENSURE_SUCCESS(rv
, rv
);
1091 nsCOMArray
<nsIFile
> prefFiles(INITIAL_PREF_FILES
);
1092 nsCOMArray
<nsIFile
> specialFiles(aSpecialFilesCount
);
1093 nsCOMPtr
<nsIFile
> prefFile
;
1095 while (hasMoreElements
&& NS_SUCCEEDED(rv
)) {
1096 nsAutoCString leafName
;
1098 nsCOMPtr
<nsISupports
> supports
;
1099 rv
= dirIterator
->GetNext(getter_AddRefs(supports
));
1100 prefFile
= do_QueryInterface(supports
);
1101 if (NS_FAILED(rv
)) {
1105 prefFile
->GetNativeLeafName(leafName
);
1106 NS_ASSERTION(!leafName
.IsEmpty(), "Failure in default prefs: directory enumerator returned empty file?");
1108 // Skip non-js files
1109 if (StringEndsWith(leafName
, NS_LITERAL_CSTRING(".js"),
1110 nsCaseInsensitiveCStringComparator())) {
1111 bool shouldParse
= true;
1112 // separate out special files
1113 for (uint32_t i
= 0; i
< aSpecialFilesCount
; ++i
) {
1114 if (leafName
.Equals(nsDependentCString(aSpecialFiles
[i
]))) {
1115 shouldParse
= false;
1116 // special files should be process in order; we put them into
1117 // the array by index; this can make the array sparse
1118 specialFiles
.ReplaceObjectAt(prefFile
, i
);
1123 prefFiles
.AppendObject(prefFile
);
1127 rv
= dirIterator
->HasMoreElements(&hasMoreElements
);
1130 if (prefFiles
.Count() + specialFiles
.Count() == 0) {
1131 NS_WARNING("No default pref files found.");
1132 if (NS_SUCCEEDED(rv
)) {
1133 rv
= NS_SUCCESS_FILE_DIRECTORY_EMPTY
;
1138 prefFiles
.Sort(pref_CompareFileNames
, nullptr);
1140 uint32_t arrayCount
= prefFiles
.Count();
1142 for (i
= 0; i
< arrayCount
; ++i
) {
1143 rv2
= openPrefFile(prefFiles
[i
]);
1144 if (NS_FAILED(rv2
)) {
1145 NS_ERROR("Default pref file not parsed successfully.");
1150 arrayCount
= specialFiles
.Count();
1151 for (i
= 0; i
< arrayCount
; ++i
) {
1152 // this may be a sparse array; test before parsing
1153 nsIFile
* file
= specialFiles
[i
];
1155 rv2
= openPrefFile(file
);
1156 if (NS_FAILED(rv2
)) {
1157 NS_ERROR("Special default pref file not parsed successfully.");
1166 static nsresult
pref_LoadPrefsInDirList(const char *listId
)
1169 nsCOMPtr
<nsIProperties
> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
, &rv
));
1173 nsCOMPtr
<nsISimpleEnumerator
> list
;
1175 NS_GET_IID(nsISimpleEnumerator
),
1176 getter_AddRefs(list
));
1181 while (NS_SUCCEEDED(list
->HasMoreElements(&hasMore
)) && hasMore
) {
1182 nsCOMPtr
<nsISupports
> elem
;
1183 list
->GetNext(getter_AddRefs(elem
));
1187 nsCOMPtr
<nsIFile
> path
= do_QueryInterface(elem
);
1192 path
->GetNativeLeafName(leaf
);
1194 // Do we care if a file provided by this process fails to load?
1195 if (Substring(leaf
, leaf
.Length() - 4).EqualsLiteral(".xpi"))
1196 ReadExtensionPrefs(path
);
1198 pref_LoadPrefsInDir(path
, nullptr, 0);
1203 static nsresult
pref_ReadPrefFromJar(nsZipArchive
* jarReader
, const char *name
)
1205 nsZipItemPtr
<char> manifest(jarReader
, name
, true);
1206 NS_ENSURE_TRUE(manifest
.Buffer(), NS_ERROR_NOT_AVAILABLE
);
1209 PREF_InitParseState(&ps
, PREF_ReaderCallback
, nullptr);
1210 PREF_ParseBuf(&ps
, manifest
, manifest
.Length());
1211 PREF_FinalizeParseState(&ps
);
1216 //----------------------------------------------------------------------------------------
1217 // Initialize default preference JavaScript buffers from
1218 // appropriate TEXT resources
1219 //----------------------------------------------------------------------------------------
1220 static nsresult
pref_InitInitialObjects()
1224 // In omni.jar case, we load the following prefs:
1225 // - jar:$gre/omni.jar!/greprefs.js
1226 // - jar:$gre/omni.jar!/defaults/pref/*.js
1227 // In non omni.jar case, we load:
1228 // - $gre/greprefs.js
1230 // In both cases, we also load:
1231 // - $gre/defaults/pref/*.js
1232 // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar)
1233 // on $app == $gre case ; we load all files instead of channel-prefs.js only
1234 // to have the same behaviour as $app != $gre, where this is required as
1235 // a supported location for GRE preferences.
1237 // When $app != $gre, we additionally load, in omni.jar case:
1238 // - jar:$app/omni.jar!/defaults/preferences/*.js
1239 // - $app/defaults/preferences/*.js
1240 // and in non omni.jar case:
1241 // - $app/defaults/preferences/*.js
1242 // When $app == $gre, we additionally load, in omni.jar case:
1243 // - jar:$gre/omni.jar!/defaults/preferences/*.js
1244 // Thus, in omni.jar case, we always load app-specific default preferences
1245 // from omni.jar, whether or not $app == $gre.
1248 nsAutoPtr
<nsZipFind
> find
;
1249 nsTArray
<nsCString
> prefEntries
;
1250 const char *entryName
;
1251 uint16_t entryNameLen
;
1253 nsRefPtr
<nsZipArchive
> jarReader
= mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE
);
1255 // Load jar:$gre/omni.jar!/greprefs.js
1256 rv
= pref_ReadPrefFromJar(jarReader
, "greprefs.js");
1257 NS_ENSURE_SUCCESS(rv
, rv
);
1259 // Load jar:$gre/omni.jar!/defaults/pref/*.js
1260 rv
= jarReader
->FindInit("defaults/pref/*.js$", &findPtr
);
1261 NS_ENSURE_SUCCESS(rv
, rv
);
1264 while (NS_SUCCEEDED(find
->FindNext(&entryName
, &entryNameLen
))) {
1265 prefEntries
.AppendElement(Substring(entryName
, entryNameLen
));
1269 for (uint32_t i
= prefEntries
.Length(); i
--; ) {
1270 rv
= pref_ReadPrefFromJar(jarReader
, prefEntries
[i
].get());
1272 NS_WARNING("Error parsing preferences.");
1275 // Load $gre/greprefs.js
1276 nsCOMPtr
<nsIFile
> greprefsFile
;
1277 rv
= NS_GetSpecialDirectory(NS_GRE_DIR
, getter_AddRefs(greprefsFile
));
1278 NS_ENSURE_SUCCESS(rv
, rv
);
1280 rv
= greprefsFile
->AppendNative(NS_LITERAL_CSTRING("greprefs.js"));
1281 NS_ENSURE_SUCCESS(rv
, rv
);
1283 rv
= openPrefFile(greprefsFile
);
1285 NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?");
1288 // Load $gre/defaults/pref/*.js
1289 nsCOMPtr
<nsIFile
> defaultPrefDir
;
1291 rv
= NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR
, getter_AddRefs(defaultPrefDir
));
1292 NS_ENSURE_SUCCESS(rv
, rv
);
1294 /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
1295 static const char* specialFiles
[] = {
1296 #if defined(XP_MACOSX)
1298 #elif defined(XP_WIN)
1300 #elif defined(XP_UNIX)
1307 #elif defined(XP_BEOS)
1312 rv
= pref_LoadPrefsInDir(defaultPrefDir
, specialFiles
, ArrayLength(specialFiles
));
1314 NS_WARNING("Error parsing application default preferences.");
1316 // Load jar:$app/omni.jar!/defaults/preferences/*.js
1317 // or jar:$gre/omni.jar!/defaults/preferences/*.js.
1318 nsRefPtr
<nsZipArchive
> appJarReader
= mozilla::Omnijar::GetReader(mozilla::Omnijar::APP
);
1319 // GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
1320 // case we look for app-specific default preferences in $gre.
1322 appJarReader
= mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE
);
1324 rv
= appJarReader
->FindInit("defaults/preferences/*.js$", &findPtr
);
1325 NS_ENSURE_SUCCESS(rv
, rv
);
1327 prefEntries
.Clear();
1328 while (NS_SUCCEEDED(find
->FindNext(&entryName
, &entryNameLen
))) {
1329 prefEntries
.AppendElement(Substring(entryName
, entryNameLen
));
1332 for (uint32_t i
= prefEntries
.Length(); i
--; ) {
1333 rv
= pref_ReadPrefFromJar(appJarReader
, prefEntries
[i
].get());
1335 NS_WARNING("Error parsing preferences.");
1339 rv
= pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST
);
1340 NS_ENSURE_SUCCESS(rv
, rv
);
1342 // Set up the correct default for toolkit.telemetry.enabled.
1343 // If this build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta
1344 // channel, telemetry is on by default, otherwise not. This is necessary
1345 // so that beta users who are testing final release builds don't flipflop
1347 if (Preferences::GetDefaultType(kTelemetryPref
) == PREF_INVALID
) {
1348 bool prerelease
= false;
1349 #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
1352 if (Preferences::GetDefaultCString(kChannelPref
).EqualsLiteral("beta")) {
1356 PREF_SetBoolPref(kTelemetryPref
, prerelease
, true);
1359 NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID
,
1360 nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID
);
1362 nsCOMPtr
<nsIObserverService
> observerService
=
1363 mozilla::services::GetObserverService();
1364 if (!observerService
)
1365 return NS_ERROR_FAILURE
;
1367 observerService
->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID
, nullptr);
1369 return pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST
);
1373 /******************************************************************************
1377 ******************************************************************************/
1381 Preferences::GetBool(const char* aPref
, bool* aResult
)
1383 NS_PRECONDITION(aResult
, "aResult must not be NULL");
1384 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1385 return PREF_GetBoolPref(aPref
, aResult
, false);
1390 Preferences::GetInt(const char* aPref
, int32_t* aResult
)
1392 NS_PRECONDITION(aResult
, "aResult must not be NULL");
1393 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1394 return PREF_GetIntPref(aPref
, aResult
, false);
1399 Preferences::GetFloat(const char* aPref
, float* aResult
)
1401 NS_PRECONDITION(aResult
, "aResult must not be NULL");
1402 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1403 nsAutoCString result
;
1404 nsresult rv
= PREF_CopyCharPref(aPref
, getter_Copies(result
), false);
1405 if (NS_SUCCEEDED(rv
)) {
1406 *aResult
= result
.ToFloat(&rv
);
1414 Preferences::GetCString(const char* aPref
)
1416 nsAdoptingCString result
;
1417 PREF_CopyCharPref(aPref
, getter_Copies(result
), false);
1423 Preferences::GetString(const char* aPref
)
1425 nsAdoptingString result
;
1426 GetString(aPref
, &result
);
1432 Preferences::GetCString(const char* aPref
, nsACString
* aResult
)
1434 NS_PRECONDITION(aResult
, "aResult must not be NULL");
1435 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1436 nsAutoCString result
;
1437 nsresult rv
= PREF_CopyCharPref(aPref
, getter_Copies(result
), false);
1438 if (NS_SUCCEEDED(rv
)) {
1446 Preferences::GetString(const char* aPref
, nsAString
* aResult
)
1448 NS_PRECONDITION(aResult
, "aResult must not be NULL");
1449 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1450 nsAutoCString result
;
1451 nsresult rv
= PREF_CopyCharPref(aPref
, getter_Copies(result
), false);
1452 if (NS_SUCCEEDED(rv
)) {
1453 CopyUTF8toUTF16(result
, *aResult
);
1460 Preferences::GetLocalizedCString(const char* aPref
)
1462 nsAdoptingCString result
;
1463 GetLocalizedCString(aPref
, &result
);
1469 Preferences::GetLocalizedString(const char* aPref
)
1471 nsAdoptingString result
;
1472 GetLocalizedString(aPref
, &result
);
1478 Preferences::GetLocalizedCString(const char* aPref
, nsACString
* aResult
)
1480 NS_PRECONDITION(aResult
, "aResult must not be NULL");
1481 nsAutoString result
;
1482 nsresult rv
= GetLocalizedString(aPref
, &result
);
1483 if (NS_SUCCEEDED(rv
)) {
1484 CopyUTF16toUTF8(result
, *aResult
);
1491 Preferences::GetLocalizedString(const char* aPref
, nsAString
* aResult
)
1493 NS_PRECONDITION(aResult
, "aResult must not be NULL");
1494 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1495 nsCOMPtr
<nsIPrefLocalizedString
> prefLocalString
;
1496 nsresult rv
= sRootBranch
->GetComplexValue(aPref
,
1497 NS_GET_IID(nsIPrefLocalizedString
),
1498 getter_AddRefs(prefLocalString
));
1499 if (NS_SUCCEEDED(rv
)) {
1500 NS_ASSERTION(prefLocalString
, "Succeeded but the result is NULL");
1501 prefLocalString
->GetData(getter_Copies(*aResult
));
1508 Preferences::GetComplex(const char* aPref
, const nsIID
&aType
, void** aResult
)
1510 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1511 return sRootBranch
->GetComplexValue(aPref
, aType
, aResult
);
1516 Preferences::SetCString(const char* aPref
, const char* aValue
)
1518 ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref
);
1519 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1520 return PREF_SetCharPref(aPref
, aValue
, false);
1525 Preferences::SetCString(const char* aPref
, const nsACString
&aValue
)
1527 ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref
);
1528 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1529 return PREF_SetCharPref(aPref
, PromiseFlatCString(aValue
).get(), false);
1534 Preferences::SetString(const char* aPref
, const char16_t
* aValue
)
1536 ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref
);
1537 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1538 return PREF_SetCharPref(aPref
, NS_ConvertUTF16toUTF8(aValue
).get(), false);
1543 Preferences::SetString(const char* aPref
, const nsAString
&aValue
)
1545 ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref
);
1546 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1547 return PREF_SetCharPref(aPref
, NS_ConvertUTF16toUTF8(aValue
).get(), false);
1552 Preferences::SetBool(const char* aPref
, bool aValue
)
1554 ENSURE_MAIN_PROCESS("Cannot SetBool from content process:", aPref
);
1555 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1556 return PREF_SetBoolPref(aPref
, aValue
, false);
1561 Preferences::SetInt(const char* aPref
, int32_t aValue
)
1563 ENSURE_MAIN_PROCESS("Cannot SetInt from content process:", aPref
);
1564 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1565 return PREF_SetIntPref(aPref
, aValue
, false);
1570 Preferences::SetFloat(const char* aPref
, float aValue
)
1572 return SetCString(aPref
, nsPrintfCString("%f", aValue
).get());
1577 Preferences::SetComplex(const char* aPref
, const nsIID
&aType
,
1578 nsISupports
* aValue
)
1580 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1581 return sRootBranch
->SetComplexValue(aPref
, aType
, aValue
);
1586 Preferences::ClearUser(const char* aPref
)
1588 ENSURE_MAIN_PROCESS("Cannot ClearUser from content process:", aPref
);
1589 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1590 return PREF_ClearUserPref(aPref
);
1595 Preferences::HasUserValue(const char* aPref
)
1597 NS_ENSURE_TRUE(InitStaticMembers(), false);
1598 return PREF_HasUserPref(aPref
);
1603 Preferences::GetType(const char* aPref
)
1605 NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID
);
1607 return NS_SUCCEEDED(sRootBranch
->GetPrefType(aPref
, &result
)) ?
1608 result
: nsIPrefBranch::PREF_INVALID
;
1613 Preferences::AddStrongObserver(nsIObserver
* aObserver
,
1616 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1617 return sRootBranch
->AddObserver(aPref
, aObserver
, false);
1622 Preferences::AddWeakObserver(nsIObserver
* aObserver
,
1625 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1626 return sRootBranch
->AddObserver(aPref
, aObserver
, true);
1631 Preferences::RemoveObserver(nsIObserver
* aObserver
,
1634 if (!sPreferences
&& sShutdown
) {
1635 return NS_OK
; // Observers have been released automatically.
1637 NS_ENSURE_TRUE(sPreferences
, NS_ERROR_NOT_AVAILABLE
);
1638 return sRootBranch
->RemoveObserver(aPref
, aObserver
);
1643 Preferences::AddStrongObservers(nsIObserver
* aObserver
,
1644 const char** aPrefs
)
1646 for (uint32_t i
= 0; aPrefs
[i
]; i
++) {
1647 nsresult rv
= AddStrongObserver(aObserver
, aPrefs
[i
]);
1648 NS_ENSURE_SUCCESS(rv
, rv
);
1655 Preferences::AddWeakObservers(nsIObserver
* aObserver
,
1656 const char** aPrefs
)
1658 for (uint32_t i
= 0; aPrefs
[i
]; i
++) {
1659 nsresult rv
= AddWeakObserver(aObserver
, aPrefs
[i
]);
1660 NS_ENSURE_SUCCESS(rv
, rv
);
1667 Preferences::RemoveObservers(nsIObserver
* aObserver
,
1668 const char** aPrefs
)
1670 if (!sPreferences
&& sShutdown
) {
1671 return NS_OK
; // Observers have been released automatically.
1673 NS_ENSURE_TRUE(sPreferences
, NS_ERROR_NOT_AVAILABLE
);
1675 for (uint32_t i
= 0; aPrefs
[i
]; i
++) {
1676 nsresult rv
= RemoveObserver(aObserver
, aPrefs
[i
]);
1677 NS_ENSURE_SUCCESS(rv
, rv
);
1684 Preferences::RegisterCallback(PrefChangedFunc aCallback
,
1688 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1690 ValueObserverHashKey
hashKey(aPref
, aCallback
);
1691 nsRefPtr
<ValueObserver
> observer
;
1692 gObserverTable
->Get(&hashKey
, getter_AddRefs(observer
));
1694 observer
->AppendClosure(aClosure
);
1698 observer
= new ValueObserver(aPref
, aCallback
);
1699 observer
->AppendClosure(aClosure
);
1700 nsresult rv
= AddStrongObserver(observer
, aPref
);
1701 NS_ENSURE_SUCCESS(rv
, rv
);
1702 gObserverTable
->Put(observer
, observer
);
1708 Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback
,
1712 nsresult rv
= RegisterCallback(aCallback
, aPref
, aClosure
);
1713 if (NS_SUCCEEDED(rv
)) {
1714 (*aCallback
)(aPref
, aClosure
);
1721 Preferences::UnregisterCallback(PrefChangedFunc aCallback
,
1725 if (!sPreferences
&& sShutdown
) {
1726 return NS_OK
; // Observers have been released automatically.
1728 NS_ENSURE_TRUE(sPreferences
, NS_ERROR_NOT_AVAILABLE
);
1730 ValueObserverHashKey
hashKey(aPref
, aCallback
);
1731 nsRefPtr
<ValueObserver
> observer
;
1732 gObserverTable
->Get(&hashKey
, getter_AddRefs(observer
));
1737 observer
->RemoveClosure(aClosure
);
1738 if (observer
->HasNoClosures()) {
1739 // Delete the callback since its list of closures is empty.
1740 gObserverTable
->Remove(observer
);
1745 static void BoolVarChanged(const char* aPref
, void* aClosure
)
1747 CacheData
* cache
= static_cast<CacheData
*>(aClosure
);
1748 *((bool*)cache
->cacheLocation
) =
1749 Preferences::GetBool(aPref
, cache
->defaultValueBool
);
1754 Preferences::AddBoolVarCache(bool* aCache
,
1758 NS_ASSERTION(aCache
, "aCache must not be NULL");
1760 AssertNotAlreadyCached("bool", aPref
, aCache
);
1762 *aCache
= GetBool(aPref
, aDefault
);
1763 CacheData
* data
= new CacheData();
1764 data
->cacheLocation
= aCache
;
1765 data
->defaultValueBool
= aDefault
;
1766 gCacheData
->AppendElement(data
);
1767 return RegisterCallback(BoolVarChanged
, aPref
, data
);
1770 static void IntVarChanged(const char* aPref
, void* aClosure
)
1772 CacheData
* cache
= static_cast<CacheData
*>(aClosure
);
1773 *((int32_t*)cache
->cacheLocation
) =
1774 Preferences::GetInt(aPref
, cache
->defaultValueInt
);
1779 Preferences::AddIntVarCache(int32_t* aCache
,
1783 NS_ASSERTION(aCache
, "aCache must not be NULL");
1785 AssertNotAlreadyCached("int", aPref
, aCache
);
1787 *aCache
= Preferences::GetInt(aPref
, aDefault
);
1788 CacheData
* data
= new CacheData();
1789 data
->cacheLocation
= aCache
;
1790 data
->defaultValueInt
= aDefault
;
1791 gCacheData
->AppendElement(data
);
1792 return RegisterCallback(IntVarChanged
, aPref
, data
);
1795 static void UintVarChanged(const char* aPref
, void* aClosure
)
1797 CacheData
* cache
= static_cast<CacheData
*>(aClosure
);
1798 *((uint32_t*)cache
->cacheLocation
) =
1799 Preferences::GetUint(aPref
, cache
->defaultValueUint
);
1804 Preferences::AddUintVarCache(uint32_t* aCache
,
1808 NS_ASSERTION(aCache
, "aCache must not be NULL");
1810 AssertNotAlreadyCached("uint", aPref
, aCache
);
1812 *aCache
= Preferences::GetUint(aPref
, aDefault
);
1813 CacheData
* data
= new CacheData();
1814 data
->cacheLocation
= aCache
;
1815 data
->defaultValueUint
= aDefault
;
1816 gCacheData
->AppendElement(data
);
1817 return RegisterCallback(UintVarChanged
, aPref
, data
);
1820 static void FloatVarChanged(const char* aPref
, void* aClosure
)
1822 CacheData
* cache
= static_cast<CacheData
*>(aClosure
);
1823 *((float*)cache
->cacheLocation
) =
1824 Preferences::GetFloat(aPref
, cache
->defaultValueFloat
);
1829 Preferences::AddFloatVarCache(float* aCache
,
1833 NS_ASSERTION(aCache
, "aCache must not be NULL");
1835 AssertNotAlreadyCached("float", aPref
, aCache
);
1837 *aCache
= Preferences::GetFloat(aPref
, aDefault
);
1838 CacheData
* data
= new CacheData();
1839 data
->cacheLocation
= aCache
;
1840 data
->defaultValueFloat
= aDefault
;
1841 gCacheData
->AppendElement(data
);
1842 return RegisterCallback(FloatVarChanged
, aPref
, data
);
1847 Preferences::GetDefaultBool(const char* aPref
, bool* aResult
)
1849 NS_PRECONDITION(aResult
, "aResult must not be NULL");
1850 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1851 return PREF_GetBoolPref(aPref
, aResult
, true);
1856 Preferences::GetDefaultInt(const char* aPref
, int32_t* aResult
)
1858 NS_PRECONDITION(aResult
, "aResult must not be NULL");
1859 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1860 return PREF_GetIntPref(aPref
, aResult
, true);
1865 Preferences::GetDefaultCString(const char* aPref
, nsACString
* aResult
)
1867 NS_PRECONDITION(aResult
, "aResult must not be NULL");
1868 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1869 nsAutoCString result
;
1870 nsresult rv
= PREF_CopyCharPref(aPref
, getter_Copies(result
), true);
1871 if (NS_SUCCEEDED(rv
)) {
1879 Preferences::GetDefaultString(const char* aPref
, nsAString
* aResult
)
1881 NS_PRECONDITION(aResult
, "aResult must not be NULL");
1882 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1883 nsAutoCString result
;
1884 nsresult rv
= PREF_CopyCharPref(aPref
, getter_Copies(result
), true);
1885 if (NS_SUCCEEDED(rv
)) {
1886 CopyUTF8toUTF16(result
, *aResult
);
1893 Preferences::GetDefaultLocalizedCString(const char* aPref
,
1894 nsACString
* aResult
)
1896 nsAutoString result
;
1897 nsresult rv
= GetDefaultLocalizedString(aPref
, &result
);
1898 if (NS_SUCCEEDED(rv
)) {
1899 CopyUTF16toUTF8(result
, *aResult
);
1906 Preferences::GetDefaultLocalizedString(const char* aPref
,
1909 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1910 nsCOMPtr
<nsIPrefLocalizedString
> prefLocalString
;
1912 sDefaultRootBranch
->GetComplexValue(aPref
,
1913 NS_GET_IID(nsIPrefLocalizedString
),
1914 getter_AddRefs(prefLocalString
));
1915 if (NS_SUCCEEDED(rv
)) {
1916 NS_ASSERTION(prefLocalString
, "Succeeded but the result is NULL");
1917 prefLocalString
->GetData(getter_Copies(*aResult
));
1924 Preferences::GetDefaultString(const char* aPref
)
1926 nsAdoptingString result
;
1927 GetDefaultString(aPref
, &result
);
1933 Preferences::GetDefaultCString(const char* aPref
)
1935 nsAdoptingCString result
;
1936 PREF_CopyCharPref(aPref
, getter_Copies(result
), true);
1942 Preferences::GetDefaultLocalizedString(const char* aPref
)
1944 nsAdoptingString result
;
1945 GetDefaultLocalizedString(aPref
, &result
);
1951 Preferences::GetDefaultLocalizedCString(const char* aPref
)
1953 nsAdoptingCString result
;
1954 GetDefaultLocalizedCString(aPref
, &result
);
1960 Preferences::GetDefaultComplex(const char* aPref
, const nsIID
&aType
,
1963 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE
);
1964 return sDefaultRootBranch
->GetComplexValue(aPref
, aType
, aResult
);
1969 Preferences::GetDefaultType(const char* aPref
)
1971 NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID
);
1973 return NS_SUCCEEDED(sDefaultRootBranch
->GetPrefType(aPref
, &result
)) ?
1974 result
: nsIPrefBranch::PREF_INVALID
;
1977 } // namespace mozilla
1979 #undef ENSURE_MAIN_PROCESS