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/. */
9 #include "nsISupports.h"
11 #include "nsCRT.h" // for atoll
13 #include "StaticComponents.h"
15 #include "nsCategoryManager.h"
17 #include "nsComponentManager.h"
18 #include "nsDirectoryService.h"
19 #include "nsDirectoryServiceDefs.h"
20 #include "nsCategoryManager.h"
21 #include "nsCategoryManagerUtils.h"
22 #include "nsLayoutModule.h"
23 #include "mozilla/MemoryReporting.h"
24 #include "nsIObserverService.h"
25 #include "nsIStringEnumerator.h"
27 #include "nsXPCOMPrivate.h"
28 #include "nsISupportsPrimitives.h"
29 #include "nsLocalFile.h"
30 #include "nsReadableUtils.h"
33 #include "nsThreadManager.h"
34 #include "nsThreadUtils.h"
36 #include "private/pprthred.h"
39 #include "ManifestParser.h"
40 #include "nsNetUtil.h"
41 #include "mozilla/Services.h"
42 #include "mozJSComponentLoader.h"
44 #include "mozilla/GenericFactory.h"
45 #include "nsSupportsPrimitives.h"
47 #include "nsIMutableArray.h"
48 #include "mozilla/DebugOnly.h"
49 #include "mozilla/FileUtils.h"
50 #include "mozilla/ScopeExit.h"
51 #include "mozilla/URLPreloader.h"
52 #include "mozilla/UniquePtr.h"
53 #include "mozilla/Variant.h"
54 #include "nsDataHashtable.h"
56 #include <new> // for placement new
58 #include "mozilla/Omnijar.h"
60 #include "mozilla/Logging.h"
61 #include "LogModulePrefWatcher.h"
64 # include "mozmemory.h"
67 using namespace mozilla
;
68 using namespace mozilla::xpcom
;
70 static LazyLogModule
nsComponentManagerLog("nsComponentManager");
73 # define SHOW_DENIED_ON_SHUTDOWN
74 # define SHOW_CI_ON_EXISTING_SERVICE
77 NS_DEFINE_CID(kCategoryManagerCID
, NS_CATEGORYMANAGER_CID
);
79 nsresult
nsGetServiceFromCategory::operator()(const nsIID
& aIID
,
80 void** aInstancePtr
) const {
83 nsCOMPtr
<nsICategoryManager
> catman
;
84 nsComponentManagerImpl
* compMgr
= nsComponentManagerImpl::gComponentManager
;
86 rv
= NS_ERROR_NOT_INITIALIZED
;
90 rv
= compMgr
->nsComponentManagerImpl::GetService(
91 kCategoryManagerCID
, NS_GET_IID(nsICategoryManager
),
92 getter_AddRefs(catman
));
97 /* find the contractID for category.entry */
98 rv
= catman
->GetCategoryEntry(mCategory
, mEntry
, value
);
102 if (value
.IsVoid()) {
103 rv
= NS_ERROR_SERVICE_NOT_AVAILABLE
;
107 rv
= compMgr
->nsComponentManagerImpl::GetServiceByContractID(
108 value
.get(), aIID
, aInstancePtr
);
121 class AutoIDString
: public nsAutoCStringN
<NSID_LENGTH
> {
123 explicit AutoIDString(const nsID
& aID
) {
124 SetLength(NSID_LENGTH
- 1);
125 aID
.ToProvidedString(
126 *reinterpret_cast<char(*)[NSID_LENGTH
]>(BeginWriting()));
135 using ProcessSelector
= Module::ProcessSelector
;
137 // Note: These must be kept in sync with the ProcessSelector definition in
139 bool ProcessSelectorMatches(ProcessSelector aSelector
) {
140 GeckoProcessType type
= XRE_GetProcessType();
141 if (type
== GeckoProcessType_GPU
) {
142 return !!(aSelector
& Module::ALLOW_IN_GPU_PROCESS
);
145 if (type
== GeckoProcessType_RDD
) {
146 return !!(aSelector
& Module::ALLOW_IN_RDD_PROCESS
);
149 if (type
== GeckoProcessType_Socket
) {
150 return !!(aSelector
& (Module::ALLOW_IN_SOCKET_PROCESS
));
153 if (type
== GeckoProcessType_VR
) {
154 return !!(aSelector
& Module::ALLOW_IN_VR_PROCESS
);
157 if (aSelector
& Module::MAIN_PROCESS_ONLY
) {
158 return type
== GeckoProcessType_Default
;
160 if (aSelector
& Module::CONTENT_PROCESS_ONLY
) {
161 return type
== GeckoProcessType_Content
;
166 static bool gProcessMatchTable
[Module::kMaxProcessSelector
+ 1];
168 bool FastProcessSelectorMatches(ProcessSelector aSelector
) {
169 return gProcessMatchTable
[size_t(aSelector
)];
173 } // namespace mozilla
178 * A wrapper simple wrapper class, which can hold either a dynamic
179 * nsFactoryEntry instance, or a static StaticModule entry, and transparently
180 * forwards method calls to the wrapped object.
182 * This allows the same code to work with either static or dynamic modules
183 * without caring about the difference.
185 class MOZ_STACK_CLASS EntryWrapper final
{
187 explicit EntryWrapper(nsFactoryEntry
* aEntry
) : mEntry(aEntry
) {}
189 explicit EntryWrapper(const StaticModule
* aEntry
) : mEntry(aEntry
) {}
191 #define MATCH(type, ifFactory, ifStatic) \
193 type operator()(nsFactoryEntry* entry) { ifFactory; } \
194 type operator()(const StaticModule* entry) { ifStatic; } \
196 return mEntry.match((Matcher()))
199 MATCH(const nsID
&, return *entry
->mCIDEntry
->cid
, return entry
->CID());
202 already_AddRefed
<nsIFactory
> GetFactory() {
203 MATCH(already_AddRefed
<nsIFactory
>, return entry
->GetFactory(),
204 return entry
->GetFactory());
208 * Creates an instance of the underlying component. This should be used in
209 * preference to GetFactory()->CreateInstance() where appropriate, since it
210 * side-steps the necessity of creating a nsIFactory instance for static
213 nsresult
CreateInstance(nsISupports
* aOuter
, const nsIID
& aIID
,
215 if (mEntry
.is
<nsFactoryEntry
*>()) {
216 return mEntry
.as
<nsFactoryEntry
*>()->CreateInstance(aOuter
, aIID
,
219 return mEntry
.as
<const StaticModule
*>()->CreateInstance(aOuter
, aIID
,
224 * Returns the cached service instance for this entry, if any. This should
225 * only be accessed while mLock is held.
227 nsISupports
* ServiceInstance() {
228 MATCH(nsISupports
*, return entry
->mServiceObject
,
229 return entry
->ServiceInstance());
231 void SetServiceInstance(already_AddRefed
<nsISupports
> aInst
) {
232 if (mEntry
.is
<nsFactoryEntry
*>()) {
233 mEntry
.as
<nsFactoryEntry
*>()->mServiceObject
= aInst
;
235 return mEntry
.as
<const StaticModule
*>()->SetServiceInstance(
241 * Returns the description string for the module this entry belongs to. For
242 * static entries, always returns "<unknown module>".
244 nsCString
ModuleDescription() {
246 return entry
->mModule
? entry
->mModule
->Description()
247 : NS_LITERAL_CSTRING("<unknown module>"),
248 return NS_LITERAL_CSTRING("<unknown module>"));
252 Variant
<nsFactoryEntry
*, const StaticModule
*> mEntry
;
255 // GetService and a few other functions need to exit their mutex mid-function
256 // without reentering it later in the block. This class supports that
257 // style of early-exit that MutexAutoUnlock doesn't.
259 class MOZ_STACK_CLASS MutexLock
{
261 explicit MutexLock(SafeMutex
& aMutex
) : mMutex(aMutex
), mLocked(false) {
272 NS_ASSERTION(!mLocked
, "Re-entering a mutex");
278 NS_ASSERTION(mLocked
, "Exiting a mutex that isn't held!");
290 // this is safe to call during InitXPCOM
291 static already_AddRefed
<nsIFile
> GetLocationFromDirectoryService(
293 nsCOMPtr
<nsIProperties
> directoryService
;
294 nsDirectoryService::Create(nullptr, NS_GET_IID(nsIProperties
),
295 getter_AddRefs(directoryService
));
297 if (!directoryService
) {
301 nsCOMPtr
<nsIFile
> file
;
303 directoryService
->Get(aProp
, NS_GET_IID(nsIFile
), getter_AddRefs(file
));
308 return file
.forget();
311 static already_AddRefed
<nsIFile
> CloneAndAppend(nsIFile
* aBase
,
312 const nsACString
& aAppend
) {
314 aBase
->Clone(getter_AddRefs(f
));
319 f
->AppendNative(aAppend
);
323 ////////////////////////////////////////////////////////////////////////////////
324 // nsComponentManagerImpl
325 ////////////////////////////////////////////////////////////////////////////////
327 nsresult
nsComponentManagerImpl::Create(nsISupports
* aOuter
, REFNSIID aIID
,
330 return NS_ERROR_NO_AGGREGATION
;
333 if (!gComponentManager
) {
334 return NS_ERROR_FAILURE
;
337 return gComponentManager
->QueryInterface(aIID
, aResult
);
340 static const int CONTRACTID_HASHTABLE_INITIAL_LENGTH
= 32;
342 nsComponentManagerImpl::nsComponentManagerImpl()
343 : mFactories(CONTRACTID_HASHTABLE_INITIAL_LENGTH
),
344 mContractIDs(CONTRACTID_HASHTABLE_INITIAL_LENGTH
),
345 mLock("nsComponentManagerImpl.mLock"),
346 mStatus(NOT_INITIALIZED
) {}
348 extern const mozilla::Module kNeckoModule
;
349 extern const mozilla::Module kPowerManagerModule
;
350 extern const mozilla::Module kContentProcessWidgetModule
;
351 #if defined(MOZ_WIDGET_COCOA) || defined(MOZ_WIDGET_UIKIT)
352 extern const mozilla::Module kWidgetModule
;
354 extern const mozilla::Module kLayoutModule
;
355 extern const mozilla::Module kKeyValueModule
;
356 extern const mozilla::Module kXREModule
;
357 extern const mozilla::Module kEmbeddingModule
;
359 static nsTArray
<const mozilla::Module
*>* sExtraStaticModules
;
362 void nsComponentManagerImpl::InitializeStaticModules() {
363 if (sExtraStaticModules
) {
367 sExtraStaticModules
= new nsTArray
<const mozilla::Module
*>;
370 nsTArray
<nsComponentManagerImpl::ComponentLocation
>*
371 nsComponentManagerImpl::sModuleLocations
;
374 void nsComponentManagerImpl::InitializeModuleLocations() {
375 if (sModuleLocations
) {
379 sModuleLocations
= new nsTArray
<ComponentLocation
>;
382 nsresult
nsComponentManagerImpl::Init() {
384 gProcessMatchTable
[size_t(ProcessSelector::ANY_PROCESS
)] =
385 ProcessSelectorMatches(ProcessSelector::ANY_PROCESS
);
386 gProcessMatchTable
[size_t(ProcessSelector::MAIN_PROCESS_ONLY
)] =
387 ProcessSelectorMatches(ProcessSelector::MAIN_PROCESS_ONLY
);
388 gProcessMatchTable
[size_t(ProcessSelector::CONTENT_PROCESS_ONLY
)] =
389 ProcessSelectorMatches(ProcessSelector::CONTENT_PROCESS_ONLY
);
390 gProcessMatchTable
[size_t(ProcessSelector::ALLOW_IN_GPU_PROCESS
)] =
391 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_PROCESS
);
392 gProcessMatchTable
[size_t(ProcessSelector::ALLOW_IN_VR_PROCESS
)] =
393 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_VR_PROCESS
);
394 gProcessMatchTable
[size_t(ProcessSelector::ALLOW_IN_SOCKET_PROCESS
)] =
395 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_SOCKET_PROCESS
);
396 gProcessMatchTable
[size_t(ProcessSelector::ALLOW_IN_RDD_PROCESS
)] =
397 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_RDD_PROCESS
);
398 gProcessMatchTable
[size_t(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS
)] =
399 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS
);
400 gProcessMatchTable
[size_t(
401 ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS
)] =
402 ProcessSelectorMatches(
403 ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS
);
404 gProcessMatchTable
[size_t(
405 ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS
)] =
406 ProcessSelectorMatches(
407 ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS
);
408 gProcessMatchTable
[size_t(
409 ProcessSelector::ALLOW_IN_RDD_AND_SOCKET_PROCESS
)] =
410 ProcessSelectorMatches(
411 ProcessSelector::ALLOW_IN_RDD_AND_SOCKET_PROCESS
);
412 gProcessMatchTable
[size_t(
413 ProcessSelector::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS
)] =
414 ProcessSelectorMatches(
415 ProcessSelector::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS
);
416 gProcessMatchTable
[size_t(
417 ProcessSelector::ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS
)] =
418 ProcessSelectorMatches(
419 ProcessSelector::ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS
);
422 MOZ_ASSERT(NOT_INITIALIZED
== mStatus
);
424 nsCOMPtr
<nsIFile
> greDir
= GetLocationFromDirectoryService(NS_GRE_DIR
);
425 nsCOMPtr
<nsIFile
> appDir
=
426 GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR
);
428 InitializeStaticModules();
430 nsCategoryManager::GetSingleton()->SuppressNotifications(true);
432 RegisterModule(&kXPCOMModule
);
433 RegisterModule(&kNeckoModule
);
434 RegisterModule(&kPowerManagerModule
);
435 RegisterModule(&kContentProcessWidgetModule
);
436 #if defined(MOZ_WIDGET_COCOA) || defined(MOZ_WIDGET_UIKIT)
437 RegisterModule(&kWidgetModule
);
439 RegisterModule(&kLayoutModule
);
440 RegisterModule(&kKeyValueModule
);
441 RegisterModule(&kXREModule
);
442 RegisterModule(&kEmbeddingModule
);
444 for (uint32_t i
= 0; i
< sExtraStaticModules
->Length(); ++i
) {
445 RegisterModule((*sExtraStaticModules
)[i
]);
448 auto* catMan
= nsCategoryManager::GetSingleton();
449 for (const auto& cat
: gStaticCategories
) {
450 for (const auto& entry
: cat
) {
451 if (entry
.Active()) {
452 catMan
->AddCategoryEntry(cat
.Name(), entry
.Entry(), entry
.Value());
457 bool loadChromeManifests
;
458 switch (XRE_GetProcessType()) {
459 // We are going to assume that only a select few (see below) process types
460 // want to load chrome manifests, and that any new process types will not
461 // want to load them, because they're not going to be executing JS.
462 case GeckoProcessType_RemoteSandboxBroker
:
464 loadChromeManifests
= false;
467 // XXX The check this code replaced implicitly let through all of these
468 // process types, but presumably only the default (parent) and content
469 // processes really need chrome manifests...?
470 case GeckoProcessType_Default
:
471 case GeckoProcessType_Plugin
:
472 case GeckoProcessType_Content
:
473 case GeckoProcessType_IPDLUnitTest
:
474 case GeckoProcessType_GMPlugin
:
475 loadChromeManifests
= true;
479 if (loadChromeManifests
) {
480 // This needs to be called very early, before anything in nsLayoutModule is
481 // used, and before any calls are made into the JS engine.
482 nsLayoutModuleInitialize();
484 mJSLoaderReady
= true;
486 // The overall order in which chrome.manifests are expected to be treated
488 // - greDir's omni.ja or greDir
489 // - appDir's omni.ja or appDir
491 InitializeModuleLocations();
492 ComponentLocation
* cl
= sModuleLocations
->AppendElement();
493 cl
->type
= NS_APP_LOCATION
;
494 RefPtr
<nsZipArchive
> greOmnijar
=
495 mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE
);
497 cl
->location
.Init(greOmnijar
, "chrome.manifest");
499 nsCOMPtr
<nsIFile
> lf
=
500 CloneAndAppend(greDir
, NS_LITERAL_CSTRING("chrome.manifest"));
501 cl
->location
.Init(lf
);
504 RefPtr
<nsZipArchive
> appOmnijar
=
505 mozilla::Omnijar::GetReader(mozilla::Omnijar::APP
);
507 cl
= sModuleLocations
->AppendElement();
508 cl
->type
= NS_APP_LOCATION
;
509 cl
->location
.Init(appOmnijar
, "chrome.manifest");
512 appDir
->Equals(greDir
, &equals
);
514 cl
= sModuleLocations
->AppendElement();
515 cl
->type
= NS_APP_LOCATION
;
516 nsCOMPtr
<nsIFile
> lf
=
517 CloneAndAppend(appDir
, NS_LITERAL_CSTRING("chrome.manifest"));
518 cl
->location
.Init(lf
);
522 RereadChromeManifests(false);
525 nsCategoryManager::GetSingleton()->SuppressNotifications(false);
527 RegisterWeakMemoryReporter(this);
529 // NB: The logging preference watcher needs to be registered late enough in
530 // startup that it's okay to use the preference system, but also as soon as
531 // possible so that log modules enabled via preferences are turned on as
532 // early as possible.
534 // We can't initialize the preference watcher when the log module manager is
535 // initialized, as a number of things attempt to start logging before the
536 // preference system is initialized.
538 // The preference system is registered as a component so at this point during
539 // component manager initialization we know it is setup and we can register
540 // for notifications.
541 LogModulePrefWatcher::RegisterPrefWatcher();
543 // Unfortunately, we can't register the nsCategoryManager memory reporter
544 // in its constructor (which is triggered by the GetSingleton() call
545 // above) because the memory reporter manager isn't initialized at that
546 // point. So we wait until now.
547 nsCategoryManager::GetSingleton()->InitMemoryReporter();
549 MOZ_LOG(nsComponentManagerLog
, LogLevel::Debug
,
550 ("nsComponentManager: Initialized."));
554 MOZ_ASSERT(!XRE_IsContentProcess() ||
555 mFactories
.Count() > CONTRACTID_HASHTABLE_INITIAL_LENGTH
/ 3,
556 "Initial component hashtable size is too large");
561 static const int kModuleVersionWithSelector
= 51;
563 template <typename T
>
564 static void AssertNotMallocAllocated(T
* aPtr
) {
565 #if defined(DEBUG) && defined(MOZ_MEMORY)
566 jemalloc_ptr_info_t info
;
567 jemalloc_ptr_info((void*)aPtr
, &info
);
568 MOZ_ASSERT(info
.tag
== TagUnknown
);
572 template <typename T
>
573 static void AssertNotStackAllocated(T
* aPtr
) {
574 // On all of our supported platforms, the stack grows down. Any address
575 // located below the address of our argument is therefore guaranteed not to be
576 // stack-allocated by the caller.
578 // For addresses above our argument, things get trickier. The main thread
579 // stack is traditionally placed at the top of the program's address space,
580 // but that is becoming less reliable as more and more systems adopt address
581 // space layout randomization strategies, so we have to guess how much space
582 // above our argument pointer we need to care about.
584 // On most systems, we're guaranteed at least several KiB at the top of each
585 // stack for TLS. We'd probably be safe assuming at least 4KiB in the stack
586 // segment above our argument address, but safer is... well, safer.
588 // For threads with huge stacks, it's theoretically possible that we could
589 // wind up being passed a stack-allocated string from farther up the stack,
590 // but this is a best-effort thing, so we'll assume we only care about the
591 // immediate caller. For that case, max 2KiB per stack frame is probably a
592 // reasonable guess most of the time, and is less than the ~4KiB that we
593 // expect for TLS, so go with that to avoid the risk of bumping into heap
594 // data just above the stack.
596 static constexpr size_t kFuzz
= 2048;
598 MOZ_ASSERT(uintptr_t(aPtr
) < uintptr_t(&aPtr
) ||
599 uintptr_t(aPtr
) > uintptr_t(&aPtr
) + kFuzz
);
603 static inline nsCString
AsLiteralCString(const char* aStr
) {
604 AssertNotMallocAllocated(aStr
);
605 AssertNotStackAllocated(aStr
);
608 str
.AssignLiteral(aStr
, strlen(aStr
));
612 void nsComponentManagerImpl::RegisterModule(const mozilla::Module
* aModule
) {
613 mLock
.AssertNotCurrentThreadOwns();
615 if (aModule
->mVersion
>= kModuleVersionWithSelector
&&
616 !ProcessSelectorMatches(aModule
->selector
)) {
621 // Scope the monitor so that we don't hold it while calling into the
623 MutexLock
lock(mLock
);
625 KnownModule
* m
= new KnownModule(aModule
);
626 mKnownStaticModules
.AppendElement(m
);
628 if (aModule
->mCIDs
) {
629 const mozilla::Module::CIDEntry
* entry
;
630 for (entry
= aModule
->mCIDs
; entry
->cid
; ++entry
) {
631 RegisterCIDEntryLocked(entry
, m
);
635 if (aModule
->mContractIDs
) {
636 const mozilla::Module::ContractIDEntry
* entry
;
637 for (entry
= aModule
->mContractIDs
; entry
->contractid
; ++entry
) {
638 RegisterContractIDLocked(entry
);
640 MOZ_ASSERT(!entry
->cid
, "Incorrectly terminated contract list");
644 if (aModule
->mCategoryEntries
) {
645 const mozilla::Module::CategoryEntry
* entry
;
646 for (entry
= aModule
->mCategoryEntries
; entry
->category
; ++entry
)
647 nsCategoryManager::GetSingleton()->AddCategoryEntry(
648 AsLiteralCString(entry
->category
), AsLiteralCString(entry
->entry
),
649 AsLiteralCString(entry
->value
));
653 void nsComponentManagerImpl::RegisterCIDEntryLocked(
654 const mozilla::Module::CIDEntry
* aEntry
, KnownModule
* aModule
) {
655 mLock
.AssertCurrentThreadOwns();
657 if (!ProcessSelectorMatches(aEntry
->processSelector
)) {
662 // If we're still in the static initialization phase, check that we're not
663 // registering something that was already registered.
664 if (mStatus
!= NORMAL
) {
665 if (StaticComponents::LookupByCID(*aEntry
->cid
)) {
666 MOZ_CRASH_UNSAFE_PRINTF(
667 "While registering XPCOM module %s, trying to re-register CID '%s' "
668 "already registered by a static component.",
669 aModule
->Description().get(), AutoIDString(*aEntry
->cid
).get());
674 if (auto entry
= mFactories
.LookupForAdd(aEntry
->cid
)) {
675 nsFactoryEntry
* f
= entry
.Data();
676 NS_WARNING("Re-registering a CID?");
680 existing
= f
->mModule
->Description();
682 existing
= "<unknown module>";
684 SafeMutexAutoUnlock
unlock(mLock
);
686 "While registering XPCOM module %s, trying to re-register CID '%s' "
687 "already registered by %s.",
688 aModule
->Description().get(), AutoIDString(*aEntry
->cid
).get(),
692 [aEntry
, aModule
]() { return new nsFactoryEntry(aEntry
, aModule
); });
696 void nsComponentManagerImpl::RegisterContractIDLocked(
697 const mozilla::Module::ContractIDEntry
* aEntry
) {
698 mLock
.AssertCurrentThreadOwns();
700 if (!ProcessSelectorMatches(aEntry
->processSelector
)) {
705 // If we're still in the static initialization phase, check that we're not
706 // registering something that was already registered.
707 if (mStatus
!= NORMAL
) {
708 if (const StaticModule
* module
= StaticComponents::LookupByContractID(
709 nsAutoCString(aEntry
->contractid
))) {
710 MOZ_CRASH_UNSAFE_PRINTF(
711 "Could not map contract ID '%s' to CID %s because it is already "
713 aEntry
->contractid
, AutoIDString(*aEntry
->cid
).get(),
714 AutoIDString(module
->CID()).get());
719 nsFactoryEntry
* f
= mFactories
.Get(aEntry
->cid
);
721 NS_WARNING("No CID found when attempting to map contract ID");
723 SafeMutexAutoUnlock
unlock(mLock
);
725 "Could not map contract ID '%s' to CID %s because no implementation of "
726 "the CID is registered.",
727 aEntry
->contractid
, AutoIDString(*aEntry
->cid
).get());
732 mContractIDs
.Put(AsLiteralCString(aEntry
->contractid
), f
);
735 static void CutExtension(nsCString
& aPath
) {
736 int32_t dotPos
= aPath
.RFindChar('.');
737 if (kNotFound
== dotPos
) {
740 aPath
.Cut(0, dotPos
+ 1);
744 static void DoRegisterManifest(NSLocationType aType
, FileLocation
& aFile
,
746 auto result
= URLPreloader::Read(aFile
);
748 nsCString
buf(result
.unwrap());
749 ParseManifest(aType
, aFile
, buf
.BeginWriting(), aChromeOnly
);
750 } else if (NS_BOOTSTRAPPED_LOCATION
!= aType
) {
752 aFile
.GetURIString(uri
);
753 LogMessage("Could not read chrome manifest '%s'.", uri
.get());
757 void nsComponentManagerImpl::RegisterManifest(NSLocationType aType
,
760 DoRegisterManifest(aType
, aFile
, aChromeOnly
);
763 void nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext
& aCx
,
764 int aLineNo
, char* const* aArgv
) {
765 char* file
= aArgv
[0];
766 FileLocation
f(aCx
.mFile
, file
);
767 RegisterManifest(aCx
.mType
, f
, aCx
.mChromeOnly
);
770 void nsComponentManagerImpl::ManifestComponent(ManifestProcessingContext
& aCx
,
772 char* const* aArgv
) {
773 mLock
.AssertNotCurrentThreadOwns();
776 char* file
= aArgv
[1];
779 if (!cid
.Parse(id
)) {
780 LogMessageWithContext(aCx
.mFile
, aLineNo
, "Malformed CID: '%s'.", id
);
784 // Precompute the hash/file data outside of the lock
785 FileLocation
fl(aCx
.mFile
, file
);
787 fl
.GetURIString(hash
);
789 MutexLock
lock(mLock
);
790 if (Maybe
<EntryWrapper
> f
= LookupByCID(lock
, cid
)) {
791 nsCString
existing(f
->ModuleDescription());
795 LogMessageWithContext(
797 "Trying to re-register CID '%s' already registered by %s.",
798 AutoIDString(cid
).get(), existing
.get());
804 km
= mKnownModules
.Get(hash
);
806 km
= new KnownModule(fl
);
807 mKnownModules
.Put(hash
, km
);
810 void* place
= mArena
.Allocate(sizeof(nsCID
));
811 nsID
* permanentCID
= static_cast<nsID
*>(place
);
814 place
= mArena
.Allocate(sizeof(mozilla::Module::CIDEntry
));
815 auto* e
= new (KnownNotNull
, place
) mozilla::Module::CIDEntry();
816 e
->cid
= permanentCID
;
818 mFactories
.Put(permanentCID
, new nsFactoryEntry(e
, km
));
821 void nsComponentManagerImpl::ManifestContract(ManifestProcessingContext
& aCx
,
822 int aLineNo
, char* const* aArgv
) {
823 mLock
.AssertNotCurrentThreadOwns();
825 char* contract
= aArgv
[0];
829 if (!cid
.Parse(id
)) {
830 LogMessageWithContext(aCx
.mFile
, aLineNo
, "Malformed CID: '%s'.", id
);
834 MutexLock
lock(mLock
);
835 nsFactoryEntry
* f
= mFactories
.Get(&cid
);
838 LogMessageWithContext(aCx
.mFile
, aLineNo
,
839 "Could not map contract ID '%s' to CID %s because no "
840 "implementation of the CID is registered.",
845 nsDependentCString
contractString(contract
);
846 StaticComponents::InvalidateContractID(nsDependentCString(contractString
));
847 mContractIDs
.Put(contractString
, f
);
850 void nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext
& aCx
,
851 int aLineNo
, char* const* aArgv
) {
852 char* category
= aArgv
[0];
853 char* key
= aArgv
[1];
854 char* value
= aArgv
[2];
856 nsCategoryManager::GetSingleton()->AddCategoryEntry(
857 nsDependentCString(category
), nsDependentCString(key
),
858 nsDependentCString(value
));
861 void nsComponentManagerImpl::RereadChromeManifests(bool aChromeOnly
) {
862 for (uint32_t i
= 0; i
< sModuleLocations
->Length(); ++i
) {
863 ComponentLocation
& l
= sModuleLocations
->ElementAt(i
);
864 RegisterManifest(l
.type
, l
.location
, aChromeOnly
);
867 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
869 obs
->NotifyObservers(nullptr, "chrome-manifests-loaded", nullptr);
873 bool nsComponentManagerImpl::KnownModule::Load() {
879 mFile
.GetURIString(extension
);
880 CutExtension(extension
);
881 if (!extension
.Equals("js")) {
885 RefPtr
<mozJSComponentLoader
> loader
= mozJSComponentLoader::Get();
886 mModule
= loader
->LoadModule(mFile
);
894 if (mModule
->loadProc
) {
895 nsresult rv
= mModule
->loadProc();
906 nsCString
nsComponentManagerImpl::KnownModule::Description() const {
909 mFile
.GetURIString(s
);
911 s
= "<static module>";
916 nsresult
nsComponentManagerImpl::Shutdown(void) {
917 MOZ_ASSERT(NORMAL
== mStatus
);
919 mStatus
= SHUTDOWN_IN_PROGRESS
;
921 // Shutdown the component manager
922 MOZ_LOG(nsComponentManagerLog
, LogLevel::Debug
,
923 ("nsComponentManager: Beginning Shutdown."));
925 UnregisterWeakMemoryReporter(this);
927 // Release all cached factories
928 mContractIDs
.Clear();
929 mFactories
.Clear(); // XXX release the objects, don't just clear
930 mKnownModules
.Clear();
931 mKnownStaticModules
.Clear();
933 StaticComponents::Shutdown();
935 delete sExtraStaticModules
;
936 delete sModuleLocations
;
938 mStatus
= SHUTDOWN_COMPLETE
;
940 MOZ_LOG(nsComponentManagerLog
, LogLevel::Debug
,
941 ("nsComponentManager: Shutdown complete."));
946 nsComponentManagerImpl::~nsComponentManagerImpl() {
947 MOZ_LOG(nsComponentManagerLog
, LogLevel::Debug
,
948 ("nsComponentManager: Beginning destruction."));
950 if (SHUTDOWN_COMPLETE
!= mStatus
) {
954 MOZ_LOG(nsComponentManagerLog
, LogLevel::Debug
,
955 ("nsComponentManager: Destroyed."));
958 NS_IMPL_ISUPPORTS(nsComponentManagerImpl
, nsIComponentManager
,
959 nsIServiceManager
, nsIComponentRegistrar
,
960 nsISupportsWeakReference
, nsIInterfaceRequestor
,
963 nsresult
nsComponentManagerImpl::GetInterface(const nsIID
& aUuid
,
965 NS_WARNING("This isn't supported");
966 // fall through to QI as anything QIable is a superset of what can be
967 // got via the GetInterface()
968 return QueryInterface(aUuid
, aResult
);
971 Maybe
<EntryWrapper
> nsComponentManagerImpl::LookupByCID(const nsID
& aCID
) {
972 return LookupByCID(MutexLock(mLock
), aCID
);
975 Maybe
<EntryWrapper
> nsComponentManagerImpl::LookupByCID(const MutexLock
&,
977 if (const StaticModule
* module
= StaticComponents::LookupByCID(aCID
)) {
978 return Some(EntryWrapper(module
));
980 if (nsFactoryEntry
* entry
= mFactories
.Get(&aCID
)) {
981 return Some(EntryWrapper(entry
));
986 Maybe
<EntryWrapper
> nsComponentManagerImpl::LookupByContractID(
987 const nsACString
& aContractID
) {
988 return LookupByContractID(MutexLock(mLock
), aContractID
);
991 Maybe
<EntryWrapper
> nsComponentManagerImpl::LookupByContractID(
992 const MutexLock
&, const nsACString
& aContractID
) {
993 if (const StaticModule
* module
=
994 StaticComponents::LookupByContractID(aContractID
)) {
995 return Some(EntryWrapper(module
));
997 if (nsFactoryEntry
* entry
= mContractIDs
.Get(aContractID
)) {
998 // UnregisterFactory might have left a stale nsFactoryEntry in
999 // mContractIDs, so we should check to see whether this entry has
1001 if (entry
->mModule
|| entry
->mFactory
|| entry
->mServiceObject
) {
1002 return Some(EntryWrapper(entry
));
1008 already_AddRefed
<nsIFactory
> nsComponentManagerImpl::FindFactory(
1009 const nsCID
& aClass
) {
1010 Maybe
<EntryWrapper
> e
= LookupByCID(aClass
);
1015 return e
->GetFactory();
1018 already_AddRefed
<nsIFactory
> nsComponentManagerImpl::FindFactory(
1019 const char* aContractID
, uint32_t aContractIDLen
) {
1020 Maybe
<EntryWrapper
> entry
=
1021 LookupByContractID(nsDependentCString(aContractID
, aContractIDLen
));
1026 return entry
->GetFactory();
1032 * Given a classID, this finds the singleton ClassObject that implements the
1033 * CID. Returns an interface of type aIID off the singleton classobject.
1036 nsComponentManagerImpl::GetClassObject(const nsCID
& aClass
, const nsIID
& aIID
,
1040 if (MOZ_LOG_TEST(nsComponentManagerLog
, LogLevel::Debug
)) {
1041 char* buf
= aClass
.ToString();
1042 PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf
);
1048 MOZ_ASSERT(aResult
!= nullptr);
1050 nsCOMPtr
<nsIFactory
> factory
= FindFactory(aClass
);
1052 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1055 rv
= factory
->QueryInterface(aIID
, aResult
);
1058 nsComponentManagerLog
, LogLevel::Warning
,
1059 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv
) ? "succeeded" : "FAILED"));
1065 nsComponentManagerImpl::GetClassObjectByContractID(const char* aContractID
,
1068 if (NS_WARN_IF(!aResult
) || NS_WARN_IF(!aContractID
)) {
1069 return NS_ERROR_INVALID_ARG
;
1074 MOZ_LOG(nsComponentManagerLog
, LogLevel::Debug
,
1075 ("nsComponentManager: GetClassObjectByContractID(%s)", aContractID
));
1077 nsCOMPtr
<nsIFactory
> factory
= FindFactory(aContractID
, strlen(aContractID
));
1079 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1082 rv
= factory
->QueryInterface(aIID
, aResult
);
1084 MOZ_LOG(nsComponentManagerLog
, LogLevel::Warning
,
1085 ("\t\tGetClassObjectByContractID() %s",
1086 NS_SUCCEEDED(rv
) ? "succeeded" : "FAILED"));
1094 * Create an instance of an object that implements an interface and belongs
1095 * to the implementation aClass using the factory. The factory is immediately
1096 * released and not held onto for any longer.
1099 nsComponentManagerImpl::CreateInstance(const nsCID
& aClass
,
1100 nsISupports
* aDelegate
,
1101 const nsIID
& aIID
, void** aResult
) {
1102 // test this first, since there's no point in creating a component during
1103 // shutdown -- whether it's available or not would depend on the order it
1104 // occurs in the list
1105 if (gXPCOMShuttingDown
) {
1106 // When processing shutdown, don't process new GetService() requests
1107 #ifdef SHOW_DENIED_ON_SHUTDOWN
1109 "Creating new instance on shutdown. Denied.\n"
1110 " CID: %s\n IID: %s\n",
1111 AutoIDString(aClass
).get(), AutoIDString(aIID
).get());
1112 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1113 return NS_ERROR_UNEXPECTED
;
1117 return NS_ERROR_NULL_POINTER
;
1121 Maybe
<EntryWrapper
> entry
= LookupByCID(aClass
);
1124 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1127 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1128 if (entry
->ServiceInstance()) {
1129 nsAutoCString message
;
1131 NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
1132 AutoIDString(aClass
) +
1133 NS_LITERAL_CSTRING("\" when a service for this CID already exists!");
1134 NS_ERROR(message
.get());
1139 nsCOMPtr
<nsIFactory
> factory
= entry
->GetFactory();
1141 rv
= factory
->CreateInstance(aDelegate
, aIID
, aResult
);
1142 if (NS_SUCCEEDED(rv
) && !*aResult
) {
1143 NS_ERROR("Factory did not return an object but returned success!");
1144 rv
= NS_ERROR_SERVICE_NOT_AVAILABLE
;
1147 // Translate error values
1148 rv
= NS_ERROR_FACTORY_NOT_REGISTERED
;
1151 if (MOZ_LOG_TEST(nsComponentManagerLog
, LogLevel::Warning
)) {
1152 char* buf
= aClass
.ToString();
1153 MOZ_LOG(nsComponentManagerLog
, LogLevel::Warning
,
1154 ("nsComponentManager: CreateInstance(%s) %s", buf
,
1155 NS_SUCCEEDED(rv
) ? "succeeded" : "FAILED"));
1165 * CreateInstanceByContractID()
1167 * A variant of CreateInstance() that creates an instance of the object that
1168 * implements the interface aIID and whose implementation has a contractID
1171 * This is only a convenience routine that turns around can calls the
1172 * CreateInstance() with classid and iid.
1175 nsComponentManagerImpl::CreateInstanceByContractID(const char* aContractID
,
1176 nsISupports
* aDelegate
,
1179 if (NS_WARN_IF(!aContractID
)) {
1180 return NS_ERROR_INVALID_ARG
;
1183 // test this first, since there's no point in creating a component during
1184 // shutdown -- whether it's available or not would depend on the order it
1185 // occurs in the list
1186 if (gXPCOMShuttingDown
) {
1187 // When processing shutdown, don't process new GetService() requests
1188 #ifdef SHOW_DENIED_ON_SHUTDOWN
1190 "Creating new instance on shutdown. Denied.\n"
1191 " ContractID: %s\n IID: %s\n",
1192 aContractID
, AutoIDString(aIID
).get());
1193 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1194 return NS_ERROR_UNEXPECTED
;
1198 return NS_ERROR_NULL_POINTER
;
1202 Maybe
<EntryWrapper
> entry
=
1203 LookupByContractID(nsDependentCString(aContractID
));
1206 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1209 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1210 if (entry
->ServiceInstance()) {
1211 nsAutoCString message
;
1213 NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
1214 nsDependentCString(aContractID
) +
1216 "\" when a service for this CID already exists! "
1217 "Add it to abusedContracts to track down the service consumer.");
1218 NS_ERROR(message
.get());
1223 nsCOMPtr
<nsIFactory
> factory
= entry
->GetFactory();
1225 rv
= factory
->CreateInstance(aDelegate
, aIID
, aResult
);
1226 if (NS_SUCCEEDED(rv
) && !*aResult
) {
1227 NS_ERROR("Factory did not return an object but returned success!");
1228 rv
= NS_ERROR_SERVICE_NOT_AVAILABLE
;
1231 // Translate error values
1232 rv
= NS_ERROR_FACTORY_NOT_REGISTERED
;
1235 MOZ_LOG(nsComponentManagerLog
, LogLevel::Warning
,
1236 ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID
,
1237 NS_SUCCEEDED(rv
) ? "succeeded" : "FAILED"));
1242 nsresult
nsComponentManagerImpl::FreeServices() {
1243 NS_ASSERTION(gXPCOMShuttingDown
,
1244 "Must be shutting down in order to free all services");
1246 if (!gXPCOMShuttingDown
) {
1247 return NS_ERROR_FAILURE
;
1250 for (auto iter
= mFactories
.Iter(); !iter
.Done(); iter
.Next()) {
1251 nsFactoryEntry
* entry
= iter
.UserData();
1252 entry
->mFactory
= nullptr;
1253 entry
->mServiceObject
= nullptr;
1256 for (const auto& module
: gStaticModules
) {
1257 module
.SetServiceInstance(nullptr);
1263 // This should only ever be called within the monitor!
1264 nsComponentManagerImpl::PendingServiceInfo
*
1265 nsComponentManagerImpl::AddPendingService(const nsCID
& aServiceCID
,
1266 PRThread
* aThread
) {
1267 PendingServiceInfo
* newInfo
= mPendingServices
.AppendElement();
1269 newInfo
->cid
= &aServiceCID
;
1270 newInfo
->thread
= aThread
;
1275 // This should only ever be called within the monitor!
1276 void nsComponentManagerImpl::RemovePendingService(const nsCID
& aServiceCID
) {
1277 uint32_t pendingCount
= mPendingServices
.Length();
1278 for (uint32_t index
= 0; index
< pendingCount
; ++index
) {
1279 const PendingServiceInfo
& info
= mPendingServices
.ElementAt(index
);
1280 if (info
.cid
->Equals(aServiceCID
)) {
1281 mPendingServices
.RemoveElementAt(index
);
1287 // This should only ever be called within the monitor!
1288 PRThread
* nsComponentManagerImpl::GetPendingServiceThread(
1289 const nsCID
& aServiceCID
) const {
1290 uint32_t pendingCount
= mPendingServices
.Length();
1291 for (uint32_t index
= 0; index
< pendingCount
; ++index
) {
1292 const PendingServiceInfo
& info
= mPendingServices
.ElementAt(index
);
1293 if (info
.cid
->Equals(aServiceCID
)) {
1300 nsresult
nsComponentManagerImpl::GetServiceLocked(MutexLock
& aLock
,
1301 EntryWrapper
& aEntry
,
1304 if (auto* service
= aEntry
.ServiceInstance()) {
1306 return service
->QueryInterface(aIID
, aResult
);
1309 PRThread
* currentPRThread
= PR_GetCurrentThread();
1310 MOZ_ASSERT(currentPRThread
, "This should never be null!");
1312 // Needed to optimize the event loop below.
1313 nsIThread
* currentThread
= nullptr;
1315 PRThread
* pendingPRThread
;
1316 while ((pendingPRThread
= GetPendingServiceThread(aEntry
.CID()))) {
1317 if (pendingPRThread
== currentPRThread
) {
1318 NS_ERROR("Recursive GetService!");
1319 return NS_ERROR_NOT_AVAILABLE
;
1322 SafeMutexAutoUnlock
unlockPending(mLock
);
1324 // If the current thread doesn't have an associated nsThread, then it's a
1325 // thread that doesn't have an event loop to process, so we'll just try
1326 // to yield to another thread in an attempt to make progress.
1327 if (!nsThreadManager::get().IsNSThread()) {
1328 PR_Sleep(PR_INTERVAL_NO_WAIT
);
1332 if (!currentThread
) {
1333 currentThread
= NS_GetCurrentThread();
1334 MOZ_ASSERT(currentThread
, "This should never be null!");
1337 // This will process a single event or yield the thread if no event is
1339 if (!NS_ProcessNextEvent(currentThread
, false)) {
1340 PR_Sleep(PR_INTERVAL_NO_WAIT
);
1344 // It's still possible that the other thread failed to create the
1345 // service so we're not guaranteed to have an entry or service yet.
1346 if (auto* service
= aEntry
.ServiceInstance()) {
1348 return service
->QueryInterface(aIID
, aResult
);
1351 DebugOnly
<PendingServiceInfo
*> newInfo
=
1352 AddPendingService(aEntry
.CID(), currentPRThread
);
1353 NS_ASSERTION(newInfo
, "Failed to add info to the array!");
1355 // We need to not be holding the service manager's lock while calling
1356 // CreateInstance, because it invokes user code which could try to re-enter
1357 // the service manager:
1359 nsCOMPtr
<nsISupports
> service
;
1360 auto cleanup
= MakeScopeExit([&]() {
1361 // `service` must be released after the lock is released, so if we fail and
1362 // still have a reference, release the lock before relasing it.
1371 SafeMutexAutoUnlock
unlock(mLock
);
1372 rv
= aEntry
.CreateInstance(nullptr, aIID
, getter_AddRefs(service
));
1374 if (NS_SUCCEEDED(rv
) && !service
) {
1375 NS_ERROR("Factory did not return an object but returned success");
1376 return NS_ERROR_SERVICE_NOT_AVAILABLE
;
1380 pendingPRThread
= GetPendingServiceThread(aEntry
.CID());
1381 MOZ_ASSERT(pendingPRThread
== currentPRThread
,
1382 "Pending service array has been changed!");
1384 RemovePendingService(aEntry
.CID());
1386 if (NS_FAILED(rv
)) {
1390 NS_ASSERTION(!aEntry
.ServiceInstance(),
1391 "Created two instances of a service!");
1393 aEntry
.SetServiceInstance(service
.forget());
1396 *aResult
= do_AddRef(aEntry
.ServiceInstance()).take();
1401 nsComponentManagerImpl::GetService(const nsCID
& aClass
, const nsIID
& aIID
,
1403 // test this first, since there's no point in returning a service during
1404 // shutdown -- whether it's available or not would depend on the order it
1405 // occurs in the list
1406 if (gXPCOMShuttingDown
) {
1407 // When processing shutdown, don't process new GetService() requests
1408 #ifdef SHOW_DENIED_ON_SHUTDOWN
1410 "Getting service on shutdown. Denied.\n"
1411 " CID: %s\n IID: %s\n",
1412 AutoIDString(aClass
).get(), AutoIDString(aIID
).get());
1413 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1414 return NS_ERROR_UNEXPECTED
;
1417 MutexLock
lock(mLock
);
1419 Maybe
<EntryWrapper
> entry
= LookupByCID(lock
, aClass
);
1421 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1424 return GetServiceLocked(lock
, *entry
, aIID
, aResult
);
1427 nsresult
nsComponentManagerImpl::GetService(ModuleID aId
, const nsIID
& aIID
,
1429 const auto& entry
= gStaticModules
[size_t(aId
)];
1431 // test this first, since there's no point in returning a service during
1432 // shutdown -- whether it's available or not would depend on the order it
1433 // occurs in the list
1434 if (gXPCOMShuttingDown
) {
1435 // When processing shutdown, don't process new GetService() requests
1436 #ifdef SHOW_DENIED_ON_SHUTDOWN
1438 "Getting service on shutdown. Denied.\n"
1439 " CID: %s\n IID: %s\n",
1440 AutoIDString(entry
.CID()).get(), AutoIDString(aIID
).get());
1441 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1442 return NS_ERROR_UNEXPECTED
;
1445 MutexLock
lock(mLock
);
1447 if (!entry
.Active()) {
1448 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1451 Maybe
<EntryWrapper
> wrapper
;
1452 if (entry
.Overridable()) {
1453 // If we expect this service to be overridden by test code, we need to look
1454 // it up by contract ID every time.
1455 wrapper
= LookupByContractID(lock
, entry
.ContractID());
1457 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1460 wrapper
.emplace(&entry
);
1462 return GetServiceLocked(lock
, *wrapper
, aIID
, aResult
);
1466 nsComponentManagerImpl::IsServiceInstantiated(const nsCID
& aClass
,
1469 // Now we want to get the service if we already got it. If not, we don't want
1470 // to create an instance of it. mmh!
1472 // test this first, since there's no point in returning a service during
1473 // shutdown -- whether it's available or not would depend on the order it
1474 // occurs in the list
1475 if (gXPCOMShuttingDown
) {
1476 // When processing shutdown, don't process new GetService() requests
1477 #ifdef SHOW_DENIED_ON_SHUTDOWN
1479 "Checking for service on shutdown. Denied.\n"
1480 " CID: %s\n IID: %s\n",
1481 AutoIDString(aClass
).get(), AutoIDString(aIID
).get());
1482 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1483 return NS_ERROR_UNEXPECTED
;
1486 if (Maybe
<EntryWrapper
> entry
= LookupByCID(aClass
)) {
1487 if (auto* service
= entry
->ServiceInstance()) {
1488 nsCOMPtr
<nsISupports
> instance
;
1489 nsresult rv
= service
->QueryInterface(aIID
, getter_AddRefs(instance
));
1490 *aResult
= (instance
!= nullptr);
1500 nsComponentManagerImpl::IsServiceInstantiatedByContractID(
1501 const char* aContractID
, const nsIID
& aIID
, bool* aResult
) {
1502 // Now we want to get the service if we already got it. If not, we don't want
1503 // to create an instance of it. mmh!
1505 // test this first, since there's no point in returning a service during
1506 // shutdown -- whether it's available or not would depend on the order it
1507 // occurs in the list
1508 if (gXPCOMShuttingDown
) {
1509 // When processing shutdown, don't process new GetService() requests
1510 #ifdef SHOW_DENIED_ON_SHUTDOWN
1512 "Checking for service on shutdown. Denied.\n"
1513 " ContractID: %s\n IID: %s\n",
1514 aContractID
, AutoIDString(aIID
).get());
1515 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1516 return NS_ERROR_UNEXPECTED
;
1519 if (Maybe
<EntryWrapper
> entry
=
1520 LookupByContractID(nsDependentCString(aContractID
))) {
1521 if (auto* service
= entry
->ServiceInstance()) {
1522 nsCOMPtr
<nsISupports
> instance
;
1523 nsresult rv
= service
->QueryInterface(aIID
, getter_AddRefs(instance
));
1524 *aResult
= (instance
!= nullptr);
1534 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID
,
1537 // test this first, since there's no point in returning a service during
1538 // shutdown -- whether it's available or not would depend on the order it
1539 // occurs in the list
1540 if (gXPCOMShuttingDown
) {
1541 // When processing shutdown, don't process new GetService() requests
1542 #ifdef SHOW_DENIED_ON_SHUTDOWN
1544 "Getting service on shutdown. Denied.\n"
1545 " ContractID: %s\n IID: %s\n",
1546 aContractID
, AutoIDString(aIID
).get());
1547 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1548 return NS_ERROR_UNEXPECTED
;
1551 MutexLock
lock(mLock
);
1553 Maybe
<EntryWrapper
> entry
=
1554 LookupByContractID(lock
, nsDependentCString(aContractID
));
1556 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1559 return GetServiceLocked(lock
, *entry
, aIID
, aResult
);
1563 nsComponentManagerImpl::RegisterFactory(const nsCID
& aClass
, const char* aName
,
1564 const char* aContractID
,
1565 nsIFactory
* aFactory
) {
1567 // If a null factory is passed in, this call just wants to reset
1568 // the contract ID to point to an existing CID entry.
1570 return NS_ERROR_INVALID_ARG
;
1573 nsDependentCString
contractID(aContractID
);
1575 SafeMutexAutoLock
lock(mLock
);
1576 nsFactoryEntry
* oldf
= mFactories
.Get(&aClass
);
1578 StaticComponents::InvalidateContractID(contractID
);
1579 mContractIDs
.Put(contractID
, oldf
);
1583 if (StaticComponents::LookupByCID(aClass
)) {
1584 // If this is the CID of a static module, just reset the invalid bit of
1585 // the static entry for this contract ID, and assume it points to the
1587 if (StaticComponents::InvalidateContractID(contractID
, false)) {
1588 mContractIDs
.Remove(contractID
);
1592 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1595 auto f
= MakeUnique
<nsFactoryEntry
>(aClass
, aFactory
);
1597 SafeMutexAutoLock
lock(mLock
);
1598 if (auto entry
= mFactories
.LookupForAdd(f
->mCIDEntry
->cid
)) {
1599 return NS_ERROR_FACTORY_EXISTS
;
1601 if (StaticComponents::LookupByCID(*f
->mCIDEntry
->cid
)) {
1603 return NS_ERROR_FACTORY_EXISTS
;
1606 nsDependentCString
contractID(aContractID
);
1607 mContractIDs
.Put(contractID
, f
.get());
1608 // We allow dynamically-registered contract IDs to override static
1609 // entries, so invalidate any static entry for this contract ID.
1610 StaticComponents::InvalidateContractID(contractID
);
1612 entry
.OrInsert([&f
]() { return f
.release(); });
1619 nsComponentManagerImpl::UnregisterFactory(const nsCID
& aClass
,
1620 nsIFactory
* aFactory
) {
1621 // Don't release the dying factory or service object until releasing
1622 // the component manager monitor.
1623 nsCOMPtr
<nsIFactory
> dyingFactory
;
1624 nsCOMPtr
<nsISupports
> dyingServiceObject
;
1627 SafeMutexAutoLock
lock(mLock
);
1628 auto entry
= mFactories
.Lookup(&aClass
);
1629 nsFactoryEntry
* f
= entry
? entry
.Data() : nullptr;
1630 if (!f
|| f
->mFactory
!= aFactory
) {
1631 // Note: We do not support unregistering static factories.
1632 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1637 // This might leave a stale contractid -> factory mapping in
1638 // place, so null out the factory entry (see
1639 // nsFactoryEntry::GetFactory)
1640 f
->mFactory
.swap(dyingFactory
);
1641 f
->mServiceObject
.swap(dyingServiceObject
);
1648 nsComponentManagerImpl::AutoRegister(nsIFile
* aLocation
) {
1649 XRE_AddManifestLocation(NS_EXTENSION_LOCATION
, aLocation
);
1654 nsComponentManagerImpl::AutoUnregister(nsIFile
* aLocation
) {
1655 NS_ERROR("AutoUnregister not implemented.");
1656 return NS_ERROR_NOT_IMPLEMENTED
;
1660 nsComponentManagerImpl::RegisterFactoryLocation(
1661 const nsCID
& aCID
, const char* aClassName
, const char* aContractID
,
1662 nsIFile
* aFile
, const char* aLoaderStr
, const char* aType
) {
1663 NS_ERROR("RegisterFactoryLocation not implemented.");
1664 return NS_ERROR_NOT_IMPLEMENTED
;
1668 nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID
& aCID
,
1670 NS_ERROR("UnregisterFactoryLocation not implemented.");
1671 return NS_ERROR_NOT_IMPLEMENTED
;
1675 nsComponentManagerImpl::IsCIDRegistered(const nsCID
& aClass
, bool* aResult
) {
1676 *aResult
= LookupByCID(aClass
).isSome();
1681 nsComponentManagerImpl::IsContractIDRegistered(const char* aClass
,
1683 if (NS_WARN_IF(!aClass
)) {
1684 return NS_ERROR_INVALID_ARG
;
1687 Maybe
<EntryWrapper
> entry
= LookupByContractID(nsDependentCString(aClass
));
1689 *aResult
= entry
.isSome();
1694 nsComponentManagerImpl::GetContractIDs(nsTArray
<nsCString
>& aResult
) {
1697 for (auto iter
= mContractIDs
.Iter(); !iter
.Done(); iter
.Next()) {
1698 aResult
.AppendElement(iter
.Key());
1701 for (const auto& entry
: gContractEntries
) {
1702 if (!entry
.Invalid()) {
1703 aResult
.AppendElement(entry
.ContractID());
1711 nsComponentManagerImpl::CIDToContractID(const nsCID
& aClass
, char** aResult
) {
1712 NS_ERROR("CIDTOContractID not implemented");
1713 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1717 nsComponentManagerImpl::ContractIDToCID(const char* aContractID
,
1720 MutexLock
lock(mLock
);
1721 Maybe
<EntryWrapper
> entry
=
1722 LookupByContractID(lock
, nsDependentCString(aContractID
));
1724 *aResult
= (nsCID
*)moz_xmalloc(sizeof(nsCID
));
1725 **aResult
= entry
->CID();
1730 return NS_ERROR_FACTORY_NOT_REGISTERED
;
1733 MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf
)
1736 nsComponentManagerImpl::CollectReports(nsIHandleReportCallback
* aHandleReport
,
1737 nsISupports
* aData
, bool aAnonymize
) {
1738 MOZ_COLLECT_REPORT("explicit/xpcom/component-manager", KIND_HEAP
, UNITS_BYTES
,
1739 SizeOfIncludingThis(ComponentManagerMallocSizeOf
),
1740 "Memory used for the XPCOM component manager.");
1745 size_t nsComponentManagerImpl::SizeOfIncludingThis(
1746 mozilla::MallocSizeOf aMallocSizeOf
) const {
1747 size_t n
= aMallocSizeOf(this);
1749 n
+= mFactories
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1750 for (auto iter
= mFactories
.ConstIter(); !iter
.Done(); iter
.Next()) {
1751 n
+= iter
.Data()->SizeOfIncludingThis(aMallocSizeOf
);
1754 n
+= mContractIDs
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1755 for (auto iter
= mContractIDs
.ConstIter(); !iter
.Done(); iter
.Next()) {
1756 // We don't measure the nsFactoryEntry data because it's owned by
1757 // mFactories (which is measured above).
1758 n
+= iter
.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
1761 n
+= sExtraStaticModules
->ShallowSizeOfIncludingThis(aMallocSizeOf
);
1762 if (sModuleLocations
) {
1763 n
+= sModuleLocations
->ShallowSizeOfIncludingThis(aMallocSizeOf
);
1766 n
+= mKnownStaticModules
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1767 n
+= mKnownModules
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1769 n
+= mArena
.SizeOfExcludingThis(aMallocSizeOf
);
1771 n
+= mPendingServices
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1773 // Measurement of the following members may be added later if DMD finds it is
1776 // - sModuleLocations' entries
1777 // - mKnownStaticModules' entries?
1778 // - mKnownModules' keys and values?
1783 ////////////////////////////////////////////////////////////////////////////////
1785 ////////////////////////////////////////////////////////////////////////////////
1787 nsFactoryEntry::nsFactoryEntry(const mozilla::Module::CIDEntry
* aEntry
,
1788 nsComponentManagerImpl::KnownModule
* aModule
)
1789 : mCIDEntry(aEntry
), mModule(aModule
) {}
1791 nsFactoryEntry::nsFactoryEntry(const nsCID
& aCID
, nsIFactory
* aFactory
)
1792 : mCIDEntry(nullptr), mModule(nullptr), mFactory(aFactory
) {
1793 auto* e
= new mozilla::Module::CIDEntry();
1794 auto* cid
= new nsCID
;
1800 nsFactoryEntry::~nsFactoryEntry() {
1801 // If this was a RegisterFactory entry, we own the CIDEntry/CID
1803 delete mCIDEntry
->cid
;
1808 already_AddRefed
<nsIFactory
> nsFactoryEntry::GetFactory() {
1809 nsComponentManagerImpl::gComponentManager
->mLock
.AssertNotCurrentThreadOwns();
1812 // RegisterFactory then UnregisterFactory can leave an entry in mContractIDs
1813 // pointing to an unusable nsFactoryEntry.
1818 if (!mModule
->Load()) {
1822 // Don't set mFactory directly, it needs to be locked
1823 nsCOMPtr
<nsIFactory
> factory
;
1825 if (mModule
->Module()->getFactoryProc
) {
1827 mModule
->Module()->getFactoryProc(*mModule
->Module(), *mCIDEntry
);
1828 } else if (mCIDEntry
->getFactoryProc
) {
1829 factory
= mCIDEntry
->getFactoryProc(*mModule
->Module(), *mCIDEntry
);
1831 NS_ASSERTION(mCIDEntry
->constructorProc
, "no getfactory or constructor");
1832 factory
= new mozilla::GenericFactory(mCIDEntry
->constructorProc
);
1838 SafeMutexAutoLock
lock(nsComponentManagerImpl::gComponentManager
->mLock
);
1839 // Threads can race to set mFactory
1841 factory
.swap(mFactory
);
1844 nsCOMPtr
<nsIFactory
> factory
= mFactory
;
1845 return factory
.forget();
1848 nsresult
nsFactoryEntry::CreateInstance(nsISupports
* aOuter
, const nsIID
& aIID
,
1850 nsCOMPtr
<nsIFactory
> factory
= GetFactory();
1851 NS_ENSURE_TRUE(factory
, NS_ERROR_FAILURE
);
1852 return factory
->CreateInstance(aOuter
, aIID
, aResult
);
1855 size_t nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) {
1856 size_t n
= aMallocSizeOf(this);
1858 // Measurement of the following members may be added later if DMD finds it is
1863 // - mServiceObject;
1868 ////////////////////////////////////////////////////////////////////////////////
1869 // Static Access Functions
1870 ////////////////////////////////////////////////////////////////////////////////
1872 nsresult
NS_GetComponentManager(nsIComponentManager
** aResult
) {
1873 if (!nsComponentManagerImpl::gComponentManager
) {
1874 return NS_ERROR_NOT_INITIALIZED
;
1877 NS_ADDREF(*aResult
= nsComponentManagerImpl::gComponentManager
);
1881 nsresult
NS_GetServiceManager(nsIServiceManager
** aResult
) {
1882 if (!nsComponentManagerImpl::gComponentManager
) {
1883 return NS_ERROR_NOT_INITIALIZED
;
1886 NS_ADDREF(*aResult
= nsComponentManagerImpl::gComponentManager
);
1890 nsresult
NS_GetComponentRegistrar(nsIComponentRegistrar
** aResult
) {
1891 if (!nsComponentManagerImpl::gComponentManager
) {
1892 return NS_ERROR_NOT_INITIALIZED
;
1895 NS_ADDREF(*aResult
= nsComponentManagerImpl::gComponentManager
);
1899 EXPORT_XPCOM_API(nsresult
)
1900 XRE_AddStaticComponent(const mozilla::Module
* aComponent
) {
1901 nsComponentManagerImpl::InitializeStaticModules();
1902 sExtraStaticModules
->AppendElement(aComponent
);
1904 if (nsComponentManagerImpl::gComponentManager
&&
1905 nsComponentManagerImpl::NORMAL
==
1906 nsComponentManagerImpl::gComponentManager
->mStatus
) {
1907 nsComponentManagerImpl::gComponentManager
->RegisterModule(aComponent
);
1914 nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile
* aLocation
) {
1915 NS_ENSURE_ARG_POINTER(aLocation
);
1918 nsresult rv
= aLocation
->GetPath(path
);
1919 if (NS_FAILED(rv
)) {
1923 if (Substring(path
, path
.Length() - 4).EqualsLiteral(".xpi")) {
1924 return XRE_AddJarManifestLocation(NS_BOOTSTRAPPED_LOCATION
, aLocation
);
1927 nsCOMPtr
<nsIFile
> manifest
=
1928 CloneAndAppend(aLocation
, NS_LITERAL_CSTRING("chrome.manifest"));
1929 return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION
, manifest
);
1933 nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile
* aLocation
) {
1934 NS_ENSURE_ARG_POINTER(aLocation
);
1936 nsCOMPtr
<nsIChromeRegistry
> cr
=
1937 mozilla::services::GetChromeRegistryService();
1939 return NS_ERROR_FAILURE
;
1943 nsresult rv
= aLocation
->GetPath(path
);
1944 if (NS_FAILED(rv
)) {
1948 nsComponentManagerImpl::ComponentLocation elem
;
1949 elem
.type
= NS_BOOTSTRAPPED_LOCATION
;
1951 if (Substring(path
, path
.Length() - 4).EqualsLiteral(".xpi")) {
1952 elem
.location
.Init(aLocation
, "chrome.manifest");
1954 nsCOMPtr
<nsIFile
> lf
=
1955 CloneAndAppend(aLocation
, NS_LITERAL_CSTRING("chrome.manifest"));
1956 elem
.location
.Init(lf
);
1959 // Remove reference.
1960 nsComponentManagerImpl::sModuleLocations
->RemoveElement(
1961 elem
, ComponentLocationComparator());
1963 rv
= cr
->CheckForNewChrome();
1968 nsComponentManagerImpl::GetComponentJSMs(nsIUTF8StringEnumerator
** aJSMs
) {
1969 nsCOMPtr
<nsIUTF8StringEnumerator
> result
=
1970 StaticComponents::GetComponentJSMs();
1971 result
.forget(aJSMs
);
1976 nsComponentManagerImpl::GetManifestLocations(nsIArray
** aLocations
) {
1977 NS_ENSURE_ARG_POINTER(aLocations
);
1978 *aLocations
= nullptr;
1980 if (!sModuleLocations
) {
1981 return NS_ERROR_NOT_INITIALIZED
;
1984 nsCOMPtr
<nsIMutableArray
> locations
= nsArray::Create();
1986 for (uint32_t i
= 0; i
< sModuleLocations
->Length(); ++i
) {
1987 ComponentLocation
& l
= sModuleLocations
->ElementAt(i
);
1988 FileLocation loc
= l
.location
;
1989 nsCString uriString
;
1990 loc
.GetURIString(uriString
);
1991 nsCOMPtr
<nsIURI
> uri
;
1992 rv
= NS_NewURI(getter_AddRefs(uri
), uriString
);
1993 if (NS_SUCCEEDED(rv
)) {
1994 locations
->AppendElement(uri
);
1998 locations
.forget(aLocations
);
2002 EXPORT_XPCOM_API(nsresult
)
2003 XRE_AddManifestLocation(NSLocationType aType
, nsIFile
* aLocation
) {
2004 nsComponentManagerImpl::InitializeModuleLocations();
2005 nsComponentManagerImpl::ComponentLocation
* c
=
2006 nsComponentManagerImpl::sModuleLocations
->AppendElement();
2008 c
->location
.Init(aLocation
);
2010 if (nsComponentManagerImpl::gComponentManager
&&
2011 nsComponentManagerImpl::NORMAL
==
2012 nsComponentManagerImpl::gComponentManager
->mStatus
) {
2013 nsComponentManagerImpl::gComponentManager
->RegisterManifest(
2014 aType
, c
->location
, false);
2020 EXPORT_XPCOM_API(nsresult
)
2021 XRE_AddJarManifestLocation(NSLocationType aType
, nsIFile
* aLocation
) {
2022 nsComponentManagerImpl::InitializeModuleLocations();
2023 nsComponentManagerImpl::ComponentLocation
* c
=
2024 nsComponentManagerImpl::sModuleLocations
->AppendElement();
2027 c
->location
.Init(aLocation
, "chrome.manifest");
2029 if (nsComponentManagerImpl::gComponentManager
&&
2030 nsComponentManagerImpl::NORMAL
==
2031 nsComponentManagerImpl::gComponentManager
->mStatus
) {
2032 nsComponentManagerImpl::gComponentManager
->RegisterManifest(
2033 aType
, c
->location
, false);
2039 // Expose some important global interfaces to rust for the rust xpcom API. These
2040 // methods return a non-owning reference to the component manager, which should
2041 // live for the lifetime of XPCOM.
2044 const nsIComponentManager
* Gecko_GetComponentManager() {
2045 return nsComponentManagerImpl::gComponentManager
;
2048 const nsIServiceManager
* Gecko_GetServiceManager() {
2049 return nsComponentManagerImpl::gComponentManager
;
2052 const nsIComponentRegistrar
* Gecko_GetComponentRegistrar() {
2053 return nsComponentManagerImpl::gComponentManager
;