xpcom/components/nsComponentManager.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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;
  1004 #ifdef PR_LOGGING
  1005     if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
  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);
  1014 #endif
  1016     return rv;
  1019 /**
  1020  * CreateInstanceByContractID()
  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.
  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)
  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;
  1051     if (aResult == nullptr)
  1053         return NS_ERROR_NULL_POINTER;
  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());
  1072 #endif
  1074     nsresult rv;
  1075     nsCOMPtr<nsIFactory> factory = entry->GetFactory();
  1076     if (factory)
  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;
  1085     else {
  1086         // Translate error values
  1087         rv = NS_ERROR_FACTORY_NOT_REGISTERED;
  1090     PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
  1091            ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
  1092             NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
  1094     return rv;
  1097 static PLDHashOperator
  1098 FreeFactoryEntries(const nsID& aCID,
  1099                    nsFactoryEntry* aEntry,
  1100                    void* arg)
  1102     aEntry->mFactory = nullptr;
  1103     aEntry->mServiceObject = nullptr;
  1104     return PL_DHASH_NEXT;
  1107 nsresult
  1108 nsComponentManagerImpl::FreeServices()
  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;
  1119 // This should only ever be called within the monitor!
  1120 nsComponentManagerImpl::PendingServiceInfo*
  1121 nsComponentManagerImpl::AddPendingService(const nsCID& aServiceCID,
  1122                                           PRThread* aThread)
  1124   PendingServiceInfo* newInfo = mPendingServices.AppendElement();
  1125   if (newInfo) {
  1126     newInfo->cid = &aServiceCID;
  1127     newInfo->thread = aThread;
  1129   return newInfo;
  1132 // This should only ever be called within the monitor!
  1133 void
  1134 nsComponentManagerImpl::RemovePendingService(const nsCID& aServiceCID)
  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;
  1146 // This should only ever be called within the monitor!
  1147 PRThread*
  1148 nsComponentManagerImpl::GetPendingServiceThread(const nsCID& aServiceCID) const
  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;
  1157   return nullptr;
  1160 NS_IMETHODIMP
  1161 nsComponentManagerImpl::GetService(const nsCID& aClass,
  1162                                    const nsIID& aIID,
  1163                                    void* *result)
  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;
  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);
  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;
  1208         SafeMutexAutoUnlock unlockPending(mLock);
  1210         if (!currentThread) {
  1211             currentThread = NS_GetCurrentThread();
  1212             MOZ_ASSERT(currentThread, "This should never be null!");
  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);
  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);
  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;
  1241         SafeMutexAutoUnlock unlock(mLock);
  1242         rv = CreateInstance(aClass, nullptr, aIID, getter_AddRefs(service));
  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;
  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;
  1271 NS_IMETHODIMP
  1272 nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass,
  1273                                               const nsIID& aIID,
  1274                                               bool *result)
  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;
  1294     nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
  1295     nsFactoryEntry* entry;
  1298         SafeMutexAutoLock lock(mLock);
  1299         entry = mFactories.Get(aClass);
  1302     if (entry && entry->mServiceObject) {
  1303         nsCOMPtr<nsISupports> service;
  1304         rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
  1305         *result = (service!=nullptr);
  1308     return rv;
  1311 NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID,
  1312                                                                         const nsIID& aIID,
  1313                                                                         bool *result)
  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;
  1332     nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
  1333     nsFactoryEntry *entry;
  1335         SafeMutexAutoLock lock(mLock);
  1336         entry = mContractIDs.Get(nsDependentCString(aContractID));
  1339     if (entry && entry->mServiceObject) {
  1340         nsCOMPtr<nsISupports> service;
  1341         rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
  1342         *result = (service!=nullptr);
  1344     return rv;
  1348 NS_IMETHODIMP
  1349 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
  1350                                                const nsIID& aIID,
  1351                                                void* *result)
  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;
  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);
  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;
  1400         SafeMutexAutoUnlock unlockPending(mLock);
  1402         if (!currentThread) {
  1403             currentThread = NS_GetCurrentThread();
  1404             MOZ_ASSERT(currentThread, "This should never be null!");
  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);
  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);
  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;
  1433         SafeMutexAutoUnlock unlock(mLock);
  1434         rv = CreateInstanceByContractID(aContractID, nullptr, aIID,
  1435                                         getter_AddRefs(service));
  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;
  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;
  1465 already_AddRefed<mozilla::ModuleLoader>
  1466 nsComponentManagerImpl::LoaderForExtension(const nsACString& aExt)
  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);
  1478     return loader.forget();
  1481 NS_IMETHODIMP
  1482 nsComponentManagerImpl::RegisterFactory(const nsCID& aClass,
  1483                                         const char* aName,
  1484                                         const char* aContractID,
  1485                                         nsIFactory* aFactory)
  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;
  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;
  1517 NS_IMETHODIMP
  1518 nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass,
  1519                                           nsIFactory* aFactory)
  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;
  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);
  1541     return NS_OK;
  1544 NS_IMETHODIMP
  1545 nsComponentManagerImpl::AutoRegister(nsIFile* aLocation)
  1547     XRE_AddManifestLocation(NS_COMPONENT_LOCATION, aLocation);
  1548     return NS_OK;
  1551 NS_IMETHODIMP
  1552 nsComponentManagerImpl::AutoUnregister(nsIFile* aLocation)
  1554     NS_ERROR("AutoUnregister not implemented.");
  1555     return NS_ERROR_NOT_IMPLEMENTED;
  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)
  1566     NS_ERROR("RegisterFactoryLocation not implemented.");
  1567     return NS_ERROR_NOT_IMPLEMENTED;
  1570 NS_IMETHODIMP
  1571 nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID& aCID,
  1572                                                   nsIFile* aFile)
  1574     NS_ERROR("UnregisterFactoryLocation not implemented.");
  1575     return NS_ERROR_NOT_IMPLEMENTED;
  1578 NS_IMETHODIMP
  1579 nsComponentManagerImpl::IsCIDRegistered(const nsCID & aClass,
  1580                                         bool *_retval)
  1582     *_retval = (nullptr != GetFactoryEntry(aClass));
  1583     return NS_OK;
  1586 NS_IMETHODIMP
  1587 nsComponentManagerImpl::IsContractIDRegistered(const char *aClass,
  1588                                                bool *_retval)
  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;
  1602 static PLDHashOperator
  1603 EnumerateCIDHelper(const nsID& id, nsFactoryEntry* entry, void* closure)
  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;
  1612 NS_IMETHODIMP
  1613 nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator **aEnumerator)
  1615     nsCOMArray<nsISupports> array;
  1616     mFactories.EnumerateRead(EnumerateCIDHelper, &array);
  1618     return NS_NewArrayEnumerator(aEnumerator, array);
  1621 static PLDHashOperator
  1622 EnumerateContractsHelper(const nsACString& contract, nsFactoryEntry* entry, void* closure)
  1624     nsTArray<nsCString>* array = static_cast<nsTArray<nsCString>*>(closure);
  1625     array->AppendElement(contract);
  1626     return PL_DHASH_NEXT;
  1629 NS_IMETHODIMP
  1630 nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator **aEnumerator)
  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);
  1643 NS_IMETHODIMP
  1644 nsComponentManagerImpl::CIDToContractID(const nsCID & aClass,
  1645                                         char **_retval)
  1647     NS_ERROR("CIDTOContractID not implemented");
  1648     return NS_ERROR_FACTORY_NOT_REGISTERED;
  1651 NS_IMETHODIMP
  1652 nsComponentManagerImpl::ContractIDToCID(const char *aContractID,
  1653                                         nsCID * *_retval)
  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;
  1664     *_retval = nullptr;
  1665     return NS_ERROR_FACTORY_NOT_REGISTERED;
  1668 static size_t
  1669 SizeOfFactoriesEntryExcludingThis(nsIDHashKey::KeyType aKey,
  1670                                   nsFactoryEntry* const &aData,
  1671                                   MallocSizeOf aMallocSizeOf,
  1672                                   void* aUserArg)
  1674     return aData->SizeOfIncludingThis(aMallocSizeOf);
  1677 static size_t
  1678 SizeOfContractIDsEntryExcludingThis(nsCStringHashKey::KeyType aKey,
  1679                                     nsFactoryEntry* const &aData,
  1680                                     MallocSizeOf aMallocSizeOf,
  1681                                     void* aUserArg)
  1683     // We don't measure the nsFactoryEntry data because its owned by mFactories
  1684     // (which measures them in SizeOfFactoriesEntryExcludingThis).
  1685     return aKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
  1688 MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf)
  1690 NS_IMETHODIMP
  1691 nsComponentManagerImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
  1692                                        nsISupports* aData)
  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.");
  1700 size_t
  1701 nsComponentManagerImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
  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;
  1731 ////////////////////////////////////////////////////////////////////////////////
  1732 // nsFactoryEntry
  1733 ////////////////////////////////////////////////////////////////////////////////
  1735 nsFactoryEntry::nsFactoryEntry(const mozilla::Module::CIDEntry* entry,
  1736                                nsComponentManagerImpl::KnownModule* module)
  1737     : mCIDEntry(entry)
  1738     , mModule(module)
  1742 nsFactoryEntry::nsFactoryEntry(const nsCID& aCID, nsIFactory* factory)
  1743     : mCIDEntry(nullptr)
  1744     , mModule(nullptr)
  1745     , mFactory(factory)
  1747     mozilla::Module::CIDEntry* e = new mozilla::Module::CIDEntry();
  1748     nsCID* cid = new nsCID;
  1749     *cid = aCID;
  1750     e->cid = cid;
  1751     mCIDEntry = e;
  1754 nsFactoryEntry::~nsFactoryEntry()
  1756     // If this was a RegisterFactory entry, we own the CIDEntry/CID
  1757     if (!mModule) {
  1758         delete mCIDEntry->cid;
  1759         delete mCIDEntry;
  1763 already_AddRefed<nsIFactory>
  1764 nsFactoryEntry::GetFactory()
  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);
  1784         else if (mCIDEntry->getFactoryProc) {
  1785             factory = mCIDEntry->getFactoryProc(*mModule->Module(), *mCIDEntry);
  1787         else {
  1788             NS_ASSERTION(mCIDEntry->constructorProc, "no getfactory or constructor");
  1789             factory = new mozilla::GenericFactory(mCIDEntry->constructorProc);
  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);
  1800     nsCOMPtr<nsIFactory> factory = mFactory;
  1801     return factory.forget();
  1804 size_t
  1805 nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
  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;
  1819 ////////////////////////////////////////////////////////////////////////////////
  1820 // Static Access Functions
  1821 ////////////////////////////////////////////////////////////////////////////////
  1823 nsresult
  1824 NS_GetComponentManager(nsIComponentManager* *result)
  1826     if (!nsComponentManagerImpl::gComponentManager)
  1827         return NS_ERROR_NOT_INITIALIZED;
  1829     NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager);
  1830     return NS_OK;
  1833 nsresult
  1834 NS_GetServiceManager(nsIServiceManager* *result)
  1836     if (!nsComponentManagerImpl::gComponentManager)
  1837         return NS_ERROR_NOT_INITIALIZED;
  1839     NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager);
  1840     return NS_OK;
  1844 nsresult
  1845 NS_GetComponentRegistrar(nsIComponentRegistrar* *result)
  1847     if (!nsComponentManagerImpl::gComponentManager)
  1848         return NS_ERROR_NOT_INITIALIZED;
  1850     NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager);
  1851     return NS_OK;
  1854 EXPORT_XPCOM_API(nsresult)
  1855 XRE_AddStaticComponent(const mozilla::Module* aComponent)
  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;
  1867 NS_IMETHODIMP
  1868 nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation)
  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);
  1879   nsCOMPtr<nsIFile> manifest =
  1880     CloneAndAppend(aLocation, NS_LITERAL_CSTRING("chrome.manifest"));
  1881   return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION, manifest);
  1884 NS_IMETHODIMP
  1885 nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation)
  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);
  1907   // Remove reference.
  1908   nsComponentManagerImpl::sModuleLocations->RemoveElement(elem, ComponentLocationComparator());
  1910   rv = cr->CheckForNewChrome();
  1911   return rv;
  1914 NS_IMETHODIMP
  1915 nsComponentManagerImpl::GetManifestLocations(nsIArray **aLocations)
  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);
  1936   locations.forget(aLocations);
  1937   return NS_OK;
  1940 EXPORT_XPCOM_API(nsresult)
  1941 XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation)
  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;
  1956 EXPORT_XPCOM_API(nsresult)
  1957 XRE_AddJarManifestLocation(NSLocationType aType, nsIFile* aLocation)
  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;

mercurial