Bug 1885565 - Part 2: Fix up parameter ordering and kDoc descriptions in NavigationBa...
[gecko.git] / xpcom / components / nsComponentManager.cpp
blob515fc82312b2c2cb9a3b51f102464fb2e8cee057
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"
61 #include "xpcpublic.h"
63 #ifdef MOZ_MEMORY
64 # include "mozmemory.h"
65 #endif
67 using namespace mozilla;
68 using namespace mozilla::xpcom;
70 static LazyLogModule nsComponentManagerLog("nsComponentManager");
72 #if 0
73 # define SHOW_DENIED_ON_SHUTDOWN
74 # define SHOW_CI_ON_EXISTING_SERVICE
75 #endif
77 namespace {
79 class AutoIDString : public nsAutoCStringN<NSID_LENGTH> {
80 public:
81 explicit AutoIDString(const nsID& aID) {
82 SetLength(NSID_LENGTH - 1);
83 aID.ToProvidedString(
84 *reinterpret_cast<char(*)[NSID_LENGTH]>(BeginWriting()));
88 } // namespace
90 namespace mozilla {
91 namespace xpcom {
93 using ProcessSelector = Module::ProcessSelector;
95 // Note: These must be kept in sync with the ProcessSelector definition in
96 // Module.h.
97 bool ProcessSelectorMatches(ProcessSelector aSelector) {
98 GeckoProcessType type = XRE_GetProcessType();
99 if (type == GeckoProcessType_GPU) {
100 return !!(aSelector & Module::ALLOW_IN_GPU_PROCESS);
103 if (type == GeckoProcessType_RDD) {
104 return !!(aSelector & Module::ALLOW_IN_RDD_PROCESS);
107 if (type == GeckoProcessType_Socket) {
108 return !!(aSelector & (Module::ALLOW_IN_SOCKET_PROCESS));
111 if (type == GeckoProcessType_VR) {
112 return !!(aSelector & Module::ALLOW_IN_VR_PROCESS);
115 if (type == GeckoProcessType_Utility) {
116 return !!(aSelector & Module::ALLOW_IN_UTILITY_PROCESS);
119 if (type == GeckoProcessType_GMPlugin) {
120 return !!(aSelector & Module::ALLOW_IN_GMPLUGIN_PROCESS);
123 // Only allow XPCOM modules which can be loaded in all processes to be loaded
124 // in the IPDLUnitTest process.
125 if (type == GeckoProcessType_IPDLUnitTest) {
126 return size_t(aSelector) == Module::kMaxProcessSelector;
129 if (aSelector & Module::MAIN_PROCESS_ONLY) {
130 return type == GeckoProcessType_Default;
132 if (aSelector & Module::CONTENT_PROCESS_ONLY) {
133 return type == GeckoProcessType_Content;
135 return true;
138 static bool gProcessMatchTable[Module::kMaxProcessSelector + 1];
140 bool FastProcessSelectorMatches(ProcessSelector aSelector) {
141 return gProcessMatchTable[size_t(aSelector)];
144 } // namespace xpcom
145 } // namespace mozilla
147 namespace {
150 * A wrapper simple wrapper class, which can hold either a dynamic
151 * nsFactoryEntry instance, or a static StaticModule entry, and transparently
152 * forwards method calls to the wrapped object.
154 * This allows the same code to work with either static or dynamic modules
155 * without caring about the difference.
157 class MOZ_STACK_CLASS EntryWrapper final {
158 public:
159 explicit EntryWrapper(nsFactoryEntry* aEntry) : mEntry(aEntry) {}
161 explicit EntryWrapper(const StaticModule* aEntry) : mEntry(aEntry) {}
163 #define MATCH(type, ifFactory, ifStatic) \
164 struct Matcher { \
165 type operator()(nsFactoryEntry* entry) { ifFactory; } \
166 type operator()(const StaticModule* entry) { ifStatic; } \
167 }; \
168 return mEntry.match((Matcher()))
170 const nsID& CID() {
171 MATCH(const nsID&, return entry->mCID, return entry->CID());
174 already_AddRefed<nsIFactory> GetFactory() {
175 MATCH(already_AddRefed<nsIFactory>, return entry->GetFactory(),
176 return entry->GetFactory());
180 * Creates an instance of the underlying component. This should be used in
181 * preference to GetFactory()->CreateInstance() where appropriate, since it
182 * side-steps the necessity of creating a nsIFactory instance for static
183 * modules.
185 nsresult CreateInstance(const nsIID& aIID, void** aResult) {
186 if (mEntry.is<nsFactoryEntry*>()) {
187 return mEntry.as<nsFactoryEntry*>()->CreateInstance(aIID, aResult);
189 return mEntry.as<const StaticModule*>()->CreateInstance(aIID, aResult);
193 * Returns the cached service instance for this entry, if any. This should
194 * only be accessed while mLock is held.
196 nsISupports* ServiceInstance() {
197 MATCH(nsISupports*, return entry->mServiceObject,
198 return entry->ServiceInstance());
200 void SetServiceInstance(already_AddRefed<nsISupports> aInst) {
201 if (mEntry.is<nsFactoryEntry*>()) {
202 mEntry.as<nsFactoryEntry*>()->mServiceObject = aInst;
203 } else {
204 return mEntry.as<const StaticModule*>()->SetServiceInstance(
205 std::move(aInst));
210 * Returns the description string for the module this entry belongs to.
211 * Currently always returns "<unknown module>".
213 nsCString ModuleDescription() { 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 = 8;
268 nsComponentManagerImpl::nsComponentManagerImpl()
269 : mFactories(CONTRACTID_HASHTABLE_INITIAL_LENGTH),
270 mContractIDs(CONTRACTID_HASHTABLE_INITIAL_LENGTH),
271 mLock("nsComponentManagerImpl.mLock"),
272 mStatus(NOT_INITIALIZED) {}
274 nsTArray<nsComponentManagerImpl::ComponentLocation>*
275 nsComponentManagerImpl::sModuleLocations;
277 /* static */
278 void nsComponentManagerImpl::InitializeModuleLocations() {
279 if (sModuleLocations) {
280 return;
283 sModuleLocations = new nsTArray<ComponentLocation>;
286 nsresult nsComponentManagerImpl::Init() {
288 gProcessMatchTable[size_t(ProcessSelector::ANY_PROCESS)] =
289 ProcessSelectorMatches(ProcessSelector::ANY_PROCESS);
290 gProcessMatchTable[size_t(ProcessSelector::MAIN_PROCESS_ONLY)] =
291 ProcessSelectorMatches(ProcessSelector::MAIN_PROCESS_ONLY);
292 gProcessMatchTable[size_t(ProcessSelector::CONTENT_PROCESS_ONLY)] =
293 ProcessSelectorMatches(ProcessSelector::CONTENT_PROCESS_ONLY);
294 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_PROCESS)] =
295 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_PROCESS);
296 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_VR_PROCESS)] =
297 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_VR_PROCESS);
298 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_SOCKET_PROCESS)] =
299 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_SOCKET_PROCESS);
300 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_RDD_PROCESS)] =
301 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_RDD_PROCESS);
302 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GMPLUGIN_PROCESS)] =
303 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GMPLUGIN_PROCESS);
304 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_MAIN_PROCESS)] =
305 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_MAIN_PROCESS);
306 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS)] =
307 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS);
308 gProcessMatchTable[size_t(
309 ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS)] =
310 ProcessSelectorMatches(
311 ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS);
312 gProcessMatchTable[size_t(
313 ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS)] =
314 ProcessSelectorMatches(
315 ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS);
316 gProcessMatchTable[size_t(
317 ProcessSelector::ALLOW_IN_RDD_AND_SOCKET_PROCESS)] =
318 ProcessSelectorMatches(
319 ProcessSelector::ALLOW_IN_RDD_AND_SOCKET_PROCESS);
320 gProcessMatchTable[size_t(
321 ProcessSelector::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS)] =
322 ProcessSelectorMatches(
323 ProcessSelector::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS);
324 gProcessMatchTable[size_t(
325 ProcessSelector::ALLOW_IN_GPU_RDD_SOCKET_AND_UTILITY_PROCESS)] =
326 ProcessSelectorMatches(
327 ProcessSelector::ALLOW_IN_GPU_RDD_SOCKET_AND_UTILITY_PROCESS);
328 gProcessMatchTable[size_t(
329 ProcessSelector::ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS)] =
330 ProcessSelectorMatches(
331 ProcessSelector::ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS);
332 gProcessMatchTable[size_t(
333 ProcessSelector::ALLOW_IN_GPU_RDD_VR_SOCKET_AND_UTILITY_PROCESS)] =
334 ProcessSelectorMatches(
335 ProcessSelector::ALLOW_IN_GPU_RDD_VR_SOCKET_AND_UTILITY_PROCESS);
336 gProcessMatchTable[size_t(
337 ProcessSelector::
338 ALLOW_IN_GPU_RDD_VR_SOCKET_UTILITY_AND_GMPLUGIN_PROCESS)] =
339 ProcessSelectorMatches(
340 ProcessSelector::
341 ALLOW_IN_GPU_RDD_VR_SOCKET_UTILITY_AND_GMPLUGIN_PROCESS);
344 MOZ_ASSERT(NOT_INITIALIZED == mStatus);
346 nsCOMPtr<nsIFile> greDir = GetLocationFromDirectoryService(NS_GRE_DIR);
347 nsCOMPtr<nsIFile> appDir =
348 GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR);
350 nsCategoryManager::GetSingleton()->SuppressNotifications(true);
352 auto* catMan = nsCategoryManager::GetSingleton();
353 for (const auto& cat : gStaticCategories) {
354 for (const auto& entry : cat) {
355 if (entry.Active()) {
356 catMan->AddCategoryEntry(cat.Name(), entry.Entry(), entry.Value());
361 // This needs to be initialized late enough, so that preferences service can
362 // be accessed but before the IO service, and we want it in all process types.
363 xpc::ReadOnlyPage::Init();
365 bool loadChromeManifests;
366 switch (XRE_GetProcessType()) {
367 // We are going to assume that only a select few (see below) process types
368 // want to load chrome manifests, and that any new process types will not
369 // want to load them, because they're not going to be executing JS.
370 case GeckoProcessType_RemoteSandboxBroker:
371 default:
372 loadChromeManifests = false;
373 break;
375 // XXX The check this code replaced implicitly let through all of these
376 // process types, but presumably only the default (parent) and content
377 // processes really need chrome manifests...?
378 case GeckoProcessType_Default:
379 case GeckoProcessType_Content:
380 loadChromeManifests = true;
381 break;
384 if (loadChromeManifests) {
385 // This needs to be called very early, before anything in nsLayoutModule is
386 // used, and before any calls are made into the JS engine.
387 nsLayoutModuleInitialize();
389 mJSLoaderReady = true;
391 // The overall order in which chrome.manifests are expected to be treated
392 // is the following:
393 // - greDir's omni.ja or greDir
394 // - appDir's omni.ja or appDir
396 InitializeModuleLocations();
397 ComponentLocation* cl = sModuleLocations->AppendElement();
398 cl->type = NS_APP_LOCATION;
399 RefPtr<nsZipArchive> greOmnijar =
400 mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
401 if (greOmnijar) {
402 cl->location.Init(greOmnijar, "chrome.manifest");
403 } else {
404 nsCOMPtr<nsIFile> lf = CloneAndAppend(greDir, "chrome.manifest"_ns);
405 cl->location.Init(lf);
408 RefPtr<nsZipArchive> appOmnijar =
409 mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
410 if (appOmnijar) {
411 cl = sModuleLocations->AppendElement();
412 cl->type = NS_APP_LOCATION;
413 cl->location.Init(appOmnijar, "chrome.manifest");
414 } else {
415 bool equals = false;
416 appDir->Equals(greDir, &equals);
417 if (!equals) {
418 cl = sModuleLocations->AppendElement();
419 cl->type = NS_APP_LOCATION;
420 nsCOMPtr<nsIFile> lf = CloneAndAppend(appDir, "chrome.manifest"_ns);
421 cl->location.Init(lf);
425 RereadChromeManifests(false);
428 nsCategoryManager::GetSingleton()->SuppressNotifications(false);
430 RegisterWeakMemoryReporter(this);
432 // NB: The logging preference watcher needs to be registered late enough in
433 // startup that it's okay to use the preference system, but also as soon as
434 // possible so that log modules enabled via preferences are turned on as
435 // early as possible.
437 // We can't initialize the preference watcher when the log module manager is
438 // initialized, as a number of things attempt to start logging before the
439 // preference system is initialized.
441 // The preference system is registered as a component so at this point during
442 // component manager initialization we know it is setup and we can register
443 // for notifications.
444 LogModulePrefWatcher::RegisterPrefWatcher();
446 // Unfortunately, we can't register the nsCategoryManager memory reporter
447 // in its constructor (which is triggered by the GetSingleton() call
448 // above) because the memory reporter manager isn't initialized at that
449 // point. So we wait until now.
450 nsCategoryManager::GetSingleton()->InitMemoryReporter();
452 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
453 ("nsComponentManager: Initialized."));
455 mStatus = NORMAL;
457 MOZ_ASSERT(!XRE_IsContentProcess() ||
458 CONTRACTID_HASHTABLE_INITIAL_LENGTH <= 8 ||
459 mFactories.Count() > CONTRACTID_HASHTABLE_INITIAL_LENGTH / 3,
460 "Initial component hashtable size is too large");
462 return NS_OK;
465 template <typename T>
466 static void AssertNotMallocAllocated(T* aPtr) {
467 #if defined(DEBUG) && defined(MOZ_MEMORY)
468 jemalloc_ptr_info_t info;
469 jemalloc_ptr_info((void*)aPtr, &info);
470 MOZ_ASSERT(info.tag == TagUnknown);
471 #endif
474 template <typename T>
475 static void AssertNotStackAllocated(T* aPtr) {
476 // On all of our supported platforms, the stack grows down. Any address
477 // located below the address of our argument is therefore guaranteed not to be
478 // stack-allocated by the caller.
480 // For addresses above our argument, things get trickier. The main thread
481 // stack is traditionally placed at the top of the program's address space,
482 // but that is becoming less reliable as more and more systems adopt address
483 // space layout randomization strategies, so we have to guess how much space
484 // above our argument pointer we need to care about.
486 // On most systems, we're guaranteed at least several KiB at the top of each
487 // stack for TLS. We'd probably be safe assuming at least 4KiB in the stack
488 // segment above our argument address, but safer is... well, safer.
490 // For threads with huge stacks, it's theoretically possible that we could
491 // wind up being passed a stack-allocated string from farther up the stack,
492 // but this is a best-effort thing, so we'll assume we only care about the
493 // immediate caller. For that case, max 2KiB per stack frame is probably a
494 // reasonable guess most of the time, and is less than the ~4KiB that we
495 // expect for TLS, so go with that to avoid the risk of bumping into heap
496 // data just above the stack.
497 #ifdef DEBUG
498 static constexpr size_t kFuzz = 2048;
500 MOZ_ASSERT(uintptr_t(aPtr) < uintptr_t(&aPtr) ||
501 uintptr_t(aPtr) > uintptr_t(&aPtr) + kFuzz);
502 #endif
505 static void DoRegisterManifest(NSLocationType aType, FileLocation& aFile,
506 bool aChromeOnly) {
507 auto result = URLPreloader::Read(aFile);
508 if (result.isOk()) {
509 nsCString buf(result.unwrap());
510 ParseManifest(aType, aFile, buf.BeginWriting(), aChromeOnly);
511 } else if (NS_BOOTSTRAPPED_LOCATION != aType) {
512 nsCString uri;
513 aFile.GetURIString(uri);
514 LogMessage("Could not read chrome manifest '%s'.", uri.get());
518 void nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
519 FileLocation& aFile,
520 bool aChromeOnly) {
521 DoRegisterManifest(aType, aFile, aChromeOnly);
524 void nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& aCx,
525 int aLineNo, char* const* aArgv) {
526 char* file = aArgv[0];
527 FileLocation f(aCx.mFile, file);
528 RegisterManifest(aCx.mType, f, aCx.mChromeOnly);
531 void nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext& aCx,
532 int aLineNo, char* const* aArgv) {
533 char* category = aArgv[0];
534 char* key = aArgv[1];
535 char* value = aArgv[2];
537 nsCategoryManager::GetSingleton()->AddCategoryEntry(
538 nsDependentCString(category), nsDependentCString(key),
539 nsDependentCString(value));
542 void nsComponentManagerImpl::RereadChromeManifests(bool aChromeOnly) {
543 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
544 ComponentLocation& l = sModuleLocations->ElementAt(i);
545 RegisterManifest(l.type, l.location, aChromeOnly);
548 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
549 if (obs) {
550 obs->NotifyObservers(nullptr, "chrome-manifests-loaded", nullptr);
554 nsresult nsComponentManagerImpl::Shutdown(void) {
555 MOZ_ASSERT(NORMAL == mStatus);
557 mStatus = SHUTDOWN_IN_PROGRESS;
559 // Shutdown the component manager
560 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
561 ("nsComponentManager: Beginning Shutdown."));
563 UnregisterWeakMemoryReporter(this);
565 // Release all cached factories
566 mContractIDs.Clear();
567 mFactories.Clear(); // XXX release the objects, don't just clear
569 StaticComponents::Shutdown();
571 delete sModuleLocations;
573 mStatus = SHUTDOWN_COMPLETE;
575 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
576 ("nsComponentManager: Shutdown complete."));
578 return NS_OK;
581 nsComponentManagerImpl::~nsComponentManagerImpl() {
582 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
583 ("nsComponentManager: Beginning destruction."));
585 if (SHUTDOWN_COMPLETE != mStatus) {
586 Shutdown();
589 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
590 ("nsComponentManager: Destroyed."));
593 NS_IMPL_ISUPPORTS(nsComponentManagerImpl, nsIComponentManager,
594 nsIServiceManager, nsIComponentRegistrar,
595 nsISupportsWeakReference, nsIInterfaceRequestor,
596 nsIMemoryReporter)
598 nsresult nsComponentManagerImpl::GetInterface(const nsIID& aUuid,
599 void** aResult) {
600 NS_WARNING("This isn't supported");
601 // fall through to QI as anything QIable is a superset of what can be
602 // got via the GetInterface()
603 return QueryInterface(aUuid, aResult);
606 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByCID(const nsID& aCID) {
607 return LookupByCID(MonitorAutoLock(mLock), aCID);
610 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByCID(const MonitorAutoLock&,
611 const nsID& aCID) {
612 if (const StaticModule* module = StaticComponents::LookupByCID(aCID)) {
613 return Some(EntryWrapper(module));
615 if (nsFactoryEntry* entry = mFactories.Get(&aCID)) {
616 return Some(EntryWrapper(entry));
618 return Nothing();
621 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByContractID(
622 const nsACString& aContractID) {
623 return LookupByContractID(MonitorAutoLock(mLock), aContractID);
626 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByContractID(
627 const MonitorAutoLock&, const nsACString& aContractID) {
628 if (const StaticModule* module =
629 StaticComponents::LookupByContractID(aContractID)) {
630 return Some(EntryWrapper(module));
632 if (nsFactoryEntry* entry = mContractIDs.Get(aContractID)) {
633 // UnregisterFactory might have left a stale nsFactoryEntry in
634 // mContractIDs, so we should check to see whether this entry has
635 // anything useful.
636 if (entry->mFactory || entry->mServiceObject) {
637 return Some(EntryWrapper(entry));
640 return Nothing();
643 already_AddRefed<nsIFactory> nsComponentManagerImpl::FindFactory(
644 const nsCID& aClass) {
645 Maybe<EntryWrapper> e = LookupByCID(aClass);
646 if (!e) {
647 return nullptr;
650 return e->GetFactory();
653 already_AddRefed<nsIFactory> nsComponentManagerImpl::FindFactory(
654 const char* aContractID, uint32_t aContractIDLen) {
655 Maybe<EntryWrapper> entry =
656 LookupByContractID(nsDependentCString(aContractID, aContractIDLen));
657 if (!entry) {
658 return nullptr;
661 return entry->GetFactory();
665 * GetClassObject()
667 * Given a classID, this finds the singleton ClassObject that implements the
668 * CID. Returns an interface of type aIID off the singleton classobject.
670 NS_IMETHODIMP
671 nsComponentManagerImpl::GetClassObject(const nsCID& aClass, const nsIID& aIID,
672 void** aResult) {
673 nsresult rv;
675 if (MOZ_LOG_TEST(nsComponentManagerLog, LogLevel::Debug)) {
676 char buf[NSID_LENGTH];
677 aClass.ToProvidedString(buf);
678 PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
681 MOZ_ASSERT(aResult != nullptr);
683 nsCOMPtr<nsIFactory> factory = FindFactory(aClass);
684 if (!factory) {
685 return NS_ERROR_FACTORY_NOT_REGISTERED;
688 rv = factory->QueryInterface(aIID, aResult);
690 MOZ_LOG(
691 nsComponentManagerLog, LogLevel::Warning,
692 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
694 return rv;
697 NS_IMETHODIMP
698 nsComponentManagerImpl::GetClassObjectByContractID(const char* aContractID,
699 const nsIID& aIID,
700 void** aResult) {
701 if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aContractID)) {
702 return NS_ERROR_INVALID_ARG;
705 nsresult rv;
707 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
708 ("nsComponentManager: GetClassObjectByContractID(%s)", aContractID));
710 nsCOMPtr<nsIFactory> factory = FindFactory(aContractID, strlen(aContractID));
711 if (!factory) {
712 return NS_ERROR_FACTORY_NOT_REGISTERED;
715 rv = factory->QueryInterface(aIID, aResult);
717 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
718 ("\t\tGetClassObjectByContractID() %s",
719 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
721 return rv;
725 * CreateInstance()
727 * Create an instance of an object that implements an interface and belongs
728 * to the implementation aClass using the factory. The factory is immediately
729 * released and not held onto for any longer.
731 NS_IMETHODIMP
732 nsComponentManagerImpl::CreateInstance(const nsCID& aClass, const nsIID& aIID,
733 void** aResult) {
734 // test this first, since there's no point in creating a component during
735 // shutdown -- whether it's available or not would depend on the order it
736 // occurs in the list
737 if (gXPCOMShuttingDown) {
738 // When processing shutdown, don't process new GetService() requests
739 #ifdef SHOW_DENIED_ON_SHUTDOWN
740 fprintf(stderr,
741 "Creating new instance on shutdown. Denied.\n"
742 " CID: %s\n IID: %s\n",
743 AutoIDString(aClass).get(), AutoIDString(aIID).get());
744 #endif /* SHOW_DENIED_ON_SHUTDOWN */
745 return NS_ERROR_UNEXPECTED;
748 if (!aResult) {
749 return NS_ERROR_NULL_POINTER;
751 *aResult = nullptr;
753 Maybe<EntryWrapper> entry = LookupByCID(aClass);
755 if (!entry) {
756 return NS_ERROR_FACTORY_NOT_REGISTERED;
759 #ifdef SHOW_CI_ON_EXISTING_SERVICE
760 if (entry->ServiceInstance()) {
761 nsAutoCString message;
762 message = "You are calling CreateInstance \""_ns + AutoIDString(aClass) +
763 "\" when a service for this CID already exists!"_ns;
764 NS_ERROR(message.get());
766 #endif
768 nsresult rv;
769 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
770 if (factory) {
771 rv = factory->CreateInstance(aIID, aResult);
772 if (NS_SUCCEEDED(rv) && !*aResult) {
773 NS_ERROR("Factory did not return an object but returned success!");
774 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
776 } else {
777 // Translate error values
778 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
781 if (MOZ_LOG_TEST(nsComponentManagerLog, LogLevel::Warning)) {
782 char buf[NSID_LENGTH];
783 aClass.ToProvidedString(buf);
784 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
785 ("nsComponentManager: CreateInstance(%s) %s", buf,
786 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
789 return rv;
793 * CreateInstanceByContractID()
795 * A variant of CreateInstance() that creates an instance of the object that
796 * implements the interface aIID and whose implementation has a contractID
797 * aContractID.
799 * This is only a convenience routine that turns around can calls the
800 * CreateInstance() with classid and iid.
802 NS_IMETHODIMP
803 nsComponentManagerImpl::CreateInstanceByContractID(const char* aContractID,
804 const nsIID& aIID,
805 void** aResult) {
806 if (NS_WARN_IF(!aContractID)) {
807 return NS_ERROR_INVALID_ARG;
810 // test this first, since there's no point in creating a component during
811 // shutdown -- whether it's available or not would depend on the order it
812 // occurs in the list
813 if (gXPCOMShuttingDown) {
814 // When processing shutdown, don't process new GetService() requests
815 #ifdef SHOW_DENIED_ON_SHUTDOWN
816 fprintf(stderr,
817 "Creating new instance on shutdown. Denied.\n"
818 " ContractID: %s\n IID: %s\n",
819 aContractID, AutoIDString(aIID).get());
820 #endif /* SHOW_DENIED_ON_SHUTDOWN */
821 return NS_ERROR_UNEXPECTED;
824 if (!aResult) {
825 return NS_ERROR_NULL_POINTER;
827 *aResult = nullptr;
829 Maybe<EntryWrapper> entry =
830 LookupByContractID(nsDependentCString(aContractID));
832 if (!entry) {
833 return NS_ERROR_FACTORY_NOT_REGISTERED;
836 #ifdef SHOW_CI_ON_EXISTING_SERVICE
837 if (entry->ServiceInstance()) {
838 nsAutoCString message;
839 message =
840 "You are calling CreateInstance \""_ns +
841 nsDependentCString(aContractID) +
842 nsLiteralCString(
843 "\" when a service for this CID already exists! "
844 "Add it to abusedContracts to track down the service consumer.");
845 NS_ERROR(message.get());
847 #endif
849 nsresult rv;
850 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
851 if (factory) {
852 rv = factory->CreateInstance(aIID, aResult);
853 if (NS_SUCCEEDED(rv) && !*aResult) {
854 NS_ERROR("Factory did not return an object but returned success!");
855 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
857 } else {
858 // Translate error values
859 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
862 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
863 ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
864 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
866 return rv;
869 nsresult nsComponentManagerImpl::FreeServices() {
870 NS_ASSERTION(gXPCOMShuttingDown,
871 "Must be shutting down in order to free all services");
873 if (!gXPCOMShuttingDown) {
874 return NS_ERROR_FAILURE;
877 for (nsFactoryEntry* entry : mFactories.Values()) {
878 entry->mFactory = nullptr;
879 entry->mServiceObject = nullptr;
882 for (const auto& module : gStaticModules) {
883 module.SetServiceInstance(nullptr);
886 return NS_OK;
889 // This should only ever be called within the monitor!
890 nsComponentManagerImpl::PendingServiceInfo*
891 nsComponentManagerImpl::AddPendingService(const nsCID& aServiceCID,
892 PRThread* aThread) {
893 PendingServiceInfo* newInfo = mPendingServices.AppendElement();
894 if (newInfo) {
895 newInfo->cid = &aServiceCID;
896 newInfo->thread = aThread;
898 return newInfo;
901 // This should only ever be called within the monitor!
902 void nsComponentManagerImpl::RemovePendingService(MonitorAutoLock& aLock,
903 const nsCID& aServiceCID) {
904 uint32_t pendingCount = mPendingServices.Length();
905 for (uint32_t index = 0; index < pendingCount; ++index) {
906 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
907 if (info.cid->Equals(aServiceCID)) {
908 mPendingServices.RemoveElementAt(index);
909 aLock.NotifyAll();
910 return;
915 // This should only ever be called within the monitor!
916 PRThread* nsComponentManagerImpl::GetPendingServiceThread(
917 const nsCID& aServiceCID) const {
918 uint32_t pendingCount = mPendingServices.Length();
919 for (uint32_t index = 0; index < pendingCount; ++index) {
920 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
921 if (info.cid->Equals(aServiceCID)) {
922 return info.thread;
925 return nullptr;
928 nsresult nsComponentManagerImpl::GetServiceLocked(Maybe<MonitorAutoLock>& aLock,
929 EntryWrapper& aEntry,
930 const nsIID& aIID,
931 void** aResult) {
932 MOZ_ASSERT(aLock.isSome());
933 if (!aLock.isSome()) {
934 return NS_ERROR_INVALID_ARG;
937 if (auto* service = aEntry.ServiceInstance()) {
938 aLock.reset();
939 return service->QueryInterface(aIID, aResult);
942 PRThread* currentPRThread = PR_GetCurrentThread();
943 MOZ_ASSERT(currentPRThread, "This should never be null!");
945 PRThread* pendingPRThread;
946 while ((pendingPRThread = GetPendingServiceThread(aEntry.CID()))) {
947 if (pendingPRThread == currentPRThread) {
948 NS_ERROR("Recursive GetService!");
949 return NS_ERROR_NOT_AVAILABLE;
952 aLock->Wait();
955 // It's still possible that the other thread failed to create the
956 // service so we're not guaranteed to have an entry or service yet.
957 if (auto* service = aEntry.ServiceInstance()) {
958 aLock.reset();
959 return service->QueryInterface(aIID, aResult);
962 DebugOnly<PendingServiceInfo*> newInfo =
963 AddPendingService(aEntry.CID(), currentPRThread);
964 NS_ASSERTION(newInfo, "Failed to add info to the array!");
966 // We need to not be holding the service manager's lock while calling
967 // CreateInstance, because it invokes user code which could try to re-enter
968 // the service manager:
970 nsCOMPtr<nsISupports> service;
971 auto cleanup = MakeScopeExit([&]() {
972 // `service` must be released after the lock is released, so if we fail and
973 // still have a reference, release the lock before releasing it.
974 if (service) {
975 MOZ_ASSERT(aLock.isSome());
976 aLock.reset();
977 service = nullptr;
980 nsresult rv;
981 mLock.AssertCurrentThreadOwns();
983 MonitorAutoUnlock unlock(mLock);
984 AUTO_PROFILER_MARKER_TEXT(
985 "GetService", OTHER, MarkerStack::Capture(),
986 nsDependentCString(nsIDToCString(aEntry.CID()).get()));
987 rv = aEntry.CreateInstance(aIID, getter_AddRefs(service));
989 if (NS_SUCCEEDED(rv) && !service) {
990 NS_ERROR("Factory did not return an object but returned success");
991 return NS_ERROR_SERVICE_NOT_AVAILABLE;
994 #ifdef DEBUG
995 pendingPRThread = GetPendingServiceThread(aEntry.CID());
996 MOZ_ASSERT(pendingPRThread == currentPRThread,
997 "Pending service array has been changed!");
998 #endif
999 MOZ_ASSERT(aLock.isSome());
1000 RemovePendingService(*aLock, aEntry.CID());
1002 if (NS_FAILED(rv)) {
1003 return rv;
1006 NS_ASSERTION(!aEntry.ServiceInstance(),
1007 "Created two instances of a service!");
1009 aEntry.SetServiceInstance(service.forget());
1011 aLock.reset();
1013 *aResult = do_AddRef(aEntry.ServiceInstance()).take();
1014 return NS_OK;
1017 NS_IMETHODIMP
1018 nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
1019 void** aResult) {
1020 // test this first, since there's no point in returning a service during
1021 // shutdown -- whether it's available or not would depend on the order it
1022 // occurs in the list
1023 if (gXPCOMShuttingDown) {
1024 // When processing shutdown, don't process new GetService() requests
1025 #ifdef SHOW_DENIED_ON_SHUTDOWN
1026 fprintf(stderr,
1027 "Getting service on shutdown. Denied.\n"
1028 " CID: %s\n IID: %s\n",
1029 AutoIDString(aClass).get(), AutoIDString(aIID).get());
1030 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1031 return NS_ERROR_UNEXPECTED;
1034 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1036 Maybe<EntryWrapper> entry = LookupByCID(*lock, aClass);
1037 if (!entry) {
1038 return NS_ERROR_FACTORY_NOT_REGISTERED;
1041 return GetServiceLocked(lock, *entry, aIID, aResult);
1044 nsresult nsComponentManagerImpl::GetService(ModuleID aId, const nsIID& aIID,
1045 void** aResult) {
1046 const auto& entry = gStaticModules[size_t(aId)];
1048 // test this first, since there's no point in returning a service during
1049 // shutdown -- whether it's available or not would depend on the order it
1050 // occurs in the list
1051 if (gXPCOMShuttingDown) {
1052 // When processing shutdown, don't process new GetService() requests
1053 #ifdef SHOW_DENIED_ON_SHUTDOWN
1054 fprintf(stderr,
1055 "Getting service on shutdown. Denied.\n"
1056 " CID: %s\n IID: %s\n",
1057 AutoIDString(entry.CID()).get(), AutoIDString(aIID).get());
1058 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1059 return NS_ERROR_UNEXPECTED;
1062 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1064 Maybe<EntryWrapper> wrapper;
1065 if (entry.Overridable()) {
1066 // If we expect this service to be overridden by test code, we need to look
1067 // it up by contract ID every time.
1068 wrapper = LookupByContractID(*lock, entry.ContractID());
1069 if (!wrapper) {
1070 return NS_ERROR_FACTORY_NOT_REGISTERED;
1072 } else if (!entry.Active()) {
1073 return NS_ERROR_FACTORY_NOT_REGISTERED;
1074 } else {
1075 wrapper.emplace(&entry);
1077 return GetServiceLocked(lock, *wrapper, aIID, aResult);
1080 NS_IMETHODIMP
1081 nsComponentManagerImpl::IsServiceInstantiated(const nsCID& aClass,
1082 const nsIID& aIID,
1083 bool* aResult) {
1084 // Now we want to get the service if we already got it. If not, we don't want
1085 // to create an instance of it. mmh!
1087 // test this first, since there's no point in returning a service during
1088 // shutdown -- whether it's available or not would depend on the order it
1089 // occurs in the list
1090 if (gXPCOMShuttingDown) {
1091 // When processing shutdown, don't process new GetService() requests
1092 #ifdef SHOW_DENIED_ON_SHUTDOWN
1093 fprintf(stderr,
1094 "Checking for service on shutdown. Denied.\n"
1095 " CID: %s\n IID: %s\n",
1096 AutoIDString(aClass).get(), AutoIDString(aIID).get());
1097 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1098 return NS_ERROR_UNEXPECTED;
1101 if (Maybe<EntryWrapper> entry = LookupByCID(aClass)) {
1102 if (auto* service = entry->ServiceInstance()) {
1103 nsCOMPtr<nsISupports> instance;
1104 nsresult rv = service->QueryInterface(aIID, getter_AddRefs(instance));
1105 *aResult = (instance != nullptr);
1106 return rv;
1110 *aResult = false;
1111 return NS_OK;
1114 NS_IMETHODIMP
1115 nsComponentManagerImpl::IsServiceInstantiatedByContractID(
1116 const char* aContractID, const nsIID& aIID, bool* aResult) {
1117 // Now we want to get the service if we already got it. If not, we don't want
1118 // to create an instance of it. mmh!
1120 // test this first, since there's no point in returning a service during
1121 // shutdown -- whether it's available or not would depend on the order it
1122 // occurs in the list
1123 if (gXPCOMShuttingDown) {
1124 // When processing shutdown, don't process new GetService() requests
1125 #ifdef SHOW_DENIED_ON_SHUTDOWN
1126 fprintf(stderr,
1127 "Checking for service on shutdown. Denied.\n"
1128 " ContractID: %s\n IID: %s\n",
1129 aContractID, AutoIDString(aIID).get());
1130 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1131 return NS_ERROR_UNEXPECTED;
1134 if (Maybe<EntryWrapper> entry =
1135 LookupByContractID(nsDependentCString(aContractID))) {
1136 if (auto* service = entry->ServiceInstance()) {
1137 nsCOMPtr<nsISupports> instance;
1138 nsresult rv = service->QueryInterface(aIID, getter_AddRefs(instance));
1139 *aResult = (instance != nullptr);
1140 return rv;
1144 *aResult = false;
1145 return NS_OK;
1148 NS_IMETHODIMP
1149 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
1150 const nsIID& aIID,
1151 void** aResult) {
1152 // test this first, since there's no point in returning a service during
1153 // shutdown -- whether it's available or not would depend on the order it
1154 // occurs in the list
1155 if (gXPCOMShuttingDown) {
1156 // When processing shutdown, don't process new GetService() requests
1157 #ifdef SHOW_DENIED_ON_SHUTDOWN
1158 fprintf(stderr,
1159 "Getting service on shutdown. Denied.\n"
1160 " ContractID: %s\n IID: %s\n",
1161 aContractID, AutoIDString(aIID).get());
1162 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1163 return NS_ERROR_UNEXPECTED;
1166 AUTO_PROFILER_LABEL_DYNAMIC_CSTR_NONSENSITIVE("GetServiceByContractID", OTHER,
1167 aContractID);
1168 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1170 Maybe<EntryWrapper> entry =
1171 LookupByContractID(*lock, nsDependentCString(aContractID));
1172 if (!entry) {
1173 return NS_ERROR_FACTORY_NOT_REGISTERED;
1176 return GetServiceLocked(lock, *entry, aIID, aResult);
1179 NS_IMETHODIMP
1180 nsComponentManagerImpl::RegisterFactory(const nsCID& aClass, const char* aName,
1181 const char* aContractID,
1182 nsIFactory* aFactory) {
1183 if (!aFactory) {
1184 // If a null factory is passed in, this call just wants to reset
1185 // the contract ID to point to an existing CID entry.
1186 if (!aContractID) {
1187 return NS_ERROR_INVALID_ARG;
1190 nsDependentCString contractID(aContractID);
1192 MonitorAutoLock lock(mLock);
1193 nsFactoryEntry* oldf = mFactories.Get(&aClass);
1194 if (oldf) {
1195 StaticComponents::InvalidateContractID(contractID);
1196 mContractIDs.InsertOrUpdate(contractID, oldf);
1197 return NS_OK;
1200 if (StaticComponents::LookupByCID(aClass)) {
1201 // If this is the CID of a static module, just reset the invalid bit of
1202 // the static entry for this contract ID, and assume it points to the
1203 // correct class.
1204 if (StaticComponents::InvalidateContractID(contractID, false)) {
1205 mContractIDs.Remove(contractID);
1206 return NS_OK;
1209 return NS_ERROR_FACTORY_NOT_REGISTERED;
1212 auto f = MakeUnique<nsFactoryEntry>(aClass, aFactory);
1214 MonitorAutoLock lock(mLock);
1215 return mFactories.WithEntryHandle(&f->mCID, [&](auto&& entry) {
1216 if (entry) {
1217 return NS_ERROR_FACTORY_EXISTS;
1219 if (StaticComponents::LookupByCID(f->mCID)) {
1220 return NS_ERROR_FACTORY_EXISTS;
1222 if (aContractID) {
1223 nsDependentCString contractID(aContractID);
1224 mContractIDs.InsertOrUpdate(contractID, f.get());
1225 // We allow dynamically-registered contract IDs to override static
1226 // entries, so invalidate any static entry for this contract ID.
1227 StaticComponents::InvalidateContractID(contractID);
1229 entry.Insert(f.release());
1231 return NS_OK;
1235 NS_IMETHODIMP
1236 nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass,
1237 nsIFactory* aFactory) {
1238 // Don't release the dying factory or service object until releasing
1239 // the component manager monitor.
1240 nsCOMPtr<nsIFactory> dyingFactory;
1241 nsCOMPtr<nsISupports> dyingServiceObject;
1244 MonitorAutoLock lock(mLock);
1245 auto entry = mFactories.Lookup(&aClass);
1246 nsFactoryEntry* f = entry ? entry.Data() : nullptr;
1247 if (!f || f->mFactory != aFactory) {
1248 // Note: We do not support unregistering static factories.
1249 return NS_ERROR_FACTORY_NOT_REGISTERED;
1252 entry.Remove();
1254 // This might leave a stale contractid -> factory mapping in
1255 // place, so null out the factory entry (see
1256 // nsFactoryEntry::GetFactory)
1257 f->mFactory.swap(dyingFactory);
1258 f->mServiceObject.swap(dyingServiceObject);
1261 return NS_OK;
1264 NS_IMETHODIMP
1265 nsComponentManagerImpl::AutoRegister(nsIFile* aLocation) {
1266 XRE_AddManifestLocation(NS_EXTENSION_LOCATION, aLocation);
1267 return NS_OK;
1270 NS_IMETHODIMP
1271 nsComponentManagerImpl::IsCIDRegistered(const nsCID& aClass, bool* aResult) {
1272 *aResult = LookupByCID(aClass).isSome();
1273 return NS_OK;
1276 NS_IMETHODIMP
1277 nsComponentManagerImpl::IsContractIDRegistered(const char* aClass,
1278 bool* aResult) {
1279 if (NS_WARN_IF(!aClass)) {
1280 return NS_ERROR_INVALID_ARG;
1283 Maybe<EntryWrapper> entry = LookupByContractID(nsDependentCString(aClass));
1285 *aResult = entry.isSome();
1286 return NS_OK;
1289 NS_IMETHODIMP
1290 nsComponentManagerImpl::GetContractIDs(nsTArray<nsCString>& aResult) {
1291 aResult = ToTArray<nsTArray<nsCString>>(mContractIDs.Keys());
1293 for (const auto& entry : gContractEntries) {
1294 if (!entry.Invalid()) {
1295 aResult.AppendElement(entry.ContractID());
1299 return NS_OK;
1302 NS_IMETHODIMP
1303 nsComponentManagerImpl::ContractIDToCID(const char* aContractID,
1304 nsCID** aResult) {
1306 MonitorAutoLock lock(mLock);
1307 Maybe<EntryWrapper> entry =
1308 LookupByContractID(lock, nsDependentCString(aContractID));
1309 if (entry) {
1310 *aResult = (nsCID*)moz_xmalloc(sizeof(nsCID));
1311 **aResult = entry->CID();
1312 return NS_OK;
1315 *aResult = nullptr;
1316 return NS_ERROR_FACTORY_NOT_REGISTERED;
1319 MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf)
1321 NS_IMETHODIMP
1322 nsComponentManagerImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
1323 nsISupports* aData, bool aAnonymize) {
1324 MOZ_COLLECT_REPORT("explicit/xpcom/component-manager", KIND_HEAP, UNITS_BYTES,
1325 SizeOfIncludingThis(ComponentManagerMallocSizeOf),
1326 "Memory used for the XPCOM component manager.");
1328 return NS_OK;
1331 size_t nsComponentManagerImpl::SizeOfIncludingThis(
1332 mozilla::MallocSizeOf aMallocSizeOf) const {
1333 size_t n = aMallocSizeOf(this);
1335 n += mFactories.ShallowSizeOfExcludingThis(aMallocSizeOf);
1336 for (const auto& data : mFactories.Values()) {
1337 n += data->SizeOfIncludingThis(aMallocSizeOf);
1340 n += mContractIDs.ShallowSizeOfExcludingThis(aMallocSizeOf);
1341 for (const auto& key : mContractIDs.Keys()) {
1342 // We don't measure the nsFactoryEntry data because it's owned by
1343 // mFactories (which is measured above).
1344 n += key.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1347 if (sModuleLocations) {
1348 n += sModuleLocations->ShallowSizeOfIncludingThis(aMallocSizeOf);
1351 n += mPendingServices.ShallowSizeOfExcludingThis(aMallocSizeOf);
1353 // Measurement of the following members may be added later if DMD finds it is
1354 // worthwhile:
1355 // - mMon
1356 // - sModuleLocations' entries
1358 return n;
1361 ////////////////////////////////////////////////////////////////////////////////
1362 // nsFactoryEntry
1363 ////////////////////////////////////////////////////////////////////////////////
1365 nsFactoryEntry::nsFactoryEntry(const nsCID& aCID, nsIFactory* aFactory)
1366 : mCID(aCID), mFactory(aFactory) {}
1368 already_AddRefed<nsIFactory> nsFactoryEntry::GetFactory() {
1369 nsComponentManagerImpl::gComponentManager->mLock.AssertNotCurrentThreadOwns();
1371 nsCOMPtr<nsIFactory> factory = mFactory;
1372 return factory.forget();
1375 nsresult nsFactoryEntry::CreateInstance(const nsIID& aIID, void** aResult) {
1376 nsCOMPtr<nsIFactory> factory = GetFactory();
1377 NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
1378 return factory->CreateInstance(aIID, aResult);
1381 size_t nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
1382 size_t n = aMallocSizeOf(this);
1384 // Measurement of the following members may be added later if DMD finds it is
1385 // worthwhile:
1386 // - mCID;
1387 // - mFactory;
1388 // - mServiceObject;
1390 return n;
1393 ////////////////////////////////////////////////////////////////////////////////
1394 // Static Access Functions
1395 ////////////////////////////////////////////////////////////////////////////////
1397 nsresult NS_GetComponentManager(nsIComponentManager** aResult) {
1398 if (!nsComponentManagerImpl::gComponentManager) {
1399 return NS_ERROR_NOT_INITIALIZED;
1402 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1403 return NS_OK;
1406 nsresult NS_GetServiceManager(nsIServiceManager** aResult) {
1407 if (!nsComponentManagerImpl::gComponentManager) {
1408 return NS_ERROR_NOT_INITIALIZED;
1411 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1412 return NS_OK;
1415 nsresult NS_GetComponentRegistrar(nsIComponentRegistrar** aResult) {
1416 if (!nsComponentManagerImpl::gComponentManager) {
1417 return NS_ERROR_NOT_INITIALIZED;
1420 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1421 return NS_OK;
1424 NS_IMETHODIMP
1425 nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation) {
1426 NS_ENSURE_ARG_POINTER(aLocation);
1428 nsString path;
1429 nsresult rv = aLocation->GetPath(path);
1430 if (NS_FAILED(rv)) {
1431 return rv;
1434 if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
1435 return XRE_AddJarManifestLocation(NS_BOOTSTRAPPED_LOCATION, aLocation);
1438 nsCOMPtr<nsIFile> manifest = CloneAndAppend(aLocation, "chrome.manifest"_ns);
1439 return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION, manifest);
1442 NS_IMETHODIMP
1443 nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation) {
1444 NS_ENSURE_ARG_POINTER(aLocation);
1446 nsCOMPtr<nsIChromeRegistry> cr = mozilla::services::GetChromeRegistry();
1447 if (!cr) {
1448 return NS_ERROR_FAILURE;
1451 nsString path;
1452 nsresult rv = aLocation->GetPath(path);
1453 if (NS_FAILED(rv)) {
1454 return rv;
1457 nsComponentManagerImpl::ComponentLocation elem;
1458 elem.type = NS_BOOTSTRAPPED_LOCATION;
1460 if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
1461 elem.location.Init(aLocation, "chrome.manifest");
1462 } else {
1463 nsCOMPtr<nsIFile> lf = CloneAndAppend(aLocation, "chrome.manifest"_ns);
1464 elem.location.Init(lf);
1467 // Remove reference.
1468 nsComponentManagerImpl::sModuleLocations->RemoveElement(
1469 elem, ComponentLocationComparator());
1471 rv = cr->CheckForNewChrome();
1472 return rv;
1475 NS_IMETHODIMP
1476 nsComponentManagerImpl::GetComponentJSMs(nsIUTF8StringEnumerator** aJSMs) {
1477 nsCOMPtr<nsIUTF8StringEnumerator> result =
1478 StaticComponents::GetComponentJSMs();
1479 result.forget(aJSMs);
1480 return NS_OK;
1483 NS_IMETHODIMP
1484 nsComponentManagerImpl::GetComponentESModules(
1485 nsIUTF8StringEnumerator** aESModules) {
1486 nsCOMPtr<nsIUTF8StringEnumerator> result =
1487 StaticComponents::GetComponentESModules();
1488 result.forget(aESModules);
1489 return NS_OK;
1492 NS_IMETHODIMP
1493 nsComponentManagerImpl::GetManifestLocations(nsIArray** aLocations) {
1494 NS_ENSURE_ARG_POINTER(aLocations);
1495 *aLocations = nullptr;
1497 if (!sModuleLocations) {
1498 return NS_ERROR_NOT_INITIALIZED;
1501 nsCOMPtr<nsIMutableArray> locations = nsArray::Create();
1502 nsresult rv;
1503 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
1504 ComponentLocation& l = sModuleLocations->ElementAt(i);
1505 FileLocation loc = l.location;
1506 nsCString uriString;
1507 loc.GetURIString(uriString);
1508 nsCOMPtr<nsIURI> uri;
1509 rv = NS_NewURI(getter_AddRefs(uri), uriString);
1510 if (NS_SUCCEEDED(rv)) {
1511 locations->AppendElement(uri);
1515 locations.forget(aLocations);
1516 return NS_OK;
1519 EXPORT_XPCOM_API(nsresult)
1520 XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation) {
1521 nsComponentManagerImpl::InitializeModuleLocations();
1522 nsComponentManagerImpl::ComponentLocation* c =
1523 nsComponentManagerImpl::sModuleLocations->AppendElement();
1524 c->type = aType;
1525 c->location.Init(aLocation);
1527 if (nsComponentManagerImpl::gComponentManager &&
1528 nsComponentManagerImpl::NORMAL ==
1529 nsComponentManagerImpl::gComponentManager->mStatus) {
1530 nsComponentManagerImpl::gComponentManager->RegisterManifest(
1531 aType, c->location, false);
1534 return NS_OK;
1537 EXPORT_XPCOM_API(nsresult)
1538 XRE_AddJarManifestLocation(NSLocationType aType, nsIFile* aLocation) {
1539 nsComponentManagerImpl::InitializeModuleLocations();
1540 nsComponentManagerImpl::ComponentLocation* c =
1541 nsComponentManagerImpl::sModuleLocations->AppendElement();
1543 c->type = aType;
1544 c->location.Init(aLocation, "chrome.manifest");
1546 if (nsComponentManagerImpl::gComponentManager &&
1547 nsComponentManagerImpl::NORMAL ==
1548 nsComponentManagerImpl::gComponentManager->mStatus) {
1549 nsComponentManagerImpl::gComponentManager->RegisterManifest(
1550 aType, c->location, false);
1553 return NS_OK;
1556 // Expose some important global interfaces to rust for the rust xpcom API. These
1557 // methods return a non-owning reference to the component manager, which should
1558 // live for the lifetime of XPCOM.
1559 extern "C" {
1561 const nsIComponentManager* Gecko_GetComponentManager() {
1562 return nsComponentManagerImpl::gComponentManager;
1565 const nsIServiceManager* Gecko_GetServiceManager() {
1566 return nsComponentManagerImpl::gComponentManager;
1569 const nsIComponentRegistrar* Gecko_GetComponentRegistrar() {
1570 return nsComponentManagerImpl::gComponentManager;
1573 // FFI-compatible version of `GetServiceHelper::operator()`.
1574 nsresult Gecko_GetServiceByModuleID(ModuleID aId, const nsIID* aIID,
1575 void** aResult) {
1576 return nsComponentManagerImpl::gComponentManager->GetService(aId, *aIID,
1577 aResult);
1580 // FFI-compatible version of `CreateInstanceHelper::operator()`.
1581 nsresult Gecko_CreateInstanceByModuleID(ModuleID aId, const nsIID* aIID,
1582 void** aResult) {
1583 const auto& entry = gStaticModules[size_t(aId)];
1584 if (!entry.Active()) {
1585 return NS_ERROR_FACTORY_NOT_REGISTERED;
1588 nsresult rv = entry.CreateInstance(*aIID, aResult);
1589 return rv;