xpcom/components/nsComponentManager.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/components/nsComponentManager.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1972 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.9 + *
    1.10 + * This Original Code has been modified by IBM Corporation.
    1.11 + * Modifications made by IBM described herein are
    1.12 + * Copyright (c) International Business Machines
    1.13 + * Corporation, 2000
    1.14 + *
    1.15 + * Modifications to Mozilla code or documentation
    1.16 + * identified per MPL Section 3.3
    1.17 + *
    1.18 + * Date             Modified by     Description of modification
    1.19 + * 04/20/2000       IBM Corp.      Added PR_CALLBACK for Optlink use in OS2
    1.20 + */
    1.21 +
    1.22 +#include <stdlib.h>
    1.23 +#include "nscore.h"
    1.24 +#include "nsISupports.h"
    1.25 +#include "nspr.h"
    1.26 +#include "nsCRT.h" // for atoll
    1.27 +
    1.28 +// Arena used by component manager for storing contractid string, dll
    1.29 +// location strings and small objects
    1.30 +// CAUTION: Arena align mask needs to be defined before including plarena.h
    1.31 +//          currently from nsComponentManager.h
    1.32 +#define PL_ARENA_CONST_ALIGN_MASK 7
    1.33 +#define NS_CM_BLOCK_SIZE (1024 * 8)
    1.34 +
    1.35 +#include "nsCategoryManager.h"
    1.36 +#include "nsCOMPtr.h"
    1.37 +#include "nsComponentManager.h"
    1.38 +#include "nsDirectoryService.h"
    1.39 +#include "nsDirectoryServiceDefs.h"
    1.40 +#include "nsCategoryManager.h"
    1.41 +#include "nsCategoryManagerUtils.h"
    1.42 +#include "xptiprivate.h"
    1.43 +#include "mozilla/MemoryReporting.h"
    1.44 +#include "mozilla/XPTInterfaceInfoManager.h"
    1.45 +#include "nsIConsoleService.h"
    1.46 +#include "nsIObserverService.h"
    1.47 +#include "nsISimpleEnumerator.h"
    1.48 +#include "nsIStringEnumerator.h"
    1.49 +#include "nsXPCOM.h"
    1.50 +#include "nsXPCOMPrivate.h"
    1.51 +#include "nsISupportsPrimitives.h"
    1.52 +#include "nsIClassInfo.h"
    1.53 +#include "nsLocalFile.h"
    1.54 +#include "nsReadableUtils.h"
    1.55 +#include "nsString.h"
    1.56 +#include "nsXPIDLString.h"
    1.57 +#include "prcmon.h"
    1.58 +#include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself...
    1.59 +#include "nsThreadUtils.h"
    1.60 +#include "prthread.h"
    1.61 +#include "private/pprthred.h"
    1.62 +#include "nsTArray.h"
    1.63 +#include "prio.h"
    1.64 +#include "ManifestParser.h"
    1.65 +#include "mozilla/Services.h"
    1.66 +
    1.67 +#include "nsManifestLineReader.h"
    1.68 +#include "mozilla/GenericFactory.h"
    1.69 +#include "nsSupportsPrimitives.h"
    1.70 +#include "nsArray.h"
    1.71 +#include "nsIMutableArray.h"
    1.72 +#include "nsArrayEnumerator.h"
    1.73 +#include "nsStringEnumerator.h"
    1.74 +#include "mozilla/FileUtils.h"
    1.75 +#include "nsNetUtil.h"
    1.76 +
    1.77 +#include <new>     // for placement new
    1.78 +
    1.79 +#include "mozilla/Omnijar.h"
    1.80 +
    1.81 +#include "prlog.h"
    1.82 +
    1.83 +using namespace mozilla;
    1.84 +
    1.85 +PRLogModuleInfo* nsComponentManagerLog = nullptr;
    1.86 +
    1.87 +// defined in nsStaticXULComponents.cpp to contain all the components in
    1.88 +// libxul.
    1.89 +extern mozilla::Module const *const *const kPStaticModules[];
    1.90 +
    1.91 +#if 0 || defined (DEBUG_timeless)
    1.92 + #define SHOW_DENIED_ON_SHUTDOWN
    1.93 + #define SHOW_CI_ON_EXISTING_SERVICE
    1.94 +#endif
    1.95 +
    1.96 +// Bloated registry buffer size to improve startup performance -- needs to
    1.97 +// be big enough to fit the entire file into memory or it'll thrash.
    1.98 +// 512K is big enough to allow for some future growth in the registry.
    1.99 +#define BIG_REGISTRY_BUFLEN   (512*1024)
   1.100 +
   1.101 +// Common Key Names
   1.102 +const char xpcomComponentsKeyName[]="software/mozilla/XPCOM/components";
   1.103 +const char xpcomKeyName[]="software/mozilla/XPCOM";
   1.104 +
   1.105 +// Common Value Names
   1.106 +const char fileSizeValueName[]="FileSize";
   1.107 +const char lastModValueName[]="LastModTimeStamp";
   1.108 +const char nativeComponentType[]="application/x-mozilla-native";
   1.109 +const char staticComponentType[]="application/x-mozilla-static";
   1.110 +
   1.111 +NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID);
   1.112 +
   1.113 +#define UID_STRING_LENGTH 39
   1.114 +
   1.115 +nsresult
   1.116 +nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
   1.117 +{
   1.118 +    nsresult rv;
   1.119 +    nsXPIDLCString value;
   1.120 +    nsCOMPtr<nsICategoryManager> catman;
   1.121 +    nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager;
   1.122 +    if (!compMgr) {
   1.123 +        rv = NS_ERROR_NOT_INITIALIZED;
   1.124 +        goto error;
   1.125 +    }
   1.126 +
   1.127 +    if (!mCategory || !mEntry) {
   1.128 +        // when categories have defaults, use that for null mEntry
   1.129 +        rv = NS_ERROR_NULL_POINTER;
   1.130 +        goto error;
   1.131 +    }
   1.132 +
   1.133 +    rv = compMgr->nsComponentManagerImpl::GetService(kCategoryManagerCID,
   1.134 +                                                     NS_GET_IID(nsICategoryManager),
   1.135 +                                                     getter_AddRefs(catman));
   1.136 +    if (NS_FAILED(rv)) goto error;
   1.137 +
   1.138 +    /* find the contractID for category.entry */
   1.139 +    rv = catman->GetCategoryEntry(mCategory, mEntry,
   1.140 +                                  getter_Copies(value));
   1.141 +    if (NS_FAILED(rv)) goto error;
   1.142 +    if (!value) {
   1.143 +        rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
   1.144 +        goto error;
   1.145 +    }
   1.146 +
   1.147 +    rv = compMgr->
   1.148 +        nsComponentManagerImpl::GetServiceByContractID(value,
   1.149 +                                                       aIID, aInstancePtr);
   1.150 +    if (NS_FAILED(rv)) {
   1.151 +    error:
   1.152 +        *aInstancePtr = 0;
   1.153 +    }
   1.154 +    if (mErrorPtr)
   1.155 +        *mErrorPtr = rv;
   1.156 +    return rv;
   1.157 +}
   1.158 +
   1.159 +////////////////////////////////////////////////////////////////////////////////
   1.160 +// Arena helper functions
   1.161 +////////////////////////////////////////////////////////////////////////////////
   1.162 +char *
   1.163 +ArenaStrndup(const char *s, uint32_t len, PLArenaPool *arena)
   1.164 +{
   1.165 +    void *mem;
   1.166 +    // Include trailing null in the len
   1.167 +    PL_ARENA_ALLOCATE(mem, arena, len+1);
   1.168 +    if (mem)
   1.169 +        memcpy(mem, s, len+1);
   1.170 +    return static_cast<char *>(mem);
   1.171 +}
   1.172 +
   1.173 +char*
   1.174 +ArenaStrdup(const char *s, PLArenaPool *arena)
   1.175 +{
   1.176 +    return ArenaStrndup(s, strlen(s), arena);
   1.177 +}
   1.178 +
   1.179 +// GetService and a few other functions need to exit their mutex mid-function
   1.180 +// without reentering it later in the block. This class supports that
   1.181 +// style of early-exit that MutexAutoUnlock doesn't.
   1.182 +
   1.183 +namespace {
   1.184 +
   1.185 +class MOZ_STACK_CLASS MutexLock
   1.186 +{
   1.187 +public:
   1.188 +    MutexLock(SafeMutex& aMutex)
   1.189 +        : mMutex(aMutex)
   1.190 +        , mLocked(false)
   1.191 +    {
   1.192 +        Lock();
   1.193 +    }
   1.194 +
   1.195 +    ~MutexLock()
   1.196 +    {
   1.197 +        if (mLocked)
   1.198 +            Unlock();
   1.199 +    }
   1.200 +
   1.201 +    void Lock()
   1.202 +    {
   1.203 +        NS_ASSERTION(!mLocked, "Re-entering a mutex");
   1.204 +        mMutex.Lock();
   1.205 +        mLocked = true;
   1.206 +    }
   1.207 +
   1.208 +    void Unlock()
   1.209 +    {
   1.210 +        NS_ASSERTION(mLocked, "Exiting a mutex that isn't held!");
   1.211 +        mMutex.Unlock();
   1.212 +        mLocked = false;
   1.213 +    }
   1.214 +
   1.215 +private:
   1.216 +    SafeMutex& mMutex;
   1.217 +    bool mLocked;
   1.218 +};
   1.219 +
   1.220 +} // anonymous namespace
   1.221 +
   1.222 +// this is safe to call during InitXPCOM
   1.223 +static already_AddRefed<nsIFile>
   1.224 +GetLocationFromDirectoryService(const char* prop)
   1.225 +{
   1.226 +    nsCOMPtr<nsIProperties> directoryService;
   1.227 +    nsDirectoryService::Create(nullptr,
   1.228 +                               NS_GET_IID(nsIProperties),
   1.229 +                               getter_AddRefs(directoryService));
   1.230 +
   1.231 +    if (!directoryService)
   1.232 +        return nullptr;
   1.233 +
   1.234 +    nsCOMPtr<nsIFile> file;
   1.235 +    nsresult rv = directoryService->Get(prop,
   1.236 +                                        NS_GET_IID(nsIFile),
   1.237 +                                        getter_AddRefs(file));
   1.238 +    if (NS_FAILED(rv))
   1.239 +        return nullptr;
   1.240 +
   1.241 +    return file.forget();
   1.242 +}
   1.243 +
   1.244 +static already_AddRefed<nsIFile>
   1.245 +CloneAndAppend(nsIFile* aBase, const nsACString& append)
   1.246 +{
   1.247 +    nsCOMPtr<nsIFile> f;
   1.248 +    aBase->Clone(getter_AddRefs(f));
   1.249 +    if (!f)
   1.250 +        return nullptr;
   1.251 +
   1.252 +    f->AppendNative(append);
   1.253 +    return f.forget();
   1.254 +}
   1.255 +
   1.256 +////////////////////////////////////////////////////////////////////////////////
   1.257 +// nsComponentManagerImpl
   1.258 +////////////////////////////////////////////////////////////////////////////////
   1.259 +
   1.260 +nsresult
   1.261 +nsComponentManagerImpl::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
   1.262 +{
   1.263 +    if (aOuter)
   1.264 +        return NS_ERROR_NO_AGGREGATION;
   1.265 +
   1.266 +    if (!gComponentManager)
   1.267 +        return NS_ERROR_FAILURE;
   1.268 +
   1.269 +    return gComponentManager->QueryInterface(aIID, aResult);
   1.270 +}
   1.271 +
   1.272 +static const int CONTRACTID_HASHTABLE_INITIAL_SIZE = 2048;
   1.273 +
   1.274 +nsComponentManagerImpl::nsComponentManagerImpl()
   1.275 +    : mFactories(CONTRACTID_HASHTABLE_INITIAL_SIZE)
   1.276 +    , mContractIDs(CONTRACTID_HASHTABLE_INITIAL_SIZE)
   1.277 +    , mLock("nsComponentManagerImpl.mLock")
   1.278 +    , mStatus(NOT_INITIALIZED)
   1.279 +{
   1.280 +}
   1.281 +
   1.282 +nsTArray<const mozilla::Module*>* nsComponentManagerImpl::sStaticModules;
   1.283 +
   1.284 +/* static */ void
   1.285 +nsComponentManagerImpl::InitializeStaticModules()
   1.286 +{
   1.287 +    if (sStaticModules)
   1.288 +        return;
   1.289 +
   1.290 +    sStaticModules = new nsTArray<const mozilla::Module*>;
   1.291 +    for (const mozilla::Module *const *const *staticModules = kPStaticModules;
   1.292 +         *staticModules; ++staticModules)
   1.293 +        sStaticModules->AppendElement(**staticModules);
   1.294 +}
   1.295 +
   1.296 +nsTArray<nsComponentManagerImpl::ComponentLocation>*
   1.297 +nsComponentManagerImpl::sModuleLocations;
   1.298 +
   1.299 +/* static */ void
   1.300 +nsComponentManagerImpl::InitializeModuleLocations()
   1.301 +{
   1.302 +    if (sModuleLocations)
   1.303 +        return;
   1.304 +
   1.305 +    sModuleLocations = new nsTArray<ComponentLocation>;
   1.306 +}
   1.307 +
   1.308 +nsresult nsComponentManagerImpl::Init()
   1.309 +{
   1.310 +    PR_ASSERT(NOT_INITIALIZED == mStatus);
   1.311 +
   1.312 +    if (nsComponentManagerLog == nullptr)
   1.313 +    {
   1.314 +        nsComponentManagerLog = PR_NewLogModule("nsComponentManager");
   1.315 +    }
   1.316 +
   1.317 +    // Initialize our arena
   1.318 +    PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE);
   1.319 +
   1.320 +    nsCOMPtr<nsIFile> greDir =
   1.321 +        GetLocationFromDirectoryService(NS_GRE_DIR);
   1.322 +    nsCOMPtr<nsIFile> appDir =
   1.323 +        GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR);
   1.324 +
   1.325 +    InitializeStaticModules();
   1.326 +    InitializeModuleLocations();
   1.327 +
   1.328 +    ComponentLocation* cl = sModuleLocations->InsertElementAt(0);
   1.329 +    nsCOMPtr<nsIFile> lf = CloneAndAppend(appDir, NS_LITERAL_CSTRING("chrome.manifest"));
   1.330 +    cl->type = NS_COMPONENT_LOCATION;
   1.331 +    cl->location.Init(lf);
   1.332 +
   1.333 +    bool equals = false;
   1.334 +    appDir->Equals(greDir, &equals);
   1.335 +    if (!equals) {
   1.336 +        cl = sModuleLocations->InsertElementAt(0);
   1.337 +        cl->type = NS_COMPONENT_LOCATION;
   1.338 +        lf = CloneAndAppend(greDir, NS_LITERAL_CSTRING("chrome.manifest"));
   1.339 +        cl->location.Init(lf);
   1.340 +    }
   1.341 +
   1.342 +    PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
   1.343 +           ("nsComponentManager: Initialized."));
   1.344 +
   1.345 +    nsresult rv = mNativeModuleLoader.Init();
   1.346 +    if (NS_FAILED(rv))
   1.347 +        return rv;
   1.348 +
   1.349 +    nsCategoryManager::GetSingleton()->SuppressNotifications(true);
   1.350 +
   1.351 +    RegisterModule(&kXPCOMModule, nullptr);
   1.352 +
   1.353 +    for (uint32_t i = 0; i < sStaticModules->Length(); ++i)
   1.354 +        RegisterModule((*sStaticModules)[i], nullptr);
   1.355 +
   1.356 +    nsRefPtr<nsZipArchive> appOmnijar = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
   1.357 +    if (appOmnijar) {
   1.358 +        cl = sModuleLocations->InsertElementAt(1); // Insert after greDir
   1.359 +        cl->type = NS_COMPONENT_LOCATION;
   1.360 +        cl->location.Init(appOmnijar, "chrome.manifest");
   1.361 +    }
   1.362 +    nsRefPtr<nsZipArchive> greOmnijar = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
   1.363 +    if (greOmnijar) {
   1.364 +        cl = sModuleLocations->InsertElementAt(0);
   1.365 +        cl->type = NS_COMPONENT_LOCATION;
   1.366 +        cl->location.Init(greOmnijar, "chrome.manifest");
   1.367 +    }
   1.368 +
   1.369 +    RereadChromeManifests(false);
   1.370 +
   1.371 +    nsCategoryManager::GetSingleton()->SuppressNotifications(false);
   1.372 +
   1.373 +    RegisterWeakMemoryReporter(this);
   1.374 +
   1.375 +    // Unfortunately, we can't register the nsCategoryManager memory reporter
   1.376 +    // in its constructor (which is triggered by the GetSingleton() call
   1.377 +    // above) because the memory reporter manager isn't initialized at that
   1.378 +    // point.  So we wait until now.
   1.379 +    nsCategoryManager::GetSingleton()->InitMemoryReporter();
   1.380 +
   1.381 +    mStatus = NORMAL;
   1.382 +
   1.383 +    return NS_OK;
   1.384 +}
   1.385 +
   1.386 +void
   1.387 +nsComponentManagerImpl::RegisterModule(const mozilla::Module* aModule,
   1.388 +                                       FileLocation* aFile)
   1.389 +{
   1.390 +    mLock.AssertNotCurrentThreadOwns();
   1.391 +
   1.392 +    {
   1.393 +        // Scope the monitor so that we don't hold it while calling into the
   1.394 +        // category manager.
   1.395 +        MutexLock lock(mLock);
   1.396 +
   1.397 +        KnownModule* m;
   1.398 +        if (aFile) {
   1.399 +            nsCString uri;
   1.400 +            aFile->GetURIString(uri);
   1.401 +            NS_ASSERTION(!mKnownModules.Get(uri),
   1.402 +                         "Must not register a binary module twice.");
   1.403 +
   1.404 +            m = new KnownModule(aModule, *aFile);
   1.405 +            mKnownModules.Put(uri, m);
   1.406 +        } else {
   1.407 +            m = new KnownModule(aModule);
   1.408 +            mKnownStaticModules.AppendElement(m);
   1.409 +        }
   1.410 +
   1.411 +        if (aModule->mCIDs) {
   1.412 +            const mozilla::Module::CIDEntry* entry;
   1.413 +            for (entry = aModule->mCIDs; entry->cid; ++entry)
   1.414 +                RegisterCIDEntryLocked(entry, m);
   1.415 +        }
   1.416 +
   1.417 +        if (aModule->mContractIDs) {
   1.418 +            const mozilla::Module::ContractIDEntry* entry;
   1.419 +            for (entry = aModule->mContractIDs; entry->contractid; ++entry)
   1.420 +                RegisterContractIDLocked(entry);
   1.421 +            MOZ_ASSERT(!entry->cid, "Incorrectly terminated contract list");
   1.422 +        }
   1.423 +    }
   1.424 +
   1.425 +    if (aModule->mCategoryEntries) {
   1.426 +        const mozilla::Module::CategoryEntry* entry;
   1.427 +        for (entry = aModule->mCategoryEntries; entry->category; ++entry)
   1.428 +            nsCategoryManager::GetSingleton()->
   1.429 +                AddCategoryEntry(entry->category,
   1.430 +                                 entry->entry,
   1.431 +                                 entry->value);
   1.432 +    }
   1.433 +}
   1.434 +
   1.435 +static bool
   1.436 +ProcessSelectorMatches(Module::ProcessSelector selector)
   1.437 +{
   1.438 +    if (selector == Module::ANY_PROCESS) {
   1.439 +        return true;
   1.440 +    }
   1.441 +
   1.442 +    GeckoProcessType type = XRE_GetProcessType();
   1.443 +    switch (selector) {
   1.444 +      case Module::MAIN_PROCESS_ONLY:
   1.445 +        return type == GeckoProcessType_Default;
   1.446 +      case Module::CONTENT_PROCESS_ONLY:
   1.447 +        return type == GeckoProcessType_Content;
   1.448 +      default:
   1.449 +        MOZ_CRASH("invalid process selector");
   1.450 +    }
   1.451 +}
   1.452 +
   1.453 +void
   1.454 +nsComponentManagerImpl::RegisterCIDEntryLocked(
   1.455 +    const mozilla::Module::CIDEntry* aEntry,
   1.456 +    KnownModule* aModule)
   1.457 +{
   1.458 +    mLock.AssertCurrentThreadOwns();
   1.459 +
   1.460 +    if (!ProcessSelectorMatches(aEntry->processSelector)) {
   1.461 +        return;
   1.462 +    }
   1.463 +
   1.464 +    nsFactoryEntry* f = mFactories.Get(*aEntry->cid);
   1.465 +    if (f) {
   1.466 +        NS_WARNING("Re-registering a CID?");
   1.467 +
   1.468 +        char idstr[NSID_LENGTH];
   1.469 +        aEntry->cid->ToProvidedString(idstr);
   1.470 +
   1.471 +        nsCString existing;
   1.472 +        if (f->mModule)
   1.473 +            existing = f->mModule->Description();
   1.474 +        else
   1.475 +            existing = "<unknown module>";
   1.476 +        SafeMutexAutoUnlock unlock(mLock);
   1.477 +        LogMessage("While registering XPCOM module %s, trying to re-register CID '%s' already registered by %s.",
   1.478 +                   aModule->Description().get(),
   1.479 +                   idstr,
   1.480 +                   existing.get());
   1.481 +        return;
   1.482 +    }
   1.483 +
   1.484 +    f = new nsFactoryEntry(aEntry, aModule);
   1.485 +    mFactories.Put(*aEntry->cid, f);
   1.486 +}
   1.487 +
   1.488 +void
   1.489 +nsComponentManagerImpl::RegisterContractIDLocked(
   1.490 +    const mozilla::Module::ContractIDEntry* aEntry)
   1.491 +{
   1.492 +    mLock.AssertCurrentThreadOwns();
   1.493 +
   1.494 +    if (!ProcessSelectorMatches(aEntry->processSelector)) {
   1.495 +        return;
   1.496 +    }
   1.497 +
   1.498 +    nsFactoryEntry* f = mFactories.Get(*aEntry->cid);
   1.499 +    if (!f) {
   1.500 +        NS_ERROR("No CID found when attempting to map contract ID");
   1.501 +
   1.502 +        char idstr[NSID_LENGTH];
   1.503 +        aEntry->cid->ToProvidedString(idstr);
   1.504 +
   1.505 +        LogMessage("Could not map contract ID '%s' to CID %s because no implementation of the CID is registered.",
   1.506 +                   aEntry->contractid,
   1.507 +                   idstr);
   1.508 +                   
   1.509 +        return;
   1.510 +    }
   1.511 +
   1.512 +    mContractIDs.Put(nsDependentCString(aEntry->contractid), f);
   1.513 +}
   1.514 +
   1.515 +static void
   1.516 +CutExtension(nsCString& path)
   1.517 +{
   1.518 +    int32_t dotPos = path.RFindChar('.');
   1.519 +    if (kNotFound == dotPos)
   1.520 +        path.Truncate();
   1.521 +    else
   1.522 +        path.Cut(0, dotPos + 1);
   1.523 +}
   1.524 +
   1.525 +void
   1.526 +nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
   1.527 +                                         FileLocation &aFile,
   1.528 +                                         bool aChromeOnly)
   1.529 +{
   1.530 +    uint32_t len;
   1.531 +    FileLocation::Data data;
   1.532 +    nsAutoArrayPtr<char> buf;
   1.533 +    nsresult rv = aFile.GetData(data);
   1.534 +    if (NS_SUCCEEDED(rv)) {
   1.535 +        rv = data.GetSize(&len);
   1.536 +    }
   1.537 +    if (NS_SUCCEEDED(rv)) {
   1.538 +        buf = new char[len + 1];
   1.539 +        rv = data.Copy(buf, len);
   1.540 +    }
   1.541 +    if (NS_SUCCEEDED(rv)) {
   1.542 +        buf[len] = '\0';
   1.543 +        ParseManifest(aType, aFile, buf, aChromeOnly);
   1.544 +    } else if (NS_BOOTSTRAPPED_LOCATION != aType) {
   1.545 +        nsCString uri;
   1.546 +        aFile.GetURIString(uri);
   1.547 +        LogMessage("Could not read chrome manifest '%s'.", uri.get());
   1.548 +    }
   1.549 +}
   1.550 +
   1.551 +void
   1.552 +nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& cx, int lineno, char *const * argv)
   1.553 +{
   1.554 +    char* file = argv[0];
   1.555 +    FileLocation f(cx.mFile, file);
   1.556 +    RegisterManifest(cx.mType, f, cx.mChromeOnly);
   1.557 +}
   1.558 +
   1.559 +void
   1.560 +nsComponentManagerImpl::ManifestBinaryComponent(ManifestProcessingContext& cx, int lineno, char *const * argv)
   1.561 +{
   1.562 +    if (cx.mFile.IsZip()) {
   1.563 +        NS_WARNING("Cannot load binary components from a jar.");
   1.564 +        LogMessageWithContext(cx.mFile, lineno,
   1.565 +                              "Cannot load binary components from a jar.");
   1.566 +        return;
   1.567 +    }
   1.568 +
   1.569 +    FileLocation f(cx.mFile, argv[0]);
   1.570 +    nsCString uri;
   1.571 +    f.GetURIString(uri);
   1.572 +
   1.573 +    if (mKnownModules.Get(uri)) {
   1.574 +        NS_WARNING("Attempting to register a binary component twice.");
   1.575 +        LogMessageWithContext(cx.mFile, lineno,
   1.576 +                              "Attempting to register a binary component twice.");
   1.577 +        return;
   1.578 +    }
   1.579 +
   1.580 +    const mozilla::Module* m = mNativeModuleLoader.LoadModule(f);
   1.581 +    // The native module loader should report an error here, we don't have to
   1.582 +    if (!m)
   1.583 +        return;
   1.584 +
   1.585 +    RegisterModule(m, &f);
   1.586 +}
   1.587 +
   1.588 +void
   1.589 +nsComponentManagerImpl::ManifestXPT(ManifestProcessingContext& cx, int lineno, char *const * argv)
   1.590 +{
   1.591 +    FileLocation f(cx.mFile, argv[0]);
   1.592 +    uint32_t len;
   1.593 +    FileLocation::Data data;
   1.594 +    nsAutoArrayPtr<char> buf;
   1.595 +    nsresult rv = f.GetData(data);
   1.596 +    if (NS_SUCCEEDED(rv)) {
   1.597 +        rv = data.GetSize(&len);
   1.598 +    }
   1.599 +    if (NS_SUCCEEDED(rv)) {
   1.600 +        buf = new char[len];
   1.601 +        rv = data.Copy(buf, len);
   1.602 +    }
   1.603 +    if (NS_SUCCEEDED(rv)) {
   1.604 +        XPTInterfaceInfoManager::GetSingleton()->RegisterBuffer(buf, len);
   1.605 +    } else {
   1.606 +        nsCString uri;
   1.607 +        f.GetURIString(uri);
   1.608 +        LogMessage("Could not read '%s'.", uri.get());
   1.609 +    }
   1.610 +}
   1.611 +
   1.612 +void
   1.613 +nsComponentManagerImpl::ManifestComponent(ManifestProcessingContext& cx, int lineno, char *const * argv)
   1.614 +{
   1.615 +    mLock.AssertNotCurrentThreadOwns();
   1.616 +
   1.617 +    char* id = argv[0];
   1.618 +    char* file = argv[1];
   1.619 +
   1.620 +    nsID cid;
   1.621 +    if (!cid.Parse(id)) {
   1.622 +        LogMessageWithContext(cx.mFile, lineno,
   1.623 +                              "Malformed CID: '%s'.", id);
   1.624 +        return;
   1.625 +    }
   1.626 +
   1.627 +    // Precompute the hash/file data outside of the lock
   1.628 +    FileLocation fl(cx.mFile, file);
   1.629 +    nsCString hash;
   1.630 +    fl.GetURIString(hash);
   1.631 +
   1.632 +    MutexLock lock(mLock);
   1.633 +    nsFactoryEntry* f = mFactories.Get(cid);
   1.634 +    if (f) {
   1.635 +        char idstr[NSID_LENGTH];
   1.636 +        cid.ToProvidedString(idstr);
   1.637 +
   1.638 +        nsCString existing;
   1.639 +        if (f->mModule)
   1.640 +            existing = f->mModule->Description();
   1.641 +        else
   1.642 +            existing = "<unknown module>";
   1.643 +
   1.644 +        lock.Unlock();
   1.645 +
   1.646 +        LogMessageWithContext(cx.mFile, lineno,
   1.647 +                              "Trying to re-register CID '%s' already registered by %s.",
   1.648 +                              idstr,
   1.649 +                              existing.get());
   1.650 +        return;
   1.651 +    }
   1.652 +
   1.653 +    KnownModule* km;
   1.654 +
   1.655 +    km = mKnownModules.Get(hash);
   1.656 +    if (!km) {
   1.657 +        km = new KnownModule(fl);
   1.658 +        mKnownModules.Put(hash, km);
   1.659 +    }
   1.660 +
   1.661 +    void* place;
   1.662 +
   1.663 +    PL_ARENA_ALLOCATE(place, &mArena, sizeof(nsCID));
   1.664 +    nsID* permanentCID = static_cast<nsID*>(place);
   1.665 +    *permanentCID = cid;
   1.666 +
   1.667 +    PL_ARENA_ALLOCATE(place, &mArena, sizeof(mozilla::Module::CIDEntry));
   1.668 +    mozilla::Module::CIDEntry* e = new (place) mozilla::Module::CIDEntry();
   1.669 +    e->cid = permanentCID;
   1.670 +
   1.671 +    f = new nsFactoryEntry(e, km);
   1.672 +    mFactories.Put(cid, f);
   1.673 +}
   1.674 +
   1.675 +void
   1.676 +nsComponentManagerImpl::ManifestContract(ManifestProcessingContext& cx, int lineno, char *const * argv)
   1.677 +{
   1.678 +    mLock.AssertNotCurrentThreadOwns();
   1.679 +
   1.680 +    char* contract = argv[0];
   1.681 +    char* id = argv[1];
   1.682 +
   1.683 +    nsID cid;
   1.684 +    if (!cid.Parse(id)) {
   1.685 +        LogMessageWithContext(cx.mFile, lineno,
   1.686 +                              "Malformed CID: '%s'.", id);
   1.687 +        return;
   1.688 +    }
   1.689 +
   1.690 +    MutexLock lock(mLock);
   1.691 +    nsFactoryEntry* f = mFactories.Get(cid);
   1.692 +    if (!f) {
   1.693 +        lock.Unlock();
   1.694 +        LogMessageWithContext(cx.mFile, lineno,
   1.695 +                              "Could not map contract ID '%s' to CID %s because no implementation of the CID is registered.",
   1.696 +                              contract, id);
   1.697 +        return;
   1.698 +    }
   1.699 +
   1.700 +    mContractIDs.Put(nsDependentCString(contract), f);
   1.701 +}
   1.702 +
   1.703 +void
   1.704 +nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext& cx, int lineno, char *const * argv)
   1.705 +{
   1.706 +    char* category = argv[0];
   1.707 +    char* key = argv[1];
   1.708 +    char* value = argv[2];
   1.709 +
   1.710 +    nsCategoryManager::GetSingleton()->
   1.711 +        AddCategoryEntry(category, key, value);
   1.712 +}
   1.713 +
   1.714 +void
   1.715 +nsComponentManagerImpl::RereadChromeManifests(bool aChromeOnly)
   1.716 +{
   1.717 +    for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
   1.718 +        ComponentLocation& l = sModuleLocations->ElementAt(i);
   1.719 +        RegisterManifest(l.type, l.location, aChromeOnly);
   1.720 +    }
   1.721 +}
   1.722 +
   1.723 +bool
   1.724 +nsComponentManagerImpl::KnownModule::EnsureLoader()
   1.725 +{
   1.726 +    if (!mLoader) {
   1.727 +        nsCString extension;
   1.728 +        mFile.GetURIString(extension);
   1.729 +        CutExtension(extension);
   1.730 +        mLoader = nsComponentManagerImpl::gComponentManager->LoaderForExtension(extension);
   1.731 +    }
   1.732 +    return !!mLoader;
   1.733 +}
   1.734 +
   1.735 +bool
   1.736 +nsComponentManagerImpl::KnownModule::Load()
   1.737 +{
   1.738 +    if (mFailed)
   1.739 +        return false;
   1.740 +    if (!mModule) {
   1.741 +        if (!EnsureLoader())
   1.742 +            return false;
   1.743 +
   1.744 +        mModule = mLoader->LoadModule(mFile);
   1.745 +
   1.746 +        if (!mModule) {
   1.747 +            mFailed = true;
   1.748 +            return false;
   1.749 +        }
   1.750 +    }
   1.751 +    if (!mLoaded) {
   1.752 +        if (mModule->loadProc) {
   1.753 +            nsresult rv = mModule->loadProc();
   1.754 +            if (NS_FAILED(rv)) {
   1.755 +                mFailed = true;
   1.756 +                return false;
   1.757 +            }
   1.758 +        }
   1.759 +        mLoaded = true;
   1.760 +    }
   1.761 +    return true;
   1.762 +}
   1.763 +
   1.764 +nsCString
   1.765 +nsComponentManagerImpl::KnownModule::Description() const
   1.766 +{
   1.767 +    nsCString s;
   1.768 +    if (mFile)
   1.769 +        mFile.GetURIString(s);
   1.770 +    else
   1.771 +        s = "<static module>";
   1.772 +    return s;
   1.773 +}
   1.774 +
   1.775 +nsresult nsComponentManagerImpl::Shutdown(void)
   1.776 +{
   1.777 +    PR_ASSERT(NORMAL == mStatus);
   1.778 +
   1.779 +    mStatus = SHUTDOWN_IN_PROGRESS;
   1.780 +
   1.781 +    // Shutdown the component manager
   1.782 +    PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown."));
   1.783 +
   1.784 +    UnregisterWeakMemoryReporter(this);
   1.785 +
   1.786 +    // Release all cached factories
   1.787 +    mContractIDs.Clear();
   1.788 +    mFactories.Clear(); // XXX release the objects, don't just clear
   1.789 +    mLoaderMap.Clear();
   1.790 +    mKnownModules.Clear();
   1.791 +    mKnownStaticModules.Clear();
   1.792 +
   1.793 +    delete sStaticModules;
   1.794 +    delete sModuleLocations;
   1.795 +
   1.796 +    // Unload libraries
   1.797 +    mNativeModuleLoader.UnloadLibraries();
   1.798 +
   1.799 +    // delete arena for strings and small objects
   1.800 +    PL_FinishArenaPool(&mArena);
   1.801 +
   1.802 +    mStatus = SHUTDOWN_COMPLETE;
   1.803 +
   1.804 +    PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Shutdown complete."));
   1.805 +
   1.806 +    return NS_OK;
   1.807 +}
   1.808 +
   1.809 +nsComponentManagerImpl::~nsComponentManagerImpl()
   1.810 +{
   1.811 +    PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning destruction."));
   1.812 +
   1.813 +    if (SHUTDOWN_COMPLETE != mStatus)
   1.814 +        Shutdown();
   1.815 +
   1.816 +    PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Destroyed."));
   1.817 +}
   1.818 +
   1.819 +NS_IMPL_ISUPPORTS(
   1.820 +    nsComponentManagerImpl,
   1.821 +    nsIComponentManager,
   1.822 +    nsIServiceManager,
   1.823 +    nsIComponentRegistrar,
   1.824 +    nsISupportsWeakReference,
   1.825 +    nsIInterfaceRequestor,
   1.826 +    nsIMemoryReporter)
   1.827 +
   1.828 +nsresult
   1.829 +nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result)
   1.830 +{
   1.831 +    NS_WARNING("This isn't supported");
   1.832 +    // fall through to QI as anything QIable is a superset of what can be
   1.833 +    // got via the GetInterface()
   1.834 +    return  QueryInterface(uuid, result);
   1.835 +}
   1.836 +
   1.837 +nsFactoryEntry *
   1.838 +nsComponentManagerImpl::GetFactoryEntry(const char *aContractID,
   1.839 +                                        uint32_t aContractIDLen)
   1.840 +{
   1.841 +    SafeMutexAutoLock lock(mLock);
   1.842 +    return mContractIDs.Get(nsDependentCString(aContractID, aContractIDLen));
   1.843 +}
   1.844 +
   1.845 +
   1.846 +nsFactoryEntry *
   1.847 +nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass)
   1.848 +{
   1.849 +    SafeMutexAutoLock lock(mLock);
   1.850 +    return mFactories.Get(aClass);
   1.851 +}
   1.852 +
   1.853 +already_AddRefed<nsIFactory>
   1.854 +nsComponentManagerImpl::FindFactory(const nsCID& aClass)
   1.855 +{
   1.856 +    nsFactoryEntry* e = GetFactoryEntry(aClass);
   1.857 +    if (!e)
   1.858 +        return nullptr;
   1.859 +
   1.860 +    return e->GetFactory();
   1.861 +}
   1.862 +
   1.863 +already_AddRefed<nsIFactory>
   1.864 +nsComponentManagerImpl::FindFactory(const char *contractID,
   1.865 +                                    uint32_t aContractIDLen)
   1.866 +{
   1.867 +    nsFactoryEntry *entry = GetFactoryEntry(contractID, aContractIDLen);
   1.868 +    if (!entry)
   1.869 +        return nullptr;
   1.870 +
   1.871 +    return entry->GetFactory();
   1.872 +}
   1.873 +
   1.874 +/**
   1.875 + * GetClassObject()
   1.876 + *
   1.877 + * Given a classID, this finds the singleton ClassObject that implements the CID.
   1.878 + * Returns an interface of type aIID off the singleton classobject.
   1.879 + */
   1.880 +NS_IMETHODIMP
   1.881 +nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID,
   1.882 +                                       void **aResult)
   1.883 +{
   1.884 +    nsresult rv;
   1.885 +
   1.886 +#ifdef PR_LOGGING
   1.887 +    if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG))
   1.888 +    {
   1.889 +        char *buf = aClass.ToString();
   1.890 +        PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
   1.891 +        if (buf)
   1.892 +            NS_Free(buf);
   1.893 +    }
   1.894 +#endif
   1.895 +
   1.896 +    PR_ASSERT(aResult != nullptr);
   1.897 +
   1.898 +    nsCOMPtr<nsIFactory> factory = FindFactory(aClass);
   1.899 +    if (!factory)
   1.900 +        return NS_ERROR_FACTORY_NOT_REGISTERED;
   1.901 +
   1.902 +    rv = factory->QueryInterface(aIID, aResult);
   1.903 +
   1.904 +    PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
   1.905 +           ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
   1.906 +
   1.907 +    return rv;
   1.908 +}
   1.909 +
   1.910 +
   1.911 +NS_IMETHODIMP
   1.912 +nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID,
   1.913 +                                                   const nsIID &aIID,
   1.914 +                                                   void **aResult)
   1.915 +{
   1.916 +    if (NS_WARN_IF(!aResult) ||
   1.917 +        NS_WARN_IF(!contractID))
   1.918 +        return NS_ERROR_INVALID_ARG;
   1.919 +
   1.920 +    nsresult rv;
   1.921 +
   1.922 +
   1.923 +#ifdef PR_LOGGING
   1.924 +    if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG))
   1.925 +    {
   1.926 +        PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID);
   1.927 +    }
   1.928 +#endif
   1.929 +
   1.930 +    nsCOMPtr<nsIFactory> factory = FindFactory(contractID, strlen(contractID));
   1.931 +    if (!factory)
   1.932 +        return NS_ERROR_FACTORY_NOT_REGISTERED;
   1.933 +
   1.934 +    rv = factory->QueryInterface(aIID, aResult);
   1.935 +
   1.936 +    PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
   1.937 +           ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
   1.938 +
   1.939 +    return rv;
   1.940 +}
   1.941 +
   1.942 +/**
   1.943 + * CreateInstance()
   1.944 + *
   1.945 + * Create an instance of an object that implements an interface and belongs
   1.946 + * to the implementation aClass using the factory. The factory is immediately
   1.947 + * released and not held onto for any longer.
   1.948 + */
   1.949 +NS_IMETHODIMP
   1.950 +nsComponentManagerImpl::CreateInstance(const nsCID &aClass,
   1.951 +                                       nsISupports *aDelegate,
   1.952 +                                       const nsIID &aIID,
   1.953 +                                       void **aResult)
   1.954 +{
   1.955 +    // test this first, since there's no point in creating a component during
   1.956 +    // shutdown -- whether it's available or not would depend on the order it
   1.957 +    // occurs in the list
   1.958 +    if (gXPCOMShuttingDown) {
   1.959 +        // When processing shutdown, don't process new GetService() requests
   1.960 +#ifdef SHOW_DENIED_ON_SHUTDOWN
   1.961 +        nsXPIDLCString cid, iid;
   1.962 +        cid.Adopt(aClass.ToString());
   1.963 +        iid.Adopt(aIID.ToString());
   1.964 +        fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
   1.965 +               "         CID: %s\n         IID: %s\n", cid.get(), iid.get());
   1.966 +#endif /* SHOW_DENIED_ON_SHUTDOWN */
   1.967 +        return NS_ERROR_UNEXPECTED;
   1.968 +    }
   1.969 +
   1.970 +    if (aResult == nullptr)
   1.971 +    {
   1.972 +        return NS_ERROR_NULL_POINTER;
   1.973 +    }
   1.974 +    *aResult = nullptr;
   1.975 +
   1.976 +    nsFactoryEntry *entry = GetFactoryEntry(aClass);
   1.977 +
   1.978 +    if (!entry)
   1.979 +        return NS_ERROR_FACTORY_NOT_REGISTERED;
   1.980 +
   1.981 +#ifdef SHOW_CI_ON_EXISTING_SERVICE
   1.982 +    if (entry->mServiceObject) {
   1.983 +        nsXPIDLCString cid;
   1.984 +        cid.Adopt(aClass.ToString());
   1.985 +        nsAutoCString message;
   1.986 +        message = NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
   1.987 +                  cid + NS_LITERAL_CSTRING("\" when a service for this CID already exists!");
   1.988 +        NS_ERROR(message.get());
   1.989 +    }
   1.990 +#endif
   1.991 +
   1.992 +    nsresult rv;
   1.993 +    nsCOMPtr<nsIFactory> factory = entry->GetFactory();
   1.994 +    if (factory)
   1.995 +    {
   1.996 +        rv = factory->CreateInstance(aDelegate, aIID, aResult);
   1.997 +        if (NS_SUCCEEDED(rv) && !*aResult) {
   1.998 +            NS_ERROR("Factory did not return an object but returned success!");
   1.999 +            rv = NS_ERROR_SERVICE_NOT_FOUND;
  1.1000 +        }
  1.1001 +    }
  1.1002 +    else {
  1.1003 +        // Translate error values
  1.1004 +        rv = NS_ERROR_FACTORY_NOT_REGISTERED;
  1.1005 +    }
  1.1006 +
  1.1007 +#ifdef PR_LOGGING
  1.1008 +    if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
  1.1009 +    {
  1.1010 +        char *buf = aClass.ToString();
  1.1011 +        PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
  1.1012 +               ("nsComponentManager: CreateInstance(%s) %s", buf,
  1.1013 +                NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
  1.1014 +        if (buf)
  1.1015 +            NS_Free(buf);
  1.1016 +    }
  1.1017 +#endif
  1.1018 +
  1.1019 +    return rv;
  1.1020 +}
  1.1021 +
  1.1022 +/**
  1.1023 + * CreateInstanceByContractID()
  1.1024 + *
  1.1025 + * A variant of CreateInstance() that creates an instance of the object that
  1.1026 + * implements the interface aIID and whose implementation has a contractID aContractID.
  1.1027 + *
  1.1028 + * This is only a convenience routine that turns around can calls the
  1.1029 + * CreateInstance() with classid and iid.
  1.1030 + */
  1.1031 +NS_IMETHODIMP
  1.1032 +nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID,
  1.1033 +                                                   nsISupports *aDelegate,
  1.1034 +                                                   const nsIID &aIID,
  1.1035 +                                                   void **aResult)
  1.1036 +{
  1.1037 +    if (NS_WARN_IF(!aContractID))
  1.1038 +        return NS_ERROR_INVALID_ARG;
  1.1039 +
  1.1040 +    // test this first, since there's no point in creating a component during
  1.1041 +    // shutdown -- whether it's available or not would depend on the order it
  1.1042 +    // occurs in the list
  1.1043 +    if (gXPCOMShuttingDown) {
  1.1044 +        // When processing shutdown, don't process new GetService() requests
  1.1045 +#ifdef SHOW_DENIED_ON_SHUTDOWN
  1.1046 +        nsXPIDLCString iid;
  1.1047 +        iid.Adopt(aIID.ToString());
  1.1048 +        fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
  1.1049 +               "  ContractID: %s\n         IID: %s\n", aContractID, iid.get());
  1.1050 +#endif /* SHOW_DENIED_ON_SHUTDOWN */
  1.1051 +        return NS_ERROR_UNEXPECTED;
  1.1052 +    }
  1.1053 +
  1.1054 +    if (aResult == nullptr)
  1.1055 +    {
  1.1056 +        return NS_ERROR_NULL_POINTER;
  1.1057 +    }
  1.1058 +    *aResult = nullptr;
  1.1059 +
  1.1060 +    nsFactoryEntry *entry = GetFactoryEntry(aContractID, strlen(aContractID));
  1.1061 +
  1.1062 +    if (!entry)
  1.1063 +        return NS_ERROR_FACTORY_NOT_REGISTERED;
  1.1064 +
  1.1065 +#ifdef SHOW_CI_ON_EXISTING_SERVICE
  1.1066 +    if (entry->mServiceObject) {
  1.1067 +        nsAutoCString message;
  1.1068 +        message =
  1.1069 +          NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
  1.1070 +          nsDependentCString(aContractID) +
  1.1071 +          NS_LITERAL_CSTRING("\" when a service for this CID already exists! "
  1.1072 +            "Add it to abusedContracts to track down the service consumer.");
  1.1073 +        NS_ERROR(message.get());
  1.1074 +    }
  1.1075 +#endif
  1.1076 +
  1.1077 +    nsresult rv;
  1.1078 +    nsCOMPtr<nsIFactory> factory = entry->GetFactory();
  1.1079 +    if (factory)
  1.1080 +    {
  1.1081 +
  1.1082 +        rv = factory->CreateInstance(aDelegate, aIID, aResult);
  1.1083 +        if (NS_SUCCEEDED(rv) && !*aResult) {
  1.1084 +            NS_ERROR("Factory did not return an object but returned success!");
  1.1085 +            rv = NS_ERROR_SERVICE_NOT_FOUND;
  1.1086 +        }
  1.1087 +    }
  1.1088 +    else {
  1.1089 +        // Translate error values
  1.1090 +        rv = NS_ERROR_FACTORY_NOT_REGISTERED;
  1.1091 +    }
  1.1092 +
  1.1093 +    PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
  1.1094 +           ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
  1.1095 +            NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
  1.1096 +
  1.1097 +    return rv;
  1.1098 +}
  1.1099 +
  1.1100 +static PLDHashOperator
  1.1101 +FreeFactoryEntries(const nsID& aCID,
  1.1102 +                   nsFactoryEntry* aEntry,
  1.1103 +                   void* arg)
  1.1104 +{
  1.1105 +    aEntry->mFactory = nullptr;
  1.1106 +    aEntry->mServiceObject = nullptr;
  1.1107 +    return PL_DHASH_NEXT;
  1.1108 +}
  1.1109 +
  1.1110 +nsresult
  1.1111 +nsComponentManagerImpl::FreeServices()
  1.1112 +{
  1.1113 +    NS_ASSERTION(gXPCOMShuttingDown, "Must be shutting down in order to free all services");
  1.1114 +
  1.1115 +    if (!gXPCOMShuttingDown)
  1.1116 +        return NS_ERROR_FAILURE;
  1.1117 +
  1.1118 +    mFactories.EnumerateRead(FreeFactoryEntries, nullptr);
  1.1119 +    return NS_OK;
  1.1120 +}
  1.1121 +
  1.1122 +// This should only ever be called within the monitor!
  1.1123 +nsComponentManagerImpl::PendingServiceInfo*
  1.1124 +nsComponentManagerImpl::AddPendingService(const nsCID& aServiceCID,
  1.1125 +                                          PRThread* aThread)
  1.1126 +{
  1.1127 +  PendingServiceInfo* newInfo = mPendingServices.AppendElement();
  1.1128 +  if (newInfo) {
  1.1129 +    newInfo->cid = &aServiceCID;
  1.1130 +    newInfo->thread = aThread;
  1.1131 +  }
  1.1132 +  return newInfo;
  1.1133 +}
  1.1134 +
  1.1135 +// This should only ever be called within the monitor!
  1.1136 +void
  1.1137 +nsComponentManagerImpl::RemovePendingService(const nsCID& aServiceCID)
  1.1138 +{
  1.1139 +  uint32_t pendingCount = mPendingServices.Length();
  1.1140 +  for (uint32_t index = 0; index < pendingCount; ++index) {
  1.1141 +    const PendingServiceInfo& info = mPendingServices.ElementAt(index);
  1.1142 +    if (info.cid->Equals(aServiceCID)) {
  1.1143 +      mPendingServices.RemoveElementAt(index);
  1.1144 +      return;
  1.1145 +    }
  1.1146 +  }
  1.1147 +}
  1.1148 +
  1.1149 +// This should only ever be called within the monitor!
  1.1150 +PRThread*
  1.1151 +nsComponentManagerImpl::GetPendingServiceThread(const nsCID& aServiceCID) const
  1.1152 +{
  1.1153 +  uint32_t pendingCount = mPendingServices.Length();
  1.1154 +  for (uint32_t index = 0; index < pendingCount; ++index) {
  1.1155 +    const PendingServiceInfo& info = mPendingServices.ElementAt(index);
  1.1156 +    if (info.cid->Equals(aServiceCID)) {
  1.1157 +      return info.thread;
  1.1158 +    }
  1.1159 +  }
  1.1160 +  return nullptr;
  1.1161 +}
  1.1162 +
  1.1163 +NS_IMETHODIMP
  1.1164 +nsComponentManagerImpl::GetService(const nsCID& aClass,
  1.1165 +                                   const nsIID& aIID,
  1.1166 +                                   void* *result)
  1.1167 +{
  1.1168 +    // test this first, since there's no point in returning a service during
  1.1169 +    // shutdown -- whether it's available or not would depend on the order it
  1.1170 +    // occurs in the list
  1.1171 +    if (gXPCOMShuttingDown) {
  1.1172 +        // When processing shutdown, don't process new GetService() requests
  1.1173 +#ifdef SHOW_DENIED_ON_SHUTDOWN
  1.1174 +        nsXPIDLCString cid, iid;
  1.1175 +        cid.Adopt(aClass.ToString());
  1.1176 +        iid.Adopt(aIID.ToString());
  1.1177 +        fprintf(stderr, "Getting service on shutdown. Denied.\n"
  1.1178 +               "         CID: %s\n         IID: %s\n", cid.get(), iid.get());
  1.1179 +#endif /* SHOW_DENIED_ON_SHUTDOWN */
  1.1180 +        return NS_ERROR_UNEXPECTED;
  1.1181 +    }
  1.1182 +
  1.1183 +    // `service` must be released after the lock is released, so it must be
  1.1184 +    // declared before the lock in this C++ block.
  1.1185 +    nsCOMPtr<nsISupports> service;
  1.1186 +    MutexLock lock(mLock);
  1.1187 +
  1.1188 +    nsFactoryEntry* entry = mFactories.Get(aClass);
  1.1189 +    if (!entry)
  1.1190 +        return NS_ERROR_FACTORY_NOT_REGISTERED;
  1.1191 +
  1.1192 +    if (entry->mServiceObject) {
  1.1193 +        lock.Unlock();
  1.1194 +        return entry->mServiceObject->QueryInterface(aIID, result);
  1.1195 +    }
  1.1196 +
  1.1197 +    PRThread* currentPRThread = PR_GetCurrentThread();
  1.1198 +    MOZ_ASSERT(currentPRThread, "This should never be null!");
  1.1199 +
  1.1200 +    // Needed to optimize the event loop below.
  1.1201 +    nsIThread* currentThread = nullptr;
  1.1202 +
  1.1203 +    PRThread* pendingPRThread;
  1.1204 +    while ((pendingPRThread = GetPendingServiceThread(aClass))) {
  1.1205 +        if (pendingPRThread == currentPRThread) {
  1.1206 +            NS_ERROR("Recursive GetService!");
  1.1207 +            return NS_ERROR_NOT_AVAILABLE;
  1.1208 +        }
  1.1209 +
  1.1210 +
  1.1211 +        SafeMutexAutoUnlock unlockPending(mLock);
  1.1212 +
  1.1213 +        if (!currentThread) {
  1.1214 +            currentThread = NS_GetCurrentThread();
  1.1215 +            MOZ_ASSERT(currentThread, "This should never be null!");
  1.1216 +        }
  1.1217 +
  1.1218 +        // This will process a single event or yield the thread if no event is
  1.1219 +        // pending.
  1.1220 +        if (!NS_ProcessNextEvent(currentThread, false)) {
  1.1221 +            PR_Sleep(PR_INTERVAL_NO_WAIT);
  1.1222 +        }
  1.1223 +    }
  1.1224 +
  1.1225 +    // It's still possible that the other thread failed to create the
  1.1226 +    // service so we're not guaranteed to have an entry or service yet.
  1.1227 +    if (entry->mServiceObject) {
  1.1228 +        lock.Unlock();
  1.1229 +        return entry->mServiceObject->QueryInterface(aIID, result);
  1.1230 +    }
  1.1231 +
  1.1232 +#ifdef DEBUG
  1.1233 +    PendingServiceInfo* newInfo =
  1.1234 +#endif
  1.1235 +    AddPendingService(aClass, currentPRThread);
  1.1236 +    NS_ASSERTION(newInfo, "Failed to add info to the array!");
  1.1237 +
  1.1238 +    // We need to not be holding the service manager's lock while calling
  1.1239 +    // CreateInstance, because it invokes user code which could try to re-enter
  1.1240 +    // the service manager:
  1.1241 +
  1.1242 +    nsresult rv;
  1.1243 +    {
  1.1244 +        SafeMutexAutoUnlock unlock(mLock);
  1.1245 +        rv = CreateInstance(aClass, nullptr, aIID, getter_AddRefs(service));
  1.1246 +    }
  1.1247 +    if (NS_SUCCEEDED(rv) && !service) {
  1.1248 +        NS_ERROR("Factory did not return an object but returned success");
  1.1249 +        return NS_ERROR_SERVICE_NOT_FOUND;
  1.1250 +    }
  1.1251 +
  1.1252 +#ifdef DEBUG
  1.1253 +    pendingPRThread = GetPendingServiceThread(aClass);
  1.1254 +    MOZ_ASSERT(pendingPRThread == currentPRThread,
  1.1255 +               "Pending service array has been changed!");
  1.1256 +#endif
  1.1257 +    RemovePendingService(aClass);
  1.1258 +
  1.1259 +    if (NS_FAILED(rv))
  1.1260 +        return rv;
  1.1261 +
  1.1262 +    NS_ASSERTION(!entry->mServiceObject, "Created two instances of a service!");
  1.1263 +
  1.1264 +    entry->mServiceObject = service.forget();
  1.1265 +
  1.1266 +    lock.Unlock();
  1.1267 +    nsISupports** sresult = reinterpret_cast<nsISupports**>(result);
  1.1268 +    *sresult = entry->mServiceObject;
  1.1269 +    (*sresult)->AddRef();
  1.1270 +
  1.1271 +    return NS_OK;
  1.1272 +}
  1.1273 +
  1.1274 +NS_IMETHODIMP
  1.1275 +nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass,
  1.1276 +                                              const nsIID& aIID,
  1.1277 +                                              bool *result)
  1.1278 +{
  1.1279 +    // Now we want to get the service if we already got it. If not, we don't want
  1.1280 +    // to create an instance of it. mmh!
  1.1281 +
  1.1282 +    // test this first, since there's no point in returning a service during
  1.1283 +    // shutdown -- whether it's available or not would depend on the order it
  1.1284 +    // occurs in the list
  1.1285 +    if (gXPCOMShuttingDown) {
  1.1286 +        // When processing shutdown, don't process new GetService() requests
  1.1287 +#ifdef SHOW_DENIED_ON_SHUTDOWN
  1.1288 +        nsXPIDLCString cid, iid;
  1.1289 +        cid.Adopt(aClass.ToString());
  1.1290 +        iid.Adopt(aIID.ToString());
  1.1291 +        fprintf(stderr, "Checking for service on shutdown. Denied.\n"
  1.1292 +               "         CID: %s\n         IID: %s\n", cid.get(), iid.get());
  1.1293 +#endif /* SHOW_DENIED_ON_SHUTDOWN */
  1.1294 +        return NS_ERROR_UNEXPECTED;
  1.1295 +    }
  1.1296 +
  1.1297 +    nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
  1.1298 +    nsFactoryEntry* entry;
  1.1299 +
  1.1300 +    {
  1.1301 +        SafeMutexAutoLock lock(mLock);
  1.1302 +        entry = mFactories.Get(aClass);
  1.1303 +    }
  1.1304 +
  1.1305 +    if (entry && entry->mServiceObject) {
  1.1306 +        nsCOMPtr<nsISupports> service;
  1.1307 +        rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
  1.1308 +        *result = (service!=nullptr);
  1.1309 +    }
  1.1310 +
  1.1311 +    return rv;
  1.1312 +}
  1.1313 +
  1.1314 +NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID,
  1.1315 +                                                                        const nsIID& aIID,
  1.1316 +                                                                        bool *result)
  1.1317 +{
  1.1318 +    // Now we want to get the service if we already got it. If not, we don't want
  1.1319 +    // to create an instance of it. mmh!
  1.1320 +
  1.1321 +    // test this first, since there's no point in returning a service during
  1.1322 +    // shutdown -- whether it's available or not would depend on the order it
  1.1323 +    // occurs in the list
  1.1324 +    if (gXPCOMShuttingDown) {
  1.1325 +        // When processing shutdown, don't process new GetService() requests
  1.1326 +#ifdef SHOW_DENIED_ON_SHUTDOWN
  1.1327 +        nsXPIDLCString iid;
  1.1328 +        iid.Adopt(aIID.ToString());
  1.1329 +        fprintf(stderr, "Checking for service on shutdown. Denied.\n"
  1.1330 +               "  ContractID: %s\n         IID: %s\n", aContractID, iid.get());
  1.1331 +#endif /* SHOW_DENIED_ON_SHUTDOWN */
  1.1332 +        return NS_ERROR_UNEXPECTED;
  1.1333 +    }
  1.1334 +
  1.1335 +    nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
  1.1336 +    nsFactoryEntry *entry;
  1.1337 +    {
  1.1338 +        SafeMutexAutoLock lock(mLock);
  1.1339 +        entry = mContractIDs.Get(nsDependentCString(aContractID));
  1.1340 +    }
  1.1341 +
  1.1342 +    if (entry && entry->mServiceObject) {
  1.1343 +        nsCOMPtr<nsISupports> service;
  1.1344 +        rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
  1.1345 +        *result = (service!=nullptr);
  1.1346 +    }
  1.1347 +    return rv;
  1.1348 +}
  1.1349 +
  1.1350 +
  1.1351 +NS_IMETHODIMP
  1.1352 +nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
  1.1353 +                                               const nsIID& aIID,
  1.1354 +                                               void* *result)
  1.1355 +{
  1.1356 +    // test this first, since there's no point in returning a service during
  1.1357 +    // shutdown -- whether it's available or not would depend on the order it
  1.1358 +    // occurs in the list
  1.1359 +    if (gXPCOMShuttingDown) {
  1.1360 +        // When processing shutdown, don't process new GetService() requests
  1.1361 +#ifdef SHOW_DENIED_ON_SHUTDOWN
  1.1362 +        nsXPIDLCString iid;
  1.1363 +        iid.Adopt(aIID.ToString());
  1.1364 +        fprintf(stderr, "Getting service on shutdown. Denied.\n"
  1.1365 +               "  ContractID: %s\n         IID: %s\n", aContractID, iid.get());
  1.1366 +#endif /* SHOW_DENIED_ON_SHUTDOWN */
  1.1367 +        return NS_ERROR_UNEXPECTED;
  1.1368 +    }
  1.1369 +
  1.1370 +    // `service` must be released after the lock is released, so it must be
  1.1371 +    // declared before the lock in this C++ block.
  1.1372 +    nsCOMPtr<nsISupports> service;
  1.1373 +    MutexLock lock(mLock);
  1.1374 +
  1.1375 +    nsFactoryEntry *entry = mContractIDs.Get(nsDependentCString(aContractID));
  1.1376 +    if (!entry)
  1.1377 +        return NS_ERROR_FACTORY_NOT_REGISTERED;
  1.1378 +
  1.1379 +    if (entry->mServiceObject) {
  1.1380 +        // We need to not be holding the service manager's monitor while calling
  1.1381 +        // QueryInterface, because it invokes user code which could try to re-enter
  1.1382 +        // the service manager, or try to grab some other lock/monitor/condvar
  1.1383 +        // and deadlock, e.g. bug 282743.
  1.1384 +        // `entry` is valid until XPCOM shutdown, so we can safely use it after
  1.1385 +        // exiting the lock.
  1.1386 +        lock.Unlock();
  1.1387 +        return entry->mServiceObject->QueryInterface(aIID, result);
  1.1388 +    }
  1.1389 +
  1.1390 +    PRThread* currentPRThread = PR_GetCurrentThread();
  1.1391 +    MOZ_ASSERT(currentPRThread, "This should never be null!");
  1.1392 +
  1.1393 +    // Needed to optimize the event loop below.
  1.1394 +    nsIThread* currentThread = nullptr;
  1.1395 +
  1.1396 +    PRThread* pendingPRThread;
  1.1397 +    while ((pendingPRThread = GetPendingServiceThread(*entry->mCIDEntry->cid))) {
  1.1398 +        if (pendingPRThread == currentPRThread) {
  1.1399 +            NS_ERROR("Recursive GetService!");
  1.1400 +            return NS_ERROR_NOT_AVAILABLE;
  1.1401 +        }
  1.1402 +
  1.1403 +        SafeMutexAutoUnlock unlockPending(mLock);
  1.1404 +
  1.1405 +        if (!currentThread) {
  1.1406 +            currentThread = NS_GetCurrentThread();
  1.1407 +            MOZ_ASSERT(currentThread, "This should never be null!");
  1.1408 +        }
  1.1409 +
  1.1410 +        // This will process a single event or yield the thread if no event is
  1.1411 +        // pending.
  1.1412 +        if (!NS_ProcessNextEvent(currentThread, false)) {
  1.1413 +            PR_Sleep(PR_INTERVAL_NO_WAIT);
  1.1414 +        }
  1.1415 +    }
  1.1416 +
  1.1417 +    if (currentThread && entry->mServiceObject) {
  1.1418 +        // If we have a currentThread then we must have waited on another thread
  1.1419 +        // to create the service. Grab it now if that succeeded.
  1.1420 +        lock.Unlock();
  1.1421 +        return entry->mServiceObject->QueryInterface(aIID, result);
  1.1422 +    }
  1.1423 +
  1.1424 +#ifdef DEBUG
  1.1425 +    PendingServiceInfo* newInfo =
  1.1426 +#endif
  1.1427 +    AddPendingService(*entry->mCIDEntry->cid, currentPRThread);
  1.1428 +    NS_ASSERTION(newInfo, "Failed to add info to the array!");
  1.1429 +
  1.1430 +    // We need to not be holding the service manager's lock while calling
  1.1431 +    // CreateInstance, because it invokes user code which could try to re-enter
  1.1432 +    // the service manager:
  1.1433 +
  1.1434 +    nsresult rv;
  1.1435 +    {
  1.1436 +        SafeMutexAutoUnlock unlock(mLock);
  1.1437 +        rv = CreateInstanceByContractID(aContractID, nullptr, aIID,
  1.1438 +                                        getter_AddRefs(service));
  1.1439 +    }
  1.1440 +    if (NS_SUCCEEDED(rv) && !service) {
  1.1441 +        NS_ERROR("Factory did not return an object but returned success");
  1.1442 +        return NS_ERROR_SERVICE_NOT_FOUND;
  1.1443 +    }
  1.1444 +
  1.1445 +#ifdef DEBUG
  1.1446 +    pendingPRThread = GetPendingServiceThread(*entry->mCIDEntry->cid);
  1.1447 +    MOZ_ASSERT(pendingPRThread == currentPRThread,
  1.1448 +               "Pending service array has been changed!");
  1.1449 +#endif
  1.1450 +    RemovePendingService(*entry->mCIDEntry->cid);
  1.1451 +
  1.1452 +    if (NS_FAILED(rv))
  1.1453 +        return rv;
  1.1454 +
  1.1455 +    NS_ASSERTION(!entry->mServiceObject, "Created two instances of a service!");
  1.1456 +
  1.1457 +    entry->mServiceObject = service.forget();
  1.1458 +
  1.1459 +    lock.Unlock();
  1.1460 +
  1.1461 +    nsISupports** sresult = reinterpret_cast<nsISupports**>(result);
  1.1462 +    *sresult = entry->mServiceObject;
  1.1463 +    (*sresult)->AddRef();
  1.1464 +
  1.1465 +    return NS_OK;
  1.1466 +}
  1.1467 +
  1.1468 +already_AddRefed<mozilla::ModuleLoader>
  1.1469 +nsComponentManagerImpl::LoaderForExtension(const nsACString& aExt)
  1.1470 +{
  1.1471 +    nsCOMPtr<mozilla::ModuleLoader> loader = mLoaderMap.Get(aExt);
  1.1472 +    if (!loader) {
  1.1473 +        loader = do_GetServiceFromCategory("module-loader",
  1.1474 +                                           PromiseFlatCString(aExt).get());
  1.1475 +        if (!loader)
  1.1476 +            return nullptr;
  1.1477 +
  1.1478 +        mLoaderMap.Put(aExt, loader);
  1.1479 +    }
  1.1480 +
  1.1481 +    return loader.forget();
  1.1482 +}
  1.1483 +
  1.1484 +NS_IMETHODIMP
  1.1485 +nsComponentManagerImpl::RegisterFactory(const nsCID& aClass,
  1.1486 +                                        const char* aName,
  1.1487 +                                        const char* aContractID,
  1.1488 +                                        nsIFactory* aFactory)
  1.1489 +{
  1.1490 +    if (!aFactory) {
  1.1491 +        // If a null factory is passed in, this call just wants to reset
  1.1492 +        // the contract ID to point to an existing CID entry.
  1.1493 +        if (!aContractID)
  1.1494 +            return NS_ERROR_INVALID_ARG;
  1.1495 +
  1.1496 +        SafeMutexAutoLock lock(mLock);
  1.1497 +        nsFactoryEntry* oldf = mFactories.Get(aClass);
  1.1498 +        if (!oldf)
  1.1499 +            return NS_ERROR_FACTORY_NOT_REGISTERED;
  1.1500 +
  1.1501 +        mContractIDs.Put(nsDependentCString(aContractID), oldf);
  1.1502 +        return NS_OK;
  1.1503 +    }
  1.1504 +
  1.1505 +    nsAutoPtr<nsFactoryEntry> f(new nsFactoryEntry(aClass, aFactory));
  1.1506 +
  1.1507 +    SafeMutexAutoLock lock(mLock);
  1.1508 +    nsFactoryEntry* oldf = mFactories.Get(aClass);
  1.1509 +    if (oldf)
  1.1510 +        return NS_ERROR_FACTORY_EXISTS;
  1.1511 +
  1.1512 +    if (aContractID)
  1.1513 +        mContractIDs.Put(nsDependentCString(aContractID), f);
  1.1514 +
  1.1515 +    mFactories.Put(aClass, f.forget());
  1.1516 +
  1.1517 +    return NS_OK;
  1.1518 +}
  1.1519 +
  1.1520 +NS_IMETHODIMP
  1.1521 +nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass,
  1.1522 +                                          nsIFactory* aFactory)
  1.1523 +{
  1.1524 +    // Don't release the dying factory or service object until releasing
  1.1525 +    // the component manager monitor.
  1.1526 +    nsCOMPtr<nsIFactory> dyingFactory;
  1.1527 +    nsCOMPtr<nsISupports> dyingServiceObject;
  1.1528 +
  1.1529 +    {
  1.1530 +        SafeMutexAutoLock lock(mLock);
  1.1531 +        nsFactoryEntry* f = mFactories.Get(aClass);
  1.1532 +        if (!f || f->mFactory != aFactory)
  1.1533 +            return NS_ERROR_FACTORY_NOT_REGISTERED;
  1.1534 +
  1.1535 +        mFactories.Remove(aClass);
  1.1536 +
  1.1537 +        // This might leave a stale contractid -> factory mapping in
  1.1538 +        // place, so null out the factory entry (see
  1.1539 +        // nsFactoryEntry::GetFactory)
  1.1540 +        f->mFactory.swap(dyingFactory);
  1.1541 +        f->mServiceObject.swap(dyingServiceObject);
  1.1542 +    }
  1.1543 +
  1.1544 +    return NS_OK;
  1.1545 +}
  1.1546 +
  1.1547 +NS_IMETHODIMP
  1.1548 +nsComponentManagerImpl::AutoRegister(nsIFile* aLocation)
  1.1549 +{
  1.1550 +    XRE_AddManifestLocation(NS_COMPONENT_LOCATION, aLocation);
  1.1551 +    return NS_OK;
  1.1552 +}
  1.1553 +
  1.1554 +NS_IMETHODIMP
  1.1555 +nsComponentManagerImpl::AutoUnregister(nsIFile* aLocation)
  1.1556 +{
  1.1557 +    NS_ERROR("AutoUnregister not implemented.");
  1.1558 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1559 +}
  1.1560 +
  1.1561 +NS_IMETHODIMP
  1.1562 +nsComponentManagerImpl::RegisterFactoryLocation(const nsCID& aCID,
  1.1563 +                                                const char* aClassName,
  1.1564 +                                                const char* aContractID,
  1.1565 +                                                nsIFile* aFile,
  1.1566 +                                                const char* aLoaderStr,
  1.1567 +                                                const char* aType)
  1.1568 +{
  1.1569 +    NS_ERROR("RegisterFactoryLocation not implemented.");
  1.1570 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1571 +}
  1.1572 +
  1.1573 +NS_IMETHODIMP
  1.1574 +nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID& aCID,
  1.1575 +                                                  nsIFile* aFile)
  1.1576 +{
  1.1577 +    NS_ERROR("UnregisterFactoryLocation not implemented.");
  1.1578 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1579 +}
  1.1580 +
  1.1581 +NS_IMETHODIMP
  1.1582 +nsComponentManagerImpl::IsCIDRegistered(const nsCID & aClass,
  1.1583 +                                        bool *_retval)
  1.1584 +{
  1.1585 +    *_retval = (nullptr != GetFactoryEntry(aClass));
  1.1586 +    return NS_OK;
  1.1587 +}
  1.1588 +
  1.1589 +NS_IMETHODIMP
  1.1590 +nsComponentManagerImpl::IsContractIDRegistered(const char *aClass,
  1.1591 +                                               bool *_retval)
  1.1592 +{
  1.1593 +    if (NS_WARN_IF(!aClass))
  1.1594 +        return NS_ERROR_INVALID_ARG;
  1.1595 +
  1.1596 +    nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass));
  1.1597 +
  1.1598 +    if (entry)
  1.1599 +        *_retval = true;
  1.1600 +    else
  1.1601 +        *_retval = false;
  1.1602 +    return NS_OK;
  1.1603 +}
  1.1604 +
  1.1605 +static PLDHashOperator
  1.1606 +EnumerateCIDHelper(const nsID& id, nsFactoryEntry* entry, void* closure)
  1.1607 +{
  1.1608 +    nsCOMArray<nsISupports> *array = static_cast<nsCOMArray<nsISupports>*>(closure);
  1.1609 +    nsCOMPtr<nsISupportsID> wrapper = new nsSupportsIDImpl();
  1.1610 +    wrapper->SetData(&id);
  1.1611 +    array->AppendObject(wrapper);
  1.1612 +    return PL_DHASH_NEXT;
  1.1613 +}
  1.1614 +
  1.1615 +NS_IMETHODIMP
  1.1616 +nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator **aEnumerator)
  1.1617 +{
  1.1618 +    nsCOMArray<nsISupports> array;
  1.1619 +    mFactories.EnumerateRead(EnumerateCIDHelper, &array);
  1.1620 +
  1.1621 +    return NS_NewArrayEnumerator(aEnumerator, array);
  1.1622 +}
  1.1623 +
  1.1624 +static PLDHashOperator
  1.1625 +EnumerateContractsHelper(const nsACString& contract, nsFactoryEntry* entry, void* closure)
  1.1626 +{
  1.1627 +    nsTArray<nsCString>* array = static_cast<nsTArray<nsCString>*>(closure);
  1.1628 +    array->AppendElement(contract);
  1.1629 +    return PL_DHASH_NEXT;
  1.1630 +}
  1.1631 +
  1.1632 +NS_IMETHODIMP
  1.1633 +nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator **aEnumerator)
  1.1634 +{
  1.1635 +    nsTArray<nsCString>* array = new nsTArray<nsCString>;
  1.1636 +    mContractIDs.EnumerateRead(EnumerateContractsHelper, array);
  1.1637 +
  1.1638 +    nsCOMPtr<nsIUTF8StringEnumerator> e;
  1.1639 +    nsresult rv = NS_NewAdoptingUTF8StringEnumerator(getter_AddRefs(e), array);
  1.1640 +    if (NS_FAILED(rv))
  1.1641 +        return rv;
  1.1642 +
  1.1643 +    return CallQueryInterface(e, aEnumerator);
  1.1644 +}
  1.1645 +
  1.1646 +NS_IMETHODIMP
  1.1647 +nsComponentManagerImpl::CIDToContractID(const nsCID & aClass,
  1.1648 +                                        char **_retval)
  1.1649 +{
  1.1650 +    NS_ERROR("CIDTOContractID not implemented");
  1.1651 +    return NS_ERROR_FACTORY_NOT_REGISTERED;
  1.1652 +}
  1.1653 +
  1.1654 +NS_IMETHODIMP
  1.1655 +nsComponentManagerImpl::ContractIDToCID(const char *aContractID,
  1.1656 +                                        nsCID * *_retval)
  1.1657 +{
  1.1658 +    {
  1.1659 +        SafeMutexAutoLock lock(mLock);
  1.1660 +        nsFactoryEntry* entry = mContractIDs.Get(nsDependentCString(aContractID));
  1.1661 +        if (entry) {
  1.1662 +            *_retval = (nsCID*) NS_Alloc(sizeof(nsCID));
  1.1663 +            **_retval = *entry->mCIDEntry->cid;
  1.1664 +            return NS_OK;
  1.1665 +        }
  1.1666 +    }
  1.1667 +    *_retval = nullptr;
  1.1668 +    return NS_ERROR_FACTORY_NOT_REGISTERED;
  1.1669 +}
  1.1670 +
  1.1671 +static size_t
  1.1672 +SizeOfFactoriesEntryExcludingThis(nsIDHashKey::KeyType aKey,
  1.1673 +                                  nsFactoryEntry* const &aData,
  1.1674 +                                  MallocSizeOf aMallocSizeOf,
  1.1675 +                                  void* aUserArg)
  1.1676 +{
  1.1677 +    return aData->SizeOfIncludingThis(aMallocSizeOf);
  1.1678 +}
  1.1679 +
  1.1680 +static size_t
  1.1681 +SizeOfContractIDsEntryExcludingThis(nsCStringHashKey::KeyType aKey,
  1.1682 +                                    nsFactoryEntry* const &aData,
  1.1683 +                                    MallocSizeOf aMallocSizeOf,
  1.1684 +                                    void* aUserArg)
  1.1685 +{
  1.1686 +    // We don't measure the nsFactoryEntry data because its owned by mFactories
  1.1687 +    // (which measures them in SizeOfFactoriesEntryExcludingThis).
  1.1688 +    return aKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
  1.1689 +}
  1.1690 +
  1.1691 +MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf)
  1.1692 +
  1.1693 +NS_IMETHODIMP
  1.1694 +nsComponentManagerImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
  1.1695 +                                       nsISupports* aData)
  1.1696 +{
  1.1697 +    return MOZ_COLLECT_REPORT(
  1.1698 +        "explicit/xpcom/component-manager", KIND_HEAP, UNITS_BYTES,
  1.1699 +        SizeOfIncludingThis(ComponentManagerMallocSizeOf),
  1.1700 +        "Memory used for the XPCOM component manager.");
  1.1701 +}
  1.1702 +
  1.1703 +size_t
  1.1704 +nsComponentManagerImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
  1.1705 +{
  1.1706 +    size_t n = aMallocSizeOf(this);
  1.1707 +    n += mLoaderMap.SizeOfExcludingThis(nullptr, aMallocSizeOf);
  1.1708 +    n += mFactories.SizeOfExcludingThis(SizeOfFactoriesEntryExcludingThis, aMallocSizeOf);
  1.1709 +    n += mContractIDs.SizeOfExcludingThis(SizeOfContractIDsEntryExcludingThis, aMallocSizeOf);
  1.1710 +
  1.1711 +    n += sStaticModules->SizeOfIncludingThis(aMallocSizeOf);
  1.1712 +    n += sModuleLocations->SizeOfIncludingThis(aMallocSizeOf);
  1.1713 +
  1.1714 +    n += mKnownStaticModules.SizeOfExcludingThis(aMallocSizeOf);
  1.1715 +    n += mKnownModules.SizeOfExcludingThis(nullptr, aMallocSizeOf);
  1.1716 +
  1.1717 +    n += PL_SizeOfArenaPoolExcludingPool(&mArena, aMallocSizeOf);
  1.1718 +
  1.1719 +    n += mPendingServices.SizeOfExcludingThis(aMallocSizeOf);
  1.1720 +
  1.1721 +    // Measurement of the following members may be added later if DMD finds it is
  1.1722 +    // worthwhile:
  1.1723 +    // - mLoaderMap's keys and values
  1.1724 +    // - mMon
  1.1725 +    // - sStaticModules' entries
  1.1726 +    // - sModuleLocations' entries
  1.1727 +    // - mNativeModuleLoader
  1.1728 +    // - mKnownStaticModules' entries?
  1.1729 +    // - mKnownModules' keys and values?
  1.1730 +
  1.1731 +    return n;
  1.1732 +}
  1.1733 +
  1.1734 +////////////////////////////////////////////////////////////////////////////////
  1.1735 +// nsFactoryEntry
  1.1736 +////////////////////////////////////////////////////////////////////////////////
  1.1737 +
  1.1738 +nsFactoryEntry::nsFactoryEntry(const mozilla::Module::CIDEntry* entry,
  1.1739 +                               nsComponentManagerImpl::KnownModule* module)
  1.1740 +    : mCIDEntry(entry)
  1.1741 +    , mModule(module)
  1.1742 +{
  1.1743 +}
  1.1744 +
  1.1745 +nsFactoryEntry::nsFactoryEntry(const nsCID& aCID, nsIFactory* factory)
  1.1746 +    : mCIDEntry(nullptr)
  1.1747 +    , mModule(nullptr)
  1.1748 +    , mFactory(factory)
  1.1749 +{
  1.1750 +    mozilla::Module::CIDEntry* e = new mozilla::Module::CIDEntry();
  1.1751 +    nsCID* cid = new nsCID;
  1.1752 +    *cid = aCID;
  1.1753 +    e->cid = cid;
  1.1754 +    mCIDEntry = e;
  1.1755 +}
  1.1756 +
  1.1757 +nsFactoryEntry::~nsFactoryEntry()
  1.1758 +{
  1.1759 +    // If this was a RegisterFactory entry, we own the CIDEntry/CID
  1.1760 +    if (!mModule) {
  1.1761 +        delete mCIDEntry->cid;
  1.1762 +        delete mCIDEntry;
  1.1763 +    }
  1.1764 +}
  1.1765 +
  1.1766 +already_AddRefed<nsIFactory>
  1.1767 +nsFactoryEntry::GetFactory()
  1.1768 +{
  1.1769 +    nsComponentManagerImpl::gComponentManager->mLock.AssertNotCurrentThreadOwns();
  1.1770 +
  1.1771 +    if (!mFactory) {
  1.1772 +        // RegisterFactory then UnregisterFactory can leave an entry in mContractIDs
  1.1773 +        // pointing to an unusable nsFactoryEntry.
  1.1774 +        if (!mModule)
  1.1775 +            return nullptr;
  1.1776 +
  1.1777 +        if (!mModule->Load())
  1.1778 +            return nullptr;
  1.1779 +
  1.1780 +        // Don't set mFactory directly, it needs to be locked
  1.1781 +        nsCOMPtr<nsIFactory> factory;
  1.1782 +
  1.1783 +        if (mModule->Module()->getFactoryProc) {
  1.1784 +            factory = mModule->Module()->getFactoryProc(*mModule->Module(),
  1.1785 +                                                        *mCIDEntry);
  1.1786 +        }
  1.1787 +        else if (mCIDEntry->getFactoryProc) {
  1.1788 +            factory = mCIDEntry->getFactoryProc(*mModule->Module(), *mCIDEntry);
  1.1789 +        }
  1.1790 +        else {
  1.1791 +            NS_ASSERTION(mCIDEntry->constructorProc, "no getfactory or constructor");
  1.1792 +            factory = new mozilla::GenericFactory(mCIDEntry->constructorProc);
  1.1793 +        }
  1.1794 +        if (!factory)
  1.1795 +            return nullptr;
  1.1796 +
  1.1797 +        SafeMutexAutoLock lock(nsComponentManagerImpl::gComponentManager->mLock);
  1.1798 +        // Threads can race to set mFactory
  1.1799 +        if (!mFactory) {
  1.1800 +            factory.swap(mFactory);
  1.1801 +        }
  1.1802 +    }
  1.1803 +    nsCOMPtr<nsIFactory> factory = mFactory;
  1.1804 +    return factory.forget();
  1.1805 +}
  1.1806 +
  1.1807 +size_t
  1.1808 +nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
  1.1809 +{
  1.1810 +    size_t n = aMallocSizeOf(this);
  1.1811 +
  1.1812 +    // Measurement of the following members may be added later if DMD finds it is
  1.1813 +    // worthwhile:
  1.1814 +    // - mCIDEntry;
  1.1815 +    // - mModule;
  1.1816 +    // - mFactory;
  1.1817 +    // - mServiceObject;
  1.1818 +
  1.1819 +    return n;
  1.1820 +}
  1.1821 +
  1.1822 +////////////////////////////////////////////////////////////////////////////////
  1.1823 +// Static Access Functions
  1.1824 +////////////////////////////////////////////////////////////////////////////////
  1.1825 +
  1.1826 +nsresult
  1.1827 +NS_GetComponentManager(nsIComponentManager* *result)
  1.1828 +{
  1.1829 +    if (!nsComponentManagerImpl::gComponentManager)
  1.1830 +        return NS_ERROR_NOT_INITIALIZED;
  1.1831 +
  1.1832 +    NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager);
  1.1833 +    return NS_OK;
  1.1834 +}
  1.1835 +
  1.1836 +nsresult
  1.1837 +NS_GetServiceManager(nsIServiceManager* *result)
  1.1838 +{
  1.1839 +    if (!nsComponentManagerImpl::gComponentManager)
  1.1840 +        return NS_ERROR_NOT_INITIALIZED;
  1.1841 +
  1.1842 +    NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager);
  1.1843 +    return NS_OK;
  1.1844 +}
  1.1845 +
  1.1846 +
  1.1847 +nsresult
  1.1848 +NS_GetComponentRegistrar(nsIComponentRegistrar* *result)
  1.1849 +{
  1.1850 +    if (!nsComponentManagerImpl::gComponentManager)
  1.1851 +        return NS_ERROR_NOT_INITIALIZED;
  1.1852 +
  1.1853 +    NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager);
  1.1854 +    return NS_OK;
  1.1855 +}
  1.1856 +
  1.1857 +EXPORT_XPCOM_API(nsresult)
  1.1858 +XRE_AddStaticComponent(const mozilla::Module* aComponent)
  1.1859 +{
  1.1860 +    nsComponentManagerImpl::InitializeStaticModules();
  1.1861 +    nsComponentManagerImpl::sStaticModules->AppendElement(aComponent);
  1.1862 +
  1.1863 +    if (nsComponentManagerImpl::gComponentManager &&
  1.1864 +        nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus)
  1.1865 +        nsComponentManagerImpl::gComponentManager->RegisterModule(aComponent, nullptr);
  1.1866 +
  1.1867 +    return NS_OK;
  1.1868 +}
  1.1869 +
  1.1870 +NS_IMETHODIMP
  1.1871 +nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation)
  1.1872 +{
  1.1873 +  nsString path;
  1.1874 +  nsresult rv = aLocation->GetPath(path);
  1.1875 +  if (NS_FAILED(rv))
  1.1876 +    return rv;
  1.1877 +
  1.1878 +  if (Substring(path, path.Length() - 4).Equals(NS_LITERAL_STRING(".xpi"))) {
  1.1879 +    return XRE_AddJarManifestLocation(NS_BOOTSTRAPPED_LOCATION, aLocation);
  1.1880 +  }
  1.1881 +
  1.1882 +  nsCOMPtr<nsIFile> manifest =
  1.1883 +    CloneAndAppend(aLocation, NS_LITERAL_CSTRING("chrome.manifest"));
  1.1884 +  return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION, manifest);
  1.1885 +}
  1.1886 +
  1.1887 +NS_IMETHODIMP
  1.1888 +nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation)
  1.1889 +{
  1.1890 +  nsCOMPtr<nsIChromeRegistry> cr = mozilla::services::GetChromeRegistryService();
  1.1891 +  if (!cr)
  1.1892 +    return NS_ERROR_FAILURE;
  1.1893 +
  1.1894 +  nsCOMPtr<nsIFile> manifest;
  1.1895 +  nsString path;
  1.1896 +  nsresult rv = aLocation->GetPath(path);
  1.1897 +  if (NS_FAILED(rv))
  1.1898 +    return rv;
  1.1899 +
  1.1900 +  nsComponentManagerImpl::ComponentLocation elem;
  1.1901 +  elem.type = NS_BOOTSTRAPPED_LOCATION;
  1.1902 +
  1.1903 +  if (Substring(path, path.Length() - 4).Equals(NS_LITERAL_STRING(".xpi"))) {
  1.1904 +    elem.location.Init(aLocation, "chrome.manifest");
  1.1905 +  } else {
  1.1906 +    nsCOMPtr<nsIFile> lf = CloneAndAppend(aLocation, NS_LITERAL_CSTRING("chrome.manifest"));
  1.1907 +    elem.location.Init(lf);
  1.1908 +  }
  1.1909 +
  1.1910 +  // Remove reference.
  1.1911 +  nsComponentManagerImpl::sModuleLocations->RemoveElement(elem, ComponentLocationComparator());
  1.1912 +
  1.1913 +  rv = cr->CheckForNewChrome();
  1.1914 +  return rv;
  1.1915 +}
  1.1916 +
  1.1917 +NS_IMETHODIMP
  1.1918 +nsComponentManagerImpl::GetManifestLocations(nsIArray **aLocations)
  1.1919 +{
  1.1920 +  NS_ENSURE_ARG_POINTER(aLocations);
  1.1921 +  *aLocations = nullptr;
  1.1922 +
  1.1923 +  if (!sModuleLocations)
  1.1924 +    return NS_ERROR_NOT_INITIALIZED;
  1.1925 +
  1.1926 +  nsCOMPtr<nsIMutableArray> locations = nsArray::Create();
  1.1927 +  nsresult rv;
  1.1928 +  for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
  1.1929 +    ComponentLocation& l = sModuleLocations->ElementAt(i);
  1.1930 +    FileLocation loc = l.location;
  1.1931 +    nsCString uriString;
  1.1932 +    loc.GetURIString(uriString);
  1.1933 +    nsCOMPtr<nsIURI> uri;
  1.1934 +    rv = NS_NewURI(getter_AddRefs(uri), uriString);
  1.1935 +    if (NS_SUCCEEDED(rv))
  1.1936 +      locations->AppendElement(uri, false);
  1.1937 +  }
  1.1938 +
  1.1939 +  locations.forget(aLocations);
  1.1940 +  return NS_OK;
  1.1941 +}
  1.1942 +
  1.1943 +EXPORT_XPCOM_API(nsresult)
  1.1944 +XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation)
  1.1945 +{
  1.1946 +    nsComponentManagerImpl::InitializeModuleLocations();
  1.1947 +    nsComponentManagerImpl::ComponentLocation* c = 
  1.1948 +        nsComponentManagerImpl::sModuleLocations->AppendElement();
  1.1949 +    c->type = aType;
  1.1950 +    c->location.Init(aLocation);
  1.1951 +
  1.1952 +    if (nsComponentManagerImpl::gComponentManager &&
  1.1953 +        nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus)
  1.1954 +        nsComponentManagerImpl::gComponentManager->RegisterManifest(aType, c->location, false);
  1.1955 +
  1.1956 +    return NS_OK;
  1.1957 +}
  1.1958 +
  1.1959 +EXPORT_XPCOM_API(nsresult)
  1.1960 +XRE_AddJarManifestLocation(NSLocationType aType, nsIFile* aLocation)
  1.1961 +{
  1.1962 +    nsComponentManagerImpl::InitializeModuleLocations();
  1.1963 +    nsComponentManagerImpl::ComponentLocation* c = 
  1.1964 +        nsComponentManagerImpl::sModuleLocations->AppendElement();
  1.1965 +
  1.1966 +    c->type = aType;
  1.1967 +    c->location.Init(aLocation, "chrome.manifest");
  1.1968 +
  1.1969 +    if (nsComponentManagerImpl::gComponentManager &&
  1.1970 +        nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus)
  1.1971 +        nsComponentManagerImpl::gComponentManager->RegisterManifest(aType, c->location, false);
  1.1972 +
  1.1973 +    return NS_OK;
  1.1974 +}
  1.1975 +

mercurial