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/. */
6 
7 #include <stdlib.h>
8 #include "nscore.h"
9 #include "nsISupports.h"
10 #include "nspr.h"
11 #include "nsCRT.h"  // for atoll
12 
13 #include "StaticComponents.h"
14 
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"
41 #include "mozJSComponentLoader.h"
42 
43 #include "mozilla/GenericFactory.h"
44 #include "nsSupportsPrimitives.h"
45 #include "nsArray.h"
46 #include "nsIMutableArray.h"
47 #include "mozilla/DebugOnly.h"
48 #include "mozilla/FileUtils.h"
49 #include "mozilla/ProfilerLabels.h"
50 #include "mozilla/ProfilerMarkers.h"
51 #include "mozilla/ScopeExit.h"
52 #include "mozilla/URLPreloader.h"
53 #include "mozilla/UniquePtr.h"
54 #include "mozilla/Variant.h"
55 
56 #include <new>  // for placement new
57 
58 #include "mozilla/Omnijar.h"
59 
60 #include "mozilla/Logging.h"
61 #include "LogModulePrefWatcher.h"
62 
63 #ifdef MOZ_MEMORY
64 #  include "mozmemory.h"
65 #endif
66 
67 using namespace mozilla;
68 using namespace mozilla::xpcom;
69 
70 static LazyLogModule nsComponentManagerLog("nsComponentManager");
71 
72 #if 0
73 #  define SHOW_DENIED_ON_SHUTDOWN
74 #  define SHOW_CI_ON_EXISTING_SERVICE
75 #endif
76 
77 namespace {
78 
79 class AutoIDString : public nsAutoCStringN<NSID_LENGTH> {
80  public:
AutoIDString(const nsID & aID)81   explicit AutoIDString(const nsID& aID) {
82     SetLength(NSID_LENGTH - 1);
83     aID.ToProvidedString(
84         *reinterpret_cast<char(*)[NSID_LENGTH]>(BeginWriting()));
85   }
86 };
87 
88 }  // namespace
89 
90 namespace mozilla {
91 namespace xpcom {
92 
93 using ProcessSelector = Module::ProcessSelector;
94 
95 // Note: These must be kept in sync with the ProcessSelector definition in
96 // Module.h.
ProcessSelectorMatches(ProcessSelector aSelector)97 bool ProcessSelectorMatches(ProcessSelector aSelector) {
98   GeckoProcessType type = XRE_GetProcessType();
99   if (type == GeckoProcessType_GPU) {
100     return !!(aSelector & Module::ALLOW_IN_GPU_PROCESS);
101   }
102 
103   if (type == GeckoProcessType_RDD) {
104     return !!(aSelector & Module::ALLOW_IN_RDD_PROCESS);
105   }
106 
107   if (type == GeckoProcessType_Socket) {
108     return !!(aSelector & (Module::ALLOW_IN_SOCKET_PROCESS));
109   }
110 
111   if (type == GeckoProcessType_VR) {
112     return !!(aSelector & Module::ALLOW_IN_VR_PROCESS);
113   }
114 
115   if (aSelector & Module::MAIN_PROCESS_ONLY) {
116     return type == GeckoProcessType_Default;
117   }
118   if (aSelector & Module::CONTENT_PROCESS_ONLY) {
119     return type == GeckoProcessType_Content;
120   }
121   return true;
122 }
123 
124 static bool gProcessMatchTable[Module::kMaxProcessSelector + 1];
125 
FastProcessSelectorMatches(ProcessSelector aSelector)126 bool FastProcessSelectorMatches(ProcessSelector aSelector) {
127   return gProcessMatchTable[size_t(aSelector)];
128 }
129 
130 }  // namespace xpcom
131 }  // namespace mozilla
132 
133 namespace {
134 
135 /**
136  * A wrapper simple wrapper class, which can hold either a dynamic
137  * nsFactoryEntry instance, or a static StaticModule entry, and transparently
138  * forwards method calls to the wrapped object.
139  *
140  * This allows the same code to work with either static or dynamic modules
141  * without caring about the difference.
142  */
143 class MOZ_STACK_CLASS EntryWrapper final {
144  public:
EntryWrapper(nsFactoryEntry * aEntry)145   explicit EntryWrapper(nsFactoryEntry* aEntry) : mEntry(aEntry) {}
146 
EntryWrapper(const StaticModule * aEntry)147   explicit EntryWrapper(const StaticModule* aEntry) : mEntry(aEntry) {}
148 
149 #define MATCH(type, ifFactory, ifStatic)                     \
150   struct Matcher {                                           \
151     type operator()(nsFactoryEntry* entry) { ifFactory; }    \
152     type operator()(const StaticModule* entry) { ifStatic; } \
153   };                                                         \
154   return mEntry.match((Matcher()))
155 
CID()156   const nsID& CID() {
157     MATCH(const nsID&, return *entry->mCIDEntry->cid, return entry->CID());
158   }
159 
GetFactory()160   already_AddRefed<nsIFactory> GetFactory() {
161     MATCH(already_AddRefed<nsIFactory>, return entry->GetFactory(),
162           return entry->GetFactory());
163   }
164 
165   /**
166    * Creates an instance of the underlying component. This should be used in
167    * preference to GetFactory()->CreateInstance() where appropriate, since it
168    * side-steps the necessity of creating a nsIFactory instance for static
169    * modules.
170    */
CreateInstance(nsISupports * aOuter,const nsIID & aIID,void ** aResult)171   nsresult CreateInstance(nsISupports* aOuter, const nsIID& aIID,
172                           void** aResult) {
173     if (mEntry.is<nsFactoryEntry*>()) {
174       return mEntry.as<nsFactoryEntry*>()->CreateInstance(aOuter, aIID,
175                                                           aResult);
176     }
177     return mEntry.as<const StaticModule*>()->CreateInstance(aOuter, aIID,
178                                                             aResult);
179   }
180 
181   /**
182    * Returns the cached service instance for this entry, if any. This should
183    * only be accessed while mLock is held.
184    */
ServiceInstance()185   nsISupports* ServiceInstance() {
186     MATCH(nsISupports*, return entry->mServiceObject,
187           return entry->ServiceInstance());
188   }
SetServiceInstance(already_AddRefed<nsISupports> aInst)189   void SetServiceInstance(already_AddRefed<nsISupports> aInst) {
190     if (mEntry.is<nsFactoryEntry*>()) {
191       mEntry.as<nsFactoryEntry*>()->mServiceObject = aInst;
192     } else {
193       return mEntry.as<const StaticModule*>()->SetServiceInstance(
194           std::move(aInst));
195     }
196   }
197 
198   /**
199    * Returns the description string for the module this entry belongs to. For
200    * static entries, always returns "<unknown module>".
201    */
ModuleDescription()202   nsCString ModuleDescription() {
203     MATCH(nsCString,
204           return entry->mModule ? entry->mModule->Description()
205                                 : "<unknown module>"_ns,
206           return "<unknown module>"_ns);
207   }
208 
209  private:
210   Variant<nsFactoryEntry*, const StaticModule*> mEntry;
211 };
212 
213 }  // namespace
214 
215 // this is safe to call during InitXPCOM
GetLocationFromDirectoryService(const char * aProp)216 static already_AddRefed<nsIFile> GetLocationFromDirectoryService(
217     const char* aProp) {
218   nsCOMPtr<nsIProperties> directoryService;
219   nsDirectoryService::Create(nullptr, NS_GET_IID(nsIProperties),
220                              getter_AddRefs(directoryService));
221 
222   if (!directoryService) {
223     return nullptr;
224   }
225 
226   nsCOMPtr<nsIFile> file;
227   nsresult rv =
228       directoryService->Get(aProp, NS_GET_IID(nsIFile), getter_AddRefs(file));
229   if (NS_FAILED(rv)) {
230     return nullptr;
231   }
232 
233   return file.forget();
234 }
235 
CloneAndAppend(nsIFile * aBase,const nsACString & aAppend)236 static already_AddRefed<nsIFile> CloneAndAppend(nsIFile* aBase,
237                                                 const nsACString& aAppend) {
238   nsCOMPtr<nsIFile> f;
239   aBase->Clone(getter_AddRefs(f));
240   if (!f) {
241     return nullptr;
242   }
243 
244   f->AppendNative(aAppend);
245   return f.forget();
246 }
247 
248 ////////////////////////////////////////////////////////////////////////////////
249 // nsComponentManagerImpl
250 ////////////////////////////////////////////////////////////////////////////////
251 
Create(nsISupports * aOuter,REFNSIID aIID,void ** aResult)252 nsresult nsComponentManagerImpl::Create(nsISupports* aOuter, REFNSIID aIID,
253                                         void** aResult) {
254   if (aOuter) {
255     return NS_ERROR_NO_AGGREGATION;
256   }
257 
258   if (!gComponentManager) {
259     return NS_ERROR_FAILURE;
260   }
261 
262   return gComponentManager->QueryInterface(aIID, aResult);
263 }
264 
265 static const int CONTRACTID_HASHTABLE_INITIAL_LENGTH = 32;
266 
nsComponentManagerImpl()267 nsComponentManagerImpl::nsComponentManagerImpl()
268     : mFactories(CONTRACTID_HASHTABLE_INITIAL_LENGTH),
269       mContractIDs(CONTRACTID_HASHTABLE_INITIAL_LENGTH),
270       mLock("nsComponentManagerImpl.mLock"),
271       mStatus(NOT_INITIALIZED) {}
272 
273 extern const mozilla::Module kNeckoModule;
274 extern const mozilla::Module kPowerManagerModule;
275 extern const mozilla::Module kContentProcessWidgetModule;
276 #if defined(MOZ_WIDGET_COCOA) || defined(MOZ_WIDGET_UIKIT)
277 extern const mozilla::Module kWidgetModule;
278 #endif
279 extern const mozilla::Module kLayoutModule;
280 extern const mozilla::Module kKeyValueModule;
281 extern const mozilla::Module kXREModule;
282 extern const mozilla::Module kEmbeddingModule;
283 
284 static nsTArray<const mozilla::Module*>* sExtraStaticModules;
285 
286 /* static */
InitializeStaticModules()287 void nsComponentManagerImpl::InitializeStaticModules() {
288   if (sExtraStaticModules) {
289     return;
290   }
291 
292   sExtraStaticModules = new nsTArray<const mozilla::Module*>;
293 }
294 
295 nsTArray<nsComponentManagerImpl::ComponentLocation>*
296     nsComponentManagerImpl::sModuleLocations;
297 
298 /* static */
InitializeModuleLocations()299 void nsComponentManagerImpl::InitializeModuleLocations() {
300   if (sModuleLocations) {
301     return;
302   }
303 
304   sModuleLocations = new nsTArray<ComponentLocation>;
305 }
306 
Init()307 nsresult nsComponentManagerImpl::Init() {
308   {
309     gProcessMatchTable[size_t(ProcessSelector::ANY_PROCESS)] =
310         ProcessSelectorMatches(ProcessSelector::ANY_PROCESS);
311     gProcessMatchTable[size_t(ProcessSelector::MAIN_PROCESS_ONLY)] =
312         ProcessSelectorMatches(ProcessSelector::MAIN_PROCESS_ONLY);
313     gProcessMatchTable[size_t(ProcessSelector::CONTENT_PROCESS_ONLY)] =
314         ProcessSelectorMatches(ProcessSelector::CONTENT_PROCESS_ONLY);
315     gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_PROCESS)] =
316         ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_PROCESS);
317     gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_VR_PROCESS)] =
318         ProcessSelectorMatches(ProcessSelector::ALLOW_IN_VR_PROCESS);
319     gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_SOCKET_PROCESS)] =
320         ProcessSelectorMatches(ProcessSelector::ALLOW_IN_SOCKET_PROCESS);
321     gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_RDD_PROCESS)] =
322         ProcessSelectorMatches(ProcessSelector::ALLOW_IN_RDD_PROCESS);
323     gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_MAIN_PROCESS)] =
324         ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_MAIN_PROCESS);
325     gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS)] =
326         ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS);
327     gProcessMatchTable[size_t(
328         ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS)] =
329         ProcessSelectorMatches(
330             ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS);
331     gProcessMatchTable[size_t(
332         ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS)] =
333         ProcessSelectorMatches(
334             ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS);
335     gProcessMatchTable[size_t(
336         ProcessSelector::ALLOW_IN_RDD_AND_SOCKET_PROCESS)] =
337         ProcessSelectorMatches(
338             ProcessSelector::ALLOW_IN_RDD_AND_SOCKET_PROCESS);
339     gProcessMatchTable[size_t(
340         ProcessSelector::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS)] =
341         ProcessSelectorMatches(
342             ProcessSelector::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS);
343     gProcessMatchTable[size_t(
344         ProcessSelector::ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS)] =
345         ProcessSelectorMatches(
346             ProcessSelector::ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS);
347   }
348 
349   MOZ_ASSERT(NOT_INITIALIZED == mStatus);
350 
351   nsCOMPtr<nsIFile> greDir = GetLocationFromDirectoryService(NS_GRE_DIR);
352   nsCOMPtr<nsIFile> appDir =
353       GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR);
354 
355   InitializeStaticModules();
356 
357   nsCategoryManager::GetSingleton()->SuppressNotifications(true);
358 
359   RegisterModule(&kXPCOMModule);
360   RegisterModule(&kNeckoModule);
361   RegisterModule(&kPowerManagerModule);
362   RegisterModule(&kContentProcessWidgetModule);
363 #if defined(MOZ_WIDGET_COCOA) || defined(MOZ_WIDGET_UIKIT)
364   RegisterModule(&kWidgetModule);
365 #endif
366   RegisterModule(&kLayoutModule);
367   RegisterModule(&kKeyValueModule);
368   RegisterModule(&kXREModule);
369   RegisterModule(&kEmbeddingModule);
370 
371   for (uint32_t i = 0; i < sExtraStaticModules->Length(); ++i) {
372     RegisterModule((*sExtraStaticModules)[i]);
373   }
374 
375   auto* catMan = nsCategoryManager::GetSingleton();
376   for (const auto& cat : gStaticCategories) {
377     for (const auto& entry : cat) {
378       if (entry.Active()) {
379         catMan->AddCategoryEntry(cat.Name(), entry.Entry(), entry.Value());
380       }
381     }
382   }
383 
384   bool loadChromeManifests;
385   switch (XRE_GetProcessType()) {
386     // We are going to assume that only a select few (see below) process types
387     // want to load chrome manifests, and that any new process types will not
388     // want to load them, because they're not going to be executing JS.
389     case GeckoProcessType_RemoteSandboxBroker:
390     default:
391       loadChromeManifests = false;
392       break;
393 
394     // XXX The check this code replaced implicitly let through all of these
395     // process types, but presumably only the default (parent) and content
396     // processes really need chrome manifests...?
397     case GeckoProcessType_Default:
398     case GeckoProcessType_Content:
399     case GeckoProcessType_IPDLUnitTest:
400     case GeckoProcessType_GMPlugin:
401       loadChromeManifests = true;
402       break;
403   }
404 
405   if (loadChromeManifests) {
406     // This needs to be called very early, before anything in nsLayoutModule is
407     // used, and before any calls are made into the JS engine.
408     nsLayoutModuleInitialize();
409 
410     mJSLoaderReady = true;
411 
412     // The overall order in which chrome.manifests are expected to be treated
413     // is the following:
414     // - greDir's omni.ja or greDir
415     // - appDir's omni.ja or appDir
416 
417     InitializeModuleLocations();
418     ComponentLocation* cl = sModuleLocations->AppendElement();
419     cl->type = NS_APP_LOCATION;
420     RefPtr<nsZipArchive> greOmnijar =
421         mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
422     if (greOmnijar) {
423       cl->location.Init(greOmnijar, "chrome.manifest");
424     } else {
425       nsCOMPtr<nsIFile> lf = CloneAndAppend(greDir, "chrome.manifest"_ns);
426       cl->location.Init(lf);
427     }
428 
429     RefPtr<nsZipArchive> appOmnijar =
430         mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
431     if (appOmnijar) {
432       cl = sModuleLocations->AppendElement();
433       cl->type = NS_APP_LOCATION;
434       cl->location.Init(appOmnijar, "chrome.manifest");
435     } else {
436       bool equals = false;
437       appDir->Equals(greDir, &equals);
438       if (!equals) {
439         cl = sModuleLocations->AppendElement();
440         cl->type = NS_APP_LOCATION;
441         nsCOMPtr<nsIFile> lf = CloneAndAppend(appDir, "chrome.manifest"_ns);
442         cl->location.Init(lf);
443       }
444     }
445 
446     RereadChromeManifests(false);
447   }
448 
449   nsCategoryManager::GetSingleton()->SuppressNotifications(false);
450 
451   RegisterWeakMemoryReporter(this);
452 
453   // NB: The logging preference watcher needs to be registered late enough in
454   // startup that it's okay to use the preference system, but also as soon as
455   // possible so that log modules enabled via preferences are turned on as
456   // early as possible.
457   //
458   // We can't initialize the preference watcher when the log module manager is
459   // initialized, as a number of things attempt to start logging before the
460   // preference system is initialized.
461   //
462   // The preference system is registered as a component so at this point during
463   // component manager initialization we know it is setup and we can register
464   // for notifications.
465   LogModulePrefWatcher::RegisterPrefWatcher();
466 
467   // Unfortunately, we can't register the nsCategoryManager memory reporter
468   // in its constructor (which is triggered by the GetSingleton() call
469   // above) because the memory reporter manager isn't initialized at that
470   // point.  So we wait until now.
471   nsCategoryManager::GetSingleton()->InitMemoryReporter();
472 
473   MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
474           ("nsComponentManager: Initialized."));
475 
476   mStatus = NORMAL;
477 
478   MOZ_ASSERT(!XRE_IsContentProcess() ||
479                  mFactories.Count() > CONTRACTID_HASHTABLE_INITIAL_LENGTH / 3,
480              "Initial component hashtable size is too large");
481 
482   return NS_OK;
483 }
484 
485 static const int kModuleVersionWithSelector = 51;
486 
487 template <typename T>
AssertNotMallocAllocated(T * aPtr)488 static void AssertNotMallocAllocated(T* aPtr) {
489 #if defined(DEBUG) && defined(MOZ_MEMORY)
490   jemalloc_ptr_info_t info;
491   jemalloc_ptr_info((void*)aPtr, &info);
492   MOZ_ASSERT(info.tag == TagUnknown);
493 #endif
494 }
495 
496 template <typename T>
AssertNotStackAllocated(T * aPtr)497 static void AssertNotStackAllocated(T* aPtr) {
498   // On all of our supported platforms, the stack grows down. Any address
499   // located below the address of our argument is therefore guaranteed not to be
500   // stack-allocated by the caller.
501   //
502   // For addresses above our argument, things get trickier. The main thread
503   // stack is traditionally placed at the top of the program's address space,
504   // but that is becoming less reliable as more and more systems adopt address
505   // space layout randomization strategies, so we have to guess how much space
506   // above our argument pointer we need to care about.
507   //
508   // On most systems, we're guaranteed at least several KiB at the top of each
509   // stack for TLS. We'd probably be safe assuming at least 4KiB in the stack
510   // segment above our argument address, but safer is... well, safer.
511   //
512   // For threads with huge stacks, it's theoretically possible that we could
513   // wind up being passed a stack-allocated string from farther up the stack,
514   // but this is a best-effort thing, so we'll assume we only care about the
515   // immediate caller. For that case, max 2KiB per stack frame is probably a
516   // reasonable guess most of the time, and is less than the ~4KiB that we
517   // expect for TLS, so go with that to avoid the risk of bumping into heap
518   // data just above the stack.
519 #ifdef DEBUG
520   static constexpr size_t kFuzz = 2048;
521 
522   MOZ_ASSERT(uintptr_t(aPtr) < uintptr_t(&aPtr) ||
523              uintptr_t(aPtr) > uintptr_t(&aPtr) + kFuzz);
524 #endif
525 }
526 
AsLiteralCString(const char * aStr)527 static inline nsCString AsLiteralCString(const char* aStr) {
528   AssertNotMallocAllocated(aStr);
529   AssertNotStackAllocated(aStr);
530 
531   nsCString str;
532   str.AssignLiteral(aStr, strlen(aStr));
533   return str;
534 }
535 
RegisterModule(const mozilla::Module * aModule)536 void nsComponentManagerImpl::RegisterModule(const mozilla::Module* aModule) {
537   mLock.AssertNotCurrentThreadOwns();
538 
539   if (aModule->mVersion >= kModuleVersionWithSelector &&
540       !ProcessSelectorMatches(aModule->selector)) {
541     return;
542   }
543 
544   {
545     // Scope the monitor so that we don't hold it while calling into the
546     // category manager.
547     MonitorAutoLock lock(mLock);
548 
549     KnownModule* m = new KnownModule(aModule);
550     mKnownStaticModules.AppendElement(m);
551 
552     if (aModule->mCIDs) {
553       const mozilla::Module::CIDEntry* entry;
554       for (entry = aModule->mCIDs; entry->cid; ++entry) {
555         RegisterCIDEntryLocked(entry, m);
556       }
557     }
558 
559     if (aModule->mContractIDs) {
560       const mozilla::Module::ContractIDEntry* entry;
561       for (entry = aModule->mContractIDs; entry->contractid; ++entry) {
562         RegisterContractIDLocked(entry);
563       }
564       MOZ_ASSERT(!entry->cid, "Incorrectly terminated contract list");
565     }
566   }
567 
568   if (aModule->mCategoryEntries) {
569     const mozilla::Module::CategoryEntry* entry;
570     for (entry = aModule->mCategoryEntries; entry->category; ++entry)
571       nsCategoryManager::GetSingleton()->AddCategoryEntry(
572           AsLiteralCString(entry->category), AsLiteralCString(entry->entry),
573           AsLiteralCString(entry->value));
574   }
575 }
576 
RegisterCIDEntryLocked(const mozilla::Module::CIDEntry * aEntry,KnownModule * aModule)577 void nsComponentManagerImpl::RegisterCIDEntryLocked(
578     const mozilla::Module::CIDEntry* aEntry, KnownModule* aModule) {
579   mLock.AssertCurrentThreadOwns();
580 
581   if (!ProcessSelectorMatches(aEntry->processSelector)) {
582     return;
583   }
584 
585 #ifdef DEBUG
586   // If we're still in the static initialization phase, check that we're not
587   // registering something that was already registered.
588   if (mStatus != NORMAL) {
589     if (StaticComponents::LookupByCID(*aEntry->cid)) {
590       MOZ_CRASH_UNSAFE_PRINTF(
591           "While registering XPCOM module %s, trying to re-register CID '%s' "
592           "already registered by a static component.",
593           aModule->Description().get(), AutoIDString(*aEntry->cid).get());
594     }
595   }
596 #endif
597 
598   mFactories.WithEntryHandle(aEntry->cid, [&](auto&& entry) {
599     if (entry) {
600       nsFactoryEntry* f = entry.Data();
601       NS_WARNING("Re-registering a CID?");
602 
603       nsCString existing;
604       if (f->mModule) {
605         existing = f->mModule->Description();
606       } else {
607         existing = "<unknown module>";
608       }
609       MonitorAutoUnlock unlock(mLock);
610       LogMessage(
611           "While registering XPCOM module %s, trying to re-register CID '%s' "
612           "already registered by %s.",
613           aModule->Description().get(), AutoIDString(*aEntry->cid).get(),
614           existing.get());
615     } else {
616       entry.Insert(new nsFactoryEntry(aEntry, aModule));
617     }
618   });
619 }
620 
RegisterContractIDLocked(const mozilla::Module::ContractIDEntry * aEntry)621 void nsComponentManagerImpl::RegisterContractIDLocked(
622     const mozilla::Module::ContractIDEntry* aEntry) {
623   mLock.AssertCurrentThreadOwns();
624 
625   if (!ProcessSelectorMatches(aEntry->processSelector)) {
626     return;
627   }
628 
629 #ifdef DEBUG
630   // If we're still in the static initialization phase, check that we're not
631   // registering something that was already registered.
632   if (mStatus != NORMAL) {
633     if (const StaticModule* module = StaticComponents::LookupByContractID(
634             nsAutoCString(aEntry->contractid))) {
635       MOZ_CRASH_UNSAFE_PRINTF(
636           "Could not map contract ID '%s' to CID %s because it is already "
637           "mapped to CID %s.",
638           aEntry->contractid, AutoIDString(*aEntry->cid).get(),
639           AutoIDString(module->CID()).get());
640     }
641   }
642 #endif
643 
644   nsFactoryEntry* f = mFactories.Get(aEntry->cid);
645   if (!f) {
646     NS_WARNING("No CID found when attempting to map contract ID");
647 
648     MonitorAutoUnlock unlock(mLock);
649     LogMessage(
650         "Could not map contract ID '%s' to CID %s because no implementation of "
651         "the CID is registered.",
652         aEntry->contractid, AutoIDString(*aEntry->cid).get());
653 
654     return;
655   }
656 
657   mContractIDs.InsertOrUpdate(AsLiteralCString(aEntry->contractid), f);
658 }
659 
CutExtension(nsCString & aPath)660 static void CutExtension(nsCString& aPath) {
661   int32_t dotPos = aPath.RFindChar('.');
662   if (kNotFound == dotPos) {
663     aPath.Truncate();
664   } else {
665     aPath.Cut(0, dotPos + 1);
666   }
667 }
668 
DoRegisterManifest(NSLocationType aType,FileLocation & aFile,bool aChromeOnly)669 static void DoRegisterManifest(NSLocationType aType, FileLocation& aFile,
670                                bool aChromeOnly) {
671   auto result = URLPreloader::Read(aFile);
672   if (result.isOk()) {
673     nsCString buf(result.unwrap());
674     ParseManifest(aType, aFile, buf.BeginWriting(), aChromeOnly);
675   } else if (NS_BOOTSTRAPPED_LOCATION != aType) {
676     nsCString uri;
677     aFile.GetURIString(uri);
678     LogMessage("Could not read chrome manifest '%s'.", uri.get());
679   }
680 }
681 
RegisterManifest(NSLocationType aType,FileLocation & aFile,bool aChromeOnly)682 void nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
683                                               FileLocation& aFile,
684                                               bool aChromeOnly) {
685   DoRegisterManifest(aType, aFile, aChromeOnly);
686 }
687 
ManifestManifest(ManifestProcessingContext & aCx,int aLineNo,char * const * aArgv)688 void nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& aCx,
689                                               int aLineNo, char* const* aArgv) {
690   char* file = aArgv[0];
691   FileLocation f(aCx.mFile, file);
692   RegisterManifest(aCx.mType, f, aCx.mChromeOnly);
693 }
694 
ManifestComponent(ManifestProcessingContext & aCx,int aLineNo,char * const * aArgv)695 void nsComponentManagerImpl::ManifestComponent(ManifestProcessingContext& aCx,
696                                                int aLineNo,
697                                                char* const* aArgv) {
698   mLock.AssertNotCurrentThreadOwns();
699 
700   char* id = aArgv[0];
701   char* file = aArgv[1];
702 
703   nsID cid;
704   if (!cid.Parse(id)) {
705     LogMessageWithContext(aCx.mFile, aLineNo, "Malformed CID: '%s'.", id);
706     return;
707   }
708 
709   // Precompute the hash/file data outside of the lock
710   FileLocation fl(aCx.mFile, file);
711   nsCString hash;
712   fl.GetURIString(hash);
713 
714   Maybe<MonitorAutoLock> lock(std::in_place, mLock);
715   if (Maybe<EntryWrapper> f = LookupByCID(*lock, cid)) {
716     nsCString existing(f->ModuleDescription());
717 
718     lock.reset();
719 
720     LogMessageWithContext(
721         aCx.mFile, aLineNo,
722         "Trying to re-register CID '%s' already registered by %s.",
723         AutoIDString(cid).get(), existing.get());
724     return;
725   }
726 
727   KnownModule* const km = mKnownModules.GetOrInsertNew(hash, fl);
728 
729   void* place = mArena.Allocate(sizeof(nsCID));
730   nsID* permanentCID = static_cast<nsID*>(place);
731   *permanentCID = cid;
732 
733   place = mArena.Allocate(sizeof(mozilla::Module::CIDEntry));
734   auto* e = new (KnownNotNull, place) mozilla::Module::CIDEntry();
735   e->cid = permanentCID;
736 
737   mFactories.InsertOrUpdate(permanentCID, new nsFactoryEntry(e, km));
738 }
739 
ManifestContract(ManifestProcessingContext & aCx,int aLineNo,char * const * aArgv)740 void nsComponentManagerImpl::ManifestContract(ManifestProcessingContext& aCx,
741                                               int aLineNo, char* const* aArgv) {
742   mLock.AssertNotCurrentThreadOwns();
743 
744   char* contract = aArgv[0];
745   char* id = aArgv[1];
746 
747   nsID cid;
748   if (!cid.Parse(id)) {
749     LogMessageWithContext(aCx.mFile, aLineNo, "Malformed CID: '%s'.", id);
750     return;
751   }
752 
753   Maybe<MonitorAutoLock> lock(std::in_place, mLock);
754   nsFactoryEntry* f = mFactories.Get(&cid);
755   if (!f) {
756     lock.reset();
757     LogMessageWithContext(aCx.mFile, aLineNo,
758                           "Could not map contract ID '%s' to CID %s because no "
759                           "implementation of the CID is registered.",
760                           contract, id);
761     return;
762   }
763 
764   nsDependentCString contractString(contract);
765   StaticComponents::InvalidateContractID(nsDependentCString(contractString));
766   mContractIDs.InsertOrUpdate(contractString, f);
767 }
768 
ManifestCategory(ManifestProcessingContext & aCx,int aLineNo,char * const * aArgv)769 void nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext& aCx,
770                                               int aLineNo, char* const* aArgv) {
771   char* category = aArgv[0];
772   char* key = aArgv[1];
773   char* value = aArgv[2];
774 
775   nsCategoryManager::GetSingleton()->AddCategoryEntry(
776       nsDependentCString(category), nsDependentCString(key),
777       nsDependentCString(value));
778 }
779 
RereadChromeManifests(bool aChromeOnly)780 void nsComponentManagerImpl::RereadChromeManifests(bool aChromeOnly) {
781   for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
782     ComponentLocation& l = sModuleLocations->ElementAt(i);
783     RegisterManifest(l.type, l.location, aChromeOnly);
784   }
785 
786   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
787   if (obs) {
788     obs->NotifyObservers(nullptr, "chrome-manifests-loaded", nullptr);
789   }
790 }
791 
Load()792 bool nsComponentManagerImpl::KnownModule::Load() {
793   if (mFailed) {
794     return false;
795   }
796   if (!mModule) {
797     nsCString extension;
798     mFile.GetURIString(extension);
799     CutExtension(extension);
800     if (!extension.Equals("js")) {
801       return false;
802     }
803 
804     RefPtr<mozJSComponentLoader> loader = mozJSComponentLoader::Get();
805     mModule = loader->LoadModule(mFile);
806 
807     if (!mModule) {
808       mFailed = true;
809       return false;
810     }
811   }
812   if (!mLoaded) {
813     if (mModule->loadProc) {
814       nsresult rv = mModule->loadProc();
815       if (NS_FAILED(rv)) {
816         mFailed = true;
817         return false;
818       }
819     }
820     mLoaded = true;
821   }
822   return true;
823 }
824 
Description() const825 nsCString nsComponentManagerImpl::KnownModule::Description() const {
826   nsCString s;
827   if (mFile) {
828     mFile.GetURIString(s);
829   } else {
830     s = "<static module>";
831   }
832   return s;
833 }
834 
Shutdown(void)835 nsresult nsComponentManagerImpl::Shutdown(void) {
836   MOZ_ASSERT(NORMAL == mStatus);
837 
838   mStatus = SHUTDOWN_IN_PROGRESS;
839 
840   // Shutdown the component manager
841   MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
842           ("nsComponentManager: Beginning Shutdown."));
843 
844   UnregisterWeakMemoryReporter(this);
845 
846   // Release all cached factories
847   mContractIDs.Clear();
848   mFactories.Clear();  // XXX release the objects, don't just clear
849   mKnownModules.Clear();
850   mKnownStaticModules.Clear();
851 
852   StaticComponents::Shutdown();
853 
854   delete sExtraStaticModules;
855   delete sModuleLocations;
856 
857   mStatus = SHUTDOWN_COMPLETE;
858 
859   MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
860           ("nsComponentManager: Shutdown complete."));
861 
862   return NS_OK;
863 }
864 
~nsComponentManagerImpl()865 nsComponentManagerImpl::~nsComponentManagerImpl() {
866   MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
867           ("nsComponentManager: Beginning destruction."));
868 
869   if (SHUTDOWN_COMPLETE != mStatus) {
870     Shutdown();
871   }
872 
873   MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
874           ("nsComponentManager: Destroyed."));
875 }
876 
NS_IMPL_ISUPPORTS(nsComponentManagerImpl,nsIComponentManager,nsIServiceManager,nsIComponentRegistrar,nsISupportsWeakReference,nsIInterfaceRequestor,nsIMemoryReporter)877 NS_IMPL_ISUPPORTS(nsComponentManagerImpl, nsIComponentManager,
878                   nsIServiceManager, nsIComponentRegistrar,
879                   nsISupportsWeakReference, nsIInterfaceRequestor,
880                   nsIMemoryReporter)
881 
882 nsresult nsComponentManagerImpl::GetInterface(const nsIID& aUuid,
883                                               void** aResult) {
884   NS_WARNING("This isn't supported");
885   // fall through to QI as anything QIable is a superset of what can be
886   // got via the GetInterface()
887   return QueryInterface(aUuid, aResult);
888 }
889 
LookupByCID(const nsID & aCID)890 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByCID(const nsID& aCID) {
891   return LookupByCID(MonitorAutoLock(mLock), aCID);
892 }
893 
LookupByCID(const MonitorAutoLock &,const nsID & aCID)894 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByCID(const MonitorAutoLock&,
895                                                         const nsID& aCID) {
896   if (const StaticModule* module = StaticComponents::LookupByCID(aCID)) {
897     return Some(EntryWrapper(module));
898   }
899   if (nsFactoryEntry* entry = mFactories.Get(&aCID)) {
900     return Some(EntryWrapper(entry));
901   }
902   return Nothing();
903 }
904 
LookupByContractID(const nsACString & aContractID)905 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByContractID(
906     const nsACString& aContractID) {
907   return LookupByContractID(MonitorAutoLock(mLock), aContractID);
908 }
909 
LookupByContractID(const MonitorAutoLock &,const nsACString & aContractID)910 Maybe<EntryWrapper> nsComponentManagerImpl::LookupByContractID(
911     const MonitorAutoLock&, const nsACString& aContractID) {
912   if (const StaticModule* module =
913           StaticComponents::LookupByContractID(aContractID)) {
914     return Some(EntryWrapper(module));
915   }
916   if (nsFactoryEntry* entry = mContractIDs.Get(aContractID)) {
917     // UnregisterFactory might have left a stale nsFactoryEntry in
918     // mContractIDs, so we should check to see whether this entry has
919     // anything useful.
920     if (entry->mModule || entry->mFactory || entry->mServiceObject) {
921       return Some(EntryWrapper(entry));
922     }
923   }
924   return Nothing();
925 }
926 
FindFactory(const nsCID & aClass)927 already_AddRefed<nsIFactory> nsComponentManagerImpl::FindFactory(
928     const nsCID& aClass) {
929   Maybe<EntryWrapper> e = LookupByCID(aClass);
930   if (!e) {
931     return nullptr;
932   }
933 
934   return e->GetFactory();
935 }
936 
FindFactory(const char * aContractID,uint32_t aContractIDLen)937 already_AddRefed<nsIFactory> nsComponentManagerImpl::FindFactory(
938     const char* aContractID, uint32_t aContractIDLen) {
939   Maybe<EntryWrapper> entry =
940       LookupByContractID(nsDependentCString(aContractID, aContractIDLen));
941   if (!entry) {
942     return nullptr;
943   }
944 
945   return entry->GetFactory();
946 }
947 
948 /**
949  * GetClassObject()
950  *
951  * Given a classID, this finds the singleton ClassObject that implements the
952  * CID. Returns an interface of type aIID off the singleton classobject.
953  */
954 NS_IMETHODIMP
GetClassObject(const nsCID & aClass,const nsIID & aIID,void ** aResult)955 nsComponentManagerImpl::GetClassObject(const nsCID& aClass, const nsIID& aIID,
956                                        void** aResult) {
957   nsresult rv;
958 
959   if (MOZ_LOG_TEST(nsComponentManagerLog, LogLevel::Debug)) {
960     char* buf = aClass.ToString();
961     PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
962     if (buf) {
963       free(buf);
964     }
965   }
966 
967   MOZ_ASSERT(aResult != nullptr);
968 
969   nsCOMPtr<nsIFactory> factory = FindFactory(aClass);
970   if (!factory) {
971     return NS_ERROR_FACTORY_NOT_REGISTERED;
972   }
973 
974   rv = factory->QueryInterface(aIID, aResult);
975 
976   MOZ_LOG(
977       nsComponentManagerLog, LogLevel::Warning,
978       ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
979 
980   return rv;
981 }
982 
983 NS_IMETHODIMP
GetClassObjectByContractID(const char * aContractID,const nsIID & aIID,void ** aResult)984 nsComponentManagerImpl::GetClassObjectByContractID(const char* aContractID,
985                                                    const nsIID& aIID,
986                                                    void** aResult) {
987   if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aContractID)) {
988     return NS_ERROR_INVALID_ARG;
989   }
990 
991   nsresult rv;
992 
993   MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
994           ("nsComponentManager: GetClassObjectByContractID(%s)", aContractID));
995 
996   nsCOMPtr<nsIFactory> factory = FindFactory(aContractID, strlen(aContractID));
997   if (!factory) {
998     return NS_ERROR_FACTORY_NOT_REGISTERED;
999   }
1000 
1001   rv = factory->QueryInterface(aIID, aResult);
1002 
1003   MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
1004           ("\t\tGetClassObjectByContractID() %s",
1005            NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1006 
1007   return rv;
1008 }
1009 
1010 /**
1011  * CreateInstance()
1012  *
1013  * Create an instance of an object that implements an interface and belongs
1014  * to the implementation aClass using the factory. The factory is immediately
1015  * released and not held onto for any longer.
1016  */
1017 NS_IMETHODIMP
CreateInstance(const nsCID & aClass,nsISupports * aDelegate,const nsIID & aIID,void ** aResult)1018 nsComponentManagerImpl::CreateInstance(const nsCID& aClass,
1019                                        nsISupports* aDelegate,
1020                                        const nsIID& aIID, void** aResult) {
1021   // test this first, since there's no point in creating a component during
1022   // shutdown -- whether it's available or not would depend on the order it
1023   // occurs in the list
1024   if (gXPCOMShuttingDown) {
1025     // When processing shutdown, don't process new GetService() requests
1026 #ifdef SHOW_DENIED_ON_SHUTDOWN
1027     fprintf(stderr,
1028             "Creating new instance on shutdown. Denied.\n"
1029             "         CID: %s\n         IID: %s\n",
1030             AutoIDString(aClass).get(), AutoIDString(aIID).get());
1031 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1032     return NS_ERROR_UNEXPECTED;
1033   }
1034 
1035   if (!aResult) {
1036     return NS_ERROR_NULL_POINTER;
1037   }
1038   *aResult = nullptr;
1039 
1040   Maybe<EntryWrapper> entry = LookupByCID(aClass);
1041 
1042   if (!entry) {
1043     return NS_ERROR_FACTORY_NOT_REGISTERED;
1044   }
1045 
1046 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1047   if (entry->ServiceInstance()) {
1048     nsAutoCString message;
1049     message = "You are calling CreateInstance \""_ns + AutoIDString(aClass) +
1050               "\" when a service for this CID already exists!"_ns;
1051     NS_ERROR(message.get());
1052   }
1053 #endif
1054 
1055   nsresult rv;
1056   nsCOMPtr<nsIFactory> factory = entry->GetFactory();
1057   if (factory) {
1058     rv = factory->CreateInstance(aDelegate, aIID, aResult);
1059     if (NS_SUCCEEDED(rv) && !*aResult) {
1060       NS_ERROR("Factory did not return an object but returned success!");
1061       rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
1062     }
1063   } else {
1064     // Translate error values
1065     rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1066   }
1067 
1068   if (MOZ_LOG_TEST(nsComponentManagerLog, LogLevel::Warning)) {
1069     char* buf = aClass.ToString();
1070     MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
1071             ("nsComponentManager: CreateInstance(%s) %s", buf,
1072              NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1073     if (buf) {
1074       free(buf);
1075     }
1076   }
1077 
1078   return rv;
1079 }
1080 
1081 /**
1082  * CreateInstanceByContractID()
1083  *
1084  * A variant of CreateInstance() that creates an instance of the object that
1085  * implements the interface aIID and whose implementation has a contractID
1086  * aContractID.
1087  *
1088  * This is only a convenience routine that turns around can calls the
1089  * CreateInstance() with classid and iid.
1090  */
1091 NS_IMETHODIMP
CreateInstanceByContractID(const char * aContractID,nsISupports * aDelegate,const nsIID & aIID,void ** aResult)1092 nsComponentManagerImpl::CreateInstanceByContractID(const char* aContractID,
1093                                                    nsISupports* aDelegate,
1094                                                    const nsIID& aIID,
1095                                                    void** aResult) {
1096   if (NS_WARN_IF(!aContractID)) {
1097     return NS_ERROR_INVALID_ARG;
1098   }
1099 
1100   // test this first, since there's no point in creating a component during
1101   // shutdown -- whether it's available or not would depend on the order it
1102   // occurs in the list
1103   if (gXPCOMShuttingDown) {
1104     // When processing shutdown, don't process new GetService() requests
1105 #ifdef SHOW_DENIED_ON_SHUTDOWN
1106     fprintf(stderr,
1107             "Creating new instance on shutdown. Denied.\n"
1108             "  ContractID: %s\n         IID: %s\n",
1109             aContractID, AutoIDString(aIID).get());
1110 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1111     return NS_ERROR_UNEXPECTED;
1112   }
1113 
1114   if (!aResult) {
1115     return NS_ERROR_NULL_POINTER;
1116   }
1117   *aResult = nullptr;
1118 
1119   Maybe<EntryWrapper> entry =
1120       LookupByContractID(nsDependentCString(aContractID));
1121 
1122   if (!entry) {
1123     return NS_ERROR_FACTORY_NOT_REGISTERED;
1124   }
1125 
1126 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1127   if (entry->ServiceInstance()) {
1128     nsAutoCString message;
1129     message =
1130         "You are calling CreateInstance \""_ns +
1131         nsDependentCString(aContractID) +
1132         nsLiteralCString(
1133             "\" when a service for this CID already exists! "
1134             "Add it to abusedContracts to track down the service consumer.");
1135     NS_ERROR(message.get());
1136   }
1137 #endif
1138 
1139   nsresult rv;
1140   nsCOMPtr<nsIFactory> factory = entry->GetFactory();
1141   if (factory) {
1142     rv = factory->CreateInstance(aDelegate, aIID, aResult);
1143     if (NS_SUCCEEDED(rv) && !*aResult) {
1144       NS_ERROR("Factory did not return an object but returned success!");
1145       rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
1146     }
1147   } else {
1148     // Translate error values
1149     rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1150   }
1151 
1152   MOZ_LOG(nsComponentManagerLog, LogLevel::Warning,
1153           ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
1154            NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1155 
1156   return rv;
1157 }
1158 
FreeServices()1159 nsresult nsComponentManagerImpl::FreeServices() {
1160   NS_ASSERTION(gXPCOMShuttingDown,
1161                "Must be shutting down in order to free all services");
1162 
1163   if (!gXPCOMShuttingDown) {
1164     return NS_ERROR_FAILURE;
1165   }
1166 
1167   for (nsFactoryEntry* entry : mFactories.Values()) {
1168     entry->mFactory = nullptr;
1169     entry->mServiceObject = nullptr;
1170   }
1171 
1172   for (const auto& module : gStaticModules) {
1173     module.SetServiceInstance(nullptr);
1174   }
1175 
1176   return NS_OK;
1177 }
1178 
1179 // This should only ever be called within the monitor!
1180 nsComponentManagerImpl::PendingServiceInfo*
AddPendingService(const nsCID & aServiceCID,PRThread * aThread)1181 nsComponentManagerImpl::AddPendingService(const nsCID& aServiceCID,
1182                                           PRThread* aThread) {
1183   PendingServiceInfo* newInfo = mPendingServices.AppendElement();
1184   if (newInfo) {
1185     newInfo->cid = &aServiceCID;
1186     newInfo->thread = aThread;
1187   }
1188   return newInfo;
1189 }
1190 
1191 // This should only ever be called within the monitor!
RemovePendingService(MonitorAutoLock & aLock,const nsCID & aServiceCID)1192 void nsComponentManagerImpl::RemovePendingService(MonitorAutoLock& aLock,
1193                                                   const nsCID& aServiceCID) {
1194   uint32_t pendingCount = mPendingServices.Length();
1195   for (uint32_t index = 0; index < pendingCount; ++index) {
1196     const PendingServiceInfo& info = mPendingServices.ElementAt(index);
1197     if (info.cid->Equals(aServiceCID)) {
1198       mPendingServices.RemoveElementAt(index);
1199       aLock.NotifyAll();
1200       return;
1201     }
1202   }
1203 }
1204 
1205 // This should only ever be called within the monitor!
GetPendingServiceThread(const nsCID & aServiceCID) const1206 PRThread* nsComponentManagerImpl::GetPendingServiceThread(
1207     const nsCID& aServiceCID) const {
1208   uint32_t pendingCount = mPendingServices.Length();
1209   for (uint32_t index = 0; index < pendingCount; ++index) {
1210     const PendingServiceInfo& info = mPendingServices.ElementAt(index);
1211     if (info.cid->Equals(aServiceCID)) {
1212       return info.thread;
1213     }
1214   }
1215   return nullptr;
1216 }
1217 
GetServiceLocked(Maybe<MonitorAutoLock> & aLock,EntryWrapper & aEntry,const nsIID & aIID,void ** aResult)1218 nsresult nsComponentManagerImpl::GetServiceLocked(Maybe<MonitorAutoLock>& aLock,
1219                                                   EntryWrapper& aEntry,
1220                                                   const nsIID& aIID,
1221                                                   void** aResult) {
1222   MOZ_ASSERT(aLock.isSome());
1223   if (!aLock.isSome()) {
1224     return NS_ERROR_INVALID_ARG;
1225   }
1226 
1227   if (auto* service = aEntry.ServiceInstance()) {
1228     aLock.reset();
1229     return service->QueryInterface(aIID, aResult);
1230   }
1231 
1232   PRThread* currentPRThread = PR_GetCurrentThread();
1233   MOZ_ASSERT(currentPRThread, "This should never be null!");
1234 
1235   PRThread* pendingPRThread;
1236   while ((pendingPRThread = GetPendingServiceThread(aEntry.CID()))) {
1237     if (pendingPRThread == currentPRThread) {
1238       NS_ERROR("Recursive GetService!");
1239       return NS_ERROR_NOT_AVAILABLE;
1240     }
1241 
1242     aLock->Wait();
1243   }
1244 
1245   // It's still possible that the other thread failed to create the
1246   // service so we're not guaranteed to have an entry or service yet.
1247   if (auto* service = aEntry.ServiceInstance()) {
1248     aLock.reset();
1249     return service->QueryInterface(aIID, aResult);
1250   }
1251 
1252   DebugOnly<PendingServiceInfo*> newInfo =
1253       AddPendingService(aEntry.CID(), currentPRThread);
1254   NS_ASSERTION(newInfo, "Failed to add info to the array!");
1255 
1256   // We need to not be holding the service manager's lock while calling
1257   // CreateInstance, because it invokes user code which could try to re-enter
1258   // the service manager:
1259 
1260   nsCOMPtr<nsISupports> service;
1261   auto cleanup = MakeScopeExit([&]() {
1262     // `service` must be released after the lock is released, so if we fail and
1263     // still have a reference, release the lock before releasing it.
1264     if (service) {
1265       MOZ_ASSERT(aLock.isSome());
1266       aLock.reset();
1267       service = nullptr;
1268     }
1269   });
1270   nsresult rv;
1271   {
1272     MonitorAutoUnlock unlock(mLock);
1273     AUTO_PROFILER_MARKER_TEXT(
1274         "GetService", OTHER, MarkerStack::Capture(),
1275         nsDependentCString(nsIDToCString(aEntry.CID()).get()));
1276     rv = aEntry.CreateInstance(nullptr, aIID, getter_AddRefs(service));
1277   }
1278   if (NS_SUCCEEDED(rv) && !service) {
1279     NS_ERROR("Factory did not return an object but returned success");
1280     return NS_ERROR_SERVICE_NOT_AVAILABLE;
1281   }
1282 
1283 #ifdef DEBUG
1284   pendingPRThread = GetPendingServiceThread(aEntry.CID());
1285   MOZ_ASSERT(pendingPRThread == currentPRThread,
1286              "Pending service array has been changed!");
1287 #endif
1288   MOZ_ASSERT(aLock.isSome());
1289   RemovePendingService(*aLock, aEntry.CID());
1290 
1291   if (NS_FAILED(rv)) {
1292     return rv;
1293   }
1294 
1295   NS_ASSERTION(!aEntry.ServiceInstance(),
1296                "Created two instances of a service!");
1297 
1298   aEntry.SetServiceInstance(service.forget());
1299 
1300   aLock.reset();
1301 
1302   *aResult = do_AddRef(aEntry.ServiceInstance()).take();
1303   return NS_OK;
1304 }
1305 
1306 NS_IMETHODIMP
GetService(const nsCID & aClass,const nsIID & aIID,void ** aResult)1307 nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
1308                                    void** aResult) {
1309   // test this first, since there's no point in returning a service during
1310   // shutdown -- whether it's available or not would depend on the order it
1311   // occurs in the list
1312   if (gXPCOMShuttingDown) {
1313     // When processing shutdown, don't process new GetService() requests
1314 #ifdef SHOW_DENIED_ON_SHUTDOWN
1315     fprintf(stderr,
1316             "Getting service on shutdown. Denied.\n"
1317             "         CID: %s\n         IID: %s\n",
1318             AutoIDString(aClass).get(), AutoIDString(aIID).get());
1319 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1320     return NS_ERROR_UNEXPECTED;
1321   }
1322 
1323   Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1324 
1325   Maybe<EntryWrapper> entry = LookupByCID(*lock, aClass);
1326   if (!entry) {
1327     return NS_ERROR_FACTORY_NOT_REGISTERED;
1328   }
1329 
1330   return GetServiceLocked(lock, *entry, aIID, aResult);
1331 }
1332 
GetService(ModuleID aId,const nsIID & aIID,void ** aResult)1333 nsresult nsComponentManagerImpl::GetService(ModuleID aId, const nsIID& aIID,
1334                                             void** aResult) {
1335   const auto& entry = gStaticModules[size_t(aId)];
1336 
1337   // test this first, since there's no point in returning a service during
1338   // shutdown -- whether it's available or not would depend on the order it
1339   // occurs in the list
1340   if (gXPCOMShuttingDown) {
1341     // When processing shutdown, don't process new GetService() requests
1342 #ifdef SHOW_DENIED_ON_SHUTDOWN
1343     fprintf(stderr,
1344             "Getting service on shutdown. Denied.\n"
1345             "         CID: %s\n         IID: %s\n",
1346             AutoIDString(entry.CID()).get(), AutoIDString(aIID).get());
1347 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1348     return NS_ERROR_UNEXPECTED;
1349   }
1350 
1351   Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1352 
1353   Maybe<EntryWrapper> wrapper;
1354   if (entry.Overridable()) {
1355     // If we expect this service to be overridden by test code, we need to look
1356     // it up by contract ID every time.
1357     wrapper = LookupByContractID(*lock, entry.ContractID());
1358     if (!wrapper) {
1359       return NS_ERROR_FACTORY_NOT_REGISTERED;
1360     }
1361   } else if (!entry.Active()) {
1362     return NS_ERROR_FACTORY_NOT_REGISTERED;
1363   } else {
1364     wrapper.emplace(&entry);
1365   }
1366   return GetServiceLocked(lock, *wrapper, aIID, aResult);
1367 }
1368 
1369 NS_IMETHODIMP
IsServiceInstantiated(const nsCID & aClass,const nsIID & aIID,bool * aResult)1370 nsComponentManagerImpl::IsServiceInstantiated(const nsCID& aClass,
1371                                               const nsIID& aIID,
1372                                               bool* aResult) {
1373   // Now we want to get the service if we already got it. If not, we don't want
1374   // to create an instance of it. mmh!
1375 
1376   // test this first, since there's no point in returning a service during
1377   // shutdown -- whether it's available or not would depend on the order it
1378   // occurs in the list
1379   if (gXPCOMShuttingDown) {
1380     // When processing shutdown, don't process new GetService() requests
1381 #ifdef SHOW_DENIED_ON_SHUTDOWN
1382     fprintf(stderr,
1383             "Checking for service on shutdown. Denied.\n"
1384             "         CID: %s\n         IID: %s\n",
1385             AutoIDString(aClass).get(), AutoIDString(aIID).get());
1386 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1387     return NS_ERROR_UNEXPECTED;
1388   }
1389 
1390   if (Maybe<EntryWrapper> entry = LookupByCID(aClass)) {
1391     if (auto* service = entry->ServiceInstance()) {
1392       nsCOMPtr<nsISupports> instance;
1393       nsresult rv = service->QueryInterface(aIID, getter_AddRefs(instance));
1394       *aResult = (instance != nullptr);
1395       return rv;
1396     }
1397   }
1398 
1399   *aResult = false;
1400   return NS_OK;
1401 }
1402 
1403 NS_IMETHODIMP
IsServiceInstantiatedByContractID(const char * aContractID,const nsIID & aIID,bool * aResult)1404 nsComponentManagerImpl::IsServiceInstantiatedByContractID(
1405     const char* aContractID, const nsIID& aIID, bool* aResult) {
1406   // Now we want to get the service if we already got it. If not, we don't want
1407   // to create an instance of it. mmh!
1408 
1409   // test this first, since there's no point in returning a service during
1410   // shutdown -- whether it's available or not would depend on the order it
1411   // occurs in the list
1412   if (gXPCOMShuttingDown) {
1413     // When processing shutdown, don't process new GetService() requests
1414 #ifdef SHOW_DENIED_ON_SHUTDOWN
1415     fprintf(stderr,
1416             "Checking for service on shutdown. Denied.\n"
1417             "  ContractID: %s\n         IID: %s\n",
1418             aContractID, AutoIDString(aIID).get());
1419 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1420     return NS_ERROR_UNEXPECTED;
1421   }
1422 
1423   if (Maybe<EntryWrapper> entry =
1424           LookupByContractID(nsDependentCString(aContractID))) {
1425     if (auto* service = entry->ServiceInstance()) {
1426       nsCOMPtr<nsISupports> instance;
1427       nsresult rv = service->QueryInterface(aIID, getter_AddRefs(instance));
1428       *aResult = (instance != nullptr);
1429       return rv;
1430     }
1431   }
1432 
1433   *aResult = false;
1434   return NS_OK;
1435 }
1436 
1437 NS_IMETHODIMP
GetServiceByContractID(const char * aContractID,const nsIID & aIID,void ** aResult)1438 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
1439                                                const nsIID& aIID,
1440                                                void** aResult) {
1441   // test this first, since there's no point in returning a service during
1442   // shutdown -- whether it's available or not would depend on the order it
1443   // occurs in the list
1444   if (gXPCOMShuttingDown) {
1445     // When processing shutdown, don't process new GetService() requests
1446 #ifdef SHOW_DENIED_ON_SHUTDOWN
1447     fprintf(stderr,
1448             "Getting service on shutdown. Denied.\n"
1449             "  ContractID: %s\n         IID: %s\n",
1450             aContractID, AutoIDString(aIID).get());
1451 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1452     return NS_ERROR_UNEXPECTED;
1453   }
1454 
1455   AUTO_PROFILER_LABEL_DYNAMIC_CSTR_NONSENSITIVE("GetServiceByContractID", OTHER,
1456                                                 aContractID);
1457   Maybe<MonitorAutoLock> lock(std::in_place, mLock);
1458 
1459   Maybe<EntryWrapper> entry =
1460       LookupByContractID(*lock, nsDependentCString(aContractID));
1461   if (!entry) {
1462     return NS_ERROR_FACTORY_NOT_REGISTERED;
1463   }
1464 
1465   return GetServiceLocked(lock, *entry, aIID, aResult);
1466 }
1467 
1468 NS_IMETHODIMP
RegisterFactory(const nsCID & aClass,const char * aName,const char * aContractID,nsIFactory * aFactory)1469 nsComponentManagerImpl::RegisterFactory(const nsCID& aClass, const char* aName,
1470                                         const char* aContractID,
1471                                         nsIFactory* aFactory) {
1472   if (!aFactory) {
1473     // If a null factory is passed in, this call just wants to reset
1474     // the contract ID to point to an existing CID entry.
1475     if (!aContractID) {
1476       return NS_ERROR_INVALID_ARG;
1477     }
1478 
1479     nsDependentCString contractID(aContractID);
1480 
1481     MonitorAutoLock lock(mLock);
1482     nsFactoryEntry* oldf = mFactories.Get(&aClass);
1483     if (oldf) {
1484       StaticComponents::InvalidateContractID(contractID);
1485       mContractIDs.InsertOrUpdate(contractID, oldf);
1486       return NS_OK;
1487     }
1488 
1489     if (StaticComponents::LookupByCID(aClass)) {
1490       // If this is the CID of a static module, just reset the invalid bit of
1491       // the static entry for this contract ID, and assume it points to the
1492       // correct class.
1493       if (StaticComponents::InvalidateContractID(contractID, false)) {
1494         mContractIDs.Remove(contractID);
1495         return NS_OK;
1496       }
1497     }
1498     return NS_ERROR_FACTORY_NOT_REGISTERED;
1499   }
1500 
1501   auto f = MakeUnique<nsFactoryEntry>(aClass, aFactory);
1502 
1503   MonitorAutoLock lock(mLock);
1504   return mFactories.WithEntryHandle(f->mCIDEntry->cid, [&](auto&& entry) {
1505     if (entry) {
1506       return NS_ERROR_FACTORY_EXISTS;
1507     }
1508     if (StaticComponents::LookupByCID(*f->mCIDEntry->cid)) {
1509       return NS_ERROR_FACTORY_EXISTS;
1510     }
1511     if (aContractID) {
1512       nsDependentCString contractID(aContractID);
1513       mContractIDs.InsertOrUpdate(contractID, f.get());
1514       // We allow dynamically-registered contract IDs to override static
1515       // entries, so invalidate any static entry for this contract ID.
1516       StaticComponents::InvalidateContractID(contractID);
1517     }
1518     entry.Insert(f.release());
1519 
1520     return NS_OK;
1521   });
1522 }
1523 
1524 NS_IMETHODIMP
UnregisterFactory(const nsCID & aClass,nsIFactory * aFactory)1525 nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass,
1526                                           nsIFactory* aFactory) {
1527   // Don't release the dying factory or service object until releasing
1528   // the component manager monitor.
1529   nsCOMPtr<nsIFactory> dyingFactory;
1530   nsCOMPtr<nsISupports> dyingServiceObject;
1531 
1532   {
1533     MonitorAutoLock lock(mLock);
1534     auto entry = mFactories.Lookup(&aClass);
1535     nsFactoryEntry* f = entry ? entry.Data() : nullptr;
1536     if (!f || f->mFactory != aFactory) {
1537       // Note: We do not support unregistering static factories.
1538       return NS_ERROR_FACTORY_NOT_REGISTERED;
1539     }
1540 
1541     entry.Remove();
1542 
1543     // This might leave a stale contractid -> factory mapping in
1544     // place, so null out the factory entry (see
1545     // nsFactoryEntry::GetFactory)
1546     f->mFactory.swap(dyingFactory);
1547     f->mServiceObject.swap(dyingServiceObject);
1548   }
1549 
1550   return NS_OK;
1551 }
1552 
1553 NS_IMETHODIMP
AutoRegister(nsIFile * aLocation)1554 nsComponentManagerImpl::AutoRegister(nsIFile* aLocation) {
1555   XRE_AddManifestLocation(NS_EXTENSION_LOCATION, aLocation);
1556   return NS_OK;
1557 }
1558 
1559 NS_IMETHODIMP
AutoUnregister(nsIFile * aLocation)1560 nsComponentManagerImpl::AutoUnregister(nsIFile* aLocation) {
1561   NS_ERROR("AutoUnregister not implemented.");
1562   return NS_ERROR_NOT_IMPLEMENTED;
1563 }
1564 
1565 NS_IMETHODIMP
RegisterFactoryLocation(const nsCID & aCID,const char * aClassName,const char * aContractID,nsIFile * aFile,const char * aLoaderStr,const char * aType)1566 nsComponentManagerImpl::RegisterFactoryLocation(
1567     const nsCID& aCID, const char* aClassName, const char* aContractID,
1568     nsIFile* aFile, const char* aLoaderStr, const char* aType) {
1569   NS_ERROR("RegisterFactoryLocation not implemented.");
1570   return NS_ERROR_NOT_IMPLEMENTED;
1571 }
1572 
1573 NS_IMETHODIMP
UnregisterFactoryLocation(const nsCID & aCID,nsIFile * aFile)1574 nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID& aCID,
1575                                                   nsIFile* aFile) {
1576   NS_ERROR("UnregisterFactoryLocation not implemented.");
1577   return NS_ERROR_NOT_IMPLEMENTED;
1578 }
1579 
1580 NS_IMETHODIMP
IsCIDRegistered(const nsCID & aClass,bool * aResult)1581 nsComponentManagerImpl::IsCIDRegistered(const nsCID& aClass, bool* aResult) {
1582   *aResult = LookupByCID(aClass).isSome();
1583   return NS_OK;
1584 }
1585 
1586 NS_IMETHODIMP
IsContractIDRegistered(const char * aClass,bool * aResult)1587 nsComponentManagerImpl::IsContractIDRegistered(const char* aClass,
1588                                                bool* aResult) {
1589   if (NS_WARN_IF(!aClass)) {
1590     return NS_ERROR_INVALID_ARG;
1591   }
1592 
1593   Maybe<EntryWrapper> entry = LookupByContractID(nsDependentCString(aClass));
1594 
1595   *aResult = entry.isSome();
1596   return NS_OK;
1597 }
1598 
1599 NS_IMETHODIMP
GetContractIDs(nsTArray<nsCString> & aResult)1600 nsComponentManagerImpl::GetContractIDs(nsTArray<nsCString>& aResult) {
1601   aResult = ToTArray<nsTArray<nsCString>>(mContractIDs.Keys());
1602 
1603   for (const auto& entry : gContractEntries) {
1604     if (!entry.Invalid()) {
1605       aResult.AppendElement(entry.ContractID());
1606     }
1607   }
1608 
1609   return NS_OK;
1610 }
1611 
1612 NS_IMETHODIMP
CIDToContractID(const nsCID & aClass,char ** aResult)1613 nsComponentManagerImpl::CIDToContractID(const nsCID& aClass, char** aResult) {
1614   NS_ERROR("CIDTOContractID not implemented");
1615   return NS_ERROR_FACTORY_NOT_REGISTERED;
1616 }
1617 
1618 NS_IMETHODIMP
ContractIDToCID(const char * aContractID,nsCID ** aResult)1619 nsComponentManagerImpl::ContractIDToCID(const char* aContractID,
1620                                         nsCID** aResult) {
1621   {
1622     MonitorAutoLock lock(mLock);
1623     Maybe<EntryWrapper> entry =
1624         LookupByContractID(lock, nsDependentCString(aContractID));
1625     if (entry) {
1626       *aResult = (nsCID*)moz_xmalloc(sizeof(nsCID));
1627       **aResult = entry->CID();
1628       return NS_OK;
1629     }
1630   }
1631   *aResult = nullptr;
1632   return NS_ERROR_FACTORY_NOT_REGISTERED;
1633 }
1634 
MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf)1635 MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf)
1636 
1637 NS_IMETHODIMP
1638 nsComponentManagerImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
1639                                        nsISupports* aData, bool aAnonymize) {
1640   MOZ_COLLECT_REPORT("explicit/xpcom/component-manager", KIND_HEAP, UNITS_BYTES,
1641                      SizeOfIncludingThis(ComponentManagerMallocSizeOf),
1642                      "Memory used for the XPCOM component manager.");
1643 
1644   return NS_OK;
1645 }
1646 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const1647 size_t nsComponentManagerImpl::SizeOfIncludingThis(
1648     mozilla::MallocSizeOf aMallocSizeOf) const {
1649   size_t n = aMallocSizeOf(this);
1650 
1651   n += mFactories.ShallowSizeOfExcludingThis(aMallocSizeOf);
1652   for (const auto& data : mFactories.Values()) {
1653     n += data->SizeOfIncludingThis(aMallocSizeOf);
1654   }
1655 
1656   n += mContractIDs.ShallowSizeOfExcludingThis(aMallocSizeOf);
1657   for (const auto& key : mContractIDs.Keys()) {
1658     // We don't measure the nsFactoryEntry data because it's owned by
1659     // mFactories (which is measured above).
1660     n += key.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1661   }
1662 
1663   n += sExtraStaticModules->ShallowSizeOfIncludingThis(aMallocSizeOf);
1664   if (sModuleLocations) {
1665     n += sModuleLocations->ShallowSizeOfIncludingThis(aMallocSizeOf);
1666   }
1667 
1668   n += mKnownStaticModules.ShallowSizeOfExcludingThis(aMallocSizeOf);
1669   n += mKnownModules.ShallowSizeOfExcludingThis(aMallocSizeOf);
1670 
1671   n += mArena.SizeOfExcludingThis(aMallocSizeOf);
1672 
1673   n += mPendingServices.ShallowSizeOfExcludingThis(aMallocSizeOf);
1674 
1675   // Measurement of the following members may be added later if DMD finds it is
1676   // worthwhile:
1677   // - mMon
1678   // - sModuleLocations' entries
1679   // - mKnownStaticModules' entries?
1680   // - mKnownModules' keys and values?
1681 
1682   return n;
1683 }
1684 
1685 ////////////////////////////////////////////////////////////////////////////////
1686 // nsFactoryEntry
1687 ////////////////////////////////////////////////////////////////////////////////
1688 
nsFactoryEntry(const mozilla::Module::CIDEntry * aEntry,nsComponentManagerImpl::KnownModule * aModule)1689 nsFactoryEntry::nsFactoryEntry(const mozilla::Module::CIDEntry* aEntry,
1690                                nsComponentManagerImpl::KnownModule* aModule)
1691     : mCIDEntry(aEntry), mModule(aModule) {}
1692 
nsFactoryEntry(const nsCID & aCID,nsIFactory * aFactory)1693 nsFactoryEntry::nsFactoryEntry(const nsCID& aCID, nsIFactory* aFactory)
1694     : mCIDEntry(nullptr), mModule(nullptr), mFactory(aFactory) {
1695   auto* e = new mozilla::Module::CIDEntry();
1696   auto* cid = new nsCID;
1697   *cid = aCID;
1698   e->cid = cid;
1699   mCIDEntry = e;
1700 }
1701 
~nsFactoryEntry()1702 nsFactoryEntry::~nsFactoryEntry() {
1703   // If this was a RegisterFactory entry, we own the CIDEntry/CID
1704   if (!mModule) {
1705     delete mCIDEntry->cid;
1706     delete mCIDEntry;
1707   }
1708 }
1709 
GetFactory()1710 already_AddRefed<nsIFactory> nsFactoryEntry::GetFactory() {
1711   nsComponentManagerImpl::gComponentManager->mLock.AssertNotCurrentThreadOwns();
1712 
1713   if (!mFactory) {
1714     // RegisterFactory then UnregisterFactory can leave an entry in mContractIDs
1715     // pointing to an unusable nsFactoryEntry.
1716     if (!mModule) {
1717       return nullptr;
1718     }
1719 
1720     if (!mModule->Load()) {
1721       return nullptr;
1722     }
1723 
1724     // Don't set mFactory directly, it needs to be locked
1725     nsCOMPtr<nsIFactory> factory;
1726 
1727     if (mModule->Module()->getFactoryProc) {
1728       factory =
1729           mModule->Module()->getFactoryProc(*mModule->Module(), *mCIDEntry);
1730     } else if (mCIDEntry->getFactoryProc) {
1731       factory = mCIDEntry->getFactoryProc(*mModule->Module(), *mCIDEntry);
1732     } else {
1733       NS_ASSERTION(mCIDEntry->constructorProc, "no getfactory or constructor");
1734       factory = new mozilla::GenericFactory(mCIDEntry->constructorProc);
1735     }
1736     if (!factory) {
1737       return nullptr;
1738     }
1739 
1740     MonitorAutoLock lock(nsComponentManagerImpl::gComponentManager->mLock);
1741     // Threads can race to set mFactory
1742     if (!mFactory) {
1743       factory.swap(mFactory);
1744     }
1745   }
1746   nsCOMPtr<nsIFactory> factory = mFactory;
1747   return factory.forget();
1748 }
1749 
CreateInstance(nsISupports * aOuter,const nsIID & aIID,void ** aResult)1750 nsresult nsFactoryEntry::CreateInstance(nsISupports* aOuter, const nsIID& aIID,
1751                                         void** aResult) {
1752   nsCOMPtr<nsIFactory> factory = GetFactory();
1753   NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
1754   return factory->CreateInstance(aOuter, aIID, aResult);
1755 }
1756 
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)1757 size_t nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
1758   size_t n = aMallocSizeOf(this);
1759 
1760   // Measurement of the following members may be added later if DMD finds it is
1761   // worthwhile:
1762   // - mCIDEntry;
1763   // - mModule;
1764   // - mFactory;
1765   // - mServiceObject;
1766 
1767   return n;
1768 }
1769 
1770 ////////////////////////////////////////////////////////////////////////////////
1771 // Static Access Functions
1772 ////////////////////////////////////////////////////////////////////////////////
1773 
NS_GetComponentManager(nsIComponentManager ** aResult)1774 nsresult NS_GetComponentManager(nsIComponentManager** aResult) {
1775   if (!nsComponentManagerImpl::gComponentManager) {
1776     return NS_ERROR_NOT_INITIALIZED;
1777   }
1778 
1779   NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1780   return NS_OK;
1781 }
1782 
NS_GetServiceManager(nsIServiceManager ** aResult)1783 nsresult NS_GetServiceManager(nsIServiceManager** aResult) {
1784   if (!nsComponentManagerImpl::gComponentManager) {
1785     return NS_ERROR_NOT_INITIALIZED;
1786   }
1787 
1788   NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1789   return NS_OK;
1790 }
1791 
NS_GetComponentRegistrar(nsIComponentRegistrar ** aResult)1792 nsresult NS_GetComponentRegistrar(nsIComponentRegistrar** aResult) {
1793   if (!nsComponentManagerImpl::gComponentManager) {
1794     return NS_ERROR_NOT_INITIALIZED;
1795   }
1796 
1797   NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1798   return NS_OK;
1799 }
1800 
1801 EXPORT_XPCOM_API(nsresult)
XRE_AddStaticComponent(const mozilla::Module * aComponent)1802 XRE_AddStaticComponent(const mozilla::Module* aComponent) {
1803   nsComponentManagerImpl::InitializeStaticModules();
1804   sExtraStaticModules->AppendElement(aComponent);
1805 
1806   if (nsComponentManagerImpl::gComponentManager &&
1807       nsComponentManagerImpl::NORMAL ==
1808           nsComponentManagerImpl::gComponentManager->mStatus) {
1809     nsComponentManagerImpl::gComponentManager->RegisterModule(aComponent);
1810   }
1811 
1812   return NS_OK;
1813 }
1814 
1815 NS_IMETHODIMP
AddBootstrappedManifestLocation(nsIFile * aLocation)1816 nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation) {
1817   NS_ENSURE_ARG_POINTER(aLocation);
1818 
1819   nsString path;
1820   nsresult rv = aLocation->GetPath(path);
1821   if (NS_FAILED(rv)) {
1822     return rv;
1823   }
1824 
1825   if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
1826     return XRE_AddJarManifestLocation(NS_BOOTSTRAPPED_LOCATION, aLocation);
1827   }
1828 
1829   nsCOMPtr<nsIFile> manifest = CloneAndAppend(aLocation, "chrome.manifest"_ns);
1830   return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION, manifest);
1831 }
1832 
1833 NS_IMETHODIMP
RemoveBootstrappedManifestLocation(nsIFile * aLocation)1834 nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation) {
1835   NS_ENSURE_ARG_POINTER(aLocation);
1836 
1837   nsCOMPtr<nsIChromeRegistry> cr = mozilla::services::GetChromeRegistry();
1838   if (!cr) {
1839     return NS_ERROR_FAILURE;
1840   }
1841 
1842   nsString path;
1843   nsresult rv = aLocation->GetPath(path);
1844   if (NS_FAILED(rv)) {
1845     return rv;
1846   }
1847 
1848   nsComponentManagerImpl::ComponentLocation elem;
1849   elem.type = NS_BOOTSTRAPPED_LOCATION;
1850 
1851   if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
1852     elem.location.Init(aLocation, "chrome.manifest");
1853   } else {
1854     nsCOMPtr<nsIFile> lf = CloneAndAppend(aLocation, "chrome.manifest"_ns);
1855     elem.location.Init(lf);
1856   }
1857 
1858   // Remove reference.
1859   nsComponentManagerImpl::sModuleLocations->RemoveElement(
1860       elem, ComponentLocationComparator());
1861 
1862   rv = cr->CheckForNewChrome();
1863   return rv;
1864 }
1865 
1866 NS_IMETHODIMP
GetComponentJSMs(nsIUTF8StringEnumerator ** aJSMs)1867 nsComponentManagerImpl::GetComponentJSMs(nsIUTF8StringEnumerator** aJSMs) {
1868   nsCOMPtr<nsIUTF8StringEnumerator> result =
1869       StaticComponents::GetComponentJSMs();
1870   result.forget(aJSMs);
1871   return NS_OK;
1872 }
1873 
1874 NS_IMETHODIMP
GetManifestLocations(nsIArray ** aLocations)1875 nsComponentManagerImpl::GetManifestLocations(nsIArray** aLocations) {
1876   NS_ENSURE_ARG_POINTER(aLocations);
1877   *aLocations = nullptr;
1878 
1879   if (!sModuleLocations) {
1880     return NS_ERROR_NOT_INITIALIZED;
1881   }
1882 
1883   nsCOMPtr<nsIMutableArray> locations = nsArray::Create();
1884   nsresult rv;
1885   for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
1886     ComponentLocation& l = sModuleLocations->ElementAt(i);
1887     FileLocation loc = l.location;
1888     nsCString uriString;
1889     loc.GetURIString(uriString);
1890     nsCOMPtr<nsIURI> uri;
1891     rv = NS_NewURI(getter_AddRefs(uri), uriString);
1892     if (NS_SUCCEEDED(rv)) {
1893       locations->AppendElement(uri);
1894     }
1895   }
1896 
1897   locations.forget(aLocations);
1898   return NS_OK;
1899 }
1900 
1901 EXPORT_XPCOM_API(nsresult)
XRE_AddManifestLocation(NSLocationType aType,nsIFile * aLocation)1902 XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation) {
1903   nsComponentManagerImpl::InitializeModuleLocations();
1904   nsComponentManagerImpl::ComponentLocation* c =
1905       nsComponentManagerImpl::sModuleLocations->AppendElement();
1906   c->type = aType;
1907   c->location.Init(aLocation);
1908 
1909   if (nsComponentManagerImpl::gComponentManager &&
1910       nsComponentManagerImpl::NORMAL ==
1911           nsComponentManagerImpl::gComponentManager->mStatus) {
1912     nsComponentManagerImpl::gComponentManager->RegisterManifest(
1913         aType, c->location, false);
1914   }
1915 
1916   return NS_OK;
1917 }
1918 
1919 EXPORT_XPCOM_API(nsresult)
XRE_AddJarManifestLocation(NSLocationType aType,nsIFile * aLocation)1920 XRE_AddJarManifestLocation(NSLocationType aType, nsIFile* aLocation) {
1921   nsComponentManagerImpl::InitializeModuleLocations();
1922   nsComponentManagerImpl::ComponentLocation* c =
1923       nsComponentManagerImpl::sModuleLocations->AppendElement();
1924 
1925   c->type = aType;
1926   c->location.Init(aLocation, "chrome.manifest");
1927 
1928   if (nsComponentManagerImpl::gComponentManager &&
1929       nsComponentManagerImpl::NORMAL ==
1930           nsComponentManagerImpl::gComponentManager->mStatus) {
1931     nsComponentManagerImpl::gComponentManager->RegisterManifest(
1932         aType, c->location, false);
1933   }
1934 
1935   return NS_OK;
1936 }
1937 
1938 // Expose some important global interfaces to rust for the rust xpcom API. These
1939 // methods return a non-owning reference to the component manager, which should
1940 // live for the lifetime of XPCOM.
1941 extern "C" {
1942 
Gecko_GetComponentManager()1943 const nsIComponentManager* Gecko_GetComponentManager() {
1944   return nsComponentManagerImpl::gComponentManager;
1945 }
1946 
Gecko_GetServiceManager()1947 const nsIServiceManager* Gecko_GetServiceManager() {
1948   return nsComponentManagerImpl::gComponentManager;
1949 }
1950 
Gecko_GetComponentRegistrar()1951 const nsIComponentRegistrar* Gecko_GetComponentRegistrar() {
1952   return nsComponentManagerImpl::gComponentManager;
1953 }
1954 }
1955