Fix typo in 9b54bd30006c008b4a951331b273613d5bac3abf
[pm.git] / xpcom / components / nsComponentManager.cpp
blobb2e588ffa1edb1880c71ff5656452db800f19d09
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 * This Original Code has been modified by IBM Corporation.
8 * Modifications made by IBM described herein are
9 * Copyright (c) International Business Machines
10 * Corporation, 2000
12 * Modifications to Mozilla code or documentation
13 * identified per MPL Section 3.3
15 * Date Modified by Description of modification
16 * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
19 #include <stdlib.h>
20 #include "nscore.h"
21 #include "nsISupports.h"
22 #include "nspr.h"
23 #include "nsCRT.h" // for atoll
25 // Arena used by component manager for storing contractid string, dll
26 // location strings and small objects
27 // CAUTION: Arena align mask needs to be defined before including plarena.h
28 // currently from nsComponentManager.h
29 #define PL_ARENA_CONST_ALIGN_MASK 7
30 #define NS_CM_BLOCK_SIZE (1024 * 8)
32 #include "nsCategoryManager.h"
33 #include "nsCOMPtr.h"
34 #include "nsComponentManager.h"
35 #include "nsDirectoryService.h"
36 #include "nsDirectoryServiceDefs.h"
37 #include "nsCategoryManager.h"
38 #include "nsCategoryManagerUtils.h"
39 #include "xptiprivate.h"
40 #include "mozilla/MemoryReporting.h"
41 #include "mozilla/XPTInterfaceInfoManager.h"
42 #include "nsIConsoleService.h"
43 #include "nsIObserverService.h"
44 #include "nsISimpleEnumerator.h"
45 #include "nsIStringEnumerator.h"
46 #include "nsXPCOM.h"
47 #include "nsXPCOMPrivate.h"
48 #include "nsISupportsPrimitives.h"
49 #include "nsIClassInfo.h"
50 #include "nsLocalFile.h"
51 #include "nsReadableUtils.h"
52 #include "nsString.h"
53 #include "nsXPIDLString.h"
54 #include "prcmon.h"
55 #include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself...
56 #include "nsThreadUtils.h"
57 #include "prthread.h"
58 #include "private/pprthred.h"
59 #include "nsTArray.h"
60 #include "prio.h"
61 #include "ManifestParser.h"
62 #include "mozilla/Services.h"
64 #include "mozilla/GenericFactory.h"
65 #include "nsSupportsPrimitives.h"
66 #include "nsArray.h"
67 #include "nsIMutableArray.h"
68 #include "nsArrayEnumerator.h"
69 #include "nsStringEnumerator.h"
70 #include "mozilla/FileUtils.h"
71 #include "nsNetUtil.h"
72 #include "nsDataHashtable.h"
74 #include <new> // for placement new
76 #include "mozilla/Omnijar.h"
78 #include "prlog.h"
80 using namespace mozilla;
82 PRLogModuleInfo* nsComponentManagerLog = nullptr;
84 #if 0 || defined (DEBUG_timeless)
85 #define SHOW_DENIED_ON_SHUTDOWN
86 #define SHOW_CI_ON_EXISTING_SERVICE
87 #endif
89 // Bloated registry buffer size to improve startup performance -- needs to
90 // be big enough to fit the entire file into memory or it'll thrash.
91 // 512K is big enough to allow for some future growth in the registry.
92 #define BIG_REGISTRY_BUFLEN (512*1024)
94 // Common Key Names
95 const char xpcomComponentsKeyName[] = "software/mozilla/XPCOM/components";
96 const char xpcomKeyName[] = "software/mozilla/XPCOM";
98 // Common Value Names
99 const char fileSizeValueName[] = "FileSize";
100 const char lastModValueName[] = "LastModTimeStamp";
101 const char nativeComponentType[] = "application/x-mozilla-native";
102 const char staticComponentType[] = "application/x-mozilla-static";
104 NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID);
106 #define UID_STRING_LENGTH 39
108 #ifdef MOZ_B2G_LOADER
109 typedef nsDataHashtable<nsCStringHashKey, bool> XPTIInfosBookType;
110 static XPTIInfosBookType* sXPTIInfosBook = nullptr;
112 static XPTIInfosBookType*
113 GetXPTIInfosBook()
115 if (!sXPTIInfosBook) {
116 sXPTIInfosBook = new XPTIInfosBookType;
118 return sXPTIInfosBook;
121 static bool
122 IsRegisteredXPTIInfo(FileLocation& aFile)
124 nsAutoCString uri;
125 aFile.GetURIString(uri);
126 return GetXPTIInfosBook()->Get(uri);
129 static void
130 MarkRegisteredXPTIInfo(FileLocation& aFile)
132 nsAutoCString uri;
133 aFile.GetURIString(uri);
134 GetXPTIInfosBook()->Put(uri, true);
136 #endif /* MOZ_B2G_LOADER */
138 nsresult
139 nsGetServiceFromCategory::operator()(const nsIID& aIID,
140 void** aInstancePtr) const
142 nsresult rv;
143 nsXPIDLCString value;
144 nsCOMPtr<nsICategoryManager> catman;
145 nsComponentManagerImpl* compMgr = nsComponentManagerImpl::gComponentManager;
146 if (!compMgr) {
147 rv = NS_ERROR_NOT_INITIALIZED;
148 goto error;
151 if (!mCategory || !mEntry) {
152 // when categories have defaults, use that for null mEntry
153 rv = NS_ERROR_NULL_POINTER;
154 goto error;
157 rv = compMgr->nsComponentManagerImpl::GetService(kCategoryManagerCID,
158 NS_GET_IID(nsICategoryManager),
159 getter_AddRefs(catman));
160 if (NS_FAILED(rv)) {
161 goto error;
164 /* find the contractID for category.entry */
165 rv = catman->GetCategoryEntry(mCategory, mEntry,
166 getter_Copies(value));
167 if (NS_FAILED(rv)) {
168 goto error;
170 if (!value) {
171 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
172 goto error;
175 rv = compMgr->nsComponentManagerImpl::GetServiceByContractID(value,
176 aIID,
177 aInstancePtr);
178 if (NS_FAILED(rv)) {
179 error:
180 *aInstancePtr = 0;
182 if (mErrorPtr) {
183 *mErrorPtr = rv;
185 return rv;
188 ////////////////////////////////////////////////////////////////////////////////
189 // Arena helper functions
190 ////////////////////////////////////////////////////////////////////////////////
191 char*
192 ArenaStrndup(const char* aStr, uint32_t aLen, PLArenaPool* aArena)
194 void* mem;
195 // Include trailing null in the aLen
196 PL_ARENA_ALLOCATE(mem, aArena, aLen + 1);
197 if (mem) {
198 memcpy(mem, aStr, aLen + 1);
200 return static_cast<char*>(mem);
203 char*
204 ArenaStrdup(const char* aStr, PLArenaPool* aArena)
206 return ArenaStrndup(aStr, strlen(aStr), aArena);
209 // GetService and a few other functions need to exit their mutex mid-function
210 // without reentering it later in the block. This class supports that
211 // style of early-exit that MutexAutoUnlock doesn't.
213 namespace {
215 class MOZ_STACK_CLASS MutexLock
217 public:
218 explicit MutexLock(SafeMutex& aMutex)
219 : mMutex(aMutex)
220 , mLocked(false)
222 Lock();
225 ~MutexLock()
227 if (mLocked) {
228 Unlock();
232 void Lock()
234 NS_ASSERTION(!mLocked, "Re-entering a mutex");
235 mMutex.Lock();
236 mLocked = true;
239 void Unlock()
241 NS_ASSERTION(mLocked, "Exiting a mutex that isn't held!");
242 mMutex.Unlock();
243 mLocked = false;
246 private:
247 SafeMutex& mMutex;
248 bool mLocked;
251 } // anonymous namespace
253 // this is safe to call during InitXPCOM
254 static already_AddRefed<nsIFile>
255 GetLocationFromDirectoryService(const char* aProp)
257 nsCOMPtr<nsIProperties> directoryService;
258 nsDirectoryService::Create(nullptr,
259 NS_GET_IID(nsIProperties),
260 getter_AddRefs(directoryService));
262 if (!directoryService) {
263 return nullptr;
266 nsCOMPtr<nsIFile> file;
267 nsresult rv = directoryService->Get(aProp,
268 NS_GET_IID(nsIFile),
269 getter_AddRefs(file));
270 if (NS_FAILED(rv)) {
271 return nullptr;
274 return file.forget();
277 static already_AddRefed<nsIFile>
278 CloneAndAppend(nsIFile* aBase, const nsACString& aAppend)
280 nsCOMPtr<nsIFile> f;
281 aBase->Clone(getter_AddRefs(f));
282 if (!f) {
283 return nullptr;
286 f->AppendNative(aAppend);
287 return f.forget();
290 ////////////////////////////////////////////////////////////////////////////////
291 // nsComponentManagerImpl
292 ////////////////////////////////////////////////////////////////////////////////
294 nsresult
295 nsComponentManagerImpl::Create(nsISupports* aOuter, REFNSIID aIID,
296 void** aResult)
298 if (aOuter) {
299 return NS_ERROR_NO_AGGREGATION;
302 if (!gComponentManager) {
303 return NS_ERROR_FAILURE;
306 return gComponentManager->QueryInterface(aIID, aResult);
309 static const int CONTRACTID_HASHTABLE_INITIAL_LENGTH = 1024;
311 nsComponentManagerImpl::nsComponentManagerImpl()
312 : mFactories(CONTRACTID_HASHTABLE_INITIAL_LENGTH)
313 , mContractIDs(CONTRACTID_HASHTABLE_INITIAL_LENGTH)
314 , mLock("nsComponentManagerImpl.mLock")
315 , mStatus(NOT_INITIALIZED)
319 nsTArray<const mozilla::Module*>* nsComponentManagerImpl::sStaticModules;
321 NSMODULE_DEFN(start_kPStaticModules);
322 NSMODULE_DEFN(end_kPStaticModules);
324 /* The content between start_kPStaticModules and end_kPStaticModules is gathered
325 * by the linker from various objects containing symbols in a specific section.
326 * ASAN considers (rightfully) the use of this content as a global buffer
327 * overflow. But this is a deliberate and well-considered choice, with no proper
328 * way to make ASAN happy. */
329 MOZ_ASAN_BLACKLIST
330 /* static */ void
331 nsComponentManagerImpl::InitializeStaticModules()
333 if (sStaticModules) {
334 return;
337 sStaticModules = new nsTArray<const mozilla::Module*>;
338 for (const mozilla::Module * const* staticModules =
339 &NSMODULE_NAME(start_kPStaticModules) + 1;
340 staticModules < &NSMODULE_NAME(end_kPStaticModules); ++staticModules)
341 if (*staticModules) { // ASAN adds padding
342 sStaticModules->AppendElement(*staticModules);
346 nsTArray<nsComponentManagerImpl::ComponentLocation>*
347 nsComponentManagerImpl::sModuleLocations;
349 /* static */ void
350 nsComponentManagerImpl::InitializeModuleLocations()
352 if (sModuleLocations) {
353 return;
356 sModuleLocations = new nsTArray<ComponentLocation>;
359 nsresult
360 nsComponentManagerImpl::Init()
362 PR_ASSERT(NOT_INITIALIZED == mStatus);
364 if (!nsComponentManagerLog) {
365 nsComponentManagerLog = PR_NewLogModule("nsComponentManager");
368 // Initialize our arena
369 PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE);
371 nsCOMPtr<nsIFile> greDir =
372 GetLocationFromDirectoryService(NS_GRE_DIR);
373 nsCOMPtr<nsIFile> appDir =
374 GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR);
376 InitializeStaticModules();
378 nsresult rv = mNativeModuleLoader.Init();
379 if (NS_FAILED(rv)) {
380 return rv;
383 nsCategoryManager::GetSingleton()->SuppressNotifications(true);
385 RegisterModule(&kXPCOMModule, nullptr);
387 for (uint32_t i = 0; i < sStaticModules->Length(); ++i) {
388 RegisterModule((*sStaticModules)[i], nullptr);
391 // The overall order in which chrome.manifests are expected to be treated
392 // is the following:
393 // - greDir
394 // - greDir's omni.ja
395 // - appDir
396 // - appDir's omni.ja
398 InitializeModuleLocations();
399 ComponentLocation* cl = sModuleLocations->AppendElement();
400 nsCOMPtr<nsIFile> lf = CloneAndAppend(greDir,
401 NS_LITERAL_CSTRING("chrome.manifest"));
402 cl->type = NS_COMPONENT_LOCATION;
403 cl->location.Init(lf);
405 nsRefPtr<nsZipArchive> greOmnijar =
406 mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
407 if (greOmnijar) {
408 cl = sModuleLocations->AppendElement();
409 cl->type = NS_COMPONENT_LOCATION;
410 cl->location.Init(greOmnijar, "chrome.manifest");
413 bool equals = false;
414 appDir->Equals(greDir, &equals);
415 if (!equals) {
416 cl = sModuleLocations->AppendElement();
417 cl->type = NS_COMPONENT_LOCATION;
418 lf = CloneAndAppend(appDir, NS_LITERAL_CSTRING("chrome.manifest"));
419 cl->location.Init(lf);
422 nsRefPtr<nsZipArchive> appOmnijar =
423 mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
424 if (appOmnijar) {
425 cl = sModuleLocations->AppendElement();
426 cl->type = NS_COMPONENT_LOCATION;
427 cl->location.Init(appOmnijar, "chrome.manifest");
430 RereadChromeManifests(false);
432 nsCategoryManager::GetSingleton()->SuppressNotifications(false);
434 RegisterWeakMemoryReporter(this);
436 // Unfortunately, we can't register the nsCategoryManager memory reporter
437 // in its constructor (which is triggered by the GetSingleton() call
438 // above) because the memory reporter manager isn't initialized at that
439 // point. So we wait until now.
440 nsCategoryManager::GetSingleton()->InitMemoryReporter();
442 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
443 ("nsComponentManager: Initialized."));
445 mStatus = NORMAL;
447 return NS_OK;
450 void
451 nsComponentManagerImpl::RegisterModule(const mozilla::Module* aModule,
452 FileLocation* aFile)
454 mLock.AssertNotCurrentThreadOwns();
457 // Scope the monitor so that we don't hold it while calling into the
458 // category manager.
459 MutexLock lock(mLock);
461 KnownModule* m;
462 if (aFile) {
463 nsCString uri;
464 aFile->GetURIString(uri);
465 NS_ASSERTION(!mKnownModules.Get(uri),
466 "Must not register a binary module twice.");
468 m = new KnownModule(aModule, *aFile);
469 mKnownModules.Put(uri, m);
470 } else {
471 m = new KnownModule(aModule);
472 mKnownStaticModules.AppendElement(m);
475 if (aModule->mCIDs) {
476 const mozilla::Module::CIDEntry* entry;
477 for (entry = aModule->mCIDs; entry->cid; ++entry) {
478 RegisterCIDEntryLocked(entry, m);
482 if (aModule->mContractIDs) {
483 const mozilla::Module::ContractIDEntry* entry;
484 for (entry = aModule->mContractIDs; entry->contractid; ++entry) {
485 RegisterContractIDLocked(entry);
487 MOZ_ASSERT(!entry->cid, "Incorrectly terminated contract list");
491 if (aModule->mCategoryEntries) {
492 const mozilla::Module::CategoryEntry* entry;
493 for (entry = aModule->mCategoryEntries; entry->category; ++entry)
494 nsCategoryManager::GetSingleton()->AddCategoryEntry(entry->category,
495 entry->entry,
496 entry->value);
500 static bool
501 ProcessSelectorMatches(Module::ProcessSelector aSelector)
503 if (aSelector == Module::ANY_PROCESS) {
504 return true;
507 GoannaProcessType type = XRE_GetProcessType();
508 switch (aSelector) {
509 case Module::MAIN_PROCESS_ONLY:
510 return type == GoannaProcessType_Default;
511 case Module::CONTENT_PROCESS_ONLY:
512 return type == GoannaProcessType_Content;
513 default:
514 MOZ_CRASH("invalid process aSelector");
518 void
519 nsComponentManagerImpl::RegisterCIDEntryLocked(
520 const mozilla::Module::CIDEntry* aEntry,
521 KnownModule* aModule)
523 mLock.AssertCurrentThreadOwns();
525 if (!ProcessSelectorMatches(aEntry->processSelector)) {
526 return;
529 nsFactoryEntry* f = mFactories.Get(*aEntry->cid);
530 if (f) {
531 NS_WARNING("Re-registering a CID?");
533 char idstr[NSID_LENGTH];
534 aEntry->cid->ToProvidedString(idstr);
536 nsCString existing;
537 if (f->mModule) {
538 existing = f->mModule->Description();
539 } else {
540 existing = "<unknown module>";
542 SafeMutexAutoUnlock unlock(mLock);
543 LogMessage("While registering XPCOM module %s, trying to re-register CID '%s' already registered by %s.",
544 aModule->Description().get(),
545 idstr,
546 existing.get());
547 return;
550 f = new nsFactoryEntry(aEntry, aModule);
551 mFactories.Put(*aEntry->cid, f);
554 void
555 nsComponentManagerImpl::RegisterContractIDLocked(
556 const mozilla::Module::ContractIDEntry* aEntry)
558 mLock.AssertCurrentThreadOwns();
560 if (!ProcessSelectorMatches(aEntry->processSelector)) {
561 return;
564 nsFactoryEntry* f = mFactories.Get(*aEntry->cid);
565 if (!f) {
566 NS_WARNING("No CID found when attempting to map contract ID");
568 char idstr[NSID_LENGTH];
569 aEntry->cid->ToProvidedString(idstr);
571 SafeMutexAutoUnlock unlock(mLock);
572 LogMessage("Could not map contract ID '%s' to CID %s because no implementation of the CID is registered.",
573 aEntry->contractid,
574 idstr);
576 return;
579 mContractIDs.Put(nsDependentCString(aEntry->contractid), f);
582 static void
583 CutExtension(nsCString& aPath)
585 int32_t dotPos = aPath.RFindChar('.');
586 if (kNotFound == dotPos) {
587 aPath.Truncate();
588 } else {
589 aPath.Cut(0, dotPos + 1);
593 static void
594 DoRegisterManifest(NSLocationType aType,
595 FileLocation& aFile,
596 bool aChromeOnly,
597 bool aXPTOnly)
599 MOZ_ASSERT(!aXPTOnly || !nsComponentManagerImpl::gComponentManager);
600 uint32_t len;
601 FileLocation::Data data;
602 nsAutoArrayPtr<char> buf;
603 nsresult rv = aFile.GetData(data);
604 if (NS_SUCCEEDED(rv)) {
605 rv = data.GetSize(&len);
607 if (NS_SUCCEEDED(rv)) {
608 buf = new char[len + 1];
609 rv = data.Copy(buf, len);
611 if (NS_SUCCEEDED(rv)) {
612 buf[len] = '\0';
613 ParseManifest(aType, aFile, buf, aChromeOnly, aXPTOnly);
617 void
618 nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
619 FileLocation& aFile,
620 bool aChromeOnly)
622 DoRegisterManifest(aType, aFile, aChromeOnly, false);
625 void
626 nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& aCx,
627 int aLineNo, char* const* aArgv)
629 char* file = aArgv[0];
630 FileLocation f(aCx.mFile, file);
631 RegisterManifest(aCx.mType, f, aCx.mChromeOnly);
634 void
635 nsComponentManagerImpl::ManifestBinaryComponent(ManifestProcessingContext& aCx,
636 int aLineNo,
637 char* const* aArgv)
639 if (aCx.mFile.IsZip()) {
640 NS_WARNING("Cannot load binary components from a jar.");
641 LogMessageWithContext(aCx.mFile, aLineNo,
642 "Cannot load binary components from a jar.");
643 return;
646 FileLocation f(aCx.mFile, aArgv[0]);
647 nsCString uri;
648 f.GetURIString(uri);
650 if (mKnownModules.Get(uri)) {
651 NS_WARNING("Attempting to register a binary component twice.");
652 LogMessageWithContext(aCx.mFile, aLineNo,
653 "Attempting to register a binary component twice.");
654 return;
657 const mozilla::Module* m = mNativeModuleLoader.LoadModule(f);
658 // The native module loader should report an error here, we don't have to
659 if (!m) {
660 return;
663 RegisterModule(m, &f);
666 static void
667 DoRegisterXPT(FileLocation& aFile)
669 #ifdef MOZ_B2G_LOADER
670 if (IsRegisteredXPTIInfo(aFile)) {
671 return;
673 #endif
675 uint32_t len;
676 FileLocation::Data data;
677 nsAutoArrayPtr<char> buf;
678 nsresult rv = aFile.GetData(data);
679 if (NS_SUCCEEDED(rv)) {
680 rv = data.GetSize(&len);
682 if (NS_SUCCEEDED(rv)) {
683 buf = new char[len];
684 rv = data.Copy(buf, len);
686 if (NS_SUCCEEDED(rv)) {
687 XPTInterfaceInfoManager::GetSingleton()->RegisterBuffer(buf, len);
688 #ifdef MOZ_B2G_LOADER
689 MarkRegisteredXPTIInfo(aFile);
690 #endif
691 } else {
692 nsCString uri;
693 aFile.GetURIString(uri);
694 LogMessage("Could not read '%s'.", uri.get());
698 void
699 nsComponentManagerImpl::ManifestXPT(ManifestProcessingContext& aCx,
700 int aLineNo, char* const* aArgv)
702 FileLocation f(aCx.mFile, aArgv[0]);
703 DoRegisterXPT(f);
706 void
707 nsComponentManagerImpl::ManifestComponent(ManifestProcessingContext& aCx,
708 int aLineNo, char* const* aArgv)
710 mLock.AssertNotCurrentThreadOwns();
712 char* id = aArgv[0];
713 char* file = aArgv[1];
715 nsID cid;
716 if (!cid.Parse(id)) {
717 LogMessageWithContext(aCx.mFile, aLineNo,
718 "Malformed CID: '%s'.", id);
719 return;
722 // Precompute the hash/file data outside of the lock
723 FileLocation fl(aCx.mFile, file);
724 nsCString hash;
725 fl.GetURIString(hash);
727 MutexLock lock(mLock);
728 nsFactoryEntry* f = mFactories.Get(cid);
729 if (f) {
730 char idstr[NSID_LENGTH];
731 cid.ToProvidedString(idstr);
733 nsCString existing;
734 if (f->mModule) {
735 existing = f->mModule->Description();
736 } else {
737 existing = "<unknown module>";
740 lock.Unlock();
742 LogMessageWithContext(aCx.mFile, aLineNo,
743 "Trying to re-register CID '%s' already registered by %s.",
744 idstr,
745 existing.get());
746 return;
749 KnownModule* km;
751 km = mKnownModules.Get(hash);
752 if (!km) {
753 km = new KnownModule(fl);
754 mKnownModules.Put(hash, km);
757 void* place;
759 PL_ARENA_ALLOCATE(place, &mArena, sizeof(nsCID));
760 nsID* permanentCID = static_cast<nsID*>(place);
761 *permanentCID = cid;
763 PL_ARENA_ALLOCATE(place, &mArena, sizeof(mozilla::Module::CIDEntry));
764 mozilla::Module::CIDEntry* e = new (place) mozilla::Module::CIDEntry();
765 e->cid = permanentCID;
767 f = new nsFactoryEntry(e, km);
768 mFactories.Put(cid, f);
771 void
772 nsComponentManagerImpl::ManifestContract(ManifestProcessingContext& aCx,
773 int aLineNo, char* const* aArgv)
775 mLock.AssertNotCurrentThreadOwns();
777 char* contract = aArgv[0];
778 char* id = aArgv[1];
780 nsID cid;
781 if (!cid.Parse(id)) {
782 LogMessageWithContext(aCx.mFile, aLineNo,
783 "Malformed CID: '%s'.", id);
784 return;
787 MutexLock lock(mLock);
788 nsFactoryEntry* f = mFactories.Get(cid);
789 if (!f) {
790 lock.Unlock();
791 LogMessageWithContext(aCx.mFile, aLineNo,
792 "Could not map contract ID '%s' to CID %s because no implementation of the CID is registered.",
793 contract, id);
794 return;
797 mContractIDs.Put(nsDependentCString(contract), f);
800 void
801 nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext& aCx,
802 int aLineNo, char* const* aArgv)
804 char* category = aArgv[0];
805 char* key = aArgv[1];
806 char* value = aArgv[2];
808 nsCategoryManager::GetSingleton()->
809 AddCategoryEntry(category, key, value);
812 void
813 nsComponentManagerImpl::RereadChromeManifests(bool aChromeOnly)
815 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
816 ComponentLocation& l = sModuleLocations->ElementAt(i);
817 RegisterManifest(l.type, l.location, aChromeOnly);
821 bool
822 nsComponentManagerImpl::KnownModule::EnsureLoader()
824 if (!mLoader) {
825 nsCString extension;
826 mFile.GetURIString(extension);
827 CutExtension(extension);
828 mLoader =
829 nsComponentManagerImpl::gComponentManager->LoaderForExtension(extension);
831 return !!mLoader;
834 bool
835 nsComponentManagerImpl::KnownModule::Load()
837 if (mFailed) {
838 return false;
840 if (!mModule) {
841 if (!EnsureLoader()) {
842 return false;
845 mModule = mLoader->LoadModule(mFile);
847 if (!mModule) {
848 mFailed = true;
849 return false;
852 if (!mLoaded) {
853 if (mModule->loadProc) {
854 nsresult rv = mModule->loadProc();
855 if (NS_FAILED(rv)) {
856 mFailed = true;
857 return false;
860 mLoaded = true;
862 return true;
865 nsCString
866 nsComponentManagerImpl::KnownModule::Description() const
868 nsCString s;
869 if (mFile) {
870 mFile.GetURIString(s);
871 } else {
872 s = "<static module>";
874 return s;
877 nsresult nsComponentManagerImpl::Shutdown(void)
879 PR_ASSERT(NORMAL == mStatus);
881 mStatus = SHUTDOWN_IN_PROGRESS;
883 // Shutdown the component manager
884 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
885 ("nsComponentManager: Beginning Shutdown."));
887 UnregisterWeakMemoryReporter(this);
889 // Release all cached factories
890 mContractIDs.Clear();
891 mFactories.Clear(); // XXX release the objects, don't just clear
892 mLoaderMap.Clear();
893 mKnownModules.Clear();
894 mKnownStaticModules.Clear();
896 delete sStaticModules;
897 delete sModuleLocations;
898 #ifdef MOZ_B2G_LOADER
899 delete sXPTIInfosBook;
900 sXPTIInfosBook = nullptr;
901 #endif
903 // Unload libraries
904 mNativeModuleLoader.UnloadLibraries();
906 // delete arena for strings and small objects
907 PL_FinishArenaPool(&mArena);
909 mStatus = SHUTDOWN_COMPLETE;
911 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
912 ("nsComponentManager: Shutdown complete."));
914 return NS_OK;
917 nsComponentManagerImpl::~nsComponentManagerImpl()
919 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
920 ("nsComponentManager: Beginning destruction."));
922 if (SHUTDOWN_COMPLETE != mStatus) {
923 Shutdown();
926 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
927 ("nsComponentManager: Destroyed."));
930 NS_IMPL_ISUPPORTS(nsComponentManagerImpl,
931 nsIComponentManager,
932 nsIServiceManager,
933 nsIComponentRegistrar,
934 nsISupportsWeakReference,
935 nsIInterfaceRequestor,
936 nsIMemoryReporter)
938 nsresult
939 nsComponentManagerImpl::GetInterface(const nsIID& aUuid, void** aResult)
941 NS_WARNING("This isn't supported");
942 // fall through to QI as anything QIable is a superset of what can be
943 // got via the GetInterface()
944 return QueryInterface(aUuid, aResult);
947 nsFactoryEntry*
948 nsComponentManagerImpl::GetFactoryEntry(const char* aContractID,
949 uint32_t aContractIDLen)
951 SafeMutexAutoLock lock(mLock);
952 return mContractIDs.Get(nsDependentCString(aContractID, aContractIDLen));
956 nsFactoryEntry*
957 nsComponentManagerImpl::GetFactoryEntry(const nsCID& aClass)
959 SafeMutexAutoLock lock(mLock);
960 return mFactories.Get(aClass);
963 already_AddRefed<nsIFactory>
964 nsComponentManagerImpl::FindFactory(const nsCID& aClass)
966 nsFactoryEntry* e = GetFactoryEntry(aClass);
967 if (!e) {
968 return nullptr;
971 return e->GetFactory();
974 already_AddRefed<nsIFactory>
975 nsComponentManagerImpl::FindFactory(const char* aContractID,
976 uint32_t aContractIDLen)
978 nsFactoryEntry* entry = GetFactoryEntry(aContractID, aContractIDLen);
979 if (!entry) {
980 return nullptr;
983 return entry->GetFactory();
987 * GetClassObject()
989 * Given a classID, this finds the singleton ClassObject that implements the CID.
990 * Returns an interface of type aIID off the singleton classobject.
992 NS_IMETHODIMP
993 nsComponentManagerImpl::GetClassObject(const nsCID& aClass, const nsIID& aIID,
994 void** aResult)
996 nsresult rv;
998 #ifdef PR_LOGGING
999 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG)) {
1000 char* buf = aClass.ToString();
1001 PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
1002 if (buf) {
1003 NS_Free(buf);
1006 #endif
1008 PR_ASSERT(aResult != nullptr);
1010 nsCOMPtr<nsIFactory> factory = FindFactory(aClass);
1011 if (!factory) {
1012 return NS_ERROR_FACTORY_NOT_REGISTERED;
1015 rv = factory->QueryInterface(aIID, aResult);
1017 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1018 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1020 return rv;
1024 NS_IMETHODIMP
1025 nsComponentManagerImpl::GetClassObjectByContractID(const char* aContractID,
1026 const nsIID& aIID,
1027 void** aResult)
1029 if (NS_WARN_IF(!aResult) ||
1030 NS_WARN_IF(!aContractID)) {
1031 return NS_ERROR_INVALID_ARG;
1034 nsresult rv;
1037 #ifdef PR_LOGGING
1038 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG)) {
1039 PR_LogPrint("nsComponentManager: GetClassObject(%s)", aContractID);
1041 #endif
1043 nsCOMPtr<nsIFactory> factory = FindFactory(aContractID, strlen(aContractID));
1044 if (!factory) {
1045 return NS_ERROR_FACTORY_NOT_REGISTERED;
1048 rv = factory->QueryInterface(aIID, aResult);
1050 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1051 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1053 return rv;
1057 * CreateInstance()
1059 * Create an instance of an object that implements an interface and belongs
1060 * to the implementation aClass using the factory. The factory is immediately
1061 * released and not held onto for any longer.
1063 NS_IMETHODIMP
1064 nsComponentManagerImpl::CreateInstance(const nsCID& aClass,
1065 nsISupports* aDelegate,
1066 const nsIID& aIID,
1067 void** aResult)
1069 // test this first, since there's no point in creating a component during
1070 // shutdown -- whether it's available or not would depend on the order it
1071 // occurs in the list
1072 if (gXPCOMShuttingDown) {
1073 // When processing shutdown, don't process new GetService() requests
1074 #ifdef SHOW_DENIED_ON_SHUTDOWN
1075 nsXPIDLCString cid, iid;
1076 cid.Adopt(aClass.ToString());
1077 iid.Adopt(aIID.ToString());
1078 fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
1079 " CID: %s\n IID: %s\n", cid.get(), iid.get());
1080 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1081 return NS_ERROR_UNEXPECTED;
1084 if (!aResult) {
1085 return NS_ERROR_NULL_POINTER;
1087 *aResult = nullptr;
1089 nsFactoryEntry* entry = GetFactoryEntry(aClass);
1091 if (!entry) {
1092 return NS_ERROR_FACTORY_NOT_REGISTERED;
1095 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1096 if (entry->mServiceObject) {
1097 nsXPIDLCString cid;
1098 cid.Adopt(aClass.ToString());
1099 nsAutoCString message;
1100 message = NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
1101 cid +
1102 NS_LITERAL_CSTRING("\" when a service for this CID already exists!");
1103 NS_ERROR(message.get());
1105 #endif
1107 nsresult rv;
1108 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
1109 if (factory) {
1110 rv = factory->CreateInstance(aDelegate, aIID, aResult);
1111 if (NS_SUCCEEDED(rv) && !*aResult) {
1112 NS_ERROR("Factory did not return an object but returned success!");
1113 rv = NS_ERROR_SERVICE_NOT_FOUND;
1115 } else {
1116 // Translate error values
1117 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1120 #ifdef PR_LOGGING
1121 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) {
1122 char* buf = aClass.ToString();
1123 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1124 ("nsComponentManager: CreateInstance(%s) %s", buf,
1125 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1126 if (buf) {
1127 NS_Free(buf);
1130 #endif
1132 return rv;
1136 * CreateInstanceByContractID()
1138 * A variant of CreateInstance() that creates an instance of the object that
1139 * implements the interface aIID and whose implementation has a contractID aContractID.
1141 * This is only a convenience routine that turns around can calls the
1142 * CreateInstance() with classid and iid.
1144 NS_IMETHODIMP
1145 nsComponentManagerImpl::CreateInstanceByContractID(const char* aContractID,
1146 nsISupports* aDelegate,
1147 const nsIID& aIID,
1148 void** aResult)
1150 if (NS_WARN_IF(!aContractID)) {
1151 return NS_ERROR_INVALID_ARG;
1154 // test this first, since there's no point in creating a component during
1155 // shutdown -- whether it's available or not would depend on the order it
1156 // occurs in the list
1157 if (gXPCOMShuttingDown) {
1158 // When processing shutdown, don't process new GetService() requests
1159 #ifdef SHOW_DENIED_ON_SHUTDOWN
1160 nsXPIDLCString iid;
1161 iid.Adopt(aIID.ToString());
1162 fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
1163 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
1164 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1165 return NS_ERROR_UNEXPECTED;
1168 if (!aResult) {
1169 return NS_ERROR_NULL_POINTER;
1171 *aResult = nullptr;
1173 nsFactoryEntry* entry = GetFactoryEntry(aContractID, strlen(aContractID));
1175 if (!entry) {
1176 return NS_ERROR_FACTORY_NOT_REGISTERED;
1179 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1180 if (entry->mServiceObject) {
1181 nsAutoCString message;
1182 message =
1183 NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
1184 nsDependentCString(aContractID) +
1185 NS_LITERAL_CSTRING("\" when a service for this CID already exists! "
1186 "Add it to abusedContracts to track down the service consumer.");
1187 NS_ERROR(message.get());
1189 #endif
1191 nsresult rv;
1192 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
1193 if (factory) {
1195 rv = factory->CreateInstance(aDelegate, aIID, aResult);
1196 if (NS_SUCCEEDED(rv) && !*aResult) {
1197 NS_ERROR("Factory did not return an object but returned success!");
1198 rv = NS_ERROR_SERVICE_NOT_FOUND;
1200 } else {
1201 // Translate error values
1202 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1205 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1206 ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
1207 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1209 return rv;
1212 static PLDHashOperator
1213 FreeFactoryEntries(const nsID& aCID,
1214 nsFactoryEntry* aEntry,
1215 void* aArg)
1217 aEntry->mFactory = nullptr;
1218 aEntry->mServiceObject = nullptr;
1219 return PL_DHASH_NEXT;
1222 nsresult
1223 nsComponentManagerImpl::FreeServices()
1225 NS_ASSERTION(gXPCOMShuttingDown,
1226 "Must be shutting down in order to free all services");
1228 if (!gXPCOMShuttingDown) {
1229 return NS_ERROR_FAILURE;
1232 mFactories.EnumerateRead(FreeFactoryEntries, nullptr);
1233 return NS_OK;
1236 // This should only ever be called within the monitor!
1237 nsComponentManagerImpl::PendingServiceInfo*
1238 nsComponentManagerImpl::AddPendingService(const nsCID& aServiceCID,
1239 PRThread* aThread)
1241 PendingServiceInfo* newInfo = mPendingServices.AppendElement();
1242 if (newInfo) {
1243 newInfo->cid = &aServiceCID;
1244 newInfo->thread = aThread;
1246 return newInfo;
1249 // This should only ever be called within the monitor!
1250 void
1251 nsComponentManagerImpl::RemovePendingService(const nsCID& aServiceCID)
1253 uint32_t pendingCount = mPendingServices.Length();
1254 for (uint32_t index = 0; index < pendingCount; ++index) {
1255 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
1256 if (info.cid->Equals(aServiceCID)) {
1257 mPendingServices.RemoveElementAt(index);
1258 return;
1263 // This should only ever be called within the monitor!
1264 PRThread*
1265 nsComponentManagerImpl::GetPendingServiceThread(const nsCID& aServiceCID) const
1267 uint32_t pendingCount = mPendingServices.Length();
1268 for (uint32_t index = 0; index < pendingCount; ++index) {
1269 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
1270 if (info.cid->Equals(aServiceCID)) {
1271 return info.thread;
1274 return nullptr;
1277 NS_IMETHODIMP
1278 nsComponentManagerImpl::GetService(const nsCID& aClass,
1279 const nsIID& aIID,
1280 void** aResult)
1282 // test this first, since there's no point in returning a service during
1283 // shutdown -- whether it's available or not would depend on the order it
1284 // occurs in the list
1285 if (gXPCOMShuttingDown) {
1286 // When processing shutdown, don't process new GetService() requests
1287 #ifdef SHOW_DENIED_ON_SHUTDOWN
1288 nsXPIDLCString cid, iid;
1289 cid.Adopt(aClass.ToString());
1290 iid.Adopt(aIID.ToString());
1291 fprintf(stderr, "Getting service on shutdown. Denied.\n"
1292 " CID: %s\n IID: %s\n", cid.get(), iid.get());
1293 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1294 return NS_ERROR_UNEXPECTED;
1297 // `service` must be released after the lock is released, so it must be
1298 // declared before the lock in this C++ block.
1299 nsCOMPtr<nsISupports> service;
1300 MutexLock lock(mLock);
1302 nsFactoryEntry* entry = mFactories.Get(aClass);
1303 if (!entry) {
1304 return NS_ERROR_FACTORY_NOT_REGISTERED;
1307 if (entry->mServiceObject) {
1308 lock.Unlock();
1309 return entry->mServiceObject->QueryInterface(aIID, aResult);
1312 PRThread* currentPRThread = PR_GetCurrentThread();
1313 MOZ_ASSERT(currentPRThread, "This should never be null!");
1315 // Needed to optimize the event loop below.
1316 nsIThread* currentThread = nullptr;
1318 PRThread* pendingPRThread;
1319 while ((pendingPRThread = GetPendingServiceThread(aClass))) {
1320 if (pendingPRThread == currentPRThread) {
1321 NS_ERROR("Recursive GetService!");
1322 return NS_ERROR_NOT_AVAILABLE;
1326 SafeMutexAutoUnlock unlockPending(mLock);
1328 if (!currentThread) {
1329 currentThread = NS_GetCurrentThread();
1330 MOZ_ASSERT(currentThread, "This should never be null!");
1333 // This will process a single event or yield the thread if no event is
1334 // pending.
1335 if (!NS_ProcessNextEvent(currentThread, false)) {
1336 PR_Sleep(PR_INTERVAL_NO_WAIT);
1340 // It's still possible that the other thread failed to create the
1341 // service so we're not guaranteed to have an entry or service yet.
1342 if (entry->mServiceObject) {
1343 lock.Unlock();
1344 return entry->mServiceObject->QueryInterface(aIID, aResult);
1347 #ifdef DEBUG
1348 PendingServiceInfo* newInfo =
1349 #endif
1350 AddPendingService(aClass, currentPRThread);
1351 NS_ASSERTION(newInfo, "Failed to add info to the array!");
1353 // We need to not be holding the service manager's lock while calling
1354 // CreateInstance, because it invokes user code which could try to re-enter
1355 // the service manager:
1357 nsresult rv;
1359 SafeMutexAutoUnlock unlock(mLock);
1360 rv = CreateInstance(aClass, nullptr, aIID, getter_AddRefs(service));
1362 if (NS_SUCCEEDED(rv) && !service) {
1363 NS_ERROR("Factory did not return an object but returned success");
1364 return NS_ERROR_SERVICE_NOT_FOUND;
1367 #ifdef DEBUG
1368 pendingPRThread = GetPendingServiceThread(aClass);
1369 MOZ_ASSERT(pendingPRThread == currentPRThread,
1370 "Pending service array has been changed!");
1371 #endif
1372 RemovePendingService(aClass);
1374 if (NS_FAILED(rv)) {
1375 return rv;
1378 NS_ASSERTION(!entry->mServiceObject, "Created two instances of a service!");
1380 entry->mServiceObject = service.forget();
1382 lock.Unlock();
1383 nsISupports** sresult = reinterpret_cast<nsISupports**>(aResult);
1384 *sresult = entry->mServiceObject;
1385 (*sresult)->AddRef();
1387 return NS_OK;
1390 NS_IMETHODIMP
1391 nsComponentManagerImpl::IsServiceInstantiated(const nsCID& aClass,
1392 const nsIID& aIID,
1393 bool* aResult)
1395 // Now we want to get the service if we already got it. If not, we don't want
1396 // to create an instance of it. mmh!
1398 // test this first, since there's no point in returning a service during
1399 // shutdown -- whether it's available or not would depend on the order it
1400 // occurs in the list
1401 if (gXPCOMShuttingDown) {
1402 // When processing shutdown, don't process new GetService() requests
1403 #ifdef SHOW_DENIED_ON_SHUTDOWN
1404 nsXPIDLCString cid, iid;
1405 cid.Adopt(aClass.ToString());
1406 iid.Adopt(aIID.ToString());
1407 fprintf(stderr, "Checking for service on shutdown. Denied.\n"
1408 " CID: %s\n IID: %s\n", cid.get(), iid.get());
1409 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1410 return NS_ERROR_UNEXPECTED;
1413 nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
1414 nsFactoryEntry* entry;
1417 SafeMutexAutoLock lock(mLock);
1418 entry = mFactories.Get(aClass);
1421 if (entry && entry->mServiceObject) {
1422 nsCOMPtr<nsISupports> service;
1423 rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
1424 *aResult = (service != nullptr);
1427 return rv;
1430 NS_IMETHODIMP
1431 nsComponentManagerImpl::IsServiceInstantiatedByContractID(
1432 const char* aContractID,
1433 const nsIID& aIID,
1434 bool* aResult)
1436 // Now we want to get the service if we already got it. If not, we don't want
1437 // to create an instance of it. mmh!
1439 // test this first, since there's no point in returning a service during
1440 // shutdown -- whether it's available or not would depend on the order it
1441 // occurs in the list
1442 if (gXPCOMShuttingDown) {
1443 // When processing shutdown, don't process new GetService() requests
1444 #ifdef SHOW_DENIED_ON_SHUTDOWN
1445 nsXPIDLCString iid;
1446 iid.Adopt(aIID.ToString());
1447 fprintf(stderr, "Checking for service on shutdown. Denied.\n"
1448 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
1449 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1450 return NS_ERROR_UNEXPECTED;
1453 nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
1454 nsFactoryEntry* entry;
1456 SafeMutexAutoLock lock(mLock);
1457 entry = mContractIDs.Get(nsDependentCString(aContractID));
1460 if (entry && entry->mServiceObject) {
1461 nsCOMPtr<nsISupports> service;
1462 rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
1463 *aResult = (service != nullptr);
1465 return rv;
1469 NS_IMETHODIMP
1470 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
1471 const nsIID& aIID,
1472 void** aResult)
1474 // test this first, since there's no point in returning a service during
1475 // shutdown -- whether it's available or not would depend on the order it
1476 // occurs in the list
1477 if (gXPCOMShuttingDown) {
1478 // When processing shutdown, don't process new GetService() requests
1479 #ifdef SHOW_DENIED_ON_SHUTDOWN
1480 nsXPIDLCString iid;
1481 iid.Adopt(aIID.ToString());
1482 fprintf(stderr, "Getting service on shutdown. Denied.\n"
1483 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
1484 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1485 return NS_ERROR_UNEXPECTED;
1488 // `service` must be released after the lock is released, so it must be
1489 // declared before the lock in this C++ block.
1490 nsCOMPtr<nsISupports> service;
1491 MutexLock lock(mLock);
1493 nsFactoryEntry* entry = mContractIDs.Get(nsDependentCString(aContractID));
1494 if (!entry) {
1495 return NS_ERROR_FACTORY_NOT_REGISTERED;
1498 if (entry->mServiceObject) {
1499 // We need to not be holding the service manager's monitor while calling
1500 // QueryInterface, because it invokes user code which could try to re-enter
1501 // the service manager, or try to grab some other lock/monitor/condvar
1502 // and deadlock, e.g. bug 282743.
1503 // `entry` is valid until XPCOM shutdown, so we can safely use it after
1504 // exiting the lock.
1505 lock.Unlock();
1506 return entry->mServiceObject->QueryInterface(aIID, aResult);
1509 PRThread* currentPRThread = PR_GetCurrentThread();
1510 MOZ_ASSERT(currentPRThread, "This should never be null!");
1512 // Needed to optimize the event loop below.
1513 nsIThread* currentThread = nullptr;
1515 PRThread* pendingPRThread;
1516 while ((pendingPRThread = GetPendingServiceThread(*entry->mCIDEntry->cid))) {
1517 if (pendingPRThread == currentPRThread) {
1518 NS_ERROR("Recursive GetService!");
1519 return NS_ERROR_NOT_AVAILABLE;
1522 SafeMutexAutoUnlock unlockPending(mLock);
1524 if (!currentThread) {
1525 currentThread = NS_GetCurrentThread();
1526 MOZ_ASSERT(currentThread, "This should never be null!");
1529 // This will process a single event or yield the thread if no event is
1530 // pending.
1531 if (!NS_ProcessNextEvent(currentThread, false)) {
1532 PR_Sleep(PR_INTERVAL_NO_WAIT);
1536 if (currentThread && entry->mServiceObject) {
1537 // If we have a currentThread then we must have waited on another thread
1538 // to create the service. Grab it now if that succeeded.
1539 lock.Unlock();
1540 return entry->mServiceObject->QueryInterface(aIID, aResult);
1543 #ifdef DEBUG
1544 PendingServiceInfo* newInfo =
1545 #endif
1546 AddPendingService(*entry->mCIDEntry->cid, currentPRThread);
1547 NS_ASSERTION(newInfo, "Failed to add info to the array!");
1549 // We need to not be holding the service manager's lock while calling
1550 // CreateInstance, because it invokes user code which could try to re-enter
1551 // the service manager:
1553 nsresult rv;
1555 SafeMutexAutoUnlock unlock(mLock);
1556 rv = CreateInstanceByContractID(aContractID, nullptr, aIID,
1557 getter_AddRefs(service));
1559 if (NS_SUCCEEDED(rv) && !service) {
1560 NS_ERROR("Factory did not return an object but returned success");
1561 return NS_ERROR_SERVICE_NOT_FOUND;
1564 #ifdef DEBUG
1565 pendingPRThread = GetPendingServiceThread(*entry->mCIDEntry->cid);
1566 MOZ_ASSERT(pendingPRThread == currentPRThread,
1567 "Pending service array has been changed!");
1568 #endif
1569 RemovePendingService(*entry->mCIDEntry->cid);
1571 if (NS_FAILED(rv)) {
1572 return rv;
1575 NS_ASSERTION(!entry->mServiceObject, "Created two instances of a service!");
1577 entry->mServiceObject = service.forget();
1579 lock.Unlock();
1581 nsISupports** sresult = reinterpret_cast<nsISupports**>(aResult);
1582 *sresult = entry->mServiceObject;
1583 (*sresult)->AddRef();
1585 return NS_OK;
1588 already_AddRefed<mozilla::ModuleLoader>
1589 nsComponentManagerImpl::LoaderForExtension(const nsACString& aExt)
1591 nsCOMPtr<mozilla::ModuleLoader> loader = mLoaderMap.Get(aExt);
1592 if (!loader) {
1593 loader = do_GetServiceFromCategory("module-loader",
1594 PromiseFlatCString(aExt).get());
1595 if (!loader) {
1596 return nullptr;
1599 mLoaderMap.Put(aExt, loader);
1602 return loader.forget();
1605 NS_IMETHODIMP
1606 nsComponentManagerImpl::RegisterFactory(const nsCID& aClass,
1607 const char* aName,
1608 const char* aContractID,
1609 nsIFactory* aFactory)
1611 if (!aFactory) {
1612 // If a null factory is passed in, this call just wants to reset
1613 // the contract ID to point to an existing CID entry.
1614 if (!aContractID) {
1615 return NS_ERROR_INVALID_ARG;
1618 SafeMutexAutoLock lock(mLock);
1619 nsFactoryEntry* oldf = mFactories.Get(aClass);
1620 if (!oldf) {
1621 return NS_ERROR_FACTORY_NOT_REGISTERED;
1624 mContractIDs.Put(nsDependentCString(aContractID), oldf);
1625 return NS_OK;
1628 nsAutoPtr<nsFactoryEntry> f(new nsFactoryEntry(aClass, aFactory));
1630 SafeMutexAutoLock lock(mLock);
1631 nsFactoryEntry* oldf = mFactories.Get(aClass);
1632 if (oldf) {
1633 return NS_ERROR_FACTORY_EXISTS;
1636 if (aContractID) {
1637 mContractIDs.Put(nsDependentCString(aContractID), f);
1640 mFactories.Put(aClass, f.forget());
1642 return NS_OK;
1645 NS_IMETHODIMP
1646 nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass,
1647 nsIFactory* aFactory)
1649 // Don't release the dying factory or service object until releasing
1650 // the component manager monitor.
1651 nsCOMPtr<nsIFactory> dyingFactory;
1652 nsCOMPtr<nsISupports> dyingServiceObject;
1655 SafeMutexAutoLock lock(mLock);
1656 nsFactoryEntry* f = mFactories.Get(aClass);
1657 if (!f || f->mFactory != aFactory) {
1658 return NS_ERROR_FACTORY_NOT_REGISTERED;
1661 mFactories.Remove(aClass);
1663 // This might leave a stale contractid -> factory mapping in
1664 // place, so null out the factory entry (see
1665 // nsFactoryEntry::GetFactory)
1666 f->mFactory.swap(dyingFactory);
1667 f->mServiceObject.swap(dyingServiceObject);
1670 return NS_OK;
1673 NS_IMETHODIMP
1674 nsComponentManagerImpl::AutoRegister(nsIFile* aLocation)
1676 XRE_AddManifestLocation(NS_COMPONENT_LOCATION, aLocation);
1677 return NS_OK;
1680 NS_IMETHODIMP
1681 nsComponentManagerImpl::AutoUnregister(nsIFile* aLocation)
1683 NS_ERROR("AutoUnregister not implemented.");
1684 return NS_ERROR_NOT_IMPLEMENTED;
1687 NS_IMETHODIMP
1688 nsComponentManagerImpl::RegisterFactoryLocation(const nsCID& aCID,
1689 const char* aClassName,
1690 const char* aContractID,
1691 nsIFile* aFile,
1692 const char* aLoaderStr,
1693 const char* aType)
1695 NS_ERROR("RegisterFactoryLocation not implemented.");
1696 return NS_ERROR_NOT_IMPLEMENTED;
1699 NS_IMETHODIMP
1700 nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID& aCID,
1701 nsIFile* aFile)
1703 NS_ERROR("UnregisterFactoryLocation not implemented.");
1704 return NS_ERROR_NOT_IMPLEMENTED;
1707 NS_IMETHODIMP
1708 nsComponentManagerImpl::IsCIDRegistered(const nsCID& aClass,
1709 bool* aResult)
1711 *aResult = (nullptr != GetFactoryEntry(aClass));
1712 return NS_OK;
1715 NS_IMETHODIMP
1716 nsComponentManagerImpl::IsContractIDRegistered(const char* aClass,
1717 bool* aResult)
1719 if (NS_WARN_IF(!aClass)) {
1720 return NS_ERROR_INVALID_ARG;
1723 nsFactoryEntry* entry = GetFactoryEntry(aClass, strlen(aClass));
1725 if (entry) {
1726 *aResult = true;
1727 } else {
1728 *aResult = false;
1730 return NS_OK;
1733 static PLDHashOperator
1734 EnumerateCIDHelper(const nsID& aId, nsFactoryEntry* aEntry, void* aClosure)
1736 nsCOMArray<nsISupports>* array =
1737 static_cast<nsCOMArray<nsISupports>*>(aClosure);
1738 nsCOMPtr<nsISupportsID> wrapper = new nsSupportsIDImpl();
1739 wrapper->SetData(&aId);
1740 array->AppendObject(wrapper);
1741 return PL_DHASH_NEXT;
1744 NS_IMETHODIMP
1745 nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator** aEnumerator)
1747 nsCOMArray<nsISupports> array;
1748 mFactories.EnumerateRead(EnumerateCIDHelper, &array);
1750 return NS_NewArrayEnumerator(aEnumerator, array);
1753 static PLDHashOperator
1754 EnumerateContractsHelper(const nsACString& aContract, nsFactoryEntry* aEntry,
1755 void* aClosure)
1757 nsTArray<nsCString>* array = static_cast<nsTArray<nsCString>*>(aClosure);
1758 array->AppendElement(aContract);
1759 return PL_DHASH_NEXT;
1762 NS_IMETHODIMP
1763 nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator** aEnumerator)
1765 nsTArray<nsCString>* array = new nsTArray<nsCString>;
1766 mContractIDs.EnumerateRead(EnumerateContractsHelper, array);
1768 nsCOMPtr<nsIUTF8StringEnumerator> e;
1769 nsresult rv = NS_NewAdoptingUTF8StringEnumerator(getter_AddRefs(e), array);
1770 if (NS_FAILED(rv)) {
1771 return rv;
1774 return CallQueryInterface(e, aEnumerator);
1777 NS_IMETHODIMP
1778 nsComponentManagerImpl::CIDToContractID(const nsCID& aClass,
1779 char** aResult)
1781 NS_ERROR("CIDTOContractID not implemented");
1782 return NS_ERROR_FACTORY_NOT_REGISTERED;
1785 NS_IMETHODIMP
1786 nsComponentManagerImpl::ContractIDToCID(const char* aContractID,
1787 nsCID** aResult)
1790 SafeMutexAutoLock lock(mLock);
1791 nsFactoryEntry* entry = mContractIDs.Get(nsDependentCString(aContractID));
1792 if (entry) {
1793 *aResult = (nsCID*)NS_Alloc(sizeof(nsCID));
1794 **aResult = *entry->mCIDEntry->cid;
1795 return NS_OK;
1798 *aResult = nullptr;
1799 return NS_ERROR_FACTORY_NOT_REGISTERED;
1802 static size_t
1803 SizeOfFactoriesEntryExcludingThis(nsIDHashKey::KeyType aKey,
1804 nsFactoryEntry* const& aData,
1805 MallocSizeOf aMallocSizeOf,
1806 void* aUserArg)
1808 return aData->SizeOfIncludingThis(aMallocSizeOf);
1811 static size_t
1812 SizeOfContractIDsEntryExcludingThis(nsCStringHashKey::KeyType aKey,
1813 nsFactoryEntry* const& aData,
1814 MallocSizeOf aMallocSizeOf,
1815 void* aUserArg)
1817 // We don't measure the nsFactoryEntry data because its owned by mFactories
1818 // (which measures them in SizeOfFactoriesEntryExcludingThis).
1819 return aKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
1822 MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf)
1824 NS_IMETHODIMP
1825 nsComponentManagerImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
1826 nsISupports* aData, bool aAnonymize)
1828 return MOZ_COLLECT_REPORT("explicit/xpcom/component-manager",
1829 KIND_HEAP, UNITS_BYTES,
1830 SizeOfIncludingThis(ComponentManagerMallocSizeOf),
1831 "Memory used for the XPCOM component manager.");
1834 size_t
1835 nsComponentManagerImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
1837 size_t n = aMallocSizeOf(this);
1838 n += mLoaderMap.SizeOfExcludingThis(nullptr, aMallocSizeOf);
1839 n += mFactories.SizeOfExcludingThis(SizeOfFactoriesEntryExcludingThis,
1840 aMallocSizeOf);
1841 n += mContractIDs.SizeOfExcludingThis(SizeOfContractIDsEntryExcludingThis,
1842 aMallocSizeOf);
1844 n += sStaticModules->SizeOfIncludingThis(aMallocSizeOf);
1845 n += sModuleLocations->SizeOfIncludingThis(aMallocSizeOf);
1847 n += mKnownStaticModules.SizeOfExcludingThis(aMallocSizeOf);
1848 n += mKnownModules.SizeOfExcludingThis(nullptr, aMallocSizeOf);
1850 n += PL_SizeOfArenaPoolExcludingPool(&mArena, aMallocSizeOf);
1852 n += mPendingServices.SizeOfExcludingThis(aMallocSizeOf);
1854 // Measurement of the following members may be added later if DMD finds it is
1855 // worthwhile:
1856 // - mLoaderMap's keys and values
1857 // - mMon
1858 // - sStaticModules' entries
1859 // - sModuleLocations' entries
1860 // - mNativeModuleLoader
1861 // - mKnownStaticModules' entries?
1862 // - mKnownModules' keys and values?
1864 return n;
1867 ////////////////////////////////////////////////////////////////////////////////
1868 // nsFactoryEntry
1869 ////////////////////////////////////////////////////////////////////////////////
1871 nsFactoryEntry::nsFactoryEntry(const mozilla::Module::CIDEntry* aEntry,
1872 nsComponentManagerImpl::KnownModule* aModule)
1873 : mCIDEntry(aEntry)
1874 , mModule(aModule)
1878 nsFactoryEntry::nsFactoryEntry(const nsCID& aCID, nsIFactory* aFactory)
1879 : mCIDEntry(nullptr)
1880 , mModule(nullptr)
1881 , mFactory(aFactory)
1883 mozilla::Module::CIDEntry* e = new mozilla::Module::CIDEntry();
1884 nsCID* cid = new nsCID;
1885 *cid = aCID;
1886 e->cid = cid;
1887 mCIDEntry = e;
1890 nsFactoryEntry::~nsFactoryEntry()
1892 // If this was a RegisterFactory entry, we own the CIDEntry/CID
1893 if (!mModule) {
1894 delete mCIDEntry->cid;
1895 delete mCIDEntry;
1899 already_AddRefed<nsIFactory>
1900 nsFactoryEntry::GetFactory()
1902 nsComponentManagerImpl::gComponentManager->mLock.AssertNotCurrentThreadOwns();
1904 if (!mFactory) {
1905 // RegisterFactory then UnregisterFactory can leave an entry in mContractIDs
1906 // pointing to an unusable nsFactoryEntry.
1907 if (!mModule) {
1908 return nullptr;
1911 if (!mModule->Load()) {
1912 return nullptr;
1915 // Don't set mFactory directly, it needs to be locked
1916 nsCOMPtr<nsIFactory> factory;
1918 if (mModule->Module()->getFactoryProc) {
1919 factory = mModule->Module()->getFactoryProc(*mModule->Module(),
1920 *mCIDEntry);
1921 } else if (mCIDEntry->getFactoryProc) {
1922 factory = mCIDEntry->getFactoryProc(*mModule->Module(), *mCIDEntry);
1923 } else {
1924 NS_ASSERTION(mCIDEntry->constructorProc, "no getfactory or constructor");
1925 factory = new mozilla::GenericFactory(mCIDEntry->constructorProc);
1927 if (!factory) {
1928 return nullptr;
1931 SafeMutexAutoLock lock(nsComponentManagerImpl::gComponentManager->mLock);
1932 // Threads can race to set mFactory
1933 if (!mFactory) {
1934 factory.swap(mFactory);
1937 nsCOMPtr<nsIFactory> factory = mFactory;
1938 return factory.forget();
1941 size_t
1942 nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
1944 size_t n = aMallocSizeOf(this);
1946 // Measurement of the following members may be added later if DMD finds it is
1947 // worthwhile:
1948 // - mCIDEntry;
1949 // - mModule;
1950 // - mFactory;
1951 // - mServiceObject;
1953 return n;
1956 ////////////////////////////////////////////////////////////////////////////////
1957 // Static Access Functions
1958 ////////////////////////////////////////////////////////////////////////////////
1960 nsresult
1961 NS_GetComponentManager(nsIComponentManager** aResult)
1963 if (!nsComponentManagerImpl::gComponentManager) {
1964 return NS_ERROR_NOT_INITIALIZED;
1967 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1968 return NS_OK;
1971 nsresult
1972 NS_GetServiceManager(nsIServiceManager** aResult)
1974 if (!nsComponentManagerImpl::gComponentManager) {
1975 return NS_ERROR_NOT_INITIALIZED;
1978 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1979 return NS_OK;
1983 nsresult
1984 NS_GetComponentRegistrar(nsIComponentRegistrar** aResult)
1986 if (!nsComponentManagerImpl::gComponentManager) {
1987 return NS_ERROR_NOT_INITIALIZED;
1990 NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
1991 return NS_OK;
1994 EXPORT_XPCOM_API(nsresult)
1995 XRE_AddStaticComponent(const mozilla::Module* aComponent)
1997 nsComponentManagerImpl::InitializeStaticModules();
1998 nsComponentManagerImpl::sStaticModules->AppendElement(aComponent);
2000 if (nsComponentManagerImpl::gComponentManager &&
2001 nsComponentManagerImpl::NORMAL ==
2002 nsComponentManagerImpl::gComponentManager->mStatus) {
2003 nsComponentManagerImpl::gComponentManager->RegisterModule(aComponent,
2004 nullptr);
2007 return NS_OK;
2010 NS_IMETHODIMP
2011 nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation)
2013 nsString path;
2014 nsresult rv = aLocation->GetPath(path);
2015 if (NS_FAILED(rv)) {
2016 return rv;
2019 if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
2020 return XRE_AddJarManifestLocation(NS_BOOTSTRAPPED_LOCATION, aLocation);
2023 nsCOMPtr<nsIFile> manifest =
2024 CloneAndAppend(aLocation, NS_LITERAL_CSTRING("chrome.manifest"));
2025 return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION, manifest);
2028 NS_IMETHODIMP
2029 nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation)
2031 nsCOMPtr<nsIChromeRegistry> cr = mozilla::services::GetChromeRegistryService();
2032 if (!cr) {
2033 return NS_ERROR_FAILURE;
2036 nsCOMPtr<nsIFile> manifest;
2037 nsString path;
2038 nsresult rv = aLocation->GetPath(path);
2039 if (NS_FAILED(rv)) {
2040 return rv;
2043 nsComponentManagerImpl::ComponentLocation elem;
2044 elem.type = NS_BOOTSTRAPPED_LOCATION;
2046 if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
2047 elem.location.Init(aLocation, "chrome.manifest");
2048 } else {
2049 nsCOMPtr<nsIFile> lf =
2050 CloneAndAppend(aLocation, NS_LITERAL_CSTRING("chrome.manifest"));
2051 elem.location.Init(lf);
2054 // Remove reference.
2055 nsComponentManagerImpl::sModuleLocations->RemoveElement(elem,
2056 ComponentLocationComparator());
2058 rv = cr->CheckForNewChrome();
2059 return rv;
2062 NS_IMETHODIMP
2063 nsComponentManagerImpl::GetManifestLocations(nsIArray** aLocations)
2065 NS_ENSURE_ARG_POINTER(aLocations);
2066 *aLocations = nullptr;
2068 if (!sModuleLocations) {
2069 return NS_ERROR_NOT_INITIALIZED;
2072 nsCOMPtr<nsIMutableArray> locations = nsArray::Create();
2073 nsresult rv;
2074 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
2075 ComponentLocation& l = sModuleLocations->ElementAt(i);
2076 FileLocation loc = l.location;
2077 nsCString uriString;
2078 loc.GetURIString(uriString);
2079 nsCOMPtr<nsIURI> uri;
2080 rv = NS_NewURI(getter_AddRefs(uri), uriString);
2081 if (NS_SUCCEEDED(rv)) {
2082 locations->AppendElement(uri, false);
2086 locations.forget(aLocations);
2087 return NS_OK;
2090 #ifdef MOZ_B2G_LOADER
2092 /* static */
2093 void
2094 nsComponentManagerImpl::XPTOnlyManifestManifest(
2095 XPTOnlyManifestProcessingContext& aCx, int aLineNo, char* const* aArgv)
2097 char* file = aArgv[0];
2098 FileLocation f(aCx.mFile, file);
2100 DoRegisterManifest(NS_COMPONENT_LOCATION, f, false, true);
2103 /* static */
2104 void
2105 nsComponentManagerImpl::XPTOnlyManifestXPT(
2106 XPTOnlyManifestProcessingContext& aCx, int aLineNo, char* const* aArgv)
2108 FileLocation f(aCx.mFile, aArgv[0]);
2109 DoRegisterXPT(f);
2113 * To load XPT Interface Information before the component manager is ready.
2115 * With this function, B2G loader could XPT interface info. as earier
2116 * as possible to gain benefit of shared memory model of the kernel.
2118 /* static */ void
2119 nsComponentManagerImpl::PreloadXPT(nsIFile* aFile)
2121 MOZ_ASSERT(!nsComponentManagerImpl::gComponentManager);
2122 FileLocation location(aFile, "chrome.manifest");
2124 DoRegisterManifest(NS_COMPONENT_LOCATION, location,
2125 false, true /* aXPTOnly */);
2128 void
2129 PreloadXPT(nsIFile* aOmnijarFile)
2131 nsComponentManagerImpl::PreloadXPT(aOmnijarFile);
2134 #endif /* MOZ_B2G_LOADER */
2136 EXPORT_XPCOM_API(nsresult)
2137 XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation)
2139 nsComponentManagerImpl::InitializeModuleLocations();
2140 nsComponentManagerImpl::ComponentLocation* c =
2141 nsComponentManagerImpl::sModuleLocations->AppendElement();
2142 c->type = aType;
2143 c->location.Init(aLocation);
2145 if (nsComponentManagerImpl::gComponentManager &&
2146 nsComponentManagerImpl::NORMAL ==
2147 nsComponentManagerImpl::gComponentManager->mStatus) {
2148 nsComponentManagerImpl::gComponentManager->RegisterManifest(aType,
2149 c->location,
2150 false);
2153 return NS_OK;
2156 EXPORT_XPCOM_API(nsresult)
2157 XRE_AddJarManifestLocation(NSLocationType aType, nsIFile* aLocation)
2159 nsComponentManagerImpl::InitializeModuleLocations();
2160 nsComponentManagerImpl::ComponentLocation* c =
2161 nsComponentManagerImpl::sModuleLocations->AppendElement();
2163 c->type = aType;
2164 c->location.Init(aLocation, "chrome.manifest");
2166 if (nsComponentManagerImpl::gComponentManager &&
2167 nsComponentManagerImpl::NORMAL ==
2168 nsComponentManagerImpl::gComponentManager->mStatus) {
2169 nsComponentManagerImpl::gComponentManager->RegisterManifest(aType,
2170 c->location,
2171 false);
2174 return NS_OK;