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