Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/.
6 *
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
11 *
12 * Modifications to Mozilla code or documentation
13 * identified per MPL Section 3.3
14 *
15 * Date Modified by Description of modification
16 * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
17 */
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 "nsManifestLineReader.h"
65 #include "mozilla/GenericFactory.h"
66 #include "nsSupportsPrimitives.h"
67 #include "nsArray.h"
68 #include "nsIMutableArray.h"
69 #include "nsArrayEnumerator.h"
70 #include "nsStringEnumerator.h"
71 #include "mozilla/FileUtils.h"
72 #include "nsNetUtil.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 // defined in nsStaticXULComponents.cpp to contain all the components in
85 // libxul.
86 extern mozilla::Module const *const *const kPStaticModules[];
88 #if 0 || defined (DEBUG_timeless)
89 #define SHOW_DENIED_ON_SHUTDOWN
90 #define SHOW_CI_ON_EXISTING_SERVICE
91 #endif
93 // Bloated registry buffer size to improve startup performance -- needs to
94 // be big enough to fit the entire file into memory or it'll thrash.
95 // 512K is big enough to allow for some future growth in the registry.
96 #define BIG_REGISTRY_BUFLEN (512*1024)
98 // Common Key Names
99 const char xpcomComponentsKeyName[]="software/mozilla/XPCOM/components";
100 const char xpcomKeyName[]="software/mozilla/XPCOM";
102 // Common Value Names
103 const char fileSizeValueName[]="FileSize";
104 const char lastModValueName[]="LastModTimeStamp";
105 const char nativeComponentType[]="application/x-mozilla-native";
106 const char staticComponentType[]="application/x-mozilla-static";
108 NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID);
110 #define UID_STRING_LENGTH 39
112 nsresult
113 nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
114 {
115 nsresult rv;
116 nsXPIDLCString value;
117 nsCOMPtr<nsICategoryManager> catman;
118 nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager;
119 if (!compMgr) {
120 rv = NS_ERROR_NOT_INITIALIZED;
121 goto error;
122 }
124 if (!mCategory || !mEntry) {
125 // when categories have defaults, use that for null mEntry
126 rv = NS_ERROR_NULL_POINTER;
127 goto error;
128 }
130 rv = compMgr->nsComponentManagerImpl::GetService(kCategoryManagerCID,
131 NS_GET_IID(nsICategoryManager),
132 getter_AddRefs(catman));
133 if (NS_FAILED(rv)) goto error;
135 /* find the contractID for category.entry */
136 rv = catman->GetCategoryEntry(mCategory, mEntry,
137 getter_Copies(value));
138 if (NS_FAILED(rv)) goto error;
139 if (!value) {
140 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
141 goto error;
142 }
144 rv = compMgr->
145 nsComponentManagerImpl::GetServiceByContractID(value,
146 aIID, aInstancePtr);
147 if (NS_FAILED(rv)) {
148 error:
149 *aInstancePtr = 0;
150 }
151 if (mErrorPtr)
152 *mErrorPtr = rv;
153 return rv;
154 }
156 ////////////////////////////////////////////////////////////////////////////////
157 // Arena helper functions
158 ////////////////////////////////////////////////////////////////////////////////
159 char *
160 ArenaStrndup(const char *s, uint32_t len, PLArenaPool *arena)
161 {
162 void *mem;
163 // Include trailing null in the len
164 PL_ARENA_ALLOCATE(mem, arena, len+1);
165 if (mem)
166 memcpy(mem, s, len+1);
167 return static_cast<char *>(mem);
168 }
170 char*
171 ArenaStrdup(const char *s, PLArenaPool *arena)
172 {
173 return ArenaStrndup(s, strlen(s), arena);
174 }
176 // GetService and a few other functions need to exit their mutex mid-function
177 // without reentering it later in the block. This class supports that
178 // style of early-exit that MutexAutoUnlock doesn't.
180 namespace {
182 class MOZ_STACK_CLASS MutexLock
183 {
184 public:
185 MutexLock(SafeMutex& aMutex)
186 : mMutex(aMutex)
187 , mLocked(false)
188 {
189 Lock();
190 }
192 ~MutexLock()
193 {
194 if (mLocked)
195 Unlock();
196 }
198 void Lock()
199 {
200 NS_ASSERTION(!mLocked, "Re-entering a mutex");
201 mMutex.Lock();
202 mLocked = true;
203 }
205 void Unlock()
206 {
207 NS_ASSERTION(mLocked, "Exiting a mutex that isn't held!");
208 mMutex.Unlock();
209 mLocked = false;
210 }
212 private:
213 SafeMutex& mMutex;
214 bool mLocked;
215 };
217 } // anonymous namespace
219 // this is safe to call during InitXPCOM
220 static already_AddRefed<nsIFile>
221 GetLocationFromDirectoryService(const char* prop)
222 {
223 nsCOMPtr<nsIProperties> directoryService;
224 nsDirectoryService::Create(nullptr,
225 NS_GET_IID(nsIProperties),
226 getter_AddRefs(directoryService));
228 if (!directoryService)
229 return nullptr;
231 nsCOMPtr<nsIFile> file;
232 nsresult rv = directoryService->Get(prop,
233 NS_GET_IID(nsIFile),
234 getter_AddRefs(file));
235 if (NS_FAILED(rv))
236 return nullptr;
238 return file.forget();
239 }
241 static already_AddRefed<nsIFile>
242 CloneAndAppend(nsIFile* aBase, const nsACString& append)
243 {
244 nsCOMPtr<nsIFile> f;
245 aBase->Clone(getter_AddRefs(f));
246 if (!f)
247 return nullptr;
249 f->AppendNative(append);
250 return f.forget();
251 }
253 ////////////////////////////////////////////////////////////////////////////////
254 // nsComponentManagerImpl
255 ////////////////////////////////////////////////////////////////////////////////
257 nsresult
258 nsComponentManagerImpl::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
259 {
260 if (aOuter)
261 return NS_ERROR_NO_AGGREGATION;
263 if (!gComponentManager)
264 return NS_ERROR_FAILURE;
266 return gComponentManager->QueryInterface(aIID, aResult);
267 }
269 static const int CONTRACTID_HASHTABLE_INITIAL_SIZE = 2048;
271 nsComponentManagerImpl::nsComponentManagerImpl()
272 : mFactories(CONTRACTID_HASHTABLE_INITIAL_SIZE)
273 , mContractIDs(CONTRACTID_HASHTABLE_INITIAL_SIZE)
274 , mLock("nsComponentManagerImpl.mLock")
275 , mStatus(NOT_INITIALIZED)
276 {
277 }
279 nsTArray<const mozilla::Module*>* nsComponentManagerImpl::sStaticModules;
281 /* static */ void
282 nsComponentManagerImpl::InitializeStaticModules()
283 {
284 if (sStaticModules)
285 return;
287 sStaticModules = new nsTArray<const mozilla::Module*>;
288 for (const mozilla::Module *const *const *staticModules = kPStaticModules;
289 *staticModules; ++staticModules)
290 sStaticModules->AppendElement(**staticModules);
291 }
293 nsTArray<nsComponentManagerImpl::ComponentLocation>*
294 nsComponentManagerImpl::sModuleLocations;
296 /* static */ void
297 nsComponentManagerImpl::InitializeModuleLocations()
298 {
299 if (sModuleLocations)
300 return;
302 sModuleLocations = new nsTArray<ComponentLocation>;
303 }
305 nsresult nsComponentManagerImpl::Init()
306 {
307 PR_ASSERT(NOT_INITIALIZED == mStatus);
309 if (nsComponentManagerLog == nullptr)
310 {
311 nsComponentManagerLog = PR_NewLogModule("nsComponentManager");
312 }
314 // Initialize our arena
315 PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE);
317 nsCOMPtr<nsIFile> greDir =
318 GetLocationFromDirectoryService(NS_GRE_DIR);
319 nsCOMPtr<nsIFile> appDir =
320 GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR);
322 InitializeStaticModules();
323 InitializeModuleLocations();
325 ComponentLocation* cl = sModuleLocations->InsertElementAt(0);
326 nsCOMPtr<nsIFile> lf = CloneAndAppend(appDir, NS_LITERAL_CSTRING("chrome.manifest"));
327 cl->type = NS_COMPONENT_LOCATION;
328 cl->location.Init(lf);
330 bool equals = false;
331 appDir->Equals(greDir, &equals);
332 if (!equals) {
333 cl = sModuleLocations->InsertElementAt(0);
334 cl->type = NS_COMPONENT_LOCATION;
335 lf = CloneAndAppend(greDir, NS_LITERAL_CSTRING("chrome.manifest"));
336 cl->location.Init(lf);
337 }
339 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
340 ("nsComponentManager: Initialized."));
342 nsresult rv = mNativeModuleLoader.Init();
343 if (NS_FAILED(rv))
344 return rv;
346 nsCategoryManager::GetSingleton()->SuppressNotifications(true);
348 RegisterModule(&kXPCOMModule, nullptr);
350 for (uint32_t i = 0; i < sStaticModules->Length(); ++i)
351 RegisterModule((*sStaticModules)[i], nullptr);
353 nsRefPtr<nsZipArchive> appOmnijar = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
354 if (appOmnijar) {
355 cl = sModuleLocations->InsertElementAt(1); // Insert after greDir
356 cl->type = NS_COMPONENT_LOCATION;
357 cl->location.Init(appOmnijar, "chrome.manifest");
358 }
359 nsRefPtr<nsZipArchive> greOmnijar = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
360 if (greOmnijar) {
361 cl = sModuleLocations->InsertElementAt(0);
362 cl->type = NS_COMPONENT_LOCATION;
363 cl->location.Init(greOmnijar, "chrome.manifest");
364 }
366 RereadChromeManifests(false);
368 nsCategoryManager::GetSingleton()->SuppressNotifications(false);
370 RegisterWeakMemoryReporter(this);
372 // Unfortunately, we can't register the nsCategoryManager memory reporter
373 // in its constructor (which is triggered by the GetSingleton() call
374 // above) because the memory reporter manager isn't initialized at that
375 // point. So we wait until now.
376 nsCategoryManager::GetSingleton()->InitMemoryReporter();
378 mStatus = NORMAL;
380 return NS_OK;
381 }
383 void
384 nsComponentManagerImpl::RegisterModule(const mozilla::Module* aModule,
385 FileLocation* aFile)
386 {
387 mLock.AssertNotCurrentThreadOwns();
389 {
390 // Scope the monitor so that we don't hold it while calling into the
391 // category manager.
392 MutexLock lock(mLock);
394 KnownModule* m;
395 if (aFile) {
396 nsCString uri;
397 aFile->GetURIString(uri);
398 NS_ASSERTION(!mKnownModules.Get(uri),
399 "Must not register a binary module twice.");
401 m = new KnownModule(aModule, *aFile);
402 mKnownModules.Put(uri, m);
403 } else {
404 m = new KnownModule(aModule);
405 mKnownStaticModules.AppendElement(m);
406 }
408 if (aModule->mCIDs) {
409 const mozilla::Module::CIDEntry* entry;
410 for (entry = aModule->mCIDs; entry->cid; ++entry)
411 RegisterCIDEntryLocked(entry, m);
412 }
414 if (aModule->mContractIDs) {
415 const mozilla::Module::ContractIDEntry* entry;
416 for (entry = aModule->mContractIDs; entry->contractid; ++entry)
417 RegisterContractIDLocked(entry);
418 MOZ_ASSERT(!entry->cid, "Incorrectly terminated contract list");
419 }
420 }
422 if (aModule->mCategoryEntries) {
423 const mozilla::Module::CategoryEntry* entry;
424 for (entry = aModule->mCategoryEntries; entry->category; ++entry)
425 nsCategoryManager::GetSingleton()->
426 AddCategoryEntry(entry->category,
427 entry->entry,
428 entry->value);
429 }
430 }
432 static bool
433 ProcessSelectorMatches(Module::ProcessSelector selector)
434 {
435 if (selector == Module::ANY_PROCESS) {
436 return true;
437 }
439 GeckoProcessType type = XRE_GetProcessType();
440 switch (selector) {
441 case Module::MAIN_PROCESS_ONLY:
442 return type == GeckoProcessType_Default;
443 case Module::CONTENT_PROCESS_ONLY:
444 return type == GeckoProcessType_Content;
445 default:
446 MOZ_CRASH("invalid process selector");
447 }
448 }
450 void
451 nsComponentManagerImpl::RegisterCIDEntryLocked(
452 const mozilla::Module::CIDEntry* aEntry,
453 KnownModule* aModule)
454 {
455 mLock.AssertCurrentThreadOwns();
457 if (!ProcessSelectorMatches(aEntry->processSelector)) {
458 return;
459 }
461 nsFactoryEntry* f = mFactories.Get(*aEntry->cid);
462 if (f) {
463 NS_WARNING("Re-registering a CID?");
465 char idstr[NSID_LENGTH];
466 aEntry->cid->ToProvidedString(idstr);
468 nsCString existing;
469 if (f->mModule)
470 existing = f->mModule->Description();
471 else
472 existing = "<unknown module>";
473 SafeMutexAutoUnlock unlock(mLock);
474 LogMessage("While registering XPCOM module %s, trying to re-register CID '%s' already registered by %s.",
475 aModule->Description().get(),
476 idstr,
477 existing.get());
478 return;
479 }
481 f = new nsFactoryEntry(aEntry, aModule);
482 mFactories.Put(*aEntry->cid, f);
483 }
485 void
486 nsComponentManagerImpl::RegisterContractIDLocked(
487 const mozilla::Module::ContractIDEntry* aEntry)
488 {
489 mLock.AssertCurrentThreadOwns();
491 if (!ProcessSelectorMatches(aEntry->processSelector)) {
492 return;
493 }
495 nsFactoryEntry* f = mFactories.Get(*aEntry->cid);
496 if (!f) {
497 NS_ERROR("No CID found when attempting to map contract ID");
499 char idstr[NSID_LENGTH];
500 aEntry->cid->ToProvidedString(idstr);
502 LogMessage("Could not map contract ID '%s' to CID %s because no implementation of the CID is registered.",
503 aEntry->contractid,
504 idstr);
506 return;
507 }
509 mContractIDs.Put(nsDependentCString(aEntry->contractid), f);
510 }
512 static void
513 CutExtension(nsCString& path)
514 {
515 int32_t dotPos = path.RFindChar('.');
516 if (kNotFound == dotPos)
517 path.Truncate();
518 else
519 path.Cut(0, dotPos + 1);
520 }
522 void
523 nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
524 FileLocation &aFile,
525 bool aChromeOnly)
526 {
527 uint32_t len;
528 FileLocation::Data data;
529 nsAutoArrayPtr<char> buf;
530 nsresult rv = aFile.GetData(data);
531 if (NS_SUCCEEDED(rv)) {
532 rv = data.GetSize(&len);
533 }
534 if (NS_SUCCEEDED(rv)) {
535 buf = new char[len + 1];
536 rv = data.Copy(buf, len);
537 }
538 if (NS_SUCCEEDED(rv)) {
539 buf[len] = '\0';
540 ParseManifest(aType, aFile, buf, aChromeOnly);
541 } else if (NS_BOOTSTRAPPED_LOCATION != aType) {
542 nsCString uri;
543 aFile.GetURIString(uri);
544 LogMessage("Could not read chrome manifest '%s'.", uri.get());
545 }
546 }
548 void
549 nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& cx, int lineno, char *const * argv)
550 {
551 char* file = argv[0];
552 FileLocation f(cx.mFile, file);
553 RegisterManifest(cx.mType, f, cx.mChromeOnly);
554 }
556 void
557 nsComponentManagerImpl::ManifestBinaryComponent(ManifestProcessingContext& cx, int lineno, char *const * argv)
558 {
559 if (cx.mFile.IsZip()) {
560 NS_WARNING("Cannot load binary components from a jar.");
561 LogMessageWithContext(cx.mFile, lineno,
562 "Cannot load binary components from a jar.");
563 return;
564 }
566 FileLocation f(cx.mFile, argv[0]);
567 nsCString uri;
568 f.GetURIString(uri);
570 if (mKnownModules.Get(uri)) {
571 NS_WARNING("Attempting to register a binary component twice.");
572 LogMessageWithContext(cx.mFile, lineno,
573 "Attempting to register a binary component twice.");
574 return;
575 }
577 const mozilla::Module* m = mNativeModuleLoader.LoadModule(f);
578 // The native module loader should report an error here, we don't have to
579 if (!m)
580 return;
582 RegisterModule(m, &f);
583 }
585 void
586 nsComponentManagerImpl::ManifestXPT(ManifestProcessingContext& cx, int lineno, char *const * argv)
587 {
588 FileLocation f(cx.mFile, argv[0]);
589 uint32_t len;
590 FileLocation::Data data;
591 nsAutoArrayPtr<char> buf;
592 nsresult rv = f.GetData(data);
593 if (NS_SUCCEEDED(rv)) {
594 rv = data.GetSize(&len);
595 }
596 if (NS_SUCCEEDED(rv)) {
597 buf = new char[len];
598 rv = data.Copy(buf, len);
599 }
600 if (NS_SUCCEEDED(rv)) {
601 XPTInterfaceInfoManager::GetSingleton()->RegisterBuffer(buf, len);
602 } else {
603 nsCString uri;
604 f.GetURIString(uri);
605 LogMessage("Could not read '%s'.", uri.get());
606 }
607 }
609 void
610 nsComponentManagerImpl::ManifestComponent(ManifestProcessingContext& cx, int lineno, char *const * argv)
611 {
612 mLock.AssertNotCurrentThreadOwns();
614 char* id = argv[0];
615 char* file = argv[1];
617 nsID cid;
618 if (!cid.Parse(id)) {
619 LogMessageWithContext(cx.mFile, lineno,
620 "Malformed CID: '%s'.", id);
621 return;
622 }
624 // Precompute the hash/file data outside of the lock
625 FileLocation fl(cx.mFile, file);
626 nsCString hash;
627 fl.GetURIString(hash);
629 MutexLock lock(mLock);
630 nsFactoryEntry* f = mFactories.Get(cid);
631 if (f) {
632 char idstr[NSID_LENGTH];
633 cid.ToProvidedString(idstr);
635 nsCString existing;
636 if (f->mModule)
637 existing = f->mModule->Description();
638 else
639 existing = "<unknown module>";
641 lock.Unlock();
643 LogMessageWithContext(cx.mFile, lineno,
644 "Trying to re-register CID '%s' already registered by %s.",
645 idstr,
646 existing.get());
647 return;
648 }
650 KnownModule* km;
652 km = mKnownModules.Get(hash);
653 if (!km) {
654 km = new KnownModule(fl);
655 mKnownModules.Put(hash, km);
656 }
658 void* place;
660 PL_ARENA_ALLOCATE(place, &mArena, sizeof(nsCID));
661 nsID* permanentCID = static_cast<nsID*>(place);
662 *permanentCID = cid;
664 PL_ARENA_ALLOCATE(place, &mArena, sizeof(mozilla::Module::CIDEntry));
665 mozilla::Module::CIDEntry* e = new (place) mozilla::Module::CIDEntry();
666 e->cid = permanentCID;
668 f = new nsFactoryEntry(e, km);
669 mFactories.Put(cid, f);
670 }
672 void
673 nsComponentManagerImpl::ManifestContract(ManifestProcessingContext& cx, int lineno, char *const * argv)
674 {
675 mLock.AssertNotCurrentThreadOwns();
677 char* contract = argv[0];
678 char* id = argv[1];
680 nsID cid;
681 if (!cid.Parse(id)) {
682 LogMessageWithContext(cx.mFile, lineno,
683 "Malformed CID: '%s'.", id);
684 return;
685 }
687 MutexLock lock(mLock);
688 nsFactoryEntry* f = mFactories.Get(cid);
689 if (!f) {
690 lock.Unlock();
691 LogMessageWithContext(cx.mFile, lineno,
692 "Could not map contract ID '%s' to CID %s because no implementation of the CID is registered.",
693 contract, id);
694 return;
695 }
697 mContractIDs.Put(nsDependentCString(contract), f);
698 }
700 void
701 nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext& cx, int lineno, char *const * argv)
702 {
703 char* category = argv[0];
704 char* key = argv[1];
705 char* value = argv[2];
707 nsCategoryManager::GetSingleton()->
708 AddCategoryEntry(category, key, value);
709 }
711 void
712 nsComponentManagerImpl::RereadChromeManifests(bool aChromeOnly)
713 {
714 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
715 ComponentLocation& l = sModuleLocations->ElementAt(i);
716 RegisterManifest(l.type, l.location, aChromeOnly);
717 }
718 }
720 bool
721 nsComponentManagerImpl::KnownModule::EnsureLoader()
722 {
723 if (!mLoader) {
724 nsCString extension;
725 mFile.GetURIString(extension);
726 CutExtension(extension);
727 mLoader = nsComponentManagerImpl::gComponentManager->LoaderForExtension(extension);
728 }
729 return !!mLoader;
730 }
732 bool
733 nsComponentManagerImpl::KnownModule::Load()
734 {
735 if (mFailed)
736 return false;
737 if (!mModule) {
738 if (!EnsureLoader())
739 return false;
741 mModule = mLoader->LoadModule(mFile);
743 if (!mModule) {
744 mFailed = true;
745 return false;
746 }
747 }
748 if (!mLoaded) {
749 if (mModule->loadProc) {
750 nsresult rv = mModule->loadProc();
751 if (NS_FAILED(rv)) {
752 mFailed = true;
753 return false;
754 }
755 }
756 mLoaded = true;
757 }
758 return true;
759 }
761 nsCString
762 nsComponentManagerImpl::KnownModule::Description() const
763 {
764 nsCString s;
765 if (mFile)
766 mFile.GetURIString(s);
767 else
768 s = "<static module>";
769 return s;
770 }
772 nsresult nsComponentManagerImpl::Shutdown(void)
773 {
774 PR_ASSERT(NORMAL == mStatus);
776 mStatus = SHUTDOWN_IN_PROGRESS;
778 // Shutdown the component manager
779 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown."));
781 UnregisterWeakMemoryReporter(this);
783 // Release all cached factories
784 mContractIDs.Clear();
785 mFactories.Clear(); // XXX release the objects, don't just clear
786 mLoaderMap.Clear();
787 mKnownModules.Clear();
788 mKnownStaticModules.Clear();
790 delete sStaticModules;
791 delete sModuleLocations;
793 // Unload libraries
794 mNativeModuleLoader.UnloadLibraries();
796 // delete arena for strings and small objects
797 PL_FinishArenaPool(&mArena);
799 mStatus = SHUTDOWN_COMPLETE;
801 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Shutdown complete."));
803 return NS_OK;
804 }
806 nsComponentManagerImpl::~nsComponentManagerImpl()
807 {
808 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning destruction."));
810 if (SHUTDOWN_COMPLETE != mStatus)
811 Shutdown();
813 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Destroyed."));
814 }
816 NS_IMPL_ISUPPORTS(
817 nsComponentManagerImpl,
818 nsIComponentManager,
819 nsIServiceManager,
820 nsIComponentRegistrar,
821 nsISupportsWeakReference,
822 nsIInterfaceRequestor,
823 nsIMemoryReporter)
825 nsresult
826 nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result)
827 {
828 NS_WARNING("This isn't supported");
829 // fall through to QI as anything QIable is a superset of what can be
830 // got via the GetInterface()
831 return QueryInterface(uuid, result);
832 }
834 nsFactoryEntry *
835 nsComponentManagerImpl::GetFactoryEntry(const char *aContractID,
836 uint32_t aContractIDLen)
837 {
838 SafeMutexAutoLock lock(mLock);
839 return mContractIDs.Get(nsDependentCString(aContractID, aContractIDLen));
840 }
843 nsFactoryEntry *
844 nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass)
845 {
846 SafeMutexAutoLock lock(mLock);
847 return mFactories.Get(aClass);
848 }
850 already_AddRefed<nsIFactory>
851 nsComponentManagerImpl::FindFactory(const nsCID& aClass)
852 {
853 nsFactoryEntry* e = GetFactoryEntry(aClass);
854 if (!e)
855 return nullptr;
857 return e->GetFactory();
858 }
860 already_AddRefed<nsIFactory>
861 nsComponentManagerImpl::FindFactory(const char *contractID,
862 uint32_t aContractIDLen)
863 {
864 nsFactoryEntry *entry = GetFactoryEntry(contractID, aContractIDLen);
865 if (!entry)
866 return nullptr;
868 return entry->GetFactory();
869 }
871 /**
872 * GetClassObject()
873 *
874 * Given a classID, this finds the singleton ClassObject that implements the CID.
875 * Returns an interface of type aIID off the singleton classobject.
876 */
877 NS_IMETHODIMP
878 nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID,
879 void **aResult)
880 {
881 nsresult rv;
883 #ifdef PR_LOGGING
884 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG))
885 {
886 char *buf = aClass.ToString();
887 PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
888 if (buf)
889 NS_Free(buf);
890 }
891 #endif
893 PR_ASSERT(aResult != nullptr);
895 nsCOMPtr<nsIFactory> factory = FindFactory(aClass);
896 if (!factory)
897 return NS_ERROR_FACTORY_NOT_REGISTERED;
899 rv = factory->QueryInterface(aIID, aResult);
901 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
902 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
904 return rv;
905 }
908 NS_IMETHODIMP
909 nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID,
910 const nsIID &aIID,
911 void **aResult)
912 {
913 if (NS_WARN_IF(!aResult) ||
914 NS_WARN_IF(!contractID))
915 return NS_ERROR_INVALID_ARG;
917 nsresult rv;
920 #ifdef PR_LOGGING
921 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG))
922 {
923 PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID);
924 }
925 #endif
927 nsCOMPtr<nsIFactory> factory = FindFactory(contractID, strlen(contractID));
928 if (!factory)
929 return NS_ERROR_FACTORY_NOT_REGISTERED;
931 rv = factory->QueryInterface(aIID, aResult);
933 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
934 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
936 return rv;
937 }
939 /**
940 * CreateInstance()
941 *
942 * Create an instance of an object that implements an interface and belongs
943 * to the implementation aClass using the factory. The factory is immediately
944 * released and not held onto for any longer.
945 */
946 NS_IMETHODIMP
947 nsComponentManagerImpl::CreateInstance(const nsCID &aClass,
948 nsISupports *aDelegate,
949 const nsIID &aIID,
950 void **aResult)
951 {
952 // test this first, since there's no point in creating a component during
953 // shutdown -- whether it's available or not would depend on the order it
954 // occurs in the list
955 if (gXPCOMShuttingDown) {
956 // When processing shutdown, don't process new GetService() requests
957 #ifdef SHOW_DENIED_ON_SHUTDOWN
958 nsXPIDLCString cid, iid;
959 cid.Adopt(aClass.ToString());
960 iid.Adopt(aIID.ToString());
961 fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
962 " CID: %s\n IID: %s\n", cid.get(), iid.get());
963 #endif /* SHOW_DENIED_ON_SHUTDOWN */
964 return NS_ERROR_UNEXPECTED;
965 }
967 if (aResult == nullptr)
968 {
969 return NS_ERROR_NULL_POINTER;
970 }
971 *aResult = nullptr;
973 nsFactoryEntry *entry = GetFactoryEntry(aClass);
975 if (!entry)
976 return NS_ERROR_FACTORY_NOT_REGISTERED;
978 #ifdef SHOW_CI_ON_EXISTING_SERVICE
979 if (entry->mServiceObject) {
980 nsXPIDLCString cid;
981 cid.Adopt(aClass.ToString());
982 nsAutoCString message;
983 message = NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
984 cid + NS_LITERAL_CSTRING("\" when a service for this CID already exists!");
985 NS_ERROR(message.get());
986 }
987 #endif
989 nsresult rv;
990 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
991 if (factory)
992 {
993 rv = factory->CreateInstance(aDelegate, aIID, aResult);
994 if (NS_SUCCEEDED(rv) && !*aResult) {
995 NS_ERROR("Factory did not return an object but returned success!");
996 rv = NS_ERROR_SERVICE_NOT_FOUND;
997 }
998 }
999 else {
1000 // Translate error values
1001 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1002 }
1004 #ifdef PR_LOGGING
1005 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
1006 {
1007 char *buf = aClass.ToString();
1008 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1009 ("nsComponentManager: CreateInstance(%s) %s", buf,
1010 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1011 if (buf)
1012 NS_Free(buf);
1013 }
1014 #endif
1016 return rv;
1017 }
1019 /**
1020 * CreateInstanceByContractID()
1021 *
1022 * A variant of CreateInstance() that creates an instance of the object that
1023 * implements the interface aIID and whose implementation has a contractID aContractID.
1024 *
1025 * This is only a convenience routine that turns around can calls the
1026 * CreateInstance() with classid and iid.
1027 */
1028 NS_IMETHODIMP
1029 nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID,
1030 nsISupports *aDelegate,
1031 const nsIID &aIID,
1032 void **aResult)
1033 {
1034 if (NS_WARN_IF(!aContractID))
1035 return NS_ERROR_INVALID_ARG;
1037 // test this first, since there's no point in creating a component during
1038 // shutdown -- whether it's available or not would depend on the order it
1039 // occurs in the list
1040 if (gXPCOMShuttingDown) {
1041 // When processing shutdown, don't process new GetService() requests
1042 #ifdef SHOW_DENIED_ON_SHUTDOWN
1043 nsXPIDLCString iid;
1044 iid.Adopt(aIID.ToString());
1045 fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
1046 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
1047 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1048 return NS_ERROR_UNEXPECTED;
1049 }
1051 if (aResult == nullptr)
1052 {
1053 return NS_ERROR_NULL_POINTER;
1054 }
1055 *aResult = nullptr;
1057 nsFactoryEntry *entry = GetFactoryEntry(aContractID, strlen(aContractID));
1059 if (!entry)
1060 return NS_ERROR_FACTORY_NOT_REGISTERED;
1062 #ifdef SHOW_CI_ON_EXISTING_SERVICE
1063 if (entry->mServiceObject) {
1064 nsAutoCString message;
1065 message =
1066 NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
1067 nsDependentCString(aContractID) +
1068 NS_LITERAL_CSTRING("\" when a service for this CID already exists! "
1069 "Add it to abusedContracts to track down the service consumer.");
1070 NS_ERROR(message.get());
1071 }
1072 #endif
1074 nsresult rv;
1075 nsCOMPtr<nsIFactory> factory = entry->GetFactory();
1076 if (factory)
1077 {
1079 rv = factory->CreateInstance(aDelegate, aIID, aResult);
1080 if (NS_SUCCEEDED(rv) && !*aResult) {
1081 NS_ERROR("Factory did not return an object but returned success!");
1082 rv = NS_ERROR_SERVICE_NOT_FOUND;
1083 }
1084 }
1085 else {
1086 // Translate error values
1087 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1088 }
1090 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1091 ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
1092 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1094 return rv;
1095 }
1097 static PLDHashOperator
1098 FreeFactoryEntries(const nsID& aCID,
1099 nsFactoryEntry* aEntry,
1100 void* arg)
1101 {
1102 aEntry->mFactory = nullptr;
1103 aEntry->mServiceObject = nullptr;
1104 return PL_DHASH_NEXT;
1105 }
1107 nsresult
1108 nsComponentManagerImpl::FreeServices()
1109 {
1110 NS_ASSERTION(gXPCOMShuttingDown, "Must be shutting down in order to free all services");
1112 if (!gXPCOMShuttingDown)
1113 return NS_ERROR_FAILURE;
1115 mFactories.EnumerateRead(FreeFactoryEntries, nullptr);
1116 return NS_OK;
1117 }
1119 // This should only ever be called within the monitor!
1120 nsComponentManagerImpl::PendingServiceInfo*
1121 nsComponentManagerImpl::AddPendingService(const nsCID& aServiceCID,
1122 PRThread* aThread)
1123 {
1124 PendingServiceInfo* newInfo = mPendingServices.AppendElement();
1125 if (newInfo) {
1126 newInfo->cid = &aServiceCID;
1127 newInfo->thread = aThread;
1128 }
1129 return newInfo;
1130 }
1132 // This should only ever be called within the monitor!
1133 void
1134 nsComponentManagerImpl::RemovePendingService(const nsCID& aServiceCID)
1135 {
1136 uint32_t pendingCount = mPendingServices.Length();
1137 for (uint32_t index = 0; index < pendingCount; ++index) {
1138 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
1139 if (info.cid->Equals(aServiceCID)) {
1140 mPendingServices.RemoveElementAt(index);
1141 return;
1142 }
1143 }
1144 }
1146 // This should only ever be called within the monitor!
1147 PRThread*
1148 nsComponentManagerImpl::GetPendingServiceThread(const nsCID& aServiceCID) const
1149 {
1150 uint32_t pendingCount = mPendingServices.Length();
1151 for (uint32_t index = 0; index < pendingCount; ++index) {
1152 const PendingServiceInfo& info = mPendingServices.ElementAt(index);
1153 if (info.cid->Equals(aServiceCID)) {
1154 return info.thread;
1155 }
1156 }
1157 return nullptr;
1158 }
1160 NS_IMETHODIMP
1161 nsComponentManagerImpl::GetService(const nsCID& aClass,
1162 const nsIID& aIID,
1163 void* *result)
1164 {
1165 // test this first, since there's no point in returning a service during
1166 // shutdown -- whether it's available or not would depend on the order it
1167 // occurs in the list
1168 if (gXPCOMShuttingDown) {
1169 // When processing shutdown, don't process new GetService() requests
1170 #ifdef SHOW_DENIED_ON_SHUTDOWN
1171 nsXPIDLCString cid, iid;
1172 cid.Adopt(aClass.ToString());
1173 iid.Adopt(aIID.ToString());
1174 fprintf(stderr, "Getting service on shutdown. Denied.\n"
1175 " CID: %s\n IID: %s\n", cid.get(), iid.get());
1176 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1177 return NS_ERROR_UNEXPECTED;
1178 }
1180 // `service` must be released after the lock is released, so it must be
1181 // declared before the lock in this C++ block.
1182 nsCOMPtr<nsISupports> service;
1183 MutexLock lock(mLock);
1185 nsFactoryEntry* entry = mFactories.Get(aClass);
1186 if (!entry)
1187 return NS_ERROR_FACTORY_NOT_REGISTERED;
1189 if (entry->mServiceObject) {
1190 lock.Unlock();
1191 return entry->mServiceObject->QueryInterface(aIID, result);
1192 }
1194 PRThread* currentPRThread = PR_GetCurrentThread();
1195 MOZ_ASSERT(currentPRThread, "This should never be null!");
1197 // Needed to optimize the event loop below.
1198 nsIThread* currentThread = nullptr;
1200 PRThread* pendingPRThread;
1201 while ((pendingPRThread = GetPendingServiceThread(aClass))) {
1202 if (pendingPRThread == currentPRThread) {
1203 NS_ERROR("Recursive GetService!");
1204 return NS_ERROR_NOT_AVAILABLE;
1205 }
1208 SafeMutexAutoUnlock unlockPending(mLock);
1210 if (!currentThread) {
1211 currentThread = NS_GetCurrentThread();
1212 MOZ_ASSERT(currentThread, "This should never be null!");
1213 }
1215 // This will process a single event or yield the thread if no event is
1216 // pending.
1217 if (!NS_ProcessNextEvent(currentThread, false)) {
1218 PR_Sleep(PR_INTERVAL_NO_WAIT);
1219 }
1220 }
1222 // It's still possible that the other thread failed to create the
1223 // service so we're not guaranteed to have an entry or service yet.
1224 if (entry->mServiceObject) {
1225 lock.Unlock();
1226 return entry->mServiceObject->QueryInterface(aIID, result);
1227 }
1229 #ifdef DEBUG
1230 PendingServiceInfo* newInfo =
1231 #endif
1232 AddPendingService(aClass, currentPRThread);
1233 NS_ASSERTION(newInfo, "Failed to add info to the array!");
1235 // We need to not be holding the service manager's lock while calling
1236 // CreateInstance, because it invokes user code which could try to re-enter
1237 // the service manager:
1239 nsresult rv;
1240 {
1241 SafeMutexAutoUnlock unlock(mLock);
1242 rv = CreateInstance(aClass, nullptr, aIID, getter_AddRefs(service));
1243 }
1244 if (NS_SUCCEEDED(rv) && !service) {
1245 NS_ERROR("Factory did not return an object but returned success");
1246 return NS_ERROR_SERVICE_NOT_FOUND;
1247 }
1249 #ifdef DEBUG
1250 pendingPRThread = GetPendingServiceThread(aClass);
1251 MOZ_ASSERT(pendingPRThread == currentPRThread,
1252 "Pending service array has been changed!");
1253 #endif
1254 RemovePendingService(aClass);
1256 if (NS_FAILED(rv))
1257 return rv;
1259 NS_ASSERTION(!entry->mServiceObject, "Created two instances of a service!");
1261 entry->mServiceObject = service.forget();
1263 lock.Unlock();
1264 nsISupports** sresult = reinterpret_cast<nsISupports**>(result);
1265 *sresult = entry->mServiceObject;
1266 (*sresult)->AddRef();
1268 return NS_OK;
1269 }
1271 NS_IMETHODIMP
1272 nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass,
1273 const nsIID& aIID,
1274 bool *result)
1275 {
1276 // Now we want to get the service if we already got it. If not, we don't want
1277 // to create an instance of it. mmh!
1279 // test this first, since there's no point in returning a service during
1280 // shutdown -- whether it's available or not would depend on the order it
1281 // occurs in the list
1282 if (gXPCOMShuttingDown) {
1283 // When processing shutdown, don't process new GetService() requests
1284 #ifdef SHOW_DENIED_ON_SHUTDOWN
1285 nsXPIDLCString cid, iid;
1286 cid.Adopt(aClass.ToString());
1287 iid.Adopt(aIID.ToString());
1288 fprintf(stderr, "Checking for service on shutdown. Denied.\n"
1289 " CID: %s\n IID: %s\n", cid.get(), iid.get());
1290 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1291 return NS_ERROR_UNEXPECTED;
1292 }
1294 nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
1295 nsFactoryEntry* entry;
1297 {
1298 SafeMutexAutoLock lock(mLock);
1299 entry = mFactories.Get(aClass);
1300 }
1302 if (entry && entry->mServiceObject) {
1303 nsCOMPtr<nsISupports> service;
1304 rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
1305 *result = (service!=nullptr);
1306 }
1308 return rv;
1309 }
1311 NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID,
1312 const nsIID& aIID,
1313 bool *result)
1314 {
1315 // Now we want to get the service if we already got it. If not, we don't want
1316 // to create an instance of it. mmh!
1318 // test this first, since there's no point in returning a service during
1319 // shutdown -- whether it's available or not would depend on the order it
1320 // occurs in the list
1321 if (gXPCOMShuttingDown) {
1322 // When processing shutdown, don't process new GetService() requests
1323 #ifdef SHOW_DENIED_ON_SHUTDOWN
1324 nsXPIDLCString iid;
1325 iid.Adopt(aIID.ToString());
1326 fprintf(stderr, "Checking for service on shutdown. Denied.\n"
1327 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
1328 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1329 return NS_ERROR_UNEXPECTED;
1330 }
1332 nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
1333 nsFactoryEntry *entry;
1334 {
1335 SafeMutexAutoLock lock(mLock);
1336 entry = mContractIDs.Get(nsDependentCString(aContractID));
1337 }
1339 if (entry && entry->mServiceObject) {
1340 nsCOMPtr<nsISupports> service;
1341 rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
1342 *result = (service!=nullptr);
1343 }
1344 return rv;
1345 }
1348 NS_IMETHODIMP
1349 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
1350 const nsIID& aIID,
1351 void* *result)
1352 {
1353 // test this first, since there's no point in returning a service during
1354 // shutdown -- whether it's available or not would depend on the order it
1355 // occurs in the list
1356 if (gXPCOMShuttingDown) {
1357 // When processing shutdown, don't process new GetService() requests
1358 #ifdef SHOW_DENIED_ON_SHUTDOWN
1359 nsXPIDLCString iid;
1360 iid.Adopt(aIID.ToString());
1361 fprintf(stderr, "Getting service on shutdown. Denied.\n"
1362 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
1363 #endif /* SHOW_DENIED_ON_SHUTDOWN */
1364 return NS_ERROR_UNEXPECTED;
1365 }
1367 // `service` must be released after the lock is released, so it must be
1368 // declared before the lock in this C++ block.
1369 nsCOMPtr<nsISupports> service;
1370 MutexLock lock(mLock);
1372 nsFactoryEntry *entry = mContractIDs.Get(nsDependentCString(aContractID));
1373 if (!entry)
1374 return NS_ERROR_FACTORY_NOT_REGISTERED;
1376 if (entry->mServiceObject) {
1377 // We need to not be holding the service manager's monitor while calling
1378 // QueryInterface, because it invokes user code which could try to re-enter
1379 // the service manager, or try to grab some other lock/monitor/condvar
1380 // and deadlock, e.g. bug 282743.
1381 // `entry` is valid until XPCOM shutdown, so we can safely use it after
1382 // exiting the lock.
1383 lock.Unlock();
1384 return entry->mServiceObject->QueryInterface(aIID, result);
1385 }
1387 PRThread* currentPRThread = PR_GetCurrentThread();
1388 MOZ_ASSERT(currentPRThread, "This should never be null!");
1390 // Needed to optimize the event loop below.
1391 nsIThread* currentThread = nullptr;
1393 PRThread* pendingPRThread;
1394 while ((pendingPRThread = GetPendingServiceThread(*entry->mCIDEntry->cid))) {
1395 if (pendingPRThread == currentPRThread) {
1396 NS_ERROR("Recursive GetService!");
1397 return NS_ERROR_NOT_AVAILABLE;
1398 }
1400 SafeMutexAutoUnlock unlockPending(mLock);
1402 if (!currentThread) {
1403 currentThread = NS_GetCurrentThread();
1404 MOZ_ASSERT(currentThread, "This should never be null!");
1405 }
1407 // This will process a single event or yield the thread if no event is
1408 // pending.
1409 if (!NS_ProcessNextEvent(currentThread, false)) {
1410 PR_Sleep(PR_INTERVAL_NO_WAIT);
1411 }
1412 }
1414 if (currentThread && entry->mServiceObject) {
1415 // If we have a currentThread then we must have waited on another thread
1416 // to create the service. Grab it now if that succeeded.
1417 lock.Unlock();
1418 return entry->mServiceObject->QueryInterface(aIID, result);
1419 }
1421 #ifdef DEBUG
1422 PendingServiceInfo* newInfo =
1423 #endif
1424 AddPendingService(*entry->mCIDEntry->cid, currentPRThread);
1425 NS_ASSERTION(newInfo, "Failed to add info to the array!");
1427 // We need to not be holding the service manager's lock while calling
1428 // CreateInstance, because it invokes user code which could try to re-enter
1429 // the service manager:
1431 nsresult rv;
1432 {
1433 SafeMutexAutoUnlock unlock(mLock);
1434 rv = CreateInstanceByContractID(aContractID, nullptr, aIID,
1435 getter_AddRefs(service));
1436 }
1437 if (NS_SUCCEEDED(rv) && !service) {
1438 NS_ERROR("Factory did not return an object but returned success");
1439 return NS_ERROR_SERVICE_NOT_FOUND;
1440 }
1442 #ifdef DEBUG
1443 pendingPRThread = GetPendingServiceThread(*entry->mCIDEntry->cid);
1444 MOZ_ASSERT(pendingPRThread == currentPRThread,
1445 "Pending service array has been changed!");
1446 #endif
1447 RemovePendingService(*entry->mCIDEntry->cid);
1449 if (NS_FAILED(rv))
1450 return rv;
1452 NS_ASSERTION(!entry->mServiceObject, "Created two instances of a service!");
1454 entry->mServiceObject = service.forget();
1456 lock.Unlock();
1458 nsISupports** sresult = reinterpret_cast<nsISupports**>(result);
1459 *sresult = entry->mServiceObject;
1460 (*sresult)->AddRef();
1462 return NS_OK;
1463 }
1465 already_AddRefed<mozilla::ModuleLoader>
1466 nsComponentManagerImpl::LoaderForExtension(const nsACString& aExt)
1467 {
1468 nsCOMPtr<mozilla::ModuleLoader> loader = mLoaderMap.Get(aExt);
1469 if (!loader) {
1470 loader = do_GetServiceFromCategory("module-loader",
1471 PromiseFlatCString(aExt).get());
1472 if (!loader)
1473 return nullptr;
1475 mLoaderMap.Put(aExt, loader);
1476 }
1478 return loader.forget();
1479 }
1481 NS_IMETHODIMP
1482 nsComponentManagerImpl::RegisterFactory(const nsCID& aClass,
1483 const char* aName,
1484 const char* aContractID,
1485 nsIFactory* aFactory)
1486 {
1487 if (!aFactory) {
1488 // If a null factory is passed in, this call just wants to reset
1489 // the contract ID to point to an existing CID entry.
1490 if (!aContractID)
1491 return NS_ERROR_INVALID_ARG;
1493 SafeMutexAutoLock lock(mLock);
1494 nsFactoryEntry* oldf = mFactories.Get(aClass);
1495 if (!oldf)
1496 return NS_ERROR_FACTORY_NOT_REGISTERED;
1498 mContractIDs.Put(nsDependentCString(aContractID), oldf);
1499 return NS_OK;
1500 }
1502 nsAutoPtr<nsFactoryEntry> f(new nsFactoryEntry(aClass, aFactory));
1504 SafeMutexAutoLock lock(mLock);
1505 nsFactoryEntry* oldf = mFactories.Get(aClass);
1506 if (oldf)
1507 return NS_ERROR_FACTORY_EXISTS;
1509 if (aContractID)
1510 mContractIDs.Put(nsDependentCString(aContractID), f);
1512 mFactories.Put(aClass, f.forget());
1514 return NS_OK;
1515 }
1517 NS_IMETHODIMP
1518 nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass,
1519 nsIFactory* aFactory)
1520 {
1521 // Don't release the dying factory or service object until releasing
1522 // the component manager monitor.
1523 nsCOMPtr<nsIFactory> dyingFactory;
1524 nsCOMPtr<nsISupports> dyingServiceObject;
1526 {
1527 SafeMutexAutoLock lock(mLock);
1528 nsFactoryEntry* f = mFactories.Get(aClass);
1529 if (!f || f->mFactory != aFactory)
1530 return NS_ERROR_FACTORY_NOT_REGISTERED;
1532 mFactories.Remove(aClass);
1534 // This might leave a stale contractid -> factory mapping in
1535 // place, so null out the factory entry (see
1536 // nsFactoryEntry::GetFactory)
1537 f->mFactory.swap(dyingFactory);
1538 f->mServiceObject.swap(dyingServiceObject);
1539 }
1541 return NS_OK;
1542 }
1544 NS_IMETHODIMP
1545 nsComponentManagerImpl::AutoRegister(nsIFile* aLocation)
1546 {
1547 XRE_AddManifestLocation(NS_COMPONENT_LOCATION, aLocation);
1548 return NS_OK;
1549 }
1551 NS_IMETHODIMP
1552 nsComponentManagerImpl::AutoUnregister(nsIFile* aLocation)
1553 {
1554 NS_ERROR("AutoUnregister not implemented.");
1555 return NS_ERROR_NOT_IMPLEMENTED;
1556 }
1558 NS_IMETHODIMP
1559 nsComponentManagerImpl::RegisterFactoryLocation(const nsCID& aCID,
1560 const char* aClassName,
1561 const char* aContractID,
1562 nsIFile* aFile,
1563 const char* aLoaderStr,
1564 const char* aType)
1565 {
1566 NS_ERROR("RegisterFactoryLocation not implemented.");
1567 return NS_ERROR_NOT_IMPLEMENTED;
1568 }
1570 NS_IMETHODIMP
1571 nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID& aCID,
1572 nsIFile* aFile)
1573 {
1574 NS_ERROR("UnregisterFactoryLocation not implemented.");
1575 return NS_ERROR_NOT_IMPLEMENTED;
1576 }
1578 NS_IMETHODIMP
1579 nsComponentManagerImpl::IsCIDRegistered(const nsCID & aClass,
1580 bool *_retval)
1581 {
1582 *_retval = (nullptr != GetFactoryEntry(aClass));
1583 return NS_OK;
1584 }
1586 NS_IMETHODIMP
1587 nsComponentManagerImpl::IsContractIDRegistered(const char *aClass,
1588 bool *_retval)
1589 {
1590 if (NS_WARN_IF(!aClass))
1591 return NS_ERROR_INVALID_ARG;
1593 nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass));
1595 if (entry)
1596 *_retval = true;
1597 else
1598 *_retval = false;
1599 return NS_OK;
1600 }
1602 static PLDHashOperator
1603 EnumerateCIDHelper(const nsID& id, nsFactoryEntry* entry, void* closure)
1604 {
1605 nsCOMArray<nsISupports> *array = static_cast<nsCOMArray<nsISupports>*>(closure);
1606 nsCOMPtr<nsISupportsID> wrapper = new nsSupportsIDImpl();
1607 wrapper->SetData(&id);
1608 array->AppendObject(wrapper);
1609 return PL_DHASH_NEXT;
1610 }
1612 NS_IMETHODIMP
1613 nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator **aEnumerator)
1614 {
1615 nsCOMArray<nsISupports> array;
1616 mFactories.EnumerateRead(EnumerateCIDHelper, &array);
1618 return NS_NewArrayEnumerator(aEnumerator, array);
1619 }
1621 static PLDHashOperator
1622 EnumerateContractsHelper(const nsACString& contract, nsFactoryEntry* entry, void* closure)
1623 {
1624 nsTArray<nsCString>* array = static_cast<nsTArray<nsCString>*>(closure);
1625 array->AppendElement(contract);
1626 return PL_DHASH_NEXT;
1627 }
1629 NS_IMETHODIMP
1630 nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator **aEnumerator)
1631 {
1632 nsTArray<nsCString>* array = new nsTArray<nsCString>;
1633 mContractIDs.EnumerateRead(EnumerateContractsHelper, array);
1635 nsCOMPtr<nsIUTF8StringEnumerator> e;
1636 nsresult rv = NS_NewAdoptingUTF8StringEnumerator(getter_AddRefs(e), array);
1637 if (NS_FAILED(rv))
1638 return rv;
1640 return CallQueryInterface(e, aEnumerator);
1641 }
1643 NS_IMETHODIMP
1644 nsComponentManagerImpl::CIDToContractID(const nsCID & aClass,
1645 char **_retval)
1646 {
1647 NS_ERROR("CIDTOContractID not implemented");
1648 return NS_ERROR_FACTORY_NOT_REGISTERED;
1649 }
1651 NS_IMETHODIMP
1652 nsComponentManagerImpl::ContractIDToCID(const char *aContractID,
1653 nsCID * *_retval)
1654 {
1655 {
1656 SafeMutexAutoLock lock(mLock);
1657 nsFactoryEntry* entry = mContractIDs.Get(nsDependentCString(aContractID));
1658 if (entry) {
1659 *_retval = (nsCID*) NS_Alloc(sizeof(nsCID));
1660 **_retval = *entry->mCIDEntry->cid;
1661 return NS_OK;
1662 }
1663 }
1664 *_retval = nullptr;
1665 return NS_ERROR_FACTORY_NOT_REGISTERED;
1666 }
1668 static size_t
1669 SizeOfFactoriesEntryExcludingThis(nsIDHashKey::KeyType aKey,
1670 nsFactoryEntry* const &aData,
1671 MallocSizeOf aMallocSizeOf,
1672 void* aUserArg)
1673 {
1674 return aData->SizeOfIncludingThis(aMallocSizeOf);
1675 }
1677 static size_t
1678 SizeOfContractIDsEntryExcludingThis(nsCStringHashKey::KeyType aKey,
1679 nsFactoryEntry* const &aData,
1680 MallocSizeOf aMallocSizeOf,
1681 void* aUserArg)
1682 {
1683 // We don't measure the nsFactoryEntry data because its owned by mFactories
1684 // (which measures them in SizeOfFactoriesEntryExcludingThis).
1685 return aKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
1686 }
1688 MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf)
1690 NS_IMETHODIMP
1691 nsComponentManagerImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
1692 nsISupports* aData)
1693 {
1694 return MOZ_COLLECT_REPORT(
1695 "explicit/xpcom/component-manager", KIND_HEAP, UNITS_BYTES,
1696 SizeOfIncludingThis(ComponentManagerMallocSizeOf),
1697 "Memory used for the XPCOM component manager.");
1698 }
1700 size_t
1701 nsComponentManagerImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
1702 {
1703 size_t n = aMallocSizeOf(this);
1704 n += mLoaderMap.SizeOfExcludingThis(nullptr, aMallocSizeOf);
1705 n += mFactories.SizeOfExcludingThis(SizeOfFactoriesEntryExcludingThis, aMallocSizeOf);
1706 n += mContractIDs.SizeOfExcludingThis(SizeOfContractIDsEntryExcludingThis, aMallocSizeOf);
1708 n += sStaticModules->SizeOfIncludingThis(aMallocSizeOf);
1709 n += sModuleLocations->SizeOfIncludingThis(aMallocSizeOf);
1711 n += mKnownStaticModules.SizeOfExcludingThis(aMallocSizeOf);
1712 n += mKnownModules.SizeOfExcludingThis(nullptr, aMallocSizeOf);
1714 n += PL_SizeOfArenaPoolExcludingPool(&mArena, aMallocSizeOf);
1716 n += mPendingServices.SizeOfExcludingThis(aMallocSizeOf);
1718 // Measurement of the following members may be added later if DMD finds it is
1719 // worthwhile:
1720 // - mLoaderMap's keys and values
1721 // - mMon
1722 // - sStaticModules' entries
1723 // - sModuleLocations' entries
1724 // - mNativeModuleLoader
1725 // - mKnownStaticModules' entries?
1726 // - mKnownModules' keys and values?
1728 return n;
1729 }
1731 ////////////////////////////////////////////////////////////////////////////////
1732 // nsFactoryEntry
1733 ////////////////////////////////////////////////////////////////////////////////
1735 nsFactoryEntry::nsFactoryEntry(const mozilla::Module::CIDEntry* entry,
1736 nsComponentManagerImpl::KnownModule* module)
1737 : mCIDEntry(entry)
1738 , mModule(module)
1739 {
1740 }
1742 nsFactoryEntry::nsFactoryEntry(const nsCID& aCID, nsIFactory* factory)
1743 : mCIDEntry(nullptr)
1744 , mModule(nullptr)
1745 , mFactory(factory)
1746 {
1747 mozilla::Module::CIDEntry* e = new mozilla::Module::CIDEntry();
1748 nsCID* cid = new nsCID;
1749 *cid = aCID;
1750 e->cid = cid;
1751 mCIDEntry = e;
1752 }
1754 nsFactoryEntry::~nsFactoryEntry()
1755 {
1756 // If this was a RegisterFactory entry, we own the CIDEntry/CID
1757 if (!mModule) {
1758 delete mCIDEntry->cid;
1759 delete mCIDEntry;
1760 }
1761 }
1763 already_AddRefed<nsIFactory>
1764 nsFactoryEntry::GetFactory()
1765 {
1766 nsComponentManagerImpl::gComponentManager->mLock.AssertNotCurrentThreadOwns();
1768 if (!mFactory) {
1769 // RegisterFactory then UnregisterFactory can leave an entry in mContractIDs
1770 // pointing to an unusable nsFactoryEntry.
1771 if (!mModule)
1772 return nullptr;
1774 if (!mModule->Load())
1775 return nullptr;
1777 // Don't set mFactory directly, it needs to be locked
1778 nsCOMPtr<nsIFactory> factory;
1780 if (mModule->Module()->getFactoryProc) {
1781 factory = mModule->Module()->getFactoryProc(*mModule->Module(),
1782 *mCIDEntry);
1783 }
1784 else if (mCIDEntry->getFactoryProc) {
1785 factory = mCIDEntry->getFactoryProc(*mModule->Module(), *mCIDEntry);
1786 }
1787 else {
1788 NS_ASSERTION(mCIDEntry->constructorProc, "no getfactory or constructor");
1789 factory = new mozilla::GenericFactory(mCIDEntry->constructorProc);
1790 }
1791 if (!factory)
1792 return nullptr;
1794 SafeMutexAutoLock lock(nsComponentManagerImpl::gComponentManager->mLock);
1795 // Threads can race to set mFactory
1796 if (!mFactory) {
1797 factory.swap(mFactory);
1798 }
1799 }
1800 nsCOMPtr<nsIFactory> factory = mFactory;
1801 return factory.forget();
1802 }
1804 size_t
1805 nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
1806 {
1807 size_t n = aMallocSizeOf(this);
1809 // Measurement of the following members may be added later if DMD finds it is
1810 // worthwhile:
1811 // - mCIDEntry;
1812 // - mModule;
1813 // - mFactory;
1814 // - mServiceObject;
1816 return n;
1817 }
1819 ////////////////////////////////////////////////////////////////////////////////
1820 // Static Access Functions
1821 ////////////////////////////////////////////////////////////////////////////////
1823 nsresult
1824 NS_GetComponentManager(nsIComponentManager* *result)
1825 {
1826 if (!nsComponentManagerImpl::gComponentManager)
1827 return NS_ERROR_NOT_INITIALIZED;
1829 NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager);
1830 return NS_OK;
1831 }
1833 nsresult
1834 NS_GetServiceManager(nsIServiceManager* *result)
1835 {
1836 if (!nsComponentManagerImpl::gComponentManager)
1837 return NS_ERROR_NOT_INITIALIZED;
1839 NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager);
1840 return NS_OK;
1841 }
1844 nsresult
1845 NS_GetComponentRegistrar(nsIComponentRegistrar* *result)
1846 {
1847 if (!nsComponentManagerImpl::gComponentManager)
1848 return NS_ERROR_NOT_INITIALIZED;
1850 NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager);
1851 return NS_OK;
1852 }
1854 EXPORT_XPCOM_API(nsresult)
1855 XRE_AddStaticComponent(const mozilla::Module* aComponent)
1856 {
1857 nsComponentManagerImpl::InitializeStaticModules();
1858 nsComponentManagerImpl::sStaticModules->AppendElement(aComponent);
1860 if (nsComponentManagerImpl::gComponentManager &&
1861 nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus)
1862 nsComponentManagerImpl::gComponentManager->RegisterModule(aComponent, nullptr);
1864 return NS_OK;
1865 }
1867 NS_IMETHODIMP
1868 nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation)
1869 {
1870 nsString path;
1871 nsresult rv = aLocation->GetPath(path);
1872 if (NS_FAILED(rv))
1873 return rv;
1875 if (Substring(path, path.Length() - 4).Equals(NS_LITERAL_STRING(".xpi"))) {
1876 return XRE_AddJarManifestLocation(NS_BOOTSTRAPPED_LOCATION, aLocation);
1877 }
1879 nsCOMPtr<nsIFile> manifest =
1880 CloneAndAppend(aLocation, NS_LITERAL_CSTRING("chrome.manifest"));
1881 return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION, manifest);
1882 }
1884 NS_IMETHODIMP
1885 nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation)
1886 {
1887 nsCOMPtr<nsIChromeRegistry> cr = mozilla::services::GetChromeRegistryService();
1888 if (!cr)
1889 return NS_ERROR_FAILURE;
1891 nsCOMPtr<nsIFile> manifest;
1892 nsString path;
1893 nsresult rv = aLocation->GetPath(path);
1894 if (NS_FAILED(rv))
1895 return rv;
1897 nsComponentManagerImpl::ComponentLocation elem;
1898 elem.type = NS_BOOTSTRAPPED_LOCATION;
1900 if (Substring(path, path.Length() - 4).Equals(NS_LITERAL_STRING(".xpi"))) {
1901 elem.location.Init(aLocation, "chrome.manifest");
1902 } else {
1903 nsCOMPtr<nsIFile> lf = CloneAndAppend(aLocation, NS_LITERAL_CSTRING("chrome.manifest"));
1904 elem.location.Init(lf);
1905 }
1907 // Remove reference.
1908 nsComponentManagerImpl::sModuleLocations->RemoveElement(elem, ComponentLocationComparator());
1910 rv = cr->CheckForNewChrome();
1911 return rv;
1912 }
1914 NS_IMETHODIMP
1915 nsComponentManagerImpl::GetManifestLocations(nsIArray **aLocations)
1916 {
1917 NS_ENSURE_ARG_POINTER(aLocations);
1918 *aLocations = nullptr;
1920 if (!sModuleLocations)
1921 return NS_ERROR_NOT_INITIALIZED;
1923 nsCOMPtr<nsIMutableArray> locations = nsArray::Create();
1924 nsresult rv;
1925 for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
1926 ComponentLocation& l = sModuleLocations->ElementAt(i);
1927 FileLocation loc = l.location;
1928 nsCString uriString;
1929 loc.GetURIString(uriString);
1930 nsCOMPtr<nsIURI> uri;
1931 rv = NS_NewURI(getter_AddRefs(uri), uriString);
1932 if (NS_SUCCEEDED(rv))
1933 locations->AppendElement(uri, false);
1934 }
1936 locations.forget(aLocations);
1937 return NS_OK;
1938 }
1940 EXPORT_XPCOM_API(nsresult)
1941 XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation)
1942 {
1943 nsComponentManagerImpl::InitializeModuleLocations();
1944 nsComponentManagerImpl::ComponentLocation* c =
1945 nsComponentManagerImpl::sModuleLocations->AppendElement();
1946 c->type = aType;
1947 c->location.Init(aLocation);
1949 if (nsComponentManagerImpl::gComponentManager &&
1950 nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus)
1951 nsComponentManagerImpl::gComponentManager->RegisterManifest(aType, c->location, false);
1953 return NS_OK;
1954 }
1956 EXPORT_XPCOM_API(nsresult)
1957 XRE_AddJarManifestLocation(NSLocationType aType, nsIFile* aLocation)
1958 {
1959 nsComponentManagerImpl::InitializeModuleLocations();
1960 nsComponentManagerImpl::ComponentLocation* c =
1961 nsComponentManagerImpl::sModuleLocations->AppendElement();
1963 c->type = aType;
1964 c->location.Init(aLocation, "chrome.manifest");
1966 if (nsComponentManagerImpl::gComponentManager &&
1967 nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus)
1968 nsComponentManagerImpl::gComponentManager->RegisterManifest(aType, c->location, false);
1970 return NS_OK;
1971 }