Backed out 3 changesets (bug 1790375) for causing wd failures on fetch_error.py....
[gecko.git] / xpcom / components / nsComponentManager.cpp
bloba55d926b4f0a2dc4b2e5b9c4144eac0f3d7c8e32
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include <stdlib.h>
8 #include "nscore.h"
9 #include "nsISupports.h"
10 #include "nspr.h"
11 #include "nsCRT.h" // for atoll
13 #include "StaticComponents.h"
15 #include "nsCategoryManager.h"
16 #include "nsCOMPtr.h"
17 #include "nsComponentManager.h"
18 #include "nsDirectoryService.h"
19 #include "nsDirectoryServiceDefs.h"
20 #include "nsCategoryManager.h"
21 #include "nsLayoutModule.h"
22 #include "mozilla/MemoryReporting.h"
23 #include "nsIObserverService.h"
24 #include "nsIStringEnumerator.h"
25 #include "nsXPCOM.h"
26 #include "nsXPCOMPrivate.h"
27 #include "nsISupportsPrimitives.h"
28 #include "nsLocalFile.h"
29 #include "nsReadableUtils.h"
30 #include "nsString.h"
31 #include "prcmon.h"
32 #include "nsThreadManager.h"
33 #include "nsThreadUtils.h"
34 #include "prthread.h"
35 #include "private/pprthred.h"
36 #include "nsTArray.h"
37 #include "prio.h"
38 #include "ManifestParser.h"
39 #include "nsNetUtil.h"
40 #include "mozilla/Services.h"
42 #include "mozilla/GenericFactory.h"
43 #include "nsSupportsPrimitives.h"
44 #include "nsArray.h"
45 #include "nsIMutableArray.h"
46 #include "mozilla/DebugOnly.h"
47 #include "mozilla/FileUtils.h"
48 #include "mozilla/ProfilerLabels.h"
49 #include "mozilla/ProfilerMarkers.h"
50 #include "mozilla/ScopeExit.h"
51 #include "mozilla/URLPreloader.h"
52 #include "mozilla/UniquePtr.h"
53 #include "mozilla/Variant.h"
55 #include <new> // for placement new
57 #include "mozilla/Omnijar.h"
59 #include "mozilla/Logging.h"
60 #include "LogModulePrefWatcher.h"
62 #ifdef MOZ_MEMORY
63 # include "mozmemory.h"
64 #endif
66 using namespace mozilla;
67 using namespace mozilla::xpcom;
69 static LazyLogModule nsComponentManagerLog("nsComponentManager");
71 #if 0
72 # define SHOW_DENIED_ON_SHUTDOWN
73 # define SHOW_CI_ON_EXISTING_SERVICE
74 #endif
76 namespace {
78 class AutoIDString : public nsAutoCStringN<NSID_LENGTH> {
79 public:
80 explicit AutoIDString(const nsID& aID) {
81 SetLength(NSID_LENGTH - 1);
82 aID.ToProvidedString(
83 *reinterpret_cast<char(*)[NSID_LENGTH]>(BeginWriting()));
87 } // namespace
89 namespace mozilla {
90 namespace xpcom {
92 using ProcessSelector = Module::ProcessSelector;
94 // Note: These must be kept in sync with the ProcessSelector definition in
95 // Module.h.
96 bool ProcessSelectorMatches(ProcessSelector aSelector) {
97 GeckoProcessType type = XRE_GetProcessType();
98 if (type == GeckoProcessType_GPU) {
99 return !!(aSelector & Module::ALLOW_IN_GPU_PROCESS);
102 if (type == GeckoProcessType_RDD) {
103 return !!(aSelector & Module::ALLOW_IN_RDD_PROCESS);
106 if (type == GeckoProcessType_Socket) {
107 return !!(aSelector & (Module::ALLOW_IN_SOCKET_PROCESS));
110 if (type == GeckoProcessType_VR) {
111 return !!(aSelector & Module::ALLOW_IN_VR_PROCESS);
114 if (type == GeckoProcessType_Utility) {
115 return !!(aSelector & Module::ALLOW_IN_UTILITY_PROCESS);
118 if (type == GeckoProcessType_GMPlugin) {
119 return !!(aSelector & Module::ALLOW_IN_GMPLUGIN_PROCESS);
122 // Only allow XPCOM modules which can be loaded in all processes to be loaded
123 // in the IPDLUnitTest process.
124 if (type == GeckoProcessType_IPDLUnitTest) {
125 return size_t(aSelector) == Module::kMaxProcessSelector;
128 if (aSelector & Module::MAIN_PROCESS_ONLY) {
129 return type == GeckoProcessType_Default;
131 if (aSelector & Module::CONTENT_PROCESS_ONLY) {
132 return type == GeckoProcessType_Content;
134 return true;
137 static bool gProcessMatchTable[Module::kMaxProcessSelector + 1];
139 bool FastProcessSelectorMatches(ProcessSelector aSelector) {
140 return gProcessMatchTable[size_t(aSelector)];
143 } // namespace xpcom
144 } // namespace mozilla
146 namespace {
149 * A wrapper simple wrapper class, which can hold either a dynamic
150 * nsFactoryEntry instance, or a static StaticModule entry, and transparently
151 * forwards method calls to the wrapped object.
153 * This allows the same code to work with either static or dynamic modules
154 * without caring about the difference.
156 class MOZ_STACK_CLASS EntryWrapper final {
157 public:
158 explicit EntryWrapper(nsFactoryEntry* aEntry) : mEntry(aEntry) {}
160 explicit EntryWrapper(const StaticModule* aEntry) : mEntry(aEntry) {}
162 #define MATCH(type, ifFactory, ifStatic) \
163 struct Matcher { \
164 type operator()(nsFactoryEntry* entry) { ifFactory; } \
165 type operator()(const StaticModule* entry) { ifStatic; } \
166 }; \
167 return mEntry.match((Matcher()))
169 const nsID& CID() {
170 MATCH(const nsID&, return entry->mCID, return entry->CID());
173 already_AddRefed<nsIFactory> GetFactory() {
174 MATCH(already_AddRefed<nsIFactory>, return entry->GetFactory(),
175 return entry->GetFactory());
179 * Creates an instance of the underlying component. This should be used in
180 * preference to GetFactory()->CreateInstance() where appropriate, since it
181 * side-steps the necessity of creating a nsIFactory instance for static
182 * modules.
184 nsresult CreateInstance(const nsIID& aIID, void** aResult) {
185 if (mEntry.is<nsFactoryEntry*>()) {
186 return mEntry.as<nsFactoryEntry*>()->CreateInstance(aIID, aResult);
188 return mEntry.as<const StaticModule*>()->CreateInstance(aIID, aResult);
192 * Returns the cached service instance for this entry, if any. This should
193 * only be accessed while mLock is held.
195 nsISupports* ServiceInstance() {
196 MATCH(nsISupports*, return entry->mServiceObject,
197 return entry->ServiceInstance());
199 void SetServiceInstance(already_AddRefed<nsISupports> aInst) {
200 if (mEntry.is<nsFactoryEntry*>()) {
201 mEntry.as<nsFactoryEntry*>()->mServiceObject = aInst;
202 } else {
203 return mEntry.as<const StaticModule*>()->SetServiceInstance(
204 std::move(aInst));
209 * Returns the description string for the module this entry belongs to.
210 * Currently always returns "<unknown module>".
212 nsCString ModuleDescription() { return "<unknown module>"_ns; }
214 private:
215 Variant<nsFactoryEntry*, const StaticModule*> mEntry;
218 } // namespace
220 // this is safe to call during InitXPCOM
221 static already_AddRefed<nsIFile> GetLocationFromDirectoryService(
222 const char* aProp) {
223 nsCOMPtr<nsIProperties> directoryService;
224 nsDirectoryService::Create(NS_GET_IID(nsIProperties),
225 getter_AddRefs(directoryService));
227 if (!directoryService) {
228 return nullptr;
231 nsCOMPtr<nsIFile> file;
232 nsresult rv =
233 directoryService->Get(aProp, NS_GET_IID(nsIFile), getter_AddRefs(file));
234 if (NS_FAILED(rv)) {
235 return nullptr;
238 return file.forget();
241 static already_AddRefed<nsIFile> CloneAndAppend(nsIFile* aBase,
242 const nsACString& aAppend) {
243 nsCOMPtr<nsIFile> f;
244 aBase->Clone(getter_AddRefs(f));
245 if (!f) {
246 return nullptr;
249 f->AppendNative(aAppend);
250 return f.forget();
253 ////////////////////////////////////////////////////////////////////////////////
254 // nsComponentManagerImpl
255 ////////////////////////////////////////////////////////////////////////////////
257 nsresult nsComponentManagerImpl::Create(REFNSIID aIID, void** aResult) {
258 if (!gComponentManager) {
259 return NS_ERROR_FAILURE;
262 return gComponentManager->QueryInterface(aIID, aResult);
265 static const int CONTRACTID_HASHTABLE_INITIAL_LENGTH = 8;
267 nsComponentManagerImpl::nsComponentManagerImpl()
268 : mFactories(CONTRACTID_HASHTABLE_INITIAL_LENGTH),
269 mContractIDs(CONTRACTID_HASHTABLE_INITIAL_LENGTH),
270 mLock("nsComponentManagerImpl.mLock"),
271 mStatus(NOT_INITIALIZED) {}
273 nsTArray<nsComponentManagerImpl::ComponentLocation>*
274 nsComponentManagerImpl::sModuleLocations;
276 /* static */
277 void nsComponentManagerImpl::InitializeModuleLocations() {
278 if (sModuleLocations) {
279 return;
282 sModuleLocations = new nsTArray<ComponentLocation>;
285 nsresult nsComponentManagerImpl::Init() {
287 gProcessMatchTable[size_t(ProcessSelector::ANY_PROCESS)] =
288 ProcessSelectorMatches(ProcessSelector::ANY_PROCESS);
289 gProcessMatchTable[size_t(ProcessSelector::MAIN_PROCESS_ONLY)] =
290 ProcessSelectorMatches(ProcessSelector::MAIN_PROCESS_ONLY);
291 gProcessMatchTable[size_t(ProcessSelector::CONTENT_PROCESS_ONLY)] =
292 ProcessSelectorMatches(ProcessSelector::CONTENT_PROCESS_ONLY);
293 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_PROCESS)] =
294 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_PROCESS);
295 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_VR_PROCESS)] =
296 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_VR_PROCESS);
297 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_SOCKET_PROCESS)] =
298 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_SOCKET_PROCESS);
299 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_RDD_PROCESS)] =
300 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_RDD_PROCESS);
301 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GMPLUGIN_PROCESS)] =
302 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GMPLUGIN_PROCESS);
303 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_MAIN_PROCESS)] =
304 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_MAIN_PROCESS);
305 gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS)] =
306 ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS);
307 gProcessMatchTable[size_t(
308 ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS)] =
309 ProcessSelectorMatches(
310 ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS);
311 gProcessMatchTable[size_t(
312 ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS)] =
313 ProcessSelectorMatches(
314 ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS);
315 gProcessMatchTable[size_t(
316 ProcessSelector::ALLOW_IN_RDD_AND_SOCKET_PROCESS)] =
317 ProcessSelectorMatches(
318 ProcessSelector::ALLOW_IN_RDD_AND_SOCKET_PROCESS);
319 gProcessMatchTable[size_t(
320 ProcessSelector::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS)] =
321 ProcessSelectorMatches(
322 ProcessSelector::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS);
323 gProcessMatchTable[size_t(
324 ProcessSelector::ALLOW_IN_GPU_RDD_SOCKET_AND_UTILITY_PROCESS)] =
325 ProcessSelectorMatches(
326 ProcessSelector::ALLOW_IN_GPU_RDD_SOCKET_AND_UTILITY_PROCESS);
327 gProcessMatchTable[size_t(
328 ProcessSelector::ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS)] =
329 ProcessSelectorMatches(
330 ProcessSelector::ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS);
331 gProcessMatchTable[size_t(
332 ProcessSelector::ALLOW_IN_GPU_RDD_VR_SOCKET_AND_UTILITY_PROCESS)] =
333 ProcessSelectorMatches(
334 ProcessSelector::ALLOW_IN_GPU_RDD_VR_SOCKET_AND_UTILITY_PROCESS);
335 gProcessMatchTable[size_t(
336 ProcessSelector::
337 ALLOW_IN_GPU_RDD_VR_SOCKET_UTILITY_AND_GMPLUGIN_PROCESS)] =
338 ProcessSelectorMatches(
339 ProcessSelector::
340 ALLOW_IN_GPU_RDD_VR_SOCKET_UTILITY_AND_GMPLUGIN_PROCESS);
343 MOZ_ASSERT(NOT_INITIALIZED == mStatus);
345 nsCOMPtr<nsIFile> greDir = GetLocationFromDirectoryService(NS_GRE_DIR);
346 nsCOMPtr<nsIFile> appDir =
347 GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR);
349 nsCategoryManager::GetSingleton()->SuppressNotifications(true);
351 auto* catMan = nsCategoryManager::GetSingleton();
352 for (const auto& cat : gStaticCategories) {
353 for (const auto& entry : cat) {
354 if (entry.Active()) {
355 catMan->AddCategoryEntry(cat.Name(), entry.Entry(), entry.Value());
360 bool loadChromeManifests;
361 switch (XRE_GetProcessType()) {
362 // We are going to assume that only a select few (see below) process types
363 // want to load chrome manifests, and that any new process types will not
364 // want to load them, because they're not going to be executing JS.
365 case GeckoProcessType_RemoteSandboxBroker:
366 default:
367 loadChromeManifests = false;
368 break;
370 // XXX The check this code replaced implicitly let through all of these
371 // process types, but presumably only the default (parent) and content
372 // processes really need chrome manifests...?
373 case GeckoProcessType_Default:
374 case GeckoProcessType_Content:
375 loadChromeManifests = true;
376 break;
379 if (loadChromeManifests) {
380 // This needs to be called very early, before anything in nsLayoutModule is
381 // used, and before any calls are made into the JS engine.
382 nsLayoutModuleInitialize();
384 mJSLoaderReady = true;
386 // The overall order in which chrome.manifests are expected to be treated
387 // is the following:
388 // - greDir's omni.ja or greDir
389 // - appDir's omni.ja or appDir
391 InitializeModuleLocations();
392 ComponentLocation* cl = sModuleLocations->AppendElement();
393 cl->type = NS_APP_LOCATION;
394 RefPtr<nsZipArchive> greOmnijar =
395 mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
396 if (greOmnijar) {
397 cl->location.Init(greOmnijar, "chrome.manifest");
398 } else {
399 nsCOMPtr<nsIFile> lf = CloneAndAppend(greDir, "chrome.manifest"_ns);
400 cl->location.Init(lf);
403 RefPtr<nsZipArchive> appOmnijar =
404 mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
405 if (appOmnijar) {
406 cl = sModuleLocations->AppendElement();
407 cl->type = NS_APP_LOCATION;
408 cl->location.Init(appOmnijar, "chrome.manifest");
409 } else {
410 bool equals = false;
411 appDir->Equals(greDir, &equals);
412 if (!equals) {
413 cl = sModuleLocations->AppendElement();
414 cl->type = NS_APP_LOCATION;
415 nsCOMPtr<nsIFile> lf = CloneAndAppend(appDir, "chrome.manifest"_ns);
416 cl->location.Init(lf);
420 RereadChromeManifests(false);
423 nsCategoryManager::GetSingleton()->SuppressNotifications(false);
425 RegisterWeakMemoryReporter(this);
427 // NB: The logging preference watcher needs to be registered late enough in
428 // startup that it's okay to use the preference system, but also as soon as
429 // possible so that log modules enabled via preferences are turned on as
430 // early as possible.
432 // We can't initialize the preference watcher when the log module manager is
433 // initialized, as a number of things attempt to start logging before the
434 // preference system is initialized.
436 // The preference system is registered as a component so at this point during
437 // component manager initialization we know it is setup and we can register
438 // for notifications.
439 LogModulePrefWatcher::RegisterPrefWatcher();
441 // Unfortunately, we can't register the nsCategoryManager memory reporter
442 // in its constructor (which is triggered by the GetSingleton() call
443 // above) because the memory reporter manager isn't initialized at that
444 // point. So we wait until now.
445 nsCategoryManager::GetSingleton()->InitMemoryReporter();
447 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
448 ("nsComponentManager: Initialized."));
450 mStatus = NORMAL;
452 MOZ_ASSERT(!XRE_IsContentProcess() ||
453 CONTRACTID_HASHTABLE_INITIAL_LENGTH <= 8 ||
454 mFactories.Count() > CONTRACTID_HASHTABLE_INITIAL_LENGTH / 3,
455 "Initial component hashtable size is too large");
457 return NS_OK;
460 template <typename T>
461 static void AssertNotMallocAllocated(T* aPtr) {
462 #if defined(DEBUG) && defined(MOZ_MEMORY)
463 jemalloc_ptr_info_t info;
464 jemalloc_ptr_info((void*)aPtr, &info);
465 MOZ_ASSERT(info.tag == TagUnknown);
466 #endif
469 template <typename T>
470 static void AssertNotStackAllocated(T* aPtr) {
471 // On all of our supported platforms, the stack grows down. Any address
472 // located below the address of our argument is therefore guaranteed not to be
473 // stack-allocated by the caller.
475 // For addresses above our argument, things get trickier. The main thread
476 // stack is traditionally placed at the top of the program's address space,
477 // but that is becoming less reliable as more and more systems adopt address
478 // space layout randomization strategies, so we have to guess how much space
479 // above our argument pointer we need to care about.
481 // On most systems, we're guaranteed at least several KiB at the top of each
482 // stack for TLS. We'd probably be safe assuming at least 4KiB in the stack
483 // segment above our argument address, but safer is... well, safer.
485 // For threads with huge stacks, it's theoretically possible that we could
486 // wind up being passed a stack-allocated string from farther up the stack,
487 // but this is a best-effort thing, so we'll assume we only care about the
488 // immediate caller. For that case, max 2KiB per stack frame is probably a
489 // reasonable guess most of the time, and is less than the ~4KiB that we
490 // expect for TLS, so go with that to avoid the risk of bumping into heap
491 // data just above the stack.
492 #ifdef DEBUG
493 static constexpr size_t kFuzz = 2048;
495 MOZ_ASSERT(uintptr_t(aPtr) < uintptr_t(&aPtr) ||
496 uintptr_t(aPtr) > uintptr_t(&aPtr) + kFuzz);
497 #endif
500 static void DoRegisterManifest(NSLocationType aType, FileLocation& aFile,
501 bool aChromeOnly) {
502 auto result = URLPreloader::Read(aFile);
503 if (result.isOk()) {
504 nsCString buf(result.unwrap());
505 ParseManifest(aType, aFile, buf.BeginWriting(), aChromeOnly);
506 } else if (NS_BOOTSTRAPPED_LOCATION != aType) {
507 nsCString uri;
508 aFile.GetURIString(uri);
509 LogMessage("Could not read chrome manifest '%s'.", uri.get());
513 void nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
514 FileLocation& aFile,
515 bool aChromeOnly) {
516 DoRegisterManifest(aType, aFile, aChromeOnly);
519 void nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& aCx,
520 int aLineNo, char* const* aArgv) {
521 char* file = aArgv[0];
522 FileLocation f(aCx.mFile, file);
523 RegisterManifest(aCx.mType, f, aCx.mChromeOnly);
526 void nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext& aCx,
527 int aLineNo, char* const* aArgv) {
528 char* category = aArgv[0];
529 char* key = aArgv[1];
530 char* value = aArgv[2];
532 nsCategoryManager::GetSingleton()->AddCategoryEntry(
533 nsDependentCString(category), nsDependentCString(key),
534 nsDependentCString(value));
537 void nsComponentManagerImpl::RereadChromeManifests(bool aChromeOnly) {
538 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
539 ComponentLocation& l = sModuleLocations->ElementAt(i);
540 RegisterManifest(l.type, l.location, aChromeOnly);
543 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
544 if (obs) {
545 obs->NotifyObservers(nullptr, "chrome-manifests-loaded", nullptr);
549 nsresult nsComponentManagerImpl::Shutdown(void) {
550 MOZ_ASSERT(NORMAL == mStatus);
552 mStatus = SHUTDOWN_IN_PROGRESS;
554 // Shutdown the component manager
555 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
556 ("nsComponentManager: Beginning Shutdown."));
558 UnregisterWeakMemoryReporter(this);
560 // Release all cached factories
561 mContractIDs.Clear();
562 mFactories.Clear(); // XXX release the objects, don't just clear
564 StaticComponents::Shutdown();
566 delete sModuleLocations;
568 mStatus = SHUTDOWN_COMPLETE;
570 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
571 ("nsComponentManager: Shutdown complete."));
573 return NS_OK;
576 nsComponentManagerImpl::~nsComponentManagerImpl() {
577 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
578 ("nsComponentManager: Beginning destruction."));
580 if (SHUTDOWN_COMPLETE != mStatus) {
581 Shutdown();
584 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
585 ("nsComponentManager: Destroyed."));
588 NS_IMPL_ISUPPORTS(nsComponentManagerImpl, nsIComponentManager,
589 nsIServiceManager, nsIComponentRegistrar,
590 nsISupportsWeakReference, nsIInterfaceRequestor,
591 nsIMemoryReporter)
593 nsresult nsComponentManagerImpl::GetInterface(const nsIID& aUuid,
594 void** aResult) {
595 NS_WARNING("This isn't supported");
596 // fall through to QI as anything QIable is a superset of what can be
597 // got via the GetInterface()
598 return QueryInterface(aUuid, aResult);
601 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByCID(const nsID& aCID) {
602 return LookupByCID(MonitorAutoLock(mLock), aCID);
605 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByCID(const MonitorAutoLock&,
606 const nsID& aCID) {
607 if (const StaticModule* module = StaticComponents::LookupByCID(aCID)) {
608 return Some(EntryWrapper(module));
610 if (nsFactoryEntry* entry = mFactories.Get(&aCID)) {
611 return Some(EntryWrapper(entry));
613 return Nothing();
616 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByContractID(
617 const nsACString& aContractID) {
618 return LookupByContractID(MonitorAutoLock(mLock), aContractID);
621 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByContractID(
622 const MonitorAutoLock&, const nsACString& aContractID) {
623 if (const StaticModule* module =
624 StaticComponents::LookupByContractID(aContractID)) {
625 return Some(EntryWrapper(module));
627 if (nsFactoryEntry* entry = mContractIDs.Get(aContractID)) {
628 // UnregisterFactory might have left a stale nsFactoryEntry in
629 // mContractIDs, so we should check to see whether this entry has
630 // anything useful.
631 if (entry->mFactory || entry->mServiceObject) {
632 return Some(EntryWrapper(entry));
635 return Nothing();
638 already_AddRefed<nsIFactory> nsComponentManagerImpl::FindFactory(
639 const nsCID& aClass) {
640 Maybe<EntryWrapper> e = LookupByCID(aClass);
641 if (!e) {
642 return nullptr;
645 return e->GetFactory();
648 already_AddRefed<nsIFactory> nsComponentManagerImpl::FindFactory(
649 const char* aContractID, uint32_t aContractIDLen) {
650 Maybe<EntryWrapper> entry =
651 LookupByContractID(nsDependentCString(aContractID, aContractIDLen));
652 if (!entry) {
653 return nullptr;
656 return entry->GetFactory();
660 * GetClassObject()
662 * Given a classID, this finds the singleton ClassObject that implements the
663 * CID. Returns an interface of type aIID off the singleton classobject.
665 NS_IMETHODIMP
666 nsComponentManagerImpl::GetClassObject(const nsCID& aClass, const nsIID& aIID,
667 void** aResult) {
668 nsresult rv;
670 if (MOZ_LOG_TEST(nsComponentManagerLog, LogLevel::Debug)) {
671 char buf[NSID_LENGTH];
672 aClass.ToProvidedString(buf);
673 PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
676 MOZ_ASSERT(aResult != nullptr);
678 nsCOMPtr<nsIFactory> factory = FindFactory(aClass);
679 if (!factory) {
680 return NS_ERROR_FACTORY_NOT_REGISTERED;
683 rv = factory->QueryInterface(aIID, aResult);
685 MOZ_LOG(
686 nsComponentManagerLog, LogLevel::Warning,
687 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
689 return rv;
692 NS_IMETHODIMP
693 nsComponentManagerImpl::GetClassObjectByContractID(const char* aContractID,
694 const nsIID& aIID,
695 void** aResult) {
696 if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aContractID)) {
697 return NS_ERROR_INVALID_ARG;
700 nsresult rv;
702 MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
703 ("nsComponentManager: GetClassObjectByContractID(%s)", aContractID));
705 nsCOMPtr<nsIFactory> factory = FindFactory(aContractID, strlen(aContractID));
706 if (!factory) {
707 return NS_ERROR_FACTORY_NOT_REGISTERED;
710 rv = factory->QueryInterface(aIID, aResult);
712 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
713 ("\t\tGetClassObjectByContractID() %s",
714 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
716 return rv;
720 * CreateInstance()
722 * Create an instance of an object that implements an interface and belongs
723 * to the implementation aClass using the factory. The factory is immediately
724 * released and not held onto for any longer.
726 NS_IMETHODIMP
727 nsComponentManagerImpl::CreateInstance(const nsCID& aClass, const nsIID& aIID,
728 void** aResult) {
729 // test this first, since there's no point in creating a component during
730 // shutdown -- whether it's available or not would depend on the order it
731 // occurs in the list
732 if (gXPCOMShuttingDown) {
733 // When processing shutdown, don't process new GetService() requests
734 #ifdef SHOW_DENIED_ON_SHUTDOWN
735 fprintf(stderr,
736 "Creating new instance on shutdown. Denied.\n"
737 " CID: %s\n IID: %s\n",
738 AutoIDString(aClass).get(), AutoIDString(aIID).get());
739 #endif /* SHOW_DENIED_ON_SHUTDOWN */
740 return NS_ERROR_UNEXPECTED;
743 if (!aResult) {
744 return NS_ERROR_NULL_POINTER;
746 *aResult = nullptr;
748 Maybe<EntryWrapper> entry = LookupByCID(aClass);
750 if (!entry) {
751 return NS_ERROR_FACTORY_NOT_REGISTERED;
754 #ifdef SHOW_CI_ON_EXISTING_SERVICE
755 if (entry->ServiceInstance()) {
756 nsAutoCString message;
757 message = "You are calling CreateInstance \""_ns + AutoIDString(aClass) +
758 "\" when a service for this CID already exists!"_ns;
759 NS_ERROR(message.get());
761 #endif
763 nsresult rv;
764 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
765 if (factory) {
766 rv = factory->CreateInstance(aIID, aResult);
767 if (NS_SUCCEEDED(rv) && !*aResult) {
768 NS_ERROR("Factory did not return an object but returned success!");
769 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
771 } else {
772 // Translate error values
773 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
776 if (MOZ_LOG_TEST(nsComponentManagerLog, LogLevel::Warning)) {
777 char buf[NSID_LENGTH];
778 aClass.ToProvidedString(buf);
779 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
780 ("nsComponentManager: CreateInstance(%s) %s", buf,
781 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
784 return rv;
788 * CreateInstanceByContractID()
790 * A variant of CreateInstance() that creates an instance of the object that
791 * implements the interface aIID and whose implementation has a contractID
792 * aContractID.
794 * This is only a convenience routine that turns around can calls the
795 * CreateInstance() with classid and iid.
797 NS_IMETHODIMP
798 nsComponentManagerImpl::CreateInstanceByContractID(const char* aContractID,
799 const nsIID& aIID,
800 void** aResult) {
801 if (NS_WARN_IF(!aContractID)) {
802 return NS_ERROR_INVALID_ARG;
805 // test this first, since there's no point in creating a component during
806 // shutdown -- whether it's available or not would depend on the order it
807 // occurs in the list
808 if (gXPCOMShuttingDown) {
809 // When processing shutdown, don't process new GetService() requests
810 #ifdef SHOW_DENIED_ON_SHUTDOWN
811 fprintf(stderr,
812 "Creating new instance on shutdown. Denied.\n"
813 " ContractID: %s\n IID: %s\n",
814 aContractID, AutoIDString(aIID).get());
815 #endif /* SHOW_DENIED_ON_SHUTDOWN */
816 return NS_ERROR_UNEXPECTED;
819 if (!aResult) {
820 return NS_ERROR_NULL_POINTER;
822 *aResult = nullptr;
824 Maybe<EntryWrapper> entry =
825 LookupByContractID(nsDependentCString(aContractID));
827 if (!entry) {
828 return NS_ERROR_FACTORY_NOT_REGISTERED;
831 #ifdef SHOW_CI_ON_EXISTING_SERVICE
832 if (entry->ServiceInstance()) {
833 nsAutoCString message;
834 message =
835 "You are calling CreateInstance \""_ns +
836 nsDependentCString(aContractID) +
837 nsLiteralCString(
838 "\" when a service for this CID already exists! "
839 "Add it to abusedContracts to track down the service consumer.");
840 NS_ERROR(message.get());
842 #endif
844 nsresult rv;
845 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
846 if (factory) {
847 rv = factory->CreateInstance(aIID, aResult);
848 if (NS_SUCCEEDED(rv) && !*aResult) {
849 NS_ERROR("Factory did not return an object but returned success!");
850 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
852 } else {
853 // Translate error values
854 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
857 MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
858 ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
859 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
861 return rv;
864 nsresult nsComponentManagerImpl::FreeServices() {
865 NS_ASSERTION(gXPCOMShuttingDown,
866 "Must be shutting down in order to free all services");
868 if (!gXPCOMShuttingDown) {
869 return NS_ERROR_FAILURE;
872 for (nsFactoryEntry* entry : mFactories.Values()) {
873 entry->mFactory = nullptr;
874 entry->mServiceObject = nullptr;
877 for (const auto& module : gStaticModules) {
878 module.SetServiceInstance(nullptr);
881 return NS_OK;
884 // This should only ever be called within the monitor!
885 nsComponentManagerImpl::PendingServiceInfo*
886 nsComponentManagerImpl::AddPendingService(const nsCID& aServiceCID,
887 PRThread* aThread) {
888 PendingServiceInfo* newInfo = mPendingServices.AppendElement();
889 if (newInfo) {
890 newInfo->cid = &aServiceCID;
891 newInfo->thread = aThread;
893 return newInfo;
896 // This should only ever be called within the monitor!
897 void nsComponentManagerImpl::RemovePendingService(MonitorAutoLock& aLock,
898 const nsCID& aServiceCID) {
899 uint32_t pendingCount = mPendingServices.Length();
900 for (uint32_t index = 0; index < pendingCount; ++index) {
901 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
902 if (info.cid->Equals(aServiceCID)) {
903 mPendingServices.RemoveElementAt(index);
904 aLock.NotifyAll();
905 return;
910 // This should only ever be called within the monitor!
911 PRThread* nsComponentManagerImpl::GetPendingServiceThread(
912 const nsCID& aServiceCID) const {
913 uint32_t pendingCount = mPendingServices.Length();
914 for (uint32_t index = 0; index < pendingCount; ++index) {
915 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
916 if (info.cid->Equals(aServiceCID)) {
917 return info.thread;
920 return nullptr;
923 nsresult nsComponentManagerImpl::GetServiceLocked(Maybe<MonitorAutoLock>& aLock,
924 EntryWrapper& aEntry,
925 const nsIID& aIID,
926 void** aResult) {
927 MOZ_ASSERT(aLock.isSome());
928 if (!aLock.isSome()) {
929 return NS_ERROR_INVALID_ARG;
932 if (auto* service = aEntry.ServiceInstance()) {
933 aLock.reset();
934 return service->QueryInterface(aIID, aResult);
937 PRThread* currentPRThread = PR_GetCurrentThread();
938 MOZ_ASSERT(currentPRThread, "This should never be null!");
940 PRThread* pendingPRThread;
941 while ((pendingPRThread = GetPendingServiceThread(aEntry.CID()))) {
942 if (pendingPRThread == currentPRThread) {
943 NS_ERROR("Recursive GetService!");
944 return NS_ERROR_NOT_AVAILABLE;
947 aLock->Wait();
950 // It's still possible that the other thread failed to create the
951 // service so we're not guaranteed to have an entry or service yet.
952 if (auto* service = aEntry.ServiceInstance()) {
953 aLock.reset();
954 return service->QueryInterface(aIID, aResult);
957 DebugOnly<PendingServiceInfo*> newInfo =
958 AddPendingService(aEntry.CID(), currentPRThread);
959 NS_ASSERTION(newInfo, "Failed to add info to the array!");
961 // We need to not be holding the service manager's lock while calling
962 // CreateInstance, because it invokes user code which could try to re-enter
963 // the service manager:
965 nsCOMPtr<nsISupports> service;
966 auto cleanup = MakeScopeExit([&]() {
967 // `service` must be released after the lock is released, so if we fail and
968 // still have a reference, release the lock before releasing it.
969 if (service) {
970 MOZ_ASSERT(aLock.isSome());
971 aLock.reset();
972 service = nullptr;
975 nsresult rv;
976 mLock.AssertCurrentThreadOwns();
978 MonitorAutoUnlock unlock(mLock);
979 AUTO_PROFILER_MARKER_TEXT(
980 "GetService", OTHER, MarkerStack::Capture(),
981 nsDependentCString(nsIDToCString(aEntry.CID()).get()));
982 rv = aEntry.CreateInstance(aIID, getter_AddRefs(service));
984 if (NS_SUCCEEDED(rv) && !service) {
985 NS_ERROR("Factory did not return an object but returned success");
986 return NS_ERROR_SERVICE_NOT_AVAILABLE;
989 #ifdef DEBUG
990 pendingPRThread = GetPendingServiceThread(aEntry.CID());
991 MOZ_ASSERT(pendingPRThread == currentPRThread,
992 "Pending service array has been changed!");
993 #endif
994 MOZ_ASSERT(aLock.isSome());
995 RemovePendingService(*aLock, aEntry.CID());
997 if (NS_FAILED(rv)) {
998 return rv;
1001 NS_ASSERTION(!aEntry.ServiceInstance(),
1002 "Created two instances of a service!");
1004 aEntry.SetServiceInstance(service.forget());
1006 aLock.reset();
1008 *aResult = do_AddRef(aEntry.ServiceInstance()).take();
1009 return NS_OK;
1012 NS_IMETHODIMP
1013 nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
1014 void** aResult) {
1015 // test this first, since there's no point in returning a service during
1016 // shutdown -- whether it's available or not would depend on the order it
1017 // occurs in the list
1018 if (gXPCOMShuttingDown) {
1019 // When processing shutdown, don't process new GetService() requests
1020 #ifdef SHOW_DENIED_ON_SHUTDOWN
1021 fprintf(stderr,
1022 "Getting service on shutdown. Denied.\n"
1023 " CID: %s\n IID: %s\n",
1024 AutoIDString(aClass).get(), AutoIDString(aIID).get());
1025 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1026 return NS_ERROR_UNEXPECTED;
1029 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1031 Maybe<EntryWrapper> entry = LookupByCID(*lock, aClass);
1032 if (!entry) {
1033 return NS_ERROR_FACTORY_NOT_REGISTERED;
1036 return GetServiceLocked(lock, *entry, aIID, aResult);
1039 nsresult nsComponentManagerImpl::GetService(ModuleID aId, const nsIID& aIID,
1040 void** aResult) {
1041 const auto& entry = gStaticModules[size_t(aId)];
1043 // test this first, since there's no point in returning a service during
1044 // shutdown -- whether it's available or not would depend on the order it
1045 // occurs in the list
1046 if (gXPCOMShuttingDown) {
1047 // When processing shutdown, don't process new GetService() requests
1048 #ifdef SHOW_DENIED_ON_SHUTDOWN
1049 fprintf(stderr,
1050 "Getting service on shutdown. Denied.\n"
1051 " CID: %s\n IID: %s\n",
1052 AutoIDString(entry.CID()).get(), AutoIDString(aIID).get());
1053 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1054 return NS_ERROR_UNEXPECTED;
1057 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1059 Maybe<EntryWrapper> wrapper;
1060 if (entry.Overridable()) {
1061 // If we expect this service to be overridden by test code, we need to look
1062 // it up by contract ID every time.
1063 wrapper = LookupByContractID(*lock, entry.ContractID());
1064 if (!wrapper) {
1065 return NS_ERROR_FACTORY_NOT_REGISTERED;
1067 } else if (!entry.Active()) {
1068 return NS_ERROR_FACTORY_NOT_REGISTERED;
1069 } else {
1070 wrapper.emplace(&entry);
1072 return GetServiceLocked(lock, *wrapper, aIID, aResult);
1075 NS_IMETHODIMP
1076 nsComponentManagerImpl::IsServiceInstantiated(const nsCID& aClass,
1077 const nsIID& aIID,
1078 bool* aResult) {
1079 // Now we want to get the service if we already got it. If not, we don't want
1080 // to create an instance of it. mmh!
1082 // test this first, since there's no point in returning a service during
1083 // shutdown -- whether it's available or not would depend on the order it
1084 // occurs in the list
1085 if (gXPCOMShuttingDown) {
1086 // When processing shutdown, don't process new GetService() requests
1087 #ifdef SHOW_DENIED_ON_SHUTDOWN
1088 fprintf(stderr,
1089 "Checking for service on shutdown. Denied.\n"
1090 " CID: %s\n IID: %s\n",
1091 AutoIDString(aClass).get(), AutoIDString(aIID).get());
1092 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1093 return NS_ERROR_UNEXPECTED;
1096 if (Maybe<EntryWrapper> entry = LookupByCID(aClass)) {
1097 if (auto* service = entry->ServiceInstance()) {
1098 nsCOMPtr<nsISupports> instance;
1099 nsresult rv = service->QueryInterface(aIID, getter_AddRefs(instance));
1100 *aResult = (instance != nullptr);
1101 return rv;
1105 *aResult = false;
1106 return NS_OK;
1109 NS_IMETHODIMP
1110 nsComponentManagerImpl::IsServiceInstantiatedByContractID(
1111 const char* aContractID, const nsIID& aIID, bool* aResult) {
1112 // Now we want to get the service if we already got it. If not, we don't want
1113 // to create an instance of it. mmh!
1115 // test this first, since there's no point in returning a service during
1116 // shutdown -- whether it's available or not would depend on the order it
1117 // occurs in the list
1118 if (gXPCOMShuttingDown) {
1119 // When processing shutdown, don't process new GetService() requests
1120 #ifdef SHOW_DENIED_ON_SHUTDOWN
1121 fprintf(stderr,
1122 "Checking for service on shutdown. Denied.\n"
1123 " ContractID: %s\n IID: %s\n",
1124 aContractID, AutoIDString(aIID).get());
1125 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1126 return NS_ERROR_UNEXPECTED;
1129 if (Maybe<EntryWrapper> entry =
1130 LookupByContractID(nsDependentCString(aContractID))) {
1131 if (auto* service = entry->ServiceInstance()) {
1132 nsCOMPtr<nsISupports> instance;
1133 nsresult rv = service->QueryInterface(aIID, getter_AddRefs(instance));
1134 *aResult = (instance != nullptr);
1135 return rv;
1139 *aResult = false;
1140 return NS_OK;
1143 NS_IMETHODIMP
1144 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
1145 const nsIID& aIID,
1146 void** aResult) {
1147 // test this first, since there's no point in returning a service during
1148 // shutdown -- whether it's available or not would depend on the order it
1149 // occurs in the list
1150 if (gXPCOMShuttingDown) {
1151 // When processing shutdown, don't process new GetService() requests
1152 #ifdef SHOW_DENIED_ON_SHUTDOWN
1153 fprintf(stderr,
1154 "Getting service on shutdown. Denied.\n"
1155 " ContractID: %s\n IID: %s\n",
1156 aContractID, AutoIDString(aIID).get());
1157 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1158 return NS_ERROR_UNEXPECTED;
1161 AUTO_PROFILER_LABEL_DYNAMIC_CSTR_NONSENSITIVE("GetServiceByContractID", OTHER,
1162 aContractID);
1163 Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1165 Maybe<EntryWrapper> entry =
1166 LookupByContractID(*lock, nsDependentCString(aContractID));
1167 if (!entry) {
1168 return NS_ERROR_FACTORY_NOT_REGISTERED;
1171 return GetServiceLocked(lock, *entry, aIID, aResult);
1174 NS_IMETHODIMP
1175 nsComponentManagerImpl::RegisterFactory(const nsCID& aClass, const char* aName,
1176 const char* aContractID,
1177 nsIFactory* aFactory) {
1178 if (!aFactory) {
1179 // If a null factory is passed in, this call just wants to reset
1180 // the contract ID to point to an existing CID entry.
1181 if (!aContractID) {
1182 return NS_ERROR_INVALID_ARG;
1185 nsDependentCString contractID(aContractID);
1187 MonitorAutoLock lock(mLock);
1188 nsFactoryEntry* oldf = mFactories.Get(&aClass);
1189 if (oldf) {
1190 StaticComponents::InvalidateContractID(contractID);
1191 mContractIDs.InsertOrUpdate(contractID, oldf);
1192 return NS_OK;
1195 if (StaticComponents::LookupByCID(aClass)) {
1196 // If this is the CID of a static module, just reset the invalid bit of
1197 // the static entry for this contract ID, and assume it points to the
1198 // correct class.
1199 if (StaticComponents::InvalidateContractID(contractID, false)) {
1200 mContractIDs.Remove(contractID);
1201 return NS_OK;
1204 return NS_ERROR_FACTORY_NOT_REGISTERED;
1207 auto f = MakeUnique<nsFactoryEntry>(aClass, aFactory);
1209 MonitorAutoLock lock(mLock);
1210 return mFactories.WithEntryHandle(&f->mCID, [&](auto&& entry) {
1211 if (entry) {
1212 return NS_ERROR_FACTORY_EXISTS;
1214 if (StaticComponents::LookupByCID(f->mCID)) {
1215 return NS_ERROR_FACTORY_EXISTS;
1217 if (aContractID) {
1218 nsDependentCString contractID(aContractID);
1219 mContractIDs.InsertOrUpdate(contractID, f.get());
1220 // We allow dynamically-registered contract IDs to override static
1221 // entries, so invalidate any static entry for this contract ID.
1222 StaticComponents::InvalidateContractID(contractID);
1224 entry.Insert(f.release());
1226 return NS_OK;
1230 NS_IMETHODIMP
1231 nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass,
1232 nsIFactory* aFactory) {
1233 // Don't release the dying factory or service object until releasing
1234 // the component manager monitor.
1235 nsCOMPtr<nsIFactory> dyingFactory;
1236 nsCOMPtr<nsISupports> dyingServiceObject;
1239 MonitorAutoLock lock(mLock);
1240 auto entry = mFactories.Lookup(&aClass);
1241 nsFactoryEntry* f = entry ? entry.Data() : nullptr;
1242 if (!f || f->mFactory != aFactory) {
1243 // Note: We do not support unregistering static factories.
1244 return NS_ERROR_FACTORY_NOT_REGISTERED;
1247 entry.Remove();
1249 // This might leave a stale contractid -> factory mapping in
1250 // place, so null out the factory entry (see
1251 // nsFactoryEntry::GetFactory)
1252 f->mFactory.swap(dyingFactory);
1253 f->mServiceObject.swap(dyingServiceObject);
1256 return NS_OK;
1259 NS_IMETHODIMP
1260 nsComponentManagerImpl::AutoRegister(nsIFile* aLocation) {
1261 XRE_AddManifestLocation(NS_EXTENSION_LOCATION, aLocation);
1262 return NS_OK;
1265 NS_IMETHODIMP
1266 nsComponentManagerImpl::IsCIDRegistered(const nsCID& aClass, bool* aResult) {
1267 *aResult = LookupByCID(aClass).isSome();
1268 return NS_OK;
1271 NS_IMETHODIMP
1272 nsComponentManagerImpl::IsContractIDRegistered(const char* aClass,
1273 bool* aResult) {
1274 if (NS_WARN_IF(!aClass)) {
1275 return NS_ERROR_INVALID_ARG;
1278 Maybe<EntryWrapper> entry = LookupByContractID(nsDependentCString(aClass));
1280 *aResult = entry.isSome();
1281 return NS_OK;
1284 NS_IMETHODIMP
1285 nsComponentManagerImpl::GetContractIDs(nsTArray<nsCString>& aResult) {
1286 aResult = ToTArray<nsTArray<nsCString>>(mContractIDs.Keys());
1288 for (const auto& entry : gContractEntries) {
1289 if (!entry.Invalid()) {
1290 aResult.AppendElement(entry.ContractID());
1294 return NS_OK;
1297 NS_IMETHODIMP
1298 nsComponentManagerImpl::ContractIDToCID(const char* aContractID,
1299 nsCID** aResult) {
1301 MonitorAutoLock lock(mLock);
1302 Maybe<EntryWrapper> entry =
1303 LookupByContractID(lock, nsDependentCString(aContractID));
1304 if (entry) {
1305 *aResult = (nsCID*)moz_xmalloc(sizeof(nsCID));
1306 **aResult = entry->CID();
1307 return NS_OK;
1310 *aResult = nullptr;
1311 return NS_ERROR_FACTORY_NOT_REGISTERED;
1314 MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf)
1316 NS_IMETHODIMP
1317 nsComponentManagerImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
1318 nsISupports* aData, bool aAnonymize) {
1319 MOZ_COLLECT_REPORT("explicit/xpcom/component-manager", KIND_HEAP, UNITS_BYTES,
1320 SizeOfIncludingThis(ComponentManagerMallocSizeOf),
1321 "Memory used for the XPCOM component manager.");
1323 return NS_OK;
1326 size_t nsComponentManagerImpl::SizeOfIncludingThis(
1327 mozilla::MallocSizeOf aMallocSizeOf) const {
1328 size_t n = aMallocSizeOf(this);
1330 n += mFactories.ShallowSizeOfExcludingThis(aMallocSizeOf);
1331 for (const auto& data : mFactories.Values()) {
1332 n += data->SizeOfIncludingThis(aMallocSizeOf);
1335 n += mContractIDs.ShallowSizeOfExcludingThis(aMallocSizeOf);
1336 for (const auto& key : mContractIDs.Keys()) {
1337 // We don't measure the nsFactoryEntry data because it's owned by
1338 // mFactories (which is measured above).
1339 n += key.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1342 if (sModuleLocations) {
1343 n += sModuleLocations->ShallowSizeOfIncludingThis(aMallocSizeOf);
1346 n += mPendingServices.ShallowSizeOfExcludingThis(aMallocSizeOf);
1348 // Measurement of the following members may be added later if DMD finds it is
1349 // worthwhile:
1350 // - mMon
1351 // - sModuleLocations' entries
1353 return n;
1356 ////////////////////////////////////////////////////////////////////////////////
1357 // nsFactoryEntry
1358 ////////////////////////////////////////////////////////////////////////////////
1360 nsFactoryEntry::nsFactoryEntry(const nsCID& aCID, nsIFactory* aFactory)
1361 : mCID(aCID), mFactory(aFactory) {}
1363 already_AddRefed<nsIFactory> nsFactoryEntry::GetFactory() {
1364 nsComponentManagerImpl::gComponentManager->mLock.AssertNotCurrentThreadOwns();
1366 nsCOMPtr<nsIFactory> factory = mFactory;
1367 return factory.forget();
1370 nsresult nsFactoryEntry::CreateInstance(const nsIID& aIID, void** aResult) {
1371 nsCOMPtr<nsIFactory> factory = GetFactory();
1372 NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
1373 return factory->CreateInstance(aIID, aResult);
1376 size_t nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
1377 size_t n = aMallocSizeOf(this);
1379 // Measurement of the following members may be added later if DMD finds it is
1380 // worthwhile:
1381 // - mCID;
1382 // - mFactory;
1383 // - mServiceObject;
1385 return n;
1388 ////////////////////////////////////////////////////////////////////////////////
1389 // Static Access Functions
1390 ////////////////////////////////////////////////////////////////////////////////
1392 nsresult NS_GetComponentManager(nsIComponentManager** aResult) {
1393 if (!nsComponentManagerImpl::gComponentManager) {
1394 return NS_ERROR_NOT_INITIALIZED;
1397 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1398 return NS_OK;
1401 nsresult NS_GetServiceManager(nsIServiceManager** aResult) {
1402 if (!nsComponentManagerImpl::gComponentManager) {
1403 return NS_ERROR_NOT_INITIALIZED;
1406 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1407 return NS_OK;
1410 nsresult NS_GetComponentRegistrar(nsIComponentRegistrar** aResult) {
1411 if (!nsComponentManagerImpl::gComponentManager) {
1412 return NS_ERROR_NOT_INITIALIZED;
1415 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1416 return NS_OK;
1419 NS_IMETHODIMP
1420 nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation) {
1421 NS_ENSURE_ARG_POINTER(aLocation);
1423 nsString path;
1424 nsresult rv = aLocation->GetPath(path);
1425 if (NS_FAILED(rv)) {
1426 return rv;
1429 if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
1430 return XRE_AddJarManifestLocation(NS_BOOTSTRAPPED_LOCATION, aLocation);
1433 nsCOMPtr<nsIFile> manifest = CloneAndAppend(aLocation, "chrome.manifest"_ns);
1434 return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION, manifest);
1437 NS_IMETHODIMP
1438 nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation) {
1439 NS_ENSURE_ARG_POINTER(aLocation);
1441 nsCOMPtr<nsIChromeRegistry> cr = mozilla::services::GetChromeRegistry();
1442 if (!cr) {
1443 return NS_ERROR_FAILURE;
1446 nsString path;
1447 nsresult rv = aLocation->GetPath(path);
1448 if (NS_FAILED(rv)) {
1449 return rv;
1452 nsComponentManagerImpl::ComponentLocation elem;
1453 elem.type = NS_BOOTSTRAPPED_LOCATION;
1455 if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
1456 elem.location.Init(aLocation, "chrome.manifest");
1457 } else {
1458 nsCOMPtr<nsIFile> lf = CloneAndAppend(aLocation, "chrome.manifest"_ns);
1459 elem.location.Init(lf);
1462 // Remove reference.
1463 nsComponentManagerImpl::sModuleLocations->RemoveElement(
1464 elem, ComponentLocationComparator());
1466 rv = cr->CheckForNewChrome();
1467 return rv;
1470 NS_IMETHODIMP
1471 nsComponentManagerImpl::GetComponentJSMs(nsIUTF8StringEnumerator** aJSMs) {
1472 nsCOMPtr<nsIUTF8StringEnumerator> result =
1473 StaticComponents::GetComponentJSMs();
1474 result.forget(aJSMs);
1475 return NS_OK;
1478 NS_IMETHODIMP
1479 nsComponentManagerImpl::GetComponentESModules(
1480 nsIUTF8StringEnumerator** aESModules) {
1481 nsCOMPtr<nsIUTF8StringEnumerator> result =
1482 StaticComponents::GetComponentESModules();
1483 result.forget(aESModules);
1484 return NS_OK;
1487 NS_IMETHODIMP
1488 nsComponentManagerImpl::GetManifestLocations(nsIArray** aLocations) {
1489 NS_ENSURE_ARG_POINTER(aLocations);
1490 *aLocations = nullptr;
1492 if (!sModuleLocations) {
1493 return NS_ERROR_NOT_INITIALIZED;
1496 nsCOMPtr<nsIMutableArray> locations = nsArray::Create();
1497 nsresult rv;
1498 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
1499 ComponentLocation& l = sModuleLocations->ElementAt(i);
1500 FileLocation loc = l.location;
1501 nsCString uriString;
1502 loc.GetURIString(uriString);
1503 nsCOMPtr<nsIURI> uri;
1504 rv = NS_NewURI(getter_AddRefs(uri), uriString);
1505 if (NS_SUCCEEDED(rv)) {
1506 locations->AppendElement(uri);
1510 locations.forget(aLocations);
1511 return NS_OK;
1514 EXPORT_XPCOM_API(nsresult)
1515 XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation) {
1516 nsComponentManagerImpl::InitializeModuleLocations();
1517 nsComponentManagerImpl::ComponentLocation* c =
1518 nsComponentManagerImpl::sModuleLocations->AppendElement();
1519 c->type = aType;
1520 c->location.Init(aLocation);
1522 if (nsComponentManagerImpl::gComponentManager &&
1523 nsComponentManagerImpl::NORMAL ==
1524 nsComponentManagerImpl::gComponentManager->mStatus) {
1525 nsComponentManagerImpl::gComponentManager->RegisterManifest(
1526 aType, c->location, false);
1529 return NS_OK;
1532 EXPORT_XPCOM_API(nsresult)
1533 XRE_AddJarManifestLocation(NSLocationType aType, nsIFile* aLocation) {
1534 nsComponentManagerImpl::InitializeModuleLocations();
1535 nsComponentManagerImpl::ComponentLocation* c =
1536 nsComponentManagerImpl::sModuleLocations->AppendElement();
1538 c->type = aType;
1539 c->location.Init(aLocation, "chrome.manifest");
1541 if (nsComponentManagerImpl::gComponentManager &&
1542 nsComponentManagerImpl::NORMAL ==
1543 nsComponentManagerImpl::gComponentManager->mStatus) {
1544 nsComponentManagerImpl::gComponentManager->RegisterManifest(
1545 aType, c->location, false);
1548 return NS_OK;
1551 // Expose some important global interfaces to rust for the rust xpcom API. These
1552 // methods return a non-owning reference to the component manager, which should
1553 // live for the lifetime of XPCOM.
1554 extern "C" {
1556 const nsIComponentManager* Gecko_GetComponentManager() {
1557 return nsComponentManagerImpl::gComponentManager;
1560 const nsIServiceManager* Gecko_GetServiceManager() {
1561 return nsComponentManagerImpl::gComponentManager;
1564 const nsIComponentRegistrar* Gecko_GetComponentRegistrar() {
1565 return nsComponentManagerImpl::gComponentManager;
1568 // FFI-compatible version of `GetServiceHelper::operator()`.
1569 nsresult Gecko_GetServiceByModuleID(ModuleID aId, const nsIID* aIID,
1570 void** aResult) {
1571 return nsComponentManagerImpl::gComponentManager->GetService(aId, *aIID,
1572 aResult);
1575 // FFI-compatible version of `CreateInstanceHelper::operator()`.
1576 nsresult Gecko_CreateInstanceByModuleID(ModuleID aId, const nsIID* aIID,
1577 void** aResult) {
1578 const auto& entry = gStaticModules[size_t(aId)];
1579 if (!entry.Active()) {
1580 return NS_ERROR_FACTORY_NOT_REGISTERED;
1583 nsresult rv = entry.CreateInstance(*aIID, aResult);
1584 return rv;