Bug 1773770: Part 5 - Migrate necko category entries to static registration. r=necko...
[gecko.git] / xpcom / components / nsComponentManager.cpp
blobb76c62d0149e5874a87fdca67d35f7c8688bd000
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 <stdlib.h>
8 #include "nscore.h"
9 #include "nsISupports.h"
10 #include "nspr.h"
11 #include "nsCRT.h" // for atoll
13 #include "StaticComponents.h"
15 #include "nsCategoryManager.h"
16 #include "nsCOMPtr.h"
17 #include "nsComponentManager.h"
18 #include "nsDirectoryService.h"
19 #include "nsDirectoryServiceDefs.h"
20 #include "nsCategoryManager.h"
21 #include "nsLayoutModule.h"
22 #include "mozilla/MemoryReporting.h"
23 #include "nsIObserverService.h"
24 #include "nsIStringEnumerator.h"
25 #include "nsXPCOM.h"
26 #include "nsXPCOMPrivate.h"
27 #include "nsISupportsPrimitives.h"
28 #include "nsLocalFile.h"
29 #include "nsReadableUtils.h"
30 #include "nsString.h"
31 #include "prcmon.h"
32 #include "nsThreadManager.h"
33 #include "nsThreadUtils.h"
34 #include "prthread.h"
35 #include "private/pprthred.h"
36 #include "nsTArray.h"
37 #include "prio.h"
38 #include "ManifestParser.h"
39 #include "nsNetUtil.h"
40 #include "mozilla/Services.h"
42 #include "mozilla/GenericFactory.h"
43 #include "nsSupportsPrimitives.h"
44 #include "nsArray.h"
45 #include "nsIMutableArray.h"
46 #include "mozilla/DebugOnly.h"
47 #include "mozilla/FileUtils.h"
48 #include "mozilla/ProfilerLabels.h"
49 #include "mozilla/ProfilerMarkers.h"
50 #include "mozilla/ScopeExit.h"
51 #include "mozilla/URLPreloader.h"
52 #include "mozilla/UniquePtr.h"
53 #include "mozilla/Variant.h"
55 #include <new> // for placement new
57 #include "mozilla/Omnijar.h"
59 #include "mozilla/Logging.h"
60 #include "LogModulePrefWatcher.h"
62 #ifdef MOZ_MEMORY
63 # include "mozmemory.h"
64 #endif
66 using namespace mozilla;
67 using namespace mozilla::xpcom;
69 static LazyLogModule nsComponentManagerLog("nsComponentManager");
71 #if 0
72 # define SHOW_DENIED_ON_SHUTDOWN
73 # define SHOW_CI_ON_EXISTING_SERVICE
74 #endif
76 namespace {
78 class AutoIDString : public nsAutoCStringN<NSID_LENGTH> {
79 public:
80 explicit AutoIDString(const nsID& aID) {
81 SetLength(NSID_LENGTH - 1);
82 aID.ToProvidedString(
83 *reinterpret_cast<char(*)[NSID_LENGTH]>(BeginWriting()));
87 } // namespace
89 namespace mozilla {
90 namespace xpcom {
92 using ProcessSelector = Module::ProcessSelector;
94 // Note: These must be kept in sync with the ProcessSelector definition in
95 // Module.h.
96 bool ProcessSelectorMatches(ProcessSelector aSelector) {
97 GeckoProcessType type = XRE_GetProcessType();
98 if (type == GeckoProcessType_GPU) {
99 return !!(aSelector & Module::ALLOW_IN_GPU_PROCESS);
102 if (type == GeckoProcessType_RDD) {
103 return !!(aSelector & Module::ALLOW_IN_RDD_PROCESS);
106 if (type == GeckoProcessType_Socket) {
107 return !!(aSelector & (Module::ALLOW_IN_SOCKET_PROCESS));
110 if (type == GeckoProcessType_VR) {
111 return !!(aSelector & Module::ALLOW_IN_VR_PROCESS);
114 if (type == GeckoProcessType_Utility) {
115 return !!(aSelector & Module::ALLOW_IN_UTILITY_PROCESS);
118 // Only allow XPCOM modules which can be loaded in all processes to be loaded
119 // in the IPDLUnitTest process.
120 if (type == GeckoProcessType_IPDLUnitTest) {
121 return size_t(aSelector) == Module::kMaxProcessSelector;
124 if (aSelector & Module::MAIN_PROCESS_ONLY) {
125 return type == GeckoProcessType_Default;
127 if (aSelector & Module::CONTENT_PROCESS_ONLY) {
128 return type == GeckoProcessType_Content;
130 return true;
133 static bool gProcessMatchTable[Module::kMaxProcessSelector + 1];
135 bool FastProcessSelectorMatches(ProcessSelector aSelector) {
136 return gProcessMatchTable[size_t(aSelector)];
139 } // namespace xpcom
140 } // namespace mozilla
142 namespace {
145 * A wrapper simple wrapper class, which can hold either a dynamic
146 * nsFactoryEntry instance, or a static StaticModule entry, and transparently
147 * forwards method calls to the wrapped object.
149 * This allows the same code to work with either static or dynamic modules
150 * without caring about the difference.
152 class MOZ_STACK_CLASS EntryWrapper final {
153 public:
154 explicit EntryWrapper(nsFactoryEntry* aEntry) : mEntry(aEntry) {}
156 explicit EntryWrapper(const StaticModule* aEntry) : mEntry(aEntry) {}
158 #define MATCH(type, ifFactory, ifStatic) \
159 struct Matcher { \
160 type operator()(nsFactoryEntry* entry) { ifFactory; } \
161 type operator()(const StaticModule* entry) { ifStatic; } \
162 }; \
163 return mEntry.match((Matcher()))
165 const nsID& CID() {
166 MATCH(const nsID&, return *entry->mCIDEntry->cid, return entry->CID());
169 already_AddRefed<nsIFactory> GetFactory() {
170 MATCH(already_AddRefed<nsIFactory>, return entry->GetFactory(),
171 return entry->GetFactory());
175 * Creates an instance of the underlying component. This should be used in
176 * preference to GetFactory()->CreateInstance() where appropriate, since it
177 * side-steps the necessity of creating a nsIFactory instance for static
178 * modules.
180 nsresult CreateInstance(const nsIID& aIID, void** aResult) {
181 if (mEntry.is<nsFactoryEntry*>()) {
182 return mEntry.as<nsFactoryEntry*>()->CreateInstance(aIID, aResult);
184 return mEntry.as<const StaticModule*>()->CreateInstance(aIID, aResult);
188 * Returns the cached service instance for this entry, if any. This should
189 * only be accessed while mLock is held.
191 nsISupports* ServiceInstance() {
192 MATCH(nsISupports*, return entry->mServiceObject,
193 return entry->ServiceInstance());
195 void SetServiceInstance(already_AddRefed<nsISupports> aInst) {
196 if (mEntry.is<nsFactoryEntry*>()) {
197 mEntry.as<nsFactoryEntry*>()->mServiceObject = aInst;
198 } else {
199 return mEntry.as<const StaticModule*>()->SetServiceInstance(
200 std::move(aInst));
205 * Returns the description string for the module this entry belongs to. For
206 * static entries, always returns "<unknown module>".
208 nsCString ModuleDescription() {
209 MATCH(nsCString,
210 return entry->mModule ? entry->mModule->Description()
211 : "<unknown module>"_ns,
212 return "<unknown module>"_ns);
215 private:
216 Variant<nsFactoryEntry*, const StaticModule*> mEntry;
219 } // namespace
221 // this is safe to call during InitXPCOM
222 static already_AddRefed<nsIFile> GetLocationFromDirectoryService(
223 const char* aProp) {
224 nsCOMPtr<nsIProperties> directoryService;
225 nsDirectoryService::Create(NS_GET_IID(nsIProperties),
226 getter_AddRefs(directoryService));
228 if (!directoryService) {
229 return nullptr;
232 nsCOMPtr<nsIFile> file;
233 nsresult rv =
234 directoryService->Get(aProp, NS_GET_IID(nsIFile), getter_AddRefs(file));
235 if (NS_FAILED(rv)) {
236 return nullptr;
239 return file.forget();
242 static already_AddRefed<nsIFile> CloneAndAppend(nsIFile* aBase,
243 const nsACString& aAppend) {
244 nsCOMPtr<nsIFile> f;
245 aBase->Clone(getter_AddRefs(f));
246 if (!f) {
247 return nullptr;
250 f->AppendNative(aAppend);
251 return f.forget();
254 ////////////////////////////////////////////////////////////////////////////////
255 // nsComponentManagerImpl
256 ////////////////////////////////////////////////////////////////////////////////
258 nsresult nsComponentManagerImpl::Create(REFNSIID aIID, void** aResult) {
259 if (!gComponentManager) {
260 return NS_ERROR_FAILURE;
263 return gComponentManager->QueryInterface(aIID, aResult);
266 static const int CONTRACTID_HASHTABLE_INITIAL_LENGTH = 16;
268 nsComponentManagerImpl::nsComponentManagerImpl()
269 : mFactories(CONTRACTID_HASHTABLE_INITIAL_LENGTH),
270 mContractIDs(CONTRACTID_HASHTABLE_INITIAL_LENGTH),
271 mLock("nsComponentManagerImpl.mLock"),
272 mStatus(NOT_INITIALIZED) {}
274 extern const mozilla::Module kPowerManagerModule;
275 extern const mozilla::Module kContentProcessWidgetModule;
276 #if defined(MOZ_WIDGET_COCOA) || defined(MOZ_WIDGET_UIKIT)
277 extern const mozilla::Module kWidgetModule;
278 #endif
280 static nsTArray<const mozilla::Module*>* sExtraStaticModules;
282 /* static */
283 void nsComponentManagerImpl::InitializeStaticModules() {
284 if (sExtraStaticModules) {
285 return;
288 sExtraStaticModules = new nsTArray<const mozilla::Module*>;
291 nsTArray<nsComponentManagerImpl::ComponentLocation>*
292 nsComponentManagerImpl::sModuleLocations;
294 /* static */
295 void nsComponentManagerImpl::InitializeModuleLocations() {
296 if (sModuleLocations) {
297 return;
300 sModuleLocations = new nsTArray<ComponentLocation>;
303 nsresult nsComponentManagerImpl::Init() {
305 gProcessMatchTable[size_t(ProcessSelector::ANY_PROCESS)] =
306 ProcessSelectorMatches(ProcessSelector::ANY_PROCESS);
307 gProcessMatchTable[size_t(ProcessSelector::MAIN_PROCESS_ONLY)] =
308 ProcessSelectorMatches(ProcessSelector::MAIN_PROCESS_ONLY);
309 gProcessMatchTable[size_t(ProcessSelector::CONTENT_PROCESS_ONLY)] =
310 ProcessSelectorMatches(ProcessSelector::CONTENT_PROCESS_ONLY);
311 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_PROCESS)] =
312 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_PROCESS);
313 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_VR_PROCESS)] =
314 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_VR_PROCESS);
315 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_SOCKET_PROCESS)] =
316 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_SOCKET_PROCESS);
317 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_RDD_PROCESS)] =
318 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_RDD_PROCESS);
319 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_MAIN_PROCESS)] =
320 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_MAIN_PROCESS);
321 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS)] =
322 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS);
323 gProcessMatchTable[size_t(
324 ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS)] =
325 ProcessSelectorMatches(
326 ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS);
327 gProcessMatchTable[size_t(
328 ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS)] =
329 ProcessSelectorMatches(
330 ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS);
331 gProcessMatchTable[size_t(
332 ProcessSelector::ALLOW_IN_RDD_AND_SOCKET_PROCESS)] =
333 ProcessSelectorMatches(
334 ProcessSelector::ALLOW_IN_RDD_AND_SOCKET_PROCESS);
335 gProcessMatchTable[size_t(
336 ProcessSelector::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS)] =
337 ProcessSelectorMatches(
338 ProcessSelector::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS);
339 gProcessMatchTable[size_t(
340 ProcessSelector::ALLOW_IN_GPU_RDD_SOCKET_AND_UTILITY_PROCESS)] =
341 ProcessSelectorMatches(
342 ProcessSelector::ALLOW_IN_GPU_RDD_SOCKET_AND_UTILITY_PROCESS);
343 gProcessMatchTable[size_t(
344 ProcessSelector::ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS)] =
345 ProcessSelectorMatches(
346 ProcessSelector::ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS);
347 gProcessMatchTable[size_t(
348 ProcessSelector::ALLOW_IN_GPU_RDD_VR_SOCKET_AND_UTILITY_PROCESS)] =
349 ProcessSelectorMatches(
350 ProcessSelector::ALLOW_IN_GPU_RDD_VR_SOCKET_AND_UTILITY_PROCESS);
353 MOZ_ASSERT(NOT_INITIALIZED == mStatus);
355 nsCOMPtr<nsIFile> greDir = GetLocationFromDirectoryService(NS_GRE_DIR);
356 nsCOMPtr<nsIFile> appDir =
357 GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR);
359 InitializeStaticModules();
361 nsCategoryManager::GetSingleton()->SuppressNotifications(true);
363 RegisterModule(&kPowerManagerModule);
364 RegisterModule(&kContentProcessWidgetModule);
365 #if defined(MOZ_WIDGET_COCOA) || defined(MOZ_WIDGET_UIKIT)
366 RegisterModule(&kWidgetModule);
367 #endif
369 for (uint32_t i = 0; i < sExtraStaticModules->Length(); ++i) {
370 RegisterModule((*sExtraStaticModules)[i]);
373 auto* catMan = nsCategoryManager::GetSingleton();
374 for (const auto& cat : gStaticCategories) {
375 for (const auto& entry : cat) {
376 if (entry.Active()) {
377 catMan->AddCategoryEntry(cat.Name(), entry.Entry(), entry.Value());
382 bool loadChromeManifests;
383 switch (XRE_GetProcessType()) {
384 // We are going to assume that only a select few (see below) process types
385 // want to load chrome manifests, and that any new process types will not
386 // want to load them, because they're not going to be executing JS.
387 case GeckoProcessType_RemoteSandboxBroker:
388 default:
389 loadChromeManifests = false;
390 break;
392 // XXX The check this code replaced implicitly let through all of these
393 // process types, but presumably only the default (parent) and content
394 // processes really need chrome manifests...?
395 case GeckoProcessType_Default:
396 case GeckoProcessType_Content:
397 case GeckoProcessType_GMPlugin:
398 loadChromeManifests = true;
399 break;
402 if (loadChromeManifests) {
403 // This needs to be called very early, before anything in nsLayoutModule is
404 // used, and before any calls are made into the JS engine.
405 nsLayoutModuleInitialize();
407 mJSLoaderReady = true;
409 // The overall order in which chrome.manifests are expected to be treated
410 // is the following:
411 // - greDir's omni.ja or greDir
412 // - appDir's omni.ja or appDir
414 InitializeModuleLocations();
415 ComponentLocation* cl = sModuleLocations->AppendElement();
416 cl->type = NS_APP_LOCATION;
417 RefPtr<nsZipArchive> greOmnijar =
418 mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
419 if (greOmnijar) {
420 cl->location.Init(greOmnijar, "chrome.manifest");
421 } else {
422 nsCOMPtr<nsIFile> lf = CloneAndAppend(greDir, "chrome.manifest"_ns);
423 cl->location.Init(lf);
426 RefPtr<nsZipArchive> appOmnijar =
427 mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
428 if (appOmnijar) {
429 cl = sModuleLocations->AppendElement();
430 cl->type = NS_APP_LOCATION;
431 cl->location.Init(appOmnijar, "chrome.manifest");
432 } else {
433 bool equals = false;
434 appDir->Equals(greDir, &equals);
435 if (!equals) {
436 cl = sModuleLocations->AppendElement();
437 cl->type = NS_APP_LOCATION;
438 nsCOMPtr<nsIFile> lf = CloneAndAppend(appDir, "chrome.manifest"_ns);
439 cl->location.Init(lf);
443 RereadChromeManifests(false);
446 nsCategoryManager::GetSingleton()->SuppressNotifications(false);
448 RegisterWeakMemoryReporter(this);
450 // NB: The logging preference watcher needs to be registered late enough in
451 // startup that it's okay to use the preference system, but also as soon as
452 // possible so that log modules enabled via preferences are turned on as
453 // early as possible.
455 // We can't initialize the preference watcher when the log module manager is
456 // initialized, as a number of things attempt to start logging before the
457 // preference system is initialized.
459 // The preference system is registered as a component so at this point during
460 // component manager initialization we know it is setup and we can register
461 // for notifications.
462 LogModulePrefWatcher::RegisterPrefWatcher();
464 // Unfortunately, we can't register the nsCategoryManager memory reporter
465 // in its constructor (which is triggered by the GetSingleton() call
466 // above) because the memory reporter manager isn't initialized at that
467 // point. So we wait until now.
468 nsCategoryManager::GetSingleton()->InitMemoryReporter();
470 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
471 ("nsComponentManager: Initialized."));
473 mStatus = NORMAL;
475 MOZ_ASSERT(!XRE_IsContentProcess() ||
476 mFactories.Count() > CONTRACTID_HASHTABLE_INITIAL_LENGTH / 3,
477 "Initial component hashtable size is too large");
479 return NS_OK;
482 static const int kModuleVersionWithSelector = 51;
484 template <typename T>
485 static void AssertNotMallocAllocated(T* aPtr) {
486 #if defined(DEBUG) && defined(MOZ_MEMORY)
487 jemalloc_ptr_info_t info;
488 jemalloc_ptr_info((void*)aPtr, &info);
489 MOZ_ASSERT(info.tag == TagUnknown);
490 #endif
493 template <typename T>
494 static void AssertNotStackAllocated(T* aPtr) {
495 // On all of our supported platforms, the stack grows down. Any address
496 // located below the address of our argument is therefore guaranteed not to be
497 // stack-allocated by the caller.
499 // For addresses above our argument, things get trickier. The main thread
500 // stack is traditionally placed at the top of the program's address space,
501 // but that is becoming less reliable as more and more systems adopt address
502 // space layout randomization strategies, so we have to guess how much space
503 // above our argument pointer we need to care about.
505 // On most systems, we're guaranteed at least several KiB at the top of each
506 // stack for TLS. We'd probably be safe assuming at least 4KiB in the stack
507 // segment above our argument address, but safer is... well, safer.
509 // For threads with huge stacks, it's theoretically possible that we could
510 // wind up being passed a stack-allocated string from farther up the stack,
511 // but this is a best-effort thing, so we'll assume we only care about the
512 // immediate caller. For that case, max 2KiB per stack frame is probably a
513 // reasonable guess most of the time, and is less than the ~4KiB that we
514 // expect for TLS, so go with that to avoid the risk of bumping into heap
515 // data just above the stack.
516 #ifdef DEBUG
517 static constexpr size_t kFuzz = 2048;
519 MOZ_ASSERT(uintptr_t(aPtr) < uintptr_t(&aPtr) ||
520 uintptr_t(aPtr) > uintptr_t(&aPtr) + kFuzz);
521 #endif
524 static inline nsCString AsLiteralCString(const char* aStr) {
525 AssertNotMallocAllocated(aStr);
526 AssertNotStackAllocated(aStr);
528 nsCString str;
529 str.AssignLiteral(aStr, strlen(aStr));
530 return str;
533 void nsComponentManagerImpl::RegisterModule(const mozilla::Module* aModule) {
534 mLock.AssertNotCurrentThreadOwns();
536 if (aModule->mVersion >= kModuleVersionWithSelector &&
537 !ProcessSelectorMatches(aModule->selector)) {
538 return;
542 // Scope the monitor so that we don't hold it while calling into the
543 // category manager.
544 MonitorAutoLock lock(mLock);
546 KnownModule* m = new KnownModule(aModule);
547 mKnownStaticModules.AppendElement(m);
549 if (aModule->mCIDs) {
550 const mozilla::Module::CIDEntry* entry;
551 for (entry = aModule->mCIDs; entry->cid; ++entry) {
552 RegisterCIDEntryLocked(entry, m);
556 if (aModule->mContractIDs) {
557 const mozilla::Module::ContractIDEntry* entry;
558 for (entry = aModule->mContractIDs; entry->contractid; ++entry) {
559 RegisterContractIDLocked(entry);
561 MOZ_ASSERT(!entry->cid, "Incorrectly terminated contract list");
565 if (aModule->mCategoryEntries) {
566 const mozilla::Module::CategoryEntry* entry;
567 for (entry = aModule->mCategoryEntries; entry->category; ++entry)
568 nsCategoryManager::GetSingleton()->AddCategoryEntry(
569 AsLiteralCString(entry->category), AsLiteralCString(entry->entry),
570 AsLiteralCString(entry->value));
574 void nsComponentManagerImpl::RegisterCIDEntryLocked(
575 const mozilla::Module::CIDEntry* aEntry, KnownModule* aModule) {
576 mLock.AssertCurrentThreadOwns();
578 if (!ProcessSelectorMatches(aEntry->processSelector)) {
579 return;
582 #ifdef DEBUG
583 // If we're still in the static initialization phase, check that we're not
584 // registering something that was already registered.
585 if (mStatus != NORMAL) {
586 if (StaticComponents::LookupByCID(*aEntry->cid)) {
587 MOZ_CRASH_UNSAFE_PRINTF(
588 "While registering XPCOM module %s, trying to re-register CID '%s' "
589 "already registered by a static component.",
590 aModule->Description().get(), AutoIDString(*aEntry->cid).get());
593 #endif
595 mFactories.WithEntryHandle(aEntry->cid, [&](auto&& entry) {
596 mLock.AssertCurrentThreadOwns();
597 if (entry) {
598 nsFactoryEntry* f = entry.Data();
599 NS_WARNING("Re-registering a CID?");
601 nsCString existing;
602 if (f->mModule) {
603 existing = f->mModule->Description();
604 } else {
605 existing = "<unknown module>";
607 MonitorAutoUnlock unlock(mLock);
608 LogMessage(
609 "While registering XPCOM module %s, trying to re-register CID '%s' "
610 "already registered by %s.",
611 aModule->Description().get(), AutoIDString(*aEntry->cid).get(),
612 existing.get());
613 } else {
614 entry.Insert(new nsFactoryEntry(aEntry, aModule));
619 void nsComponentManagerImpl::RegisterContractIDLocked(
620 const mozilla::Module::ContractIDEntry* aEntry) {
621 mLock.AssertCurrentThreadOwns();
623 if (!ProcessSelectorMatches(aEntry->processSelector)) {
624 return;
627 #ifdef DEBUG
628 // If we're still in the static initialization phase, check that we're not
629 // registering something that was already registered.
630 if (mStatus != NORMAL) {
631 if (const StaticModule* module = StaticComponents::LookupByContractID(
632 nsAutoCString(aEntry->contractid))) {
633 MOZ_CRASH_UNSAFE_PRINTF(
634 "Could not map contract ID '%s' to CID %s because it is already "
635 "mapped to CID %s.",
636 aEntry->contractid, AutoIDString(*aEntry->cid).get(),
637 AutoIDString(module->CID()).get());
640 #endif
642 nsFactoryEntry* f = mFactories.Get(aEntry->cid);
643 if (!f) {
644 NS_WARNING("No CID found when attempting to map contract ID");
646 MonitorAutoUnlock unlock(mLock);
647 LogMessage(
648 "Could not map contract ID '%s' to CID %s because no implementation of "
649 "the CID is registered.",
650 aEntry->contractid, AutoIDString(*aEntry->cid).get());
652 return;
655 mContractIDs.InsertOrUpdate(AsLiteralCString(aEntry->contractid), f);
658 static void DoRegisterManifest(NSLocationType aType, FileLocation& aFile,
659 bool aChromeOnly) {
660 auto result = URLPreloader::Read(aFile);
661 if (result.isOk()) {
662 nsCString buf(result.unwrap());
663 ParseManifest(aType, aFile, buf.BeginWriting(), aChromeOnly);
664 } else if (NS_BOOTSTRAPPED_LOCATION != aType) {
665 nsCString uri;
666 aFile.GetURIString(uri);
667 LogMessage("Could not read chrome manifest '%s'.", uri.get());
671 void nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
672 FileLocation& aFile,
673 bool aChromeOnly) {
674 DoRegisterManifest(aType, aFile, aChromeOnly);
677 void nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& aCx,
678 int aLineNo, char* const* aArgv) {
679 char* file = aArgv[0];
680 FileLocation f(aCx.mFile, file);
681 RegisterManifest(aCx.mType, f, aCx.mChromeOnly);
684 void nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext& aCx,
685 int aLineNo, char* const* aArgv) {
686 char* category = aArgv[0];
687 char* key = aArgv[1];
688 char* value = aArgv[2];
690 nsCategoryManager::GetSingleton()->AddCategoryEntry(
691 nsDependentCString(category), nsDependentCString(key),
692 nsDependentCString(value));
695 void nsComponentManagerImpl::RereadChromeManifests(bool aChromeOnly) {
696 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
697 ComponentLocation& l = sModuleLocations->ElementAt(i);
698 RegisterManifest(l.type, l.location, aChromeOnly);
701 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
702 if (obs) {
703 obs->NotifyObservers(nullptr, "chrome-manifests-loaded", nullptr);
707 bool nsComponentManagerImpl::KnownModule::Load() {
708 if (mFailed) {
709 return false;
711 MOZ_ASSERT(mModule);
712 if (!mLoaded) {
713 if (mModule->loadProc) {
714 nsresult rv = mModule->loadProc();
715 if (NS_FAILED(rv)) {
716 mFailed = true;
717 return false;
720 mLoaded = true;
722 return true;
725 nsCString nsComponentManagerImpl::KnownModule::Description() const {
726 return "<static module>"_ns;
729 nsresult nsComponentManagerImpl::Shutdown(void) {
730 MOZ_ASSERT(NORMAL == mStatus);
732 mStatus = SHUTDOWN_IN_PROGRESS;
734 // Shutdown the component manager
735 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
736 ("nsComponentManager: Beginning Shutdown."));
738 UnregisterWeakMemoryReporter(this);
740 // Release all cached factories
741 mContractIDs.Clear();
742 mFactories.Clear(); // XXX release the objects, don't just clear
743 mKnownStaticModules.Clear();
745 StaticComponents::Shutdown();
747 delete sExtraStaticModules;
748 delete sModuleLocations;
750 mStatus = SHUTDOWN_COMPLETE;
752 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
753 ("nsComponentManager: Shutdown complete."));
755 return NS_OK;
758 nsComponentManagerImpl::~nsComponentManagerImpl() {
759 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
760 ("nsComponentManager: Beginning destruction."));
762 if (SHUTDOWN_COMPLETE != mStatus) {
763 Shutdown();
766 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
767 ("nsComponentManager: Destroyed."));
770 NS_IMPL_ISUPPORTS(nsComponentManagerImpl, nsIComponentManager,
771 nsIServiceManager, nsIComponentRegistrar,
772 nsISupportsWeakReference, nsIInterfaceRequestor,
773 nsIMemoryReporter)
775 nsresult nsComponentManagerImpl::GetInterface(const nsIID& aUuid,
776 void** aResult) {
777 NS_WARNING("This isn't supported");
778 // fall through to QI as anything QIable is a superset of what can be
779 // got via the GetInterface()
780 return QueryInterface(aUuid, aResult);
783 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByCID(const nsID& aCID) {
784 return LookupByCID(MonitorAutoLock(mLock), aCID);
787 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByCID(const MonitorAutoLock&,
788 const nsID& aCID) {
789 if (const StaticModule* module = StaticComponents::LookupByCID(aCID)) {
790 return Some(EntryWrapper(module));
792 if (nsFactoryEntry* entry = mFactories.Get(&aCID)) {
793 return Some(EntryWrapper(entry));
795 return Nothing();
798 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByContractID(
799 const nsACString& aContractID) {
800 return LookupByContractID(MonitorAutoLock(mLock), aContractID);
803 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByContractID(
804 const MonitorAutoLock&, const nsACString& aContractID) {
805 if (const StaticModule* module =
806 StaticComponents::LookupByContractID(aContractID)) {
807 return Some(EntryWrapper(module));
809 if (nsFactoryEntry* entry = mContractIDs.Get(aContractID)) {
810 // UnregisterFactory might have left a stale nsFactoryEntry in
811 // mContractIDs, so we should check to see whether this entry has
812 // anything useful.
813 if (entry->mModule || entry->mFactory || entry->mServiceObject) {
814 return Some(EntryWrapper(entry));
817 return Nothing();
820 already_AddRefed<nsIFactory> nsComponentManagerImpl::FindFactory(
821 const nsCID& aClass) {
822 Maybe<EntryWrapper> e = LookupByCID(aClass);
823 if (!e) {
824 return nullptr;
827 return e->GetFactory();
830 already_AddRefed<nsIFactory> nsComponentManagerImpl::FindFactory(
831 const char* aContractID, uint32_t aContractIDLen) {
832 Maybe<EntryWrapper> entry =
833 LookupByContractID(nsDependentCString(aContractID, aContractIDLen));
834 if (!entry) {
835 return nullptr;
838 return entry->GetFactory();
842 * GetClassObject()
844 * Given a classID, this finds the singleton ClassObject that implements the
845 * CID. Returns an interface of type aIID off the singleton classobject.
847 NS_IMETHODIMP
848 nsComponentManagerImpl::GetClassObject(const nsCID& aClass, const nsIID& aIID,
849 void** aResult) {
850 nsresult rv;
852 if (MOZ_LOG_TEST(nsComponentManagerLog, LogLevel::Debug)) {
853 char* buf = aClass.ToString();
854 PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
855 if (buf) {
856 free(buf);
860 MOZ_ASSERT(aResult != nullptr);
862 nsCOMPtr<nsIFactory> factory = FindFactory(aClass);
863 if (!factory) {
864 return NS_ERROR_FACTORY_NOT_REGISTERED;
867 rv = factory->QueryInterface(aIID, aResult);
869 MOZ_LOG(
870 nsComponentManagerLog, LogLevel::Warning,
871 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
873 return rv;
876 NS_IMETHODIMP
877 nsComponentManagerImpl::GetClassObjectByContractID(const char* aContractID,
878 const nsIID& aIID,
879 void** aResult) {
880 if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aContractID)) {
881 return NS_ERROR_INVALID_ARG;
884 nsresult rv;
886 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
887 ("nsComponentManager: GetClassObjectByContractID(%s)", aContractID));
889 nsCOMPtr<nsIFactory> factory = FindFactory(aContractID, strlen(aContractID));
890 if (!factory) {
891 return NS_ERROR_FACTORY_NOT_REGISTERED;
894 rv = factory->QueryInterface(aIID, aResult);
896 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
897 ("\t\tGetClassObjectByContractID() %s",
898 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
900 return rv;
904 * CreateInstance()
906 * Create an instance of an object that implements an interface and belongs
907 * to the implementation aClass using the factory. The factory is immediately
908 * released and not held onto for any longer.
910 NS_IMETHODIMP
911 nsComponentManagerImpl::CreateInstance(const nsCID& aClass, const nsIID& aIID,
912 void** aResult) {
913 // test this first, since there's no point in creating a component during
914 // shutdown -- whether it's available or not would depend on the order it
915 // occurs in the list
916 if (gXPCOMShuttingDown) {
917 // When processing shutdown, don't process new GetService() requests
918 #ifdef SHOW_DENIED_ON_SHUTDOWN
919 fprintf(stderr,
920 "Creating new instance on shutdown. Denied.\n"
921 " CID: %s\n IID: %s\n",
922 AutoIDString(aClass).get(), AutoIDString(aIID).get());
923 #endif /* SHOW_DENIED_ON_SHUTDOWN */
924 return NS_ERROR_UNEXPECTED;
927 if (!aResult) {
928 return NS_ERROR_NULL_POINTER;
930 *aResult = nullptr;
932 Maybe<EntryWrapper> entry = LookupByCID(aClass);
934 if (!entry) {
935 return NS_ERROR_FACTORY_NOT_REGISTERED;
938 #ifdef SHOW_CI_ON_EXISTING_SERVICE
939 if (entry->ServiceInstance()) {
940 nsAutoCString message;
941 message = "You are calling CreateInstance \""_ns + AutoIDString(aClass) +
942 "\" when a service for this CID already exists!"_ns;
943 NS_ERROR(message.get());
945 #endif
947 nsresult rv;
948 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
949 if (factory) {
950 rv = factory->CreateInstance(aIID, aResult);
951 if (NS_SUCCEEDED(rv) && !*aResult) {
952 NS_ERROR("Factory did not return an object but returned success!");
953 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
955 } else {
956 // Translate error values
957 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
960 if (MOZ_LOG_TEST(nsComponentManagerLog, LogLevel::Warning)) {
961 char* buf = aClass.ToString();
962 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
963 ("nsComponentManager: CreateInstance(%s) %s", buf,
964 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
965 if (buf) {
966 free(buf);
970 return rv;
974 * CreateInstanceByContractID()
976 * A variant of CreateInstance() that creates an instance of the object that
977 * implements the interface aIID and whose implementation has a contractID
978 * aContractID.
980 * This is only a convenience routine that turns around can calls the
981 * CreateInstance() with classid and iid.
983 NS_IMETHODIMP
984 nsComponentManagerImpl::CreateInstanceByContractID(const char* aContractID,
985 const nsIID& aIID,
986 void** aResult) {
987 if (NS_WARN_IF(!aContractID)) {
988 return NS_ERROR_INVALID_ARG;
991 // test this first, since there's no point in creating a component during
992 // shutdown -- whether it's available or not would depend on the order it
993 // occurs in the list
994 if (gXPCOMShuttingDown) {
995 // When processing shutdown, don't process new GetService() requests
996 #ifdef SHOW_DENIED_ON_SHUTDOWN
997 fprintf(stderr,
998 "Creating new instance on shutdown. Denied.\n"
999 " ContractID: %s\n IID: %s\n",
1000 aContractID, AutoIDString(aIID).get());
1001 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1002 return NS_ERROR_UNEXPECTED;
1005 if (!aResult) {
1006 return NS_ERROR_NULL_POINTER;
1008 *aResult = nullptr;
1010 Maybe<EntryWrapper> entry =
1011 LookupByContractID(nsDependentCString(aContractID));
1013 if (!entry) {
1014 return NS_ERROR_FACTORY_NOT_REGISTERED;
1017 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1018 if (entry->ServiceInstance()) {
1019 nsAutoCString message;
1020 message =
1021 "You are calling CreateInstance \""_ns +
1022 nsDependentCString(aContractID) +
1023 nsLiteralCString(
1024 "\" when a service for this CID already exists! "
1025 "Add it to abusedContracts to track down the service consumer.");
1026 NS_ERROR(message.get());
1028 #endif
1030 nsresult rv;
1031 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
1032 if (factory) {
1033 rv = factory->CreateInstance(aIID, aResult);
1034 if (NS_SUCCEEDED(rv) && !*aResult) {
1035 NS_ERROR("Factory did not return an object but returned success!");
1036 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
1038 } else {
1039 // Translate error values
1040 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1043 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
1044 ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
1045 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1047 return rv;
1050 nsresult nsComponentManagerImpl::FreeServices() {
1051 NS_ASSERTION(gXPCOMShuttingDown,
1052 "Must be shutting down in order to free all services");
1054 if (!gXPCOMShuttingDown) {
1055 return NS_ERROR_FAILURE;
1058 for (nsFactoryEntry* entry : mFactories.Values()) {
1059 entry->mFactory = nullptr;
1060 entry->mServiceObject = nullptr;
1063 for (const auto& module : gStaticModules) {
1064 module.SetServiceInstance(nullptr);
1067 return NS_OK;
1070 // This should only ever be called within the monitor!
1071 nsComponentManagerImpl::PendingServiceInfo*
1072 nsComponentManagerImpl::AddPendingService(const nsCID& aServiceCID,
1073 PRThread* aThread) {
1074 PendingServiceInfo* newInfo = mPendingServices.AppendElement();
1075 if (newInfo) {
1076 newInfo->cid = &aServiceCID;
1077 newInfo->thread = aThread;
1079 return newInfo;
1082 // This should only ever be called within the monitor!
1083 void nsComponentManagerImpl::RemovePendingService(MonitorAutoLock& aLock,
1084 const nsCID& aServiceCID) {
1085 uint32_t pendingCount = mPendingServices.Length();
1086 for (uint32_t index = 0; index < pendingCount; ++index) {
1087 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
1088 if (info.cid->Equals(aServiceCID)) {
1089 mPendingServices.RemoveElementAt(index);
1090 aLock.NotifyAll();
1091 return;
1096 // This should only ever be called within the monitor!
1097 PRThread* nsComponentManagerImpl::GetPendingServiceThread(
1098 const nsCID& aServiceCID) const {
1099 uint32_t pendingCount = mPendingServices.Length();
1100 for (uint32_t index = 0; index < pendingCount; ++index) {
1101 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
1102 if (info.cid->Equals(aServiceCID)) {
1103 return info.thread;
1106 return nullptr;
1109 nsresult nsComponentManagerImpl::GetServiceLocked(Maybe<MonitorAutoLock>& aLock,
1110 EntryWrapper& aEntry,
1111 const nsIID& aIID,
1112 void** aResult) {
1113 MOZ_ASSERT(aLock.isSome());
1114 if (!aLock.isSome()) {
1115 return NS_ERROR_INVALID_ARG;
1118 if (auto* service = aEntry.ServiceInstance()) {
1119 aLock.reset();
1120 return service->QueryInterface(aIID, aResult);
1123 PRThread* currentPRThread = PR_GetCurrentThread();
1124 MOZ_ASSERT(currentPRThread, "This should never be null!");
1126 PRThread* pendingPRThread;
1127 while ((pendingPRThread = GetPendingServiceThread(aEntry.CID()))) {
1128 if (pendingPRThread == currentPRThread) {
1129 NS_ERROR("Recursive GetService!");
1130 return NS_ERROR_NOT_AVAILABLE;
1133 aLock->Wait();
1136 // It's still possible that the other thread failed to create the
1137 // service so we're not guaranteed to have an entry or service yet.
1138 if (auto* service = aEntry.ServiceInstance()) {
1139 aLock.reset();
1140 return service->QueryInterface(aIID, aResult);
1143 DebugOnly<PendingServiceInfo*> newInfo =
1144 AddPendingService(aEntry.CID(), currentPRThread);
1145 NS_ASSERTION(newInfo, "Failed to add info to the array!");
1147 // We need to not be holding the service manager's lock while calling
1148 // CreateInstance, because it invokes user code which could try to re-enter
1149 // the service manager:
1151 nsCOMPtr<nsISupports> service;
1152 auto cleanup = MakeScopeExit([&]() {
1153 // `service` must be released after the lock is released, so if we fail and
1154 // still have a reference, release the lock before releasing it.
1155 if (service) {
1156 MOZ_ASSERT(aLock.isSome());
1157 aLock.reset();
1158 service = nullptr;
1161 nsresult rv;
1162 mLock.AssertCurrentThreadOwns();
1164 MonitorAutoUnlock unlock(mLock);
1165 AUTO_PROFILER_MARKER_TEXT(
1166 "GetService", OTHER, MarkerStack::Capture(),
1167 nsDependentCString(nsIDToCString(aEntry.CID()).get()));
1168 rv = aEntry.CreateInstance(aIID, getter_AddRefs(service));
1170 if (NS_SUCCEEDED(rv) && !service) {
1171 NS_ERROR("Factory did not return an object but returned success");
1172 return NS_ERROR_SERVICE_NOT_AVAILABLE;
1175 #ifdef DEBUG
1176 pendingPRThread = GetPendingServiceThread(aEntry.CID());
1177 MOZ_ASSERT(pendingPRThread == currentPRThread,
1178 "Pending service array has been changed!");
1179 #endif
1180 MOZ_ASSERT(aLock.isSome());
1181 RemovePendingService(*aLock, aEntry.CID());
1183 if (NS_FAILED(rv)) {
1184 return rv;
1187 NS_ASSERTION(!aEntry.ServiceInstance(),
1188 "Created two instances of a service!");
1190 aEntry.SetServiceInstance(service.forget());
1192 aLock.reset();
1194 *aResult = do_AddRef(aEntry.ServiceInstance()).take();
1195 return NS_OK;
1198 NS_IMETHODIMP
1199 nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
1200 void** aResult) {
1201 // test this first, since there's no point in returning a service during
1202 // shutdown -- whether it's available or not would depend on the order it
1203 // occurs in the list
1204 if (gXPCOMShuttingDown) {
1205 // When processing shutdown, don't process new GetService() requests
1206 #ifdef SHOW_DENIED_ON_SHUTDOWN
1207 fprintf(stderr,
1208 "Getting service on shutdown. Denied.\n"
1209 " CID: %s\n IID: %s\n",
1210 AutoIDString(aClass).get(), AutoIDString(aIID).get());
1211 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1212 return NS_ERROR_UNEXPECTED;
1215 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1217 Maybe<EntryWrapper> entry = LookupByCID(*lock, aClass);
1218 if (!entry) {
1219 return NS_ERROR_FACTORY_NOT_REGISTERED;
1222 return GetServiceLocked(lock, *entry, aIID, aResult);
1225 nsresult nsComponentManagerImpl::GetService(ModuleID aId, const nsIID& aIID,
1226 void** aResult) {
1227 const auto& entry = gStaticModules[size_t(aId)];
1229 // test this first, since there's no point in returning a service during
1230 // shutdown -- whether it's available or not would depend on the order it
1231 // occurs in the list
1232 if (gXPCOMShuttingDown) {
1233 // When processing shutdown, don't process new GetService() requests
1234 #ifdef SHOW_DENIED_ON_SHUTDOWN
1235 fprintf(stderr,
1236 "Getting service on shutdown. Denied.\n"
1237 " CID: %s\n IID: %s\n",
1238 AutoIDString(entry.CID()).get(), AutoIDString(aIID).get());
1239 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1240 return NS_ERROR_UNEXPECTED;
1243 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1245 Maybe<EntryWrapper> wrapper;
1246 if (entry.Overridable()) {
1247 // If we expect this service to be overridden by test code, we need to look
1248 // it up by contract ID every time.
1249 wrapper = LookupByContractID(*lock, entry.ContractID());
1250 if (!wrapper) {
1251 return NS_ERROR_FACTORY_NOT_REGISTERED;
1253 } else if (!entry.Active()) {
1254 return NS_ERROR_FACTORY_NOT_REGISTERED;
1255 } else {
1256 wrapper.emplace(&entry);
1258 return GetServiceLocked(lock, *wrapper, aIID, aResult);
1261 NS_IMETHODIMP
1262 nsComponentManagerImpl::IsServiceInstantiated(const nsCID& aClass,
1263 const nsIID& aIID,
1264 bool* aResult) {
1265 // Now we want to get the service if we already got it. If not, we don't want
1266 // to create an instance of it. mmh!
1268 // test this first, since there's no point in returning a service during
1269 // shutdown -- whether it's available or not would depend on the order it
1270 // occurs in the list
1271 if (gXPCOMShuttingDown) {
1272 // When processing shutdown, don't process new GetService() requests
1273 #ifdef SHOW_DENIED_ON_SHUTDOWN
1274 fprintf(stderr,
1275 "Checking for service on shutdown. Denied.\n"
1276 " CID: %s\n IID: %s\n",
1277 AutoIDString(aClass).get(), AutoIDString(aIID).get());
1278 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1279 return NS_ERROR_UNEXPECTED;
1282 if (Maybe<EntryWrapper> entry = LookupByCID(aClass)) {
1283 if (auto* service = entry->ServiceInstance()) {
1284 nsCOMPtr<nsISupports> instance;
1285 nsresult rv = service->QueryInterface(aIID, getter_AddRefs(instance));
1286 *aResult = (instance != nullptr);
1287 return rv;
1291 *aResult = false;
1292 return NS_OK;
1295 NS_IMETHODIMP
1296 nsComponentManagerImpl::IsServiceInstantiatedByContractID(
1297 const char* aContractID, const nsIID& aIID, bool* aResult) {
1298 // Now we want to get the service if we already got it. If not, we don't want
1299 // to create an instance of it. mmh!
1301 // test this first, since there's no point in returning a service during
1302 // shutdown -- whether it's available or not would depend on the order it
1303 // occurs in the list
1304 if (gXPCOMShuttingDown) {
1305 // When processing shutdown, don't process new GetService() requests
1306 #ifdef SHOW_DENIED_ON_SHUTDOWN
1307 fprintf(stderr,
1308 "Checking for service on shutdown. Denied.\n"
1309 " ContractID: %s\n IID: %s\n",
1310 aContractID, AutoIDString(aIID).get());
1311 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1312 return NS_ERROR_UNEXPECTED;
1315 if (Maybe<EntryWrapper> entry =
1316 LookupByContractID(nsDependentCString(aContractID))) {
1317 if (auto* service = entry->ServiceInstance()) {
1318 nsCOMPtr<nsISupports> instance;
1319 nsresult rv = service->QueryInterface(aIID, getter_AddRefs(instance));
1320 *aResult = (instance != nullptr);
1321 return rv;
1325 *aResult = false;
1326 return NS_OK;
1329 NS_IMETHODIMP
1330 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
1331 const nsIID& aIID,
1332 void** aResult) {
1333 // test this first, since there's no point in returning a service during
1334 // shutdown -- whether it's available or not would depend on the order it
1335 // occurs in the list
1336 if (gXPCOMShuttingDown) {
1337 // When processing shutdown, don't process new GetService() requests
1338 #ifdef SHOW_DENIED_ON_SHUTDOWN
1339 fprintf(stderr,
1340 "Getting service on shutdown. Denied.\n"
1341 " ContractID: %s\n IID: %s\n",
1342 aContractID, AutoIDString(aIID).get());
1343 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1344 return NS_ERROR_UNEXPECTED;
1347 AUTO_PROFILER_LABEL_DYNAMIC_CSTR_NONSENSITIVE("GetServiceByContractID", OTHER,
1348 aContractID);
1349 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1351 Maybe<EntryWrapper> entry =
1352 LookupByContractID(*lock, nsDependentCString(aContractID));
1353 if (!entry) {
1354 return NS_ERROR_FACTORY_NOT_REGISTERED;
1357 return GetServiceLocked(lock, *entry, aIID, aResult);
1360 NS_IMETHODIMP
1361 nsComponentManagerImpl::RegisterFactory(const nsCID& aClass, const char* aName,
1362 const char* aContractID,
1363 nsIFactory* aFactory) {
1364 if (!aFactory) {
1365 // If a null factory is passed in, this call just wants to reset
1366 // the contract ID to point to an existing CID entry.
1367 if (!aContractID) {
1368 return NS_ERROR_INVALID_ARG;
1371 nsDependentCString contractID(aContractID);
1373 MonitorAutoLock lock(mLock);
1374 nsFactoryEntry* oldf = mFactories.Get(&aClass);
1375 if (oldf) {
1376 StaticComponents::InvalidateContractID(contractID);
1377 mContractIDs.InsertOrUpdate(contractID, oldf);
1378 return NS_OK;
1381 if (StaticComponents::LookupByCID(aClass)) {
1382 // If this is the CID of a static module, just reset the invalid bit of
1383 // the static entry for this contract ID, and assume it points to the
1384 // correct class.
1385 if (StaticComponents::InvalidateContractID(contractID, false)) {
1386 mContractIDs.Remove(contractID);
1387 return NS_OK;
1390 return NS_ERROR_FACTORY_NOT_REGISTERED;
1393 auto f = MakeUnique<nsFactoryEntry>(aClass, aFactory);
1395 MonitorAutoLock lock(mLock);
1396 return mFactories.WithEntryHandle(f->mCIDEntry->cid, [&](auto&& entry) {
1397 if (entry) {
1398 return NS_ERROR_FACTORY_EXISTS;
1400 if (StaticComponents::LookupByCID(*f->mCIDEntry->cid)) {
1401 return NS_ERROR_FACTORY_EXISTS;
1403 if (aContractID) {
1404 nsDependentCString contractID(aContractID);
1405 mContractIDs.InsertOrUpdate(contractID, f.get());
1406 // We allow dynamically-registered contract IDs to override static
1407 // entries, so invalidate any static entry for this contract ID.
1408 StaticComponents::InvalidateContractID(contractID);
1410 entry.Insert(f.release());
1412 return NS_OK;
1416 NS_IMETHODIMP
1417 nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass,
1418 nsIFactory* aFactory) {
1419 // Don't release the dying factory or service object until releasing
1420 // the component manager monitor.
1421 nsCOMPtr<nsIFactory> dyingFactory;
1422 nsCOMPtr<nsISupports> dyingServiceObject;
1425 MonitorAutoLock lock(mLock);
1426 auto entry = mFactories.Lookup(&aClass);
1427 nsFactoryEntry* f = entry ? entry.Data() : nullptr;
1428 if (!f || f->mFactory != aFactory) {
1429 // Note: We do not support unregistering static factories.
1430 return NS_ERROR_FACTORY_NOT_REGISTERED;
1433 entry.Remove();
1435 // This might leave a stale contractid -> factory mapping in
1436 // place, so null out the factory entry (see
1437 // nsFactoryEntry::GetFactory)
1438 f->mFactory.swap(dyingFactory);
1439 f->mServiceObject.swap(dyingServiceObject);
1442 return NS_OK;
1445 NS_IMETHODIMP
1446 nsComponentManagerImpl::AutoRegister(nsIFile* aLocation) {
1447 XRE_AddManifestLocation(NS_EXTENSION_LOCATION, aLocation);
1448 return NS_OK;
1451 NS_IMETHODIMP
1452 nsComponentManagerImpl::AutoUnregister(nsIFile* aLocation) {
1453 NS_ERROR("AutoUnregister not implemented.");
1454 return NS_ERROR_NOT_IMPLEMENTED;
1457 NS_IMETHODIMP
1458 nsComponentManagerImpl::RegisterFactoryLocation(
1459 const nsCID& aCID, const char* aClassName, const char* aContractID,
1460 nsIFile* aFile, const char* aLoaderStr, const char* aType) {
1461 NS_ERROR("RegisterFactoryLocation not implemented.");
1462 return NS_ERROR_NOT_IMPLEMENTED;
1465 NS_IMETHODIMP
1466 nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID& aCID,
1467 nsIFile* aFile) {
1468 NS_ERROR("UnregisterFactoryLocation not implemented.");
1469 return NS_ERROR_NOT_IMPLEMENTED;
1472 NS_IMETHODIMP
1473 nsComponentManagerImpl::IsCIDRegistered(const nsCID& aClass, bool* aResult) {
1474 *aResult = LookupByCID(aClass).isSome();
1475 return NS_OK;
1478 NS_IMETHODIMP
1479 nsComponentManagerImpl::IsContractIDRegistered(const char* aClass,
1480 bool* aResult) {
1481 if (NS_WARN_IF(!aClass)) {
1482 return NS_ERROR_INVALID_ARG;
1485 Maybe<EntryWrapper> entry = LookupByContractID(nsDependentCString(aClass));
1487 *aResult = entry.isSome();
1488 return NS_OK;
1491 NS_IMETHODIMP
1492 nsComponentManagerImpl::GetContractIDs(nsTArray<nsCString>& aResult) {
1493 aResult = ToTArray<nsTArray<nsCString>>(mContractIDs.Keys());
1495 for (const auto& entry : gContractEntries) {
1496 if (!entry.Invalid()) {
1497 aResult.AppendElement(entry.ContractID());
1501 return NS_OK;
1504 NS_IMETHODIMP
1505 nsComponentManagerImpl::CIDToContractID(const nsCID& aClass, char** aResult) {
1506 NS_ERROR("CIDTOContractID not implemented");
1507 return NS_ERROR_FACTORY_NOT_REGISTERED;
1510 NS_IMETHODIMP
1511 nsComponentManagerImpl::ContractIDToCID(const char* aContractID,
1512 nsCID** aResult) {
1514 MonitorAutoLock lock(mLock);
1515 Maybe<EntryWrapper> entry =
1516 LookupByContractID(lock, nsDependentCString(aContractID));
1517 if (entry) {
1518 *aResult = (nsCID*)moz_xmalloc(sizeof(nsCID));
1519 **aResult = entry->CID();
1520 return NS_OK;
1523 *aResult = nullptr;
1524 return NS_ERROR_FACTORY_NOT_REGISTERED;
1527 MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf)
1529 NS_IMETHODIMP
1530 nsComponentManagerImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
1531 nsISupports* aData, bool aAnonymize) {
1532 MOZ_COLLECT_REPORT("explicit/xpcom/component-manager", KIND_HEAP, UNITS_BYTES,
1533 SizeOfIncludingThis(ComponentManagerMallocSizeOf),
1534 "Memory used for the XPCOM component manager.");
1536 return NS_OK;
1539 size_t nsComponentManagerImpl::SizeOfIncludingThis(
1540 mozilla::MallocSizeOf aMallocSizeOf) const {
1541 size_t n = aMallocSizeOf(this);
1543 n += mFactories.ShallowSizeOfExcludingThis(aMallocSizeOf);
1544 for (const auto& data : mFactories.Values()) {
1545 n += data->SizeOfIncludingThis(aMallocSizeOf);
1548 n += mContractIDs.ShallowSizeOfExcludingThis(aMallocSizeOf);
1549 for (const auto& key : mContractIDs.Keys()) {
1550 // We don't measure the nsFactoryEntry data because it's owned by
1551 // mFactories (which is measured above).
1552 n += key.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1555 n += sExtraStaticModules->ShallowSizeOfIncludingThis(aMallocSizeOf);
1556 if (sModuleLocations) {
1557 n += sModuleLocations->ShallowSizeOfIncludingThis(aMallocSizeOf);
1560 n += mKnownStaticModules.ShallowSizeOfExcludingThis(aMallocSizeOf);
1562 n += mPendingServices.ShallowSizeOfExcludingThis(aMallocSizeOf);
1564 // Measurement of the following members may be added later if DMD finds it is
1565 // worthwhile:
1566 // - mMon
1567 // - sModuleLocations' entries
1568 // - mKnownStaticModules' entries?
1570 return n;
1573 ////////////////////////////////////////////////////////////////////////////////
1574 // nsFactoryEntry
1575 ////////////////////////////////////////////////////////////////////////////////
1577 nsFactoryEntry::nsFactoryEntry(const mozilla::Module::CIDEntry* aEntry,
1578 nsComponentManagerImpl::KnownModule* aModule)
1579 : mCIDEntry(aEntry), mModule(aModule) {}
1581 nsFactoryEntry::nsFactoryEntry(const nsCID& aCID, nsIFactory* aFactory)
1582 : mCIDEntry(nullptr), mModule(nullptr), mFactory(aFactory) {
1583 auto* e = new mozilla::Module::CIDEntry();
1584 auto* cid = new nsCID;
1585 *cid = aCID;
1586 e->cid = cid;
1587 mCIDEntry = e;
1590 nsFactoryEntry::~nsFactoryEntry() {
1591 // If this was a RegisterFactory entry, we own the CIDEntry/CID
1592 if (!mModule) {
1593 delete mCIDEntry->cid;
1594 delete mCIDEntry;
1598 already_AddRefed<nsIFactory> nsFactoryEntry::GetFactory() {
1599 nsComponentManagerImpl::gComponentManager->mLock.AssertNotCurrentThreadOwns();
1601 if (!mFactory) {
1602 // RegisterFactory then UnregisterFactory can leave an entry in mContractIDs
1603 // pointing to an unusable nsFactoryEntry.
1604 if (!mModule) {
1605 return nullptr;
1608 if (!mModule->Load()) {
1609 return nullptr;
1612 // Don't set mFactory directly, it needs to be locked
1613 nsCOMPtr<nsIFactory> factory;
1615 if (mModule->Module()->getFactoryProc) {
1616 factory =
1617 mModule->Module()->getFactoryProc(*mModule->Module(), *mCIDEntry);
1618 } else if (mCIDEntry->getFactoryProc) {
1619 factory = mCIDEntry->getFactoryProc(*mModule->Module(), *mCIDEntry);
1620 } else {
1621 NS_ASSERTION(mCIDEntry->constructorProc, "no getfactory or constructor");
1622 factory = new mozilla::GenericFactory(mCIDEntry->constructorProc);
1624 if (!factory) {
1625 return nullptr;
1628 MonitorAutoLock lock(nsComponentManagerImpl::gComponentManager->mLock);
1629 // Threads can race to set mFactory
1630 if (!mFactory) {
1631 factory.swap(mFactory);
1634 nsCOMPtr<nsIFactory> factory = mFactory;
1635 return factory.forget();
1638 nsresult nsFactoryEntry::CreateInstance(const nsIID& aIID, void** aResult) {
1639 nsCOMPtr<nsIFactory> factory = GetFactory();
1640 NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
1641 return factory->CreateInstance(aIID, aResult);
1644 size_t nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
1645 size_t n = aMallocSizeOf(this);
1647 // Measurement of the following members may be added later if DMD finds it is
1648 // worthwhile:
1649 // - mCIDEntry;
1650 // - mModule;
1651 // - mFactory;
1652 // - mServiceObject;
1654 return n;
1657 ////////////////////////////////////////////////////////////////////////////////
1658 // Static Access Functions
1659 ////////////////////////////////////////////////////////////////////////////////
1661 nsresult NS_GetComponentManager(nsIComponentManager** aResult) {
1662 if (!nsComponentManagerImpl::gComponentManager) {
1663 return NS_ERROR_NOT_INITIALIZED;
1666 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1667 return NS_OK;
1670 nsresult NS_GetServiceManager(nsIServiceManager** aResult) {
1671 if (!nsComponentManagerImpl::gComponentManager) {
1672 return NS_ERROR_NOT_INITIALIZED;
1675 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1676 return NS_OK;
1679 nsresult NS_GetComponentRegistrar(nsIComponentRegistrar** aResult) {
1680 if (!nsComponentManagerImpl::gComponentManager) {
1681 return NS_ERROR_NOT_INITIALIZED;
1684 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1685 return NS_OK;
1688 EXPORT_XPCOM_API(nsresult)
1689 XRE_AddStaticComponent(const mozilla::Module* aComponent) {
1690 nsComponentManagerImpl::InitializeStaticModules();
1691 sExtraStaticModules->AppendElement(aComponent);
1693 if (nsComponentManagerImpl::gComponentManager &&
1694 nsComponentManagerImpl::NORMAL ==
1695 nsComponentManagerImpl::gComponentManager->mStatus) {
1696 nsComponentManagerImpl::gComponentManager->RegisterModule(aComponent);
1699 return NS_OK;
1702 NS_IMETHODIMP
1703 nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation) {
1704 NS_ENSURE_ARG_POINTER(aLocation);
1706 nsString path;
1707 nsresult rv = aLocation->GetPath(path);
1708 if (NS_FAILED(rv)) {
1709 return rv;
1712 if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
1713 return XRE_AddJarManifestLocation(NS_BOOTSTRAPPED_LOCATION, aLocation);
1716 nsCOMPtr<nsIFile> manifest = CloneAndAppend(aLocation, "chrome.manifest"_ns);
1717 return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION, manifest);
1720 NS_IMETHODIMP
1721 nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation) {
1722 NS_ENSURE_ARG_POINTER(aLocation);
1724 nsCOMPtr<nsIChromeRegistry> cr = mozilla::services::GetChromeRegistry();
1725 if (!cr) {
1726 return NS_ERROR_FAILURE;
1729 nsString path;
1730 nsresult rv = aLocation->GetPath(path);
1731 if (NS_FAILED(rv)) {
1732 return rv;
1735 nsComponentManagerImpl::ComponentLocation elem;
1736 elem.type = NS_BOOTSTRAPPED_LOCATION;
1738 if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
1739 elem.location.Init(aLocation, "chrome.manifest");
1740 } else {
1741 nsCOMPtr<nsIFile> lf = CloneAndAppend(aLocation, "chrome.manifest"_ns);
1742 elem.location.Init(lf);
1745 // Remove reference.
1746 nsComponentManagerImpl::sModuleLocations->RemoveElement(
1747 elem, ComponentLocationComparator());
1749 rv = cr->CheckForNewChrome();
1750 return rv;
1753 NS_IMETHODIMP
1754 nsComponentManagerImpl::GetComponentJSMs(nsIUTF8StringEnumerator** aJSMs) {
1755 nsCOMPtr<nsIUTF8StringEnumerator> result =
1756 StaticComponents::GetComponentJSMs();
1757 result.forget(aJSMs);
1758 return NS_OK;
1761 NS_IMETHODIMP
1762 nsComponentManagerImpl::GetComponentESModules(
1763 nsIUTF8StringEnumerator** aESModules) {
1764 nsCOMPtr<nsIUTF8StringEnumerator> result =
1765 StaticComponents::GetComponentESModules();
1766 result.forget(aESModules);
1767 return NS_OK;
1770 NS_IMETHODIMP
1771 nsComponentManagerImpl::GetManifestLocations(nsIArray** aLocations) {
1772 NS_ENSURE_ARG_POINTER(aLocations);
1773 *aLocations = nullptr;
1775 if (!sModuleLocations) {
1776 return NS_ERROR_NOT_INITIALIZED;
1779 nsCOMPtr<nsIMutableArray> locations = nsArray::Create();
1780 nsresult rv;
1781 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
1782 ComponentLocation& l = sModuleLocations->ElementAt(i);
1783 FileLocation loc = l.location;
1784 nsCString uriString;
1785 loc.GetURIString(uriString);
1786 nsCOMPtr<nsIURI> uri;
1787 rv = NS_NewURI(getter_AddRefs(uri), uriString);
1788 if (NS_SUCCEEDED(rv)) {
1789 locations->AppendElement(uri);
1793 locations.forget(aLocations);
1794 return NS_OK;
1797 EXPORT_XPCOM_API(nsresult)
1798 XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation) {
1799 nsComponentManagerImpl::InitializeModuleLocations();
1800 nsComponentManagerImpl::ComponentLocation* c =
1801 nsComponentManagerImpl::sModuleLocations->AppendElement();
1802 c->type = aType;
1803 c->location.Init(aLocation);
1805 if (nsComponentManagerImpl::gComponentManager &&
1806 nsComponentManagerImpl::NORMAL ==
1807 nsComponentManagerImpl::gComponentManager->mStatus) {
1808 nsComponentManagerImpl::gComponentManager->RegisterManifest(
1809 aType, c->location, false);
1812 return NS_OK;
1815 EXPORT_XPCOM_API(nsresult)
1816 XRE_AddJarManifestLocation(NSLocationType aType, nsIFile* aLocation) {
1817 nsComponentManagerImpl::InitializeModuleLocations();
1818 nsComponentManagerImpl::ComponentLocation* c =
1819 nsComponentManagerImpl::sModuleLocations->AppendElement();
1821 c->type = aType;
1822 c->location.Init(aLocation, "chrome.manifest");
1824 if (nsComponentManagerImpl::gComponentManager &&
1825 nsComponentManagerImpl::NORMAL ==
1826 nsComponentManagerImpl::gComponentManager->mStatus) {
1827 nsComponentManagerImpl::gComponentManager->RegisterManifest(
1828 aType, c->location, false);
1831 return NS_OK;
1834 // Expose some important global interfaces to rust for the rust xpcom API. These
1835 // methods return a non-owning reference to the component manager, which should
1836 // live for the lifetime of XPCOM.
1837 extern "C" {
1839 const nsIComponentManager* Gecko_GetComponentManager() {
1840 return nsComponentManagerImpl::gComponentManager;
1843 const nsIServiceManager* Gecko_GetServiceManager() {
1844 return nsComponentManagerImpl::gComponentManager;
1847 const nsIComponentRegistrar* Gecko_GetComponentRegistrar() {
1848 return nsComponentManagerImpl::gComponentManager;