Bug 1910362 - Create new Nimbus helper r=aaronmt,ohorvath
[gecko.git] / xpcom / components / nsComponentManager.cpp
blob27eb4dc393eb429eae91c8669bab881800e13d91
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 default:
371 loadChromeManifests = false;
372 break;
374 // XXX The check this code replaced implicitly let through all of these
375 // process types, but presumably only the default (parent) and content
376 // processes really need chrome manifests...?
377 case GeckoProcessType_Default:
378 case GeckoProcessType_Content:
379 loadChromeManifests = true;
380 break;
383 if (loadChromeManifests) {
384 // This needs to be called very early, before anything in nsLayoutModule is
385 // used, and before any calls are made into the JS engine.
386 nsLayoutModuleInitialize();
388 mJSLoaderReady = true;
390 // The overall order in which chrome.manifests are expected to be treated
391 // is the following:
392 // - greDir's omni.ja or greDir
393 // - appDir's omni.ja or appDir
395 InitializeModuleLocations();
396 ComponentLocation* cl = sModuleLocations->AppendElement();
397 cl->type = NS_APP_LOCATION;
398 RefPtr<nsZipArchive> greOmnijar =
399 mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
400 if (greOmnijar) {
401 cl->location.Init(greOmnijar, "chrome.manifest");
402 } else {
403 nsCOMPtr<nsIFile> lf = CloneAndAppend(greDir, "chrome.manifest"_ns);
404 cl->location.Init(lf);
407 RefPtr<nsZipArchive> appOmnijar =
408 mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
409 if (appOmnijar) {
410 cl = sModuleLocations->AppendElement();
411 cl->type = NS_APP_LOCATION;
412 cl->location.Init(appOmnijar, "chrome.manifest");
413 } else {
414 bool equals = false;
415 appDir->Equals(greDir, &equals);
416 if (!equals) {
417 cl = sModuleLocations->AppendElement();
418 cl->type = NS_APP_LOCATION;
419 nsCOMPtr<nsIFile> lf = CloneAndAppend(appDir, "chrome.manifest"_ns);
420 cl->location.Init(lf);
424 RereadChromeManifests(false);
427 nsCategoryManager::GetSingleton()->SuppressNotifications(false);
429 RegisterWeakMemoryReporter(this);
431 // NB: The logging preference watcher needs to be registered late enough in
432 // startup that it's okay to use the preference system, but also as soon as
433 // possible so that log modules enabled via preferences are turned on as
434 // early as possible.
436 // We can't initialize the preference watcher when the log module manager is
437 // initialized, as a number of things attempt to start logging before the
438 // preference system is initialized.
440 // The preference system is registered as a component so at this point during
441 // component manager initialization we know it is setup and we can register
442 // for notifications.
443 LogModulePrefWatcher::RegisterPrefWatcher();
445 // Unfortunately, we can't register the nsCategoryManager memory reporter
446 // in its constructor (which is triggered by the GetSingleton() call
447 // above) because the memory reporter manager isn't initialized at that
448 // point. So we wait until now.
449 nsCategoryManager::GetSingleton()->InitMemoryReporter();
451 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
452 ("nsComponentManager: Initialized."));
454 mStatus = NORMAL;
456 MOZ_ASSERT(!XRE_IsContentProcess() ||
457 CONTRACTID_HASHTABLE_INITIAL_LENGTH <= 8 ||
458 mFactories.Count() > CONTRACTID_HASHTABLE_INITIAL_LENGTH / 3,
459 "Initial component hashtable size is too large");
461 return NS_OK;
464 template <typename T>
465 static void AssertNotMallocAllocated(T* aPtr) {
466 #if defined(DEBUG) && defined(MOZ_MEMORY)
467 jemalloc_ptr_info_t info;
468 jemalloc_ptr_info((void*)aPtr, &info);
469 MOZ_ASSERT(info.tag == TagUnknown);
470 #endif
473 template <typename T>
474 static void AssertNotStackAllocated(T* aPtr) {
475 // On all of our supported platforms, the stack grows down. Any address
476 // located below the address of our argument is therefore guaranteed not to be
477 // stack-allocated by the caller.
479 // For addresses above our argument, things get trickier. The main thread
480 // stack is traditionally placed at the top of the program's address space,
481 // but that is becoming less reliable as more and more systems adopt address
482 // space layout randomization strategies, so we have to guess how much space
483 // above our argument pointer we need to care about.
485 // On most systems, we're guaranteed at least several KiB at the top of each
486 // stack for TLS. We'd probably be safe assuming at least 4KiB in the stack
487 // segment above our argument address, but safer is... well, safer.
489 // For threads with huge stacks, it's theoretically possible that we could
490 // wind up being passed a stack-allocated string from farther up the stack,
491 // but this is a best-effort thing, so we'll assume we only care about the
492 // immediate caller. For that case, max 2KiB per stack frame is probably a
493 // reasonable guess most of the time, and is less than the ~4KiB that we
494 // expect for TLS, so go with that to avoid the risk of bumping into heap
495 // data just above the stack.
496 #ifdef DEBUG
497 static constexpr size_t kFuzz = 2048;
499 MOZ_ASSERT(uintptr_t(aPtr) < uintptr_t(&aPtr) ||
500 uintptr_t(aPtr) > uintptr_t(&aPtr) + kFuzz);
501 #endif
504 static void DoRegisterManifest(NSLocationType aType, FileLocation& aFile,
505 bool aChromeOnly) {
506 auto result = URLPreloader::Read(aFile);
507 if (result.isOk()) {
508 nsCString buf(result.unwrap());
509 ParseManifest(aType, aFile, buf.BeginWriting(), aChromeOnly);
510 } else if (NS_BOOTSTRAPPED_LOCATION != aType) {
511 nsCString uri;
512 aFile.GetURIString(uri);
513 LogMessage("Could not read chrome manifest '%s'.", uri.get());
517 void nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
518 FileLocation& aFile,
519 bool aChromeOnly) {
520 DoRegisterManifest(aType, aFile, aChromeOnly);
523 void nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& aCx,
524 int aLineNo, char* const* aArgv) {
525 char* file = aArgv[0];
526 FileLocation f(aCx.mFile, file);
527 RegisterManifest(aCx.mType, f, aCx.mChromeOnly);
530 void nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext& aCx,
531 int aLineNo, char* const* aArgv) {
532 char* category = aArgv[0];
533 char* key = aArgv[1];
534 char* value = aArgv[2];
536 nsCategoryManager::GetSingleton()->AddCategoryEntry(
537 nsDependentCString(category), nsDependentCString(key),
538 nsDependentCString(value));
541 void nsComponentManagerImpl::RereadChromeManifests(bool aChromeOnly) {
542 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
543 ComponentLocation& l = sModuleLocations->ElementAt(i);
544 RegisterManifest(l.type, l.location, aChromeOnly);
547 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
548 if (obs) {
549 obs->NotifyObservers(nullptr, "chrome-manifests-loaded", nullptr);
553 nsresult nsComponentManagerImpl::Shutdown(void) {
554 MOZ_ASSERT(NORMAL == mStatus);
556 mStatus = SHUTDOWN_IN_PROGRESS;
558 // Shutdown the component manager
559 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
560 ("nsComponentManager: Beginning Shutdown."));
562 UnregisterWeakMemoryReporter(this);
564 // Release all cached factories
565 mContractIDs.Clear();
566 mFactories.Clear(); // XXX release the objects, don't just clear
568 StaticComponents::Shutdown();
570 delete sModuleLocations;
572 mStatus = SHUTDOWN_COMPLETE;
574 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
575 ("nsComponentManager: Shutdown complete."));
577 return NS_OK;
580 nsComponentManagerImpl::~nsComponentManagerImpl() {
581 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
582 ("nsComponentManager: Beginning destruction."));
584 if (SHUTDOWN_COMPLETE != mStatus) {
585 Shutdown();
588 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
589 ("nsComponentManager: Destroyed."));
592 NS_IMPL_ISUPPORTS(nsComponentManagerImpl, nsIComponentManager,
593 nsIServiceManager, nsIComponentRegistrar,
594 nsISupportsWeakReference, nsIInterfaceRequestor,
595 nsIMemoryReporter)
597 nsresult nsComponentManagerImpl::GetInterface(const nsIID& aUuid,
598 void** aResult) {
599 NS_WARNING("This isn't supported");
600 // fall through to QI as anything QIable is a superset of what can be
601 // got via the GetInterface()
602 return QueryInterface(aUuid, aResult);
605 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByCID(const nsID& aCID) {
606 return LookupByCID(MonitorAutoLock(mLock), aCID);
609 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByCID(const MonitorAutoLock&,
610 const nsID& aCID) {
611 if (const StaticModule* module = StaticComponents::LookupByCID(aCID)) {
612 return Some(EntryWrapper(module));
614 if (nsFactoryEntry* entry = mFactories.Get(&aCID)) {
615 return Some(EntryWrapper(entry));
617 return Nothing();
620 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByContractID(
621 const nsACString& aContractID) {
622 return LookupByContractID(MonitorAutoLock(mLock), aContractID);
625 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByContractID(
626 const MonitorAutoLock&, const nsACString& aContractID) {
627 if (const StaticModule* module =
628 StaticComponents::LookupByContractID(aContractID)) {
629 return Some(EntryWrapper(module));
631 if (nsFactoryEntry* entry = mContractIDs.Get(aContractID)) {
632 // UnregisterFactory might have left a stale nsFactoryEntry in
633 // mContractIDs, so we should check to see whether this entry has
634 // anything useful.
635 if (entry->mFactory || entry->mServiceObject) {
636 return Some(EntryWrapper(entry));
639 return Nothing();
642 already_AddRefed<nsIFactory> nsComponentManagerImpl::FindFactory(
643 const nsCID& aClass) {
644 Maybe<EntryWrapper> e = LookupByCID(aClass);
645 if (!e) {
646 return nullptr;
649 return e->GetFactory();
652 already_AddRefed<nsIFactory> nsComponentManagerImpl::FindFactory(
653 const char* aContractID, uint32_t aContractIDLen) {
654 Maybe<EntryWrapper> entry =
655 LookupByContractID(nsDependentCString(aContractID, aContractIDLen));
656 if (!entry) {
657 return nullptr;
660 return entry->GetFactory();
664 * GetClassObject()
666 * Given a classID, this finds the singleton ClassObject that implements the
667 * CID. Returns an interface of type aIID off the singleton classobject.
669 NS_IMETHODIMP
670 nsComponentManagerImpl::GetClassObject(const nsCID& aClass, const nsIID& aIID,
671 void** aResult) {
672 nsresult rv;
674 if (MOZ_LOG_TEST(nsComponentManagerLog, LogLevel::Debug)) {
675 char buf[NSID_LENGTH];
676 aClass.ToProvidedString(buf);
677 PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
680 MOZ_ASSERT(aResult != nullptr);
682 nsCOMPtr<nsIFactory> factory = FindFactory(aClass);
683 if (!factory) {
684 return NS_ERROR_FACTORY_NOT_REGISTERED;
687 rv = factory->QueryInterface(aIID, aResult);
689 MOZ_LOG(
690 nsComponentManagerLog, LogLevel::Warning,
691 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
693 return rv;
696 NS_IMETHODIMP
697 nsComponentManagerImpl::GetClassObjectByContractID(const char* aContractID,
698 const nsIID& aIID,
699 void** aResult) {
700 if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aContractID)) {
701 return NS_ERROR_INVALID_ARG;
704 nsresult rv;
706 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
707 ("nsComponentManager: GetClassObjectByContractID(%s)", aContractID));
709 nsCOMPtr<nsIFactory> factory = FindFactory(aContractID, strlen(aContractID));
710 if (!factory) {
711 return NS_ERROR_FACTORY_NOT_REGISTERED;
714 rv = factory->QueryInterface(aIID, aResult);
716 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
717 ("\t\tGetClassObjectByContractID() %s",
718 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
720 return rv;
724 * CreateInstance()
726 * Create an instance of an object that implements an interface and belongs
727 * to the implementation aClass using the factory. The factory is immediately
728 * released and not held onto for any longer.
730 NS_IMETHODIMP
731 nsComponentManagerImpl::CreateInstance(const nsCID& aClass, const nsIID& aIID,
732 void** aResult) {
733 // test this first, since there's no point in creating a component during
734 // shutdown -- whether it's available or not would depend on the order it
735 // occurs in the list
736 if (gXPCOMShuttingDown) {
737 // When processing shutdown, don't process new GetService() requests
738 #ifdef SHOW_DENIED_ON_SHUTDOWN
739 fprintf(stderr,
740 "Creating new instance on shutdown. Denied.\n"
741 " CID: %s\n IID: %s\n",
742 AutoIDString(aClass).get(), AutoIDString(aIID).get());
743 #endif /* SHOW_DENIED_ON_SHUTDOWN */
744 return NS_ERROR_UNEXPECTED;
747 if (!aResult) {
748 return NS_ERROR_NULL_POINTER;
750 *aResult = nullptr;
752 Maybe<EntryWrapper> entry = LookupByCID(aClass);
754 if (!entry) {
755 return NS_ERROR_FACTORY_NOT_REGISTERED;
758 #ifdef SHOW_CI_ON_EXISTING_SERVICE
759 if (entry->ServiceInstance()) {
760 nsAutoCString message;
761 message = "You are calling CreateInstance \""_ns + AutoIDString(aClass) +
762 "\" when a service for this CID already exists!"_ns;
763 NS_ERROR(message.get());
765 #endif
767 nsresult rv;
768 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
769 if (factory) {
770 rv = factory->CreateInstance(aIID, aResult);
771 if (NS_SUCCEEDED(rv) && !*aResult) {
772 NS_ERROR("Factory did not return an object but returned success!");
773 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
775 } else {
776 // Translate error values
777 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
780 if (MOZ_LOG_TEST(nsComponentManagerLog, LogLevel::Warning)) {
781 char buf[NSID_LENGTH];
782 aClass.ToProvidedString(buf);
783 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
784 ("nsComponentManager: CreateInstance(%s) %s", buf,
785 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
788 return rv;
792 * CreateInstanceByContractID()
794 * A variant of CreateInstance() that creates an instance of the object that
795 * implements the interface aIID and whose implementation has a contractID
796 * aContractID.
798 * This is only a convenience routine that turns around can calls the
799 * CreateInstance() with classid and iid.
801 NS_IMETHODIMP
802 nsComponentManagerImpl::CreateInstanceByContractID(const char* aContractID,
803 const nsIID& aIID,
804 void** aResult) {
805 if (NS_WARN_IF(!aContractID)) {
806 return NS_ERROR_INVALID_ARG;
809 // test this first, since there's no point in creating a component during
810 // shutdown -- whether it's available or not would depend on the order it
811 // occurs in the list
812 if (gXPCOMShuttingDown) {
813 // When processing shutdown, don't process new GetService() requests
814 #ifdef SHOW_DENIED_ON_SHUTDOWN
815 fprintf(stderr,
816 "Creating new instance on shutdown. Denied.\n"
817 " ContractID: %s\n IID: %s\n",
818 aContractID, AutoIDString(aIID).get());
819 #endif /* SHOW_DENIED_ON_SHUTDOWN */
820 return NS_ERROR_UNEXPECTED;
823 if (!aResult) {
824 return NS_ERROR_NULL_POINTER;
826 *aResult = nullptr;
828 Maybe<EntryWrapper> entry =
829 LookupByContractID(nsDependentCString(aContractID));
831 if (!entry) {
832 return NS_ERROR_FACTORY_NOT_REGISTERED;
835 #ifdef SHOW_CI_ON_EXISTING_SERVICE
836 if (entry->ServiceInstance()) {
837 nsAutoCString message;
838 message =
839 "You are calling CreateInstance \""_ns +
840 nsDependentCString(aContractID) +
841 nsLiteralCString(
842 "\" when a service for this CID already exists! "
843 "Add it to abusedContracts to track down the service consumer.");
844 NS_ERROR(message.get());
846 #endif
848 nsresult rv;
849 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
850 if (factory) {
851 rv = factory->CreateInstance(aIID, aResult);
852 if (NS_SUCCEEDED(rv) && !*aResult) {
853 NS_ERROR("Factory did not return an object but returned success!");
854 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
856 } else {
857 // Translate error values
858 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
861 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
862 ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
863 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
865 return rv;
868 nsresult nsComponentManagerImpl::FreeServices() {
869 NS_ASSERTION(gXPCOMShuttingDown,
870 "Must be shutting down in order to free all services");
872 if (!gXPCOMShuttingDown) {
873 return NS_ERROR_FAILURE;
876 for (nsFactoryEntry* entry : mFactories.Values()) {
877 entry->mFactory = nullptr;
878 entry->mServiceObject = nullptr;
881 for (const auto& module : gStaticModules) {
882 module.SetServiceInstance(nullptr);
885 return NS_OK;
888 // This should only ever be called within the monitor!
889 nsComponentManagerImpl::PendingServiceInfo*
890 nsComponentManagerImpl::AddPendingService(const nsCID& aServiceCID,
891 PRThread* aThread) {
892 PendingServiceInfo* newInfo = mPendingServices.AppendElement();
893 if (newInfo) {
894 newInfo->cid = &aServiceCID;
895 newInfo->thread = aThread;
897 return newInfo;
900 // This should only ever be called within the monitor!
901 void nsComponentManagerImpl::RemovePendingService(MonitorAutoLock& aLock,
902 const nsCID& aServiceCID) {
903 uint32_t pendingCount = mPendingServices.Length();
904 for (uint32_t index = 0; index < pendingCount; ++index) {
905 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
906 if (info.cid->Equals(aServiceCID)) {
907 mPendingServices.RemoveElementAt(index);
908 aLock.NotifyAll();
909 return;
914 // This should only ever be called within the monitor!
915 PRThread* nsComponentManagerImpl::GetPendingServiceThread(
916 const nsCID& aServiceCID) const {
917 uint32_t pendingCount = mPendingServices.Length();
918 for (uint32_t index = 0; index < pendingCount; ++index) {
919 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
920 if (info.cid->Equals(aServiceCID)) {
921 return info.thread;
924 return nullptr;
927 nsresult nsComponentManagerImpl::GetServiceLocked(Maybe<MonitorAutoLock>& aLock,
928 EntryWrapper& aEntry,
929 const nsIID& aIID,
930 void** aResult) {
931 MOZ_ASSERT(aLock.isSome());
932 if (!aLock.isSome()) {
933 return NS_ERROR_INVALID_ARG;
936 if (auto* service = aEntry.ServiceInstance()) {
937 aLock.reset();
938 return service->QueryInterface(aIID, aResult);
941 PRThread* currentPRThread = PR_GetCurrentThread();
942 MOZ_ASSERT(currentPRThread, "This should never be null!");
944 PRThread* pendingPRThread;
945 while ((pendingPRThread = GetPendingServiceThread(aEntry.CID()))) {
946 if (pendingPRThread == currentPRThread) {
947 NS_ERROR("Recursive GetService!");
948 return NS_ERROR_NOT_AVAILABLE;
951 aLock->Wait();
954 // It's still possible that the other thread failed to create the
955 // service so we're not guaranteed to have an entry or service yet.
956 if (auto* service = aEntry.ServiceInstance()) {
957 aLock.reset();
958 return service->QueryInterface(aIID, aResult);
961 DebugOnly<PendingServiceInfo*> newInfo =
962 AddPendingService(aEntry.CID(), currentPRThread);
963 NS_ASSERTION(newInfo, "Failed to add info to the array!");
965 // We need to not be holding the service manager's lock while calling
966 // CreateInstance, because it invokes user code which could try to re-enter
967 // the service manager:
969 nsCOMPtr<nsISupports> service;
970 auto cleanup = MakeScopeExit([&]() {
971 // `service` must be released after the lock is released, so if we fail and
972 // still have a reference, release the lock before releasing it.
973 if (service) {
974 MOZ_ASSERT(aLock.isSome());
975 aLock.reset();
976 service = nullptr;
979 nsresult rv;
980 mLock.AssertCurrentThreadOwns();
982 MonitorAutoUnlock unlock(mLock);
983 AUTO_PROFILER_MARKER_TEXT(
984 "GetService", OTHER, MarkerStack::Capture(),
985 nsDependentCString(nsIDToCString(aEntry.CID()).get()));
986 rv = aEntry.CreateInstance(aIID, getter_AddRefs(service));
988 if (NS_SUCCEEDED(rv) && !service) {
989 NS_ERROR("Factory did not return an object but returned success");
990 return NS_ERROR_SERVICE_NOT_AVAILABLE;
993 #ifdef DEBUG
994 pendingPRThread = GetPendingServiceThread(aEntry.CID());
995 MOZ_ASSERT(pendingPRThread == currentPRThread,
996 "Pending service array has been changed!");
997 #endif
998 MOZ_ASSERT(aLock.isSome());
999 RemovePendingService(*aLock, aEntry.CID());
1001 if (NS_FAILED(rv)) {
1002 return rv;
1005 NS_ASSERTION(!aEntry.ServiceInstance(),
1006 "Created two instances of a service!");
1008 aEntry.SetServiceInstance(service.forget());
1010 aLock.reset();
1012 *aResult = do_AddRef(aEntry.ServiceInstance()).take();
1013 return NS_OK;
1016 NS_IMETHODIMP
1017 nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
1018 void** aResult) {
1019 // test this first, since there's no point in returning a service during
1020 // shutdown -- whether it's available or not would depend on the order it
1021 // occurs in the list
1022 if (gXPCOMShuttingDown) {
1023 // When processing shutdown, don't process new GetService() requests
1024 #ifdef SHOW_DENIED_ON_SHUTDOWN
1025 fprintf(stderr,
1026 "Getting service on shutdown. Denied.\n"
1027 " CID: %s\n IID: %s\n",
1028 AutoIDString(aClass).get(), AutoIDString(aIID).get());
1029 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1030 return NS_ERROR_UNEXPECTED;
1033 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1035 Maybe<EntryWrapper> entry = LookupByCID(*lock, aClass);
1036 if (!entry) {
1037 return NS_ERROR_FACTORY_NOT_REGISTERED;
1040 return GetServiceLocked(lock, *entry, aIID, aResult);
1043 nsresult nsComponentManagerImpl::GetService(ModuleID aId, const nsIID& aIID,
1044 void** aResult) {
1045 const auto& entry = gStaticModules[size_t(aId)];
1047 // test this first, since there's no point in returning a service during
1048 // shutdown -- whether it's available or not would depend on the order it
1049 // occurs in the list
1050 if (gXPCOMShuttingDown) {
1051 // When processing shutdown, don't process new GetService() requests
1052 #ifdef SHOW_DENIED_ON_SHUTDOWN
1053 fprintf(stderr,
1054 "Getting service on shutdown. Denied.\n"
1055 " CID: %s\n IID: %s\n",
1056 AutoIDString(entry.CID()).get(), AutoIDString(aIID).get());
1057 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1058 return NS_ERROR_UNEXPECTED;
1061 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1063 Maybe<EntryWrapper> wrapper;
1064 if (entry.Overridable()) {
1065 // If we expect this service to be overridden by test code, we need to look
1066 // it up by contract ID every time.
1067 wrapper = LookupByContractID(*lock, entry.ContractID());
1068 if (!wrapper) {
1069 return NS_ERROR_FACTORY_NOT_REGISTERED;
1071 } else if (!entry.Active()) {
1072 return NS_ERROR_FACTORY_NOT_REGISTERED;
1073 } else {
1074 wrapper.emplace(&entry);
1076 return GetServiceLocked(lock, *wrapper, aIID, aResult);
1079 NS_IMETHODIMP
1080 nsComponentManagerImpl::IsServiceInstantiated(const nsCID& aClass,
1081 const nsIID& aIID,
1082 bool* aResult) {
1083 // Now we want to get the service if we already got it. If not, we don't want
1084 // to create an instance of it. mmh!
1086 // test this first, since there's no point in returning a service during
1087 // shutdown -- whether it's available or not would depend on the order it
1088 // occurs in the list
1089 if (gXPCOMShuttingDown) {
1090 // When processing shutdown, don't process new GetService() requests
1091 #ifdef SHOW_DENIED_ON_SHUTDOWN
1092 fprintf(stderr,
1093 "Checking for service on shutdown. Denied.\n"
1094 " CID: %s\n IID: %s\n",
1095 AutoIDString(aClass).get(), AutoIDString(aIID).get());
1096 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1097 return NS_ERROR_UNEXPECTED;
1100 if (Maybe<EntryWrapper> entry = LookupByCID(aClass)) {
1101 if (auto* service = entry->ServiceInstance()) {
1102 nsCOMPtr<nsISupports> instance;
1103 nsresult rv = service->QueryInterface(aIID, getter_AddRefs(instance));
1104 *aResult = (instance != nullptr);
1105 return rv;
1109 *aResult = false;
1110 return NS_OK;
1113 NS_IMETHODIMP
1114 nsComponentManagerImpl::IsServiceInstantiatedByContractID(
1115 const char* aContractID, const nsIID& aIID, bool* aResult) {
1116 // Now we want to get the service if we already got it. If not, we don't want
1117 // to create an instance of it. mmh!
1119 // test this first, since there's no point in returning a service during
1120 // shutdown -- whether it's available or not would depend on the order it
1121 // occurs in the list
1122 if (gXPCOMShuttingDown) {
1123 // When processing shutdown, don't process new GetService() requests
1124 #ifdef SHOW_DENIED_ON_SHUTDOWN
1125 fprintf(stderr,
1126 "Checking for service on shutdown. Denied.\n"
1127 " ContractID: %s\n IID: %s\n",
1128 aContractID, AutoIDString(aIID).get());
1129 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1130 return NS_ERROR_UNEXPECTED;
1133 if (Maybe<EntryWrapper> entry =
1134 LookupByContractID(nsDependentCString(aContractID))) {
1135 if (auto* service = entry->ServiceInstance()) {
1136 nsCOMPtr<nsISupports> instance;
1137 nsresult rv = service->QueryInterface(aIID, getter_AddRefs(instance));
1138 *aResult = (instance != nullptr);
1139 return rv;
1143 *aResult = false;
1144 return NS_OK;
1147 NS_IMETHODIMP
1148 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
1149 const nsIID& aIID,
1150 void** aResult) {
1151 // test this first, since there's no point in returning a service during
1152 // shutdown -- whether it's available or not would depend on the order it
1153 // occurs in the list
1154 if (gXPCOMShuttingDown) {
1155 // When processing shutdown, don't process new GetService() requests
1156 #ifdef SHOW_DENIED_ON_SHUTDOWN
1157 fprintf(stderr,
1158 "Getting service on shutdown. Denied.\n"
1159 " ContractID: %s\n IID: %s\n",
1160 aContractID, AutoIDString(aIID).get());
1161 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1162 return NS_ERROR_UNEXPECTED;
1165 AUTO_PROFILER_LABEL_DYNAMIC_CSTR_NONSENSITIVE("GetServiceByContractID", OTHER,
1166 aContractID);
1167 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1169 Maybe<EntryWrapper> entry =
1170 LookupByContractID(*lock, nsDependentCString(aContractID));
1171 if (!entry) {
1172 return NS_ERROR_FACTORY_NOT_REGISTERED;
1175 return GetServiceLocked(lock, *entry, aIID, aResult);
1178 NS_IMETHODIMP
1179 nsComponentManagerImpl::RegisterFactory(const nsCID& aClass, const char* aName,
1180 const char* aContractID,
1181 nsIFactory* aFactory) {
1182 if (!aFactory) {
1183 // If a null factory is passed in, this call just wants to reset
1184 // the contract ID to point to an existing CID entry.
1185 if (!aContractID) {
1186 return NS_ERROR_INVALID_ARG;
1189 nsDependentCString contractID(aContractID);
1191 MonitorAutoLock lock(mLock);
1192 nsFactoryEntry* oldf = mFactories.Get(&aClass);
1193 if (oldf) {
1194 StaticComponents::InvalidateContractID(contractID);
1195 mContractIDs.InsertOrUpdate(contractID, oldf);
1196 return NS_OK;
1199 if (StaticComponents::LookupByCID(aClass)) {
1200 // If this is the CID of a static module, just reset the invalid bit of
1201 // the static entry for this contract ID, and assume it points to the
1202 // correct class.
1203 if (StaticComponents::InvalidateContractID(contractID, false)) {
1204 mContractIDs.Remove(contractID);
1205 return NS_OK;
1208 return NS_ERROR_FACTORY_NOT_REGISTERED;
1211 auto f = MakeUnique<nsFactoryEntry>(aClass, aFactory);
1213 MonitorAutoLock lock(mLock);
1214 return mFactories.WithEntryHandle(&f->mCID, [&](auto&& entry) {
1215 if (entry) {
1216 return NS_ERROR_FACTORY_EXISTS;
1218 if (StaticComponents::LookupByCID(f->mCID)) {
1219 return NS_ERROR_FACTORY_EXISTS;
1221 if (aContractID) {
1222 nsDependentCString contractID(aContractID);
1223 mContractIDs.InsertOrUpdate(contractID, f.get());
1224 // We allow dynamically-registered contract IDs to override static
1225 // entries, so invalidate any static entry for this contract ID.
1226 StaticComponents::InvalidateContractID(contractID);
1228 entry.Insert(f.release());
1230 return NS_OK;
1234 NS_IMETHODIMP
1235 nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass,
1236 nsIFactory* aFactory) {
1237 // Don't release the dying factory or service object until releasing
1238 // the component manager monitor.
1239 nsCOMPtr<nsIFactory> dyingFactory;
1240 nsCOMPtr<nsISupports> dyingServiceObject;
1243 MonitorAutoLock lock(mLock);
1244 auto entry = mFactories.Lookup(&aClass);
1245 nsFactoryEntry* f = entry ? entry.Data() : nullptr;
1246 if (!f || f->mFactory != aFactory) {
1247 // Note: We do not support unregistering static factories.
1248 return NS_ERROR_FACTORY_NOT_REGISTERED;
1251 entry.Remove();
1253 // This might leave a stale contractid -> factory mapping in
1254 // place, so null out the factory entry (see
1255 // nsFactoryEntry::GetFactory)
1256 f->mFactory.swap(dyingFactory);
1257 f->mServiceObject.swap(dyingServiceObject);
1260 return NS_OK;
1263 NS_IMETHODIMP
1264 nsComponentManagerImpl::AutoRegister(nsIFile* aLocation) {
1265 XRE_AddManifestLocation(NS_EXTENSION_LOCATION, aLocation);
1266 return NS_OK;
1269 NS_IMETHODIMP
1270 nsComponentManagerImpl::IsCIDRegistered(const nsCID& aClass, bool* aResult) {
1271 *aResult = LookupByCID(aClass).isSome();
1272 return NS_OK;
1275 NS_IMETHODIMP
1276 nsComponentManagerImpl::IsContractIDRegistered(const char* aClass,
1277 bool* aResult) {
1278 if (NS_WARN_IF(!aClass)) {
1279 return NS_ERROR_INVALID_ARG;
1282 Maybe<EntryWrapper> entry = LookupByContractID(nsDependentCString(aClass));
1284 *aResult = entry.isSome();
1285 return NS_OK;
1288 NS_IMETHODIMP
1289 nsComponentManagerImpl::GetContractIDs(nsTArray<nsCString>& aResult) {
1290 aResult = ToTArray<nsTArray<nsCString>>(mContractIDs.Keys());
1292 for (const auto& entry : gContractEntries) {
1293 if (!entry.Invalid()) {
1294 aResult.AppendElement(entry.ContractID());
1298 return NS_OK;
1301 NS_IMETHODIMP
1302 nsComponentManagerImpl::ContractIDToCID(const char* aContractID,
1303 nsCID** aResult) {
1305 MonitorAutoLock lock(mLock);
1306 Maybe<EntryWrapper> entry =
1307 LookupByContractID(lock, nsDependentCString(aContractID));
1308 if (entry) {
1309 *aResult = (nsCID*)moz_xmalloc(sizeof(nsCID));
1310 **aResult = entry->CID();
1311 return NS_OK;
1314 *aResult = nullptr;
1315 return NS_ERROR_FACTORY_NOT_REGISTERED;
1318 MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf)
1320 NS_IMETHODIMP
1321 nsComponentManagerImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
1322 nsISupports* aData, bool aAnonymize) {
1323 MOZ_COLLECT_REPORT("explicit/xpcom/component-manager", KIND_HEAP, UNITS_BYTES,
1324 SizeOfIncludingThis(ComponentManagerMallocSizeOf),
1325 "Memory used for the XPCOM component manager.");
1327 return NS_OK;
1330 size_t nsComponentManagerImpl::SizeOfIncludingThis(
1331 mozilla::MallocSizeOf aMallocSizeOf) const {
1332 size_t n = aMallocSizeOf(this);
1334 n += mFactories.ShallowSizeOfExcludingThis(aMallocSizeOf);
1335 for (const auto& data : mFactories.Values()) {
1336 n += data->SizeOfIncludingThis(aMallocSizeOf);
1339 n += mContractIDs.ShallowSizeOfExcludingThis(aMallocSizeOf);
1340 for (const auto& key : mContractIDs.Keys()) {
1341 // We don't measure the nsFactoryEntry data because it's owned by
1342 // mFactories (which is measured above).
1343 n += key.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1346 if (sModuleLocations) {
1347 n += sModuleLocations->ShallowSizeOfIncludingThis(aMallocSizeOf);
1350 n += mPendingServices.ShallowSizeOfExcludingThis(aMallocSizeOf);
1352 // Measurement of the following members may be added later if DMD finds it is
1353 // worthwhile:
1354 // - mMon
1355 // - sModuleLocations' entries
1357 return n;
1360 ////////////////////////////////////////////////////////////////////////////////
1361 // nsFactoryEntry
1362 ////////////////////////////////////////////////////////////////////////////////
1364 nsFactoryEntry::nsFactoryEntry(const nsCID& aCID, nsIFactory* aFactory)
1365 : mCID(aCID), mFactory(aFactory) {}
1367 already_AddRefed<nsIFactory> nsFactoryEntry::GetFactory() {
1368 nsComponentManagerImpl::gComponentManager->mLock.AssertNotCurrentThreadOwns();
1370 nsCOMPtr<nsIFactory> factory = mFactory;
1371 return factory.forget();
1374 nsresult nsFactoryEntry::CreateInstance(const nsIID& aIID, void** aResult) {
1375 nsCOMPtr<nsIFactory> factory = GetFactory();
1376 NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
1377 return factory->CreateInstance(aIID, aResult);
1380 size_t nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
1381 size_t n = aMallocSizeOf(this);
1383 // Measurement of the following members may be added later if DMD finds it is
1384 // worthwhile:
1385 // - mCID;
1386 // - mFactory;
1387 // - mServiceObject;
1389 return n;
1392 ////////////////////////////////////////////////////////////////////////////////
1393 // Static Access Functions
1394 ////////////////////////////////////////////////////////////////////////////////
1396 nsresult NS_GetComponentManager(nsIComponentManager** aResult) {
1397 if (!nsComponentManagerImpl::gComponentManager) {
1398 return NS_ERROR_NOT_INITIALIZED;
1401 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1402 return NS_OK;
1405 nsresult NS_GetServiceManager(nsIServiceManager** aResult) {
1406 if (!nsComponentManagerImpl::gComponentManager) {
1407 return NS_ERROR_NOT_INITIALIZED;
1410 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1411 return NS_OK;
1414 nsresult NS_GetComponentRegistrar(nsIComponentRegistrar** aResult) {
1415 if (!nsComponentManagerImpl::gComponentManager) {
1416 return NS_ERROR_NOT_INITIALIZED;
1419 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1420 return NS_OK;
1423 NS_IMETHODIMP
1424 nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation) {
1425 NS_ENSURE_ARG_POINTER(aLocation);
1427 nsString path;
1428 nsresult rv = aLocation->GetPath(path);
1429 if (NS_FAILED(rv)) {
1430 return rv;
1433 if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
1434 return XRE_AddJarManifestLocation(NS_BOOTSTRAPPED_LOCATION, aLocation);
1437 nsCOMPtr<nsIFile> manifest = CloneAndAppend(aLocation, "chrome.manifest"_ns);
1438 return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION, manifest);
1441 NS_IMETHODIMP
1442 nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation) {
1443 NS_ENSURE_ARG_POINTER(aLocation);
1445 nsCOMPtr<nsIChromeRegistry> cr = mozilla::services::GetChromeRegistry();
1446 if (!cr) {
1447 return NS_ERROR_FAILURE;
1450 nsString path;
1451 nsresult rv = aLocation->GetPath(path);
1452 if (NS_FAILED(rv)) {
1453 return rv;
1456 nsComponentManagerImpl::ComponentLocation elem;
1457 elem.type = NS_BOOTSTRAPPED_LOCATION;
1459 if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
1460 elem.location.Init(aLocation, "chrome.manifest");
1461 } else {
1462 nsCOMPtr<nsIFile> lf = CloneAndAppend(aLocation, "chrome.manifest"_ns);
1463 elem.location.Init(lf);
1466 // Remove reference.
1467 nsComponentManagerImpl::sModuleLocations->RemoveElement(
1468 elem, ComponentLocationComparator());
1470 rv = cr->CheckForNewChrome();
1471 return rv;
1474 NS_IMETHODIMP
1475 nsComponentManagerImpl::GetComponentJSMs(nsIUTF8StringEnumerator** aJSMs) {
1476 nsCOMPtr<nsIUTF8StringEnumerator> result =
1477 StaticComponents::GetComponentJSMs();
1478 result.forget(aJSMs);
1479 return NS_OK;
1482 NS_IMETHODIMP
1483 nsComponentManagerImpl::GetComponentESModules(
1484 nsIUTF8StringEnumerator** aESModules) {
1485 nsCOMPtr<nsIUTF8StringEnumerator> result =
1486 StaticComponents::GetComponentESModules();
1487 result.forget(aESModules);
1488 return NS_OK;
1491 NS_IMETHODIMP
1492 nsComponentManagerImpl::GetManifestLocations(nsIArray** aLocations) {
1493 NS_ENSURE_ARG_POINTER(aLocations);
1494 *aLocations = nullptr;
1496 if (!sModuleLocations) {
1497 return NS_ERROR_NOT_INITIALIZED;
1500 nsCOMPtr<nsIMutableArray> locations = nsArray::Create();
1501 nsresult rv;
1502 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
1503 ComponentLocation& l = sModuleLocations->ElementAt(i);
1504 FileLocation loc = l.location;
1505 nsCString uriString;
1506 loc.GetURIString(uriString);
1507 nsCOMPtr<nsIURI> uri;
1508 rv = NS_NewURI(getter_AddRefs(uri), uriString);
1509 if (NS_SUCCEEDED(rv)) {
1510 locations->AppendElement(uri);
1514 locations.forget(aLocations);
1515 return NS_OK;
1518 EXPORT_XPCOM_API(nsresult)
1519 XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation) {
1520 nsComponentManagerImpl::InitializeModuleLocations();
1521 nsComponentManagerImpl::ComponentLocation* c =
1522 nsComponentManagerImpl::sModuleLocations->AppendElement();
1523 c->type = aType;
1524 c->location.Init(aLocation);
1526 if (nsComponentManagerImpl::gComponentManager &&
1527 nsComponentManagerImpl::NORMAL ==
1528 nsComponentManagerImpl::gComponentManager->mStatus) {
1529 nsComponentManagerImpl::gComponentManager->RegisterManifest(
1530 aType, c->location, false);
1533 return NS_OK;
1536 EXPORT_XPCOM_API(nsresult)
1537 XRE_AddJarManifestLocation(NSLocationType aType, nsIFile* aLocation) {
1538 nsComponentManagerImpl::InitializeModuleLocations();
1539 nsComponentManagerImpl::ComponentLocation* c =
1540 nsComponentManagerImpl::sModuleLocations->AppendElement();
1542 c->type = aType;
1543 c->location.Init(aLocation, "chrome.manifest");
1545 if (nsComponentManagerImpl::gComponentManager &&
1546 nsComponentManagerImpl::NORMAL ==
1547 nsComponentManagerImpl::gComponentManager->mStatus) {
1548 nsComponentManagerImpl::gComponentManager->RegisterManifest(
1549 aType, c->location, false);
1552 return NS_OK;
1555 // Expose some important global interfaces to rust for the rust xpcom API. These
1556 // methods return a non-owning reference to the component manager, which should
1557 // live for the lifetime of XPCOM.
1558 extern "C" {
1560 const nsIComponentManager* Gecko_GetComponentManager() {
1561 return nsComponentManagerImpl::gComponentManager;
1564 const nsIServiceManager* Gecko_GetServiceManager() {
1565 return nsComponentManagerImpl::gComponentManager;
1568 const nsIComponentRegistrar* Gecko_GetComponentRegistrar() {
1569 return nsComponentManagerImpl::gComponentManager;
1572 // FFI-compatible version of `GetServiceHelper::operator()`.
1573 nsresult Gecko_GetServiceByModuleID(ModuleID aId, const nsIID* aIID,
1574 void** aResult) {
1575 return nsComponentManagerImpl::gComponentManager->GetService(aId, *aIID,
1576 aResult);
1579 // FFI-compatible version of `CreateInstanceHelper::operator()`.
1580 nsresult Gecko_CreateInstanceByModuleID(ModuleID aId, const nsIID* aIID,
1581 void** aResult) {
1582 const auto& entry = gStaticModules[size_t(aId)];
1583 if (!entry.Active()) {
1584 return NS_ERROR_FACTORY_NOT_REGISTERED;
1587 nsresult rv = entry.CreateInstance(*aIID, aResult);
1588 return rv;