michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim: set ts=8 sts=4 et sw=4 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: * michael@0: * This Original Code has been modified by IBM Corporation. michael@0: * Modifications made by IBM described herein are michael@0: * Copyright (c) International Business Machines michael@0: * Corporation, 2000 michael@0: * michael@0: * Modifications to Mozilla code or documentation michael@0: * identified per MPL Section 3.3 michael@0: * michael@0: * Date Modified by Description of modification michael@0: * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 michael@0: */ michael@0: michael@0: #include michael@0: #include "nscore.h" michael@0: #include "nsISupports.h" michael@0: #include "nspr.h" michael@0: #include "nsCRT.h" // for atoll michael@0: michael@0: // Arena used by component manager for storing contractid string, dll michael@0: // location strings and small objects michael@0: // CAUTION: Arena align mask needs to be defined before including plarena.h michael@0: // currently from nsComponentManager.h michael@0: #define PL_ARENA_CONST_ALIGN_MASK 7 michael@0: #define NS_CM_BLOCK_SIZE (1024 * 8) michael@0: michael@0: #include "nsCategoryManager.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsComponentManager.h" michael@0: #include "nsDirectoryService.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: #include "nsCategoryManager.h" michael@0: #include "nsCategoryManagerUtils.h" michael@0: #include "xptiprivate.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/XPTInterfaceInfoManager.h" michael@0: #include "nsIConsoleService.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsISimpleEnumerator.h" michael@0: #include "nsIStringEnumerator.h" michael@0: #include "nsXPCOM.h" michael@0: #include "nsXPCOMPrivate.h" michael@0: #include "nsISupportsPrimitives.h" michael@0: #include "nsIClassInfo.h" michael@0: #include "nsLocalFile.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsString.h" michael@0: #include "nsXPIDLString.h" michael@0: #include "prcmon.h" michael@0: #include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself... michael@0: #include "nsThreadUtils.h" michael@0: #include "prthread.h" michael@0: #include "private/pprthred.h" michael@0: #include "nsTArray.h" michael@0: #include "prio.h" michael@0: #include "ManifestParser.h" michael@0: #include "mozilla/Services.h" michael@0: michael@0: #include "nsManifestLineReader.h" michael@0: #include "mozilla/GenericFactory.h" michael@0: #include "nsSupportsPrimitives.h" michael@0: #include "nsArray.h" michael@0: #include "nsIMutableArray.h" michael@0: #include "nsArrayEnumerator.h" michael@0: #include "nsStringEnumerator.h" michael@0: #include "mozilla/FileUtils.h" michael@0: #include "nsNetUtil.h" michael@0: michael@0: #include // for placement new michael@0: michael@0: #include "mozilla/Omnijar.h" michael@0: michael@0: #include "prlog.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: PRLogModuleInfo* nsComponentManagerLog = nullptr; michael@0: michael@0: // defined in nsStaticXULComponents.cpp to contain all the components in michael@0: // libxul. michael@0: extern mozilla::Module const *const *const kPStaticModules[]; michael@0: michael@0: #if 0 || defined (DEBUG_timeless) michael@0: #define SHOW_DENIED_ON_SHUTDOWN michael@0: #define SHOW_CI_ON_EXISTING_SERVICE michael@0: #endif michael@0: michael@0: // Bloated registry buffer size to improve startup performance -- needs to michael@0: // be big enough to fit the entire file into memory or it'll thrash. michael@0: // 512K is big enough to allow for some future growth in the registry. michael@0: #define BIG_REGISTRY_BUFLEN (512*1024) michael@0: michael@0: // Common Key Names michael@0: const char xpcomComponentsKeyName[]="software/mozilla/XPCOM/components"; michael@0: const char xpcomKeyName[]="software/mozilla/XPCOM"; michael@0: michael@0: // Common Value Names michael@0: const char fileSizeValueName[]="FileSize"; michael@0: const char lastModValueName[]="LastModTimeStamp"; michael@0: const char nativeComponentType[]="application/x-mozilla-native"; michael@0: const char staticComponentType[]="application/x-mozilla-static"; michael@0: michael@0: NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID); michael@0: michael@0: #define UID_STRING_LENGTH 39 michael@0: michael@0: nsresult michael@0: nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const michael@0: { michael@0: nsresult rv; michael@0: nsXPIDLCString value; michael@0: nsCOMPtr catman; michael@0: nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; michael@0: if (!compMgr) { michael@0: rv = NS_ERROR_NOT_INITIALIZED; michael@0: goto error; michael@0: } michael@0: michael@0: if (!mCategory || !mEntry) { michael@0: // when categories have defaults, use that for null mEntry michael@0: rv = NS_ERROR_NULL_POINTER; michael@0: goto error; michael@0: } michael@0: michael@0: rv = compMgr->nsComponentManagerImpl::GetService(kCategoryManagerCID, michael@0: NS_GET_IID(nsICategoryManager), michael@0: getter_AddRefs(catman)); michael@0: if (NS_FAILED(rv)) goto error; michael@0: michael@0: /* find the contractID for category.entry */ michael@0: rv = catman->GetCategoryEntry(mCategory, mEntry, michael@0: getter_Copies(value)); michael@0: if (NS_FAILED(rv)) goto error; michael@0: if (!value) { michael@0: rv = NS_ERROR_SERVICE_NOT_AVAILABLE; michael@0: goto error; michael@0: } michael@0: michael@0: rv = compMgr-> michael@0: nsComponentManagerImpl::GetServiceByContractID(value, michael@0: aIID, aInstancePtr); michael@0: if (NS_FAILED(rv)) { michael@0: error: michael@0: *aInstancePtr = 0; michael@0: } michael@0: if (mErrorPtr) michael@0: *mErrorPtr = rv; michael@0: return rv; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Arena helper functions michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: char * michael@0: ArenaStrndup(const char *s, uint32_t len, PLArenaPool *arena) michael@0: { michael@0: void *mem; michael@0: // Include trailing null in the len michael@0: PL_ARENA_ALLOCATE(mem, arena, len+1); michael@0: if (mem) michael@0: memcpy(mem, s, len+1); michael@0: return static_cast(mem); michael@0: } michael@0: michael@0: char* michael@0: ArenaStrdup(const char *s, PLArenaPool *arena) michael@0: { michael@0: return ArenaStrndup(s, strlen(s), arena); michael@0: } michael@0: michael@0: // GetService and a few other functions need to exit their mutex mid-function michael@0: // without reentering it later in the block. This class supports that michael@0: // style of early-exit that MutexAutoUnlock doesn't. michael@0: michael@0: namespace { michael@0: michael@0: class MOZ_STACK_CLASS MutexLock michael@0: { michael@0: public: michael@0: MutexLock(SafeMutex& aMutex) michael@0: : mMutex(aMutex) michael@0: , mLocked(false) michael@0: { michael@0: Lock(); michael@0: } michael@0: michael@0: ~MutexLock() michael@0: { michael@0: if (mLocked) michael@0: Unlock(); michael@0: } michael@0: michael@0: void Lock() michael@0: { michael@0: NS_ASSERTION(!mLocked, "Re-entering a mutex"); michael@0: mMutex.Lock(); michael@0: mLocked = true; michael@0: } michael@0: michael@0: void Unlock() michael@0: { michael@0: NS_ASSERTION(mLocked, "Exiting a mutex that isn't held!"); michael@0: mMutex.Unlock(); michael@0: mLocked = false; michael@0: } michael@0: michael@0: private: michael@0: SafeMutex& mMutex; michael@0: bool mLocked; michael@0: }; michael@0: michael@0: } // anonymous namespace michael@0: michael@0: // this is safe to call during InitXPCOM michael@0: static already_AddRefed michael@0: GetLocationFromDirectoryService(const char* prop) michael@0: { michael@0: nsCOMPtr directoryService; michael@0: nsDirectoryService::Create(nullptr, michael@0: NS_GET_IID(nsIProperties), michael@0: getter_AddRefs(directoryService)); michael@0: michael@0: if (!directoryService) michael@0: return nullptr; michael@0: michael@0: nsCOMPtr file; michael@0: nsresult rv = directoryService->Get(prop, michael@0: NS_GET_IID(nsIFile), michael@0: getter_AddRefs(file)); michael@0: if (NS_FAILED(rv)) michael@0: return nullptr; michael@0: michael@0: return file.forget(); michael@0: } michael@0: michael@0: static already_AddRefed michael@0: CloneAndAppend(nsIFile* aBase, const nsACString& append) michael@0: { michael@0: nsCOMPtr f; michael@0: aBase->Clone(getter_AddRefs(f)); michael@0: if (!f) michael@0: return nullptr; michael@0: michael@0: f->AppendNative(append); michael@0: return f.forget(); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsComponentManagerImpl michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: nsresult michael@0: nsComponentManagerImpl::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult) michael@0: { michael@0: if (aOuter) michael@0: return NS_ERROR_NO_AGGREGATION; michael@0: michael@0: if (!gComponentManager) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return gComponentManager->QueryInterface(aIID, aResult); michael@0: } michael@0: michael@0: static const int CONTRACTID_HASHTABLE_INITIAL_SIZE = 2048; michael@0: michael@0: nsComponentManagerImpl::nsComponentManagerImpl() michael@0: : mFactories(CONTRACTID_HASHTABLE_INITIAL_SIZE) michael@0: , mContractIDs(CONTRACTID_HASHTABLE_INITIAL_SIZE) michael@0: , mLock("nsComponentManagerImpl.mLock") michael@0: , mStatus(NOT_INITIALIZED) michael@0: { michael@0: } michael@0: michael@0: nsTArray* nsComponentManagerImpl::sStaticModules; michael@0: michael@0: /* static */ void michael@0: nsComponentManagerImpl::InitializeStaticModules() michael@0: { michael@0: if (sStaticModules) michael@0: return; michael@0: michael@0: sStaticModules = new nsTArray; michael@0: for (const mozilla::Module *const *const *staticModules = kPStaticModules; michael@0: *staticModules; ++staticModules) michael@0: sStaticModules->AppendElement(**staticModules); michael@0: } michael@0: michael@0: nsTArray* michael@0: nsComponentManagerImpl::sModuleLocations; michael@0: michael@0: /* static */ void michael@0: nsComponentManagerImpl::InitializeModuleLocations() michael@0: { michael@0: if (sModuleLocations) michael@0: return; michael@0: michael@0: sModuleLocations = new nsTArray; michael@0: } michael@0: michael@0: nsresult nsComponentManagerImpl::Init() michael@0: { michael@0: PR_ASSERT(NOT_INITIALIZED == mStatus); michael@0: michael@0: if (nsComponentManagerLog == nullptr) michael@0: { michael@0: nsComponentManagerLog = PR_NewLogModule("nsComponentManager"); michael@0: } michael@0: michael@0: // Initialize our arena michael@0: PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE); michael@0: michael@0: nsCOMPtr greDir = michael@0: GetLocationFromDirectoryService(NS_GRE_DIR); michael@0: nsCOMPtr appDir = michael@0: GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR); michael@0: michael@0: InitializeStaticModules(); michael@0: InitializeModuleLocations(); michael@0: michael@0: ComponentLocation* cl = sModuleLocations->InsertElementAt(0); michael@0: nsCOMPtr lf = CloneAndAppend(appDir, NS_LITERAL_CSTRING("chrome.manifest")); michael@0: cl->type = NS_COMPONENT_LOCATION; michael@0: cl->location.Init(lf); michael@0: michael@0: bool equals = false; michael@0: appDir->Equals(greDir, &equals); michael@0: if (!equals) { michael@0: cl = sModuleLocations->InsertElementAt(0); michael@0: cl->type = NS_COMPONENT_LOCATION; michael@0: lf = CloneAndAppend(greDir, NS_LITERAL_CSTRING("chrome.manifest")); michael@0: cl->location.Init(lf); michael@0: } michael@0: michael@0: PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, michael@0: ("nsComponentManager: Initialized.")); michael@0: michael@0: nsresult rv = mNativeModuleLoader.Init(); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsCategoryManager::GetSingleton()->SuppressNotifications(true); michael@0: michael@0: RegisterModule(&kXPCOMModule, nullptr); michael@0: michael@0: for (uint32_t i = 0; i < sStaticModules->Length(); ++i) michael@0: RegisterModule((*sStaticModules)[i], nullptr); michael@0: michael@0: nsRefPtr appOmnijar = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP); michael@0: if (appOmnijar) { michael@0: cl = sModuleLocations->InsertElementAt(1); // Insert after greDir michael@0: cl->type = NS_COMPONENT_LOCATION; michael@0: cl->location.Init(appOmnijar, "chrome.manifest"); michael@0: } michael@0: nsRefPtr greOmnijar = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE); michael@0: if (greOmnijar) { michael@0: cl = sModuleLocations->InsertElementAt(0); michael@0: cl->type = NS_COMPONENT_LOCATION; michael@0: cl->location.Init(greOmnijar, "chrome.manifest"); michael@0: } michael@0: michael@0: RereadChromeManifests(false); michael@0: michael@0: nsCategoryManager::GetSingleton()->SuppressNotifications(false); michael@0: michael@0: RegisterWeakMemoryReporter(this); michael@0: michael@0: // Unfortunately, we can't register the nsCategoryManager memory reporter michael@0: // in its constructor (which is triggered by the GetSingleton() call michael@0: // above) because the memory reporter manager isn't initialized at that michael@0: // point. So we wait until now. michael@0: nsCategoryManager::GetSingleton()->InitMemoryReporter(); michael@0: michael@0: mStatus = NORMAL; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsComponentManagerImpl::RegisterModule(const mozilla::Module* aModule, michael@0: FileLocation* aFile) michael@0: { michael@0: mLock.AssertNotCurrentThreadOwns(); michael@0: michael@0: { michael@0: // Scope the monitor so that we don't hold it while calling into the michael@0: // category manager. michael@0: MutexLock lock(mLock); michael@0: michael@0: KnownModule* m; michael@0: if (aFile) { michael@0: nsCString uri; michael@0: aFile->GetURIString(uri); michael@0: NS_ASSERTION(!mKnownModules.Get(uri), michael@0: "Must not register a binary module twice."); michael@0: michael@0: m = new KnownModule(aModule, *aFile); michael@0: mKnownModules.Put(uri, m); michael@0: } else { michael@0: m = new KnownModule(aModule); michael@0: mKnownStaticModules.AppendElement(m); michael@0: } michael@0: michael@0: if (aModule->mCIDs) { michael@0: const mozilla::Module::CIDEntry* entry; michael@0: for (entry = aModule->mCIDs; entry->cid; ++entry) michael@0: RegisterCIDEntryLocked(entry, m); michael@0: } michael@0: michael@0: if (aModule->mContractIDs) { michael@0: const mozilla::Module::ContractIDEntry* entry; michael@0: for (entry = aModule->mContractIDs; entry->contractid; ++entry) michael@0: RegisterContractIDLocked(entry); michael@0: MOZ_ASSERT(!entry->cid, "Incorrectly terminated contract list"); michael@0: } michael@0: } michael@0: michael@0: if (aModule->mCategoryEntries) { michael@0: const mozilla::Module::CategoryEntry* entry; michael@0: for (entry = aModule->mCategoryEntries; entry->category; ++entry) michael@0: nsCategoryManager::GetSingleton()-> michael@0: AddCategoryEntry(entry->category, michael@0: entry->entry, michael@0: entry->value); michael@0: } michael@0: } michael@0: michael@0: static bool michael@0: ProcessSelectorMatches(Module::ProcessSelector selector) michael@0: { michael@0: if (selector == Module::ANY_PROCESS) { michael@0: return true; michael@0: } michael@0: michael@0: GeckoProcessType type = XRE_GetProcessType(); michael@0: switch (selector) { michael@0: case Module::MAIN_PROCESS_ONLY: michael@0: return type == GeckoProcessType_Default; michael@0: case Module::CONTENT_PROCESS_ONLY: michael@0: return type == GeckoProcessType_Content; michael@0: default: michael@0: MOZ_CRASH("invalid process selector"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsComponentManagerImpl::RegisterCIDEntryLocked( michael@0: const mozilla::Module::CIDEntry* aEntry, michael@0: KnownModule* aModule) michael@0: { michael@0: mLock.AssertCurrentThreadOwns(); michael@0: michael@0: if (!ProcessSelectorMatches(aEntry->processSelector)) { michael@0: return; michael@0: } michael@0: michael@0: nsFactoryEntry* f = mFactories.Get(*aEntry->cid); michael@0: if (f) { michael@0: NS_WARNING("Re-registering a CID?"); michael@0: michael@0: char idstr[NSID_LENGTH]; michael@0: aEntry->cid->ToProvidedString(idstr); michael@0: michael@0: nsCString existing; michael@0: if (f->mModule) michael@0: existing = f->mModule->Description(); michael@0: else michael@0: existing = ""; michael@0: SafeMutexAutoUnlock unlock(mLock); michael@0: LogMessage("While registering XPCOM module %s, trying to re-register CID '%s' already registered by %s.", michael@0: aModule->Description().get(), michael@0: idstr, michael@0: existing.get()); michael@0: return; michael@0: } michael@0: michael@0: f = new nsFactoryEntry(aEntry, aModule); michael@0: mFactories.Put(*aEntry->cid, f); michael@0: } michael@0: michael@0: void michael@0: nsComponentManagerImpl::RegisterContractIDLocked( michael@0: const mozilla::Module::ContractIDEntry* aEntry) michael@0: { michael@0: mLock.AssertCurrentThreadOwns(); michael@0: michael@0: if (!ProcessSelectorMatches(aEntry->processSelector)) { michael@0: return; michael@0: } michael@0: michael@0: nsFactoryEntry* f = mFactories.Get(*aEntry->cid); michael@0: if (!f) { michael@0: NS_ERROR("No CID found when attempting to map contract ID"); michael@0: michael@0: char idstr[NSID_LENGTH]; michael@0: aEntry->cid->ToProvidedString(idstr); michael@0: michael@0: LogMessage("Could not map contract ID '%s' to CID %s because no implementation of the CID is registered.", michael@0: aEntry->contractid, michael@0: idstr); michael@0: michael@0: return; michael@0: } michael@0: michael@0: mContractIDs.Put(nsDependentCString(aEntry->contractid), f); michael@0: } michael@0: michael@0: static void michael@0: CutExtension(nsCString& path) michael@0: { michael@0: int32_t dotPos = path.RFindChar('.'); michael@0: if (kNotFound == dotPos) michael@0: path.Truncate(); michael@0: else michael@0: path.Cut(0, dotPos + 1); michael@0: } michael@0: michael@0: void michael@0: nsComponentManagerImpl::RegisterManifest(NSLocationType aType, michael@0: FileLocation &aFile, michael@0: bool aChromeOnly) michael@0: { michael@0: uint32_t len; michael@0: FileLocation::Data data; michael@0: nsAutoArrayPtr buf; michael@0: nsresult rv = aFile.GetData(data); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = data.GetSize(&len); michael@0: } michael@0: if (NS_SUCCEEDED(rv)) { michael@0: buf = new char[len + 1]; michael@0: rv = data.Copy(buf, len); michael@0: } michael@0: if (NS_SUCCEEDED(rv)) { michael@0: buf[len] = '\0'; michael@0: ParseManifest(aType, aFile, buf, aChromeOnly); michael@0: } else if (NS_BOOTSTRAPPED_LOCATION != aType) { michael@0: nsCString uri; michael@0: aFile.GetURIString(uri); michael@0: LogMessage("Could not read chrome manifest '%s'.", uri.get()); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& cx, int lineno, char *const * argv) michael@0: { michael@0: char* file = argv[0]; michael@0: FileLocation f(cx.mFile, file); michael@0: RegisterManifest(cx.mType, f, cx.mChromeOnly); michael@0: } michael@0: michael@0: void michael@0: nsComponentManagerImpl::ManifestBinaryComponent(ManifestProcessingContext& cx, int lineno, char *const * argv) michael@0: { michael@0: if (cx.mFile.IsZip()) { michael@0: NS_WARNING("Cannot load binary components from a jar."); michael@0: LogMessageWithContext(cx.mFile, lineno, michael@0: "Cannot load binary components from a jar."); michael@0: return; michael@0: } michael@0: michael@0: FileLocation f(cx.mFile, argv[0]); michael@0: nsCString uri; michael@0: f.GetURIString(uri); michael@0: michael@0: if (mKnownModules.Get(uri)) { michael@0: NS_WARNING("Attempting to register a binary component twice."); michael@0: LogMessageWithContext(cx.mFile, lineno, michael@0: "Attempting to register a binary component twice."); michael@0: return; michael@0: } michael@0: michael@0: const mozilla::Module* m = mNativeModuleLoader.LoadModule(f); michael@0: // The native module loader should report an error here, we don't have to michael@0: if (!m) michael@0: return; michael@0: michael@0: RegisterModule(m, &f); michael@0: } michael@0: michael@0: void michael@0: nsComponentManagerImpl::ManifestXPT(ManifestProcessingContext& cx, int lineno, char *const * argv) michael@0: { michael@0: FileLocation f(cx.mFile, argv[0]); michael@0: uint32_t len; michael@0: FileLocation::Data data; michael@0: nsAutoArrayPtr buf; michael@0: nsresult rv = f.GetData(data); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = data.GetSize(&len); michael@0: } michael@0: if (NS_SUCCEEDED(rv)) { michael@0: buf = new char[len]; michael@0: rv = data.Copy(buf, len); michael@0: } michael@0: if (NS_SUCCEEDED(rv)) { michael@0: XPTInterfaceInfoManager::GetSingleton()->RegisterBuffer(buf, len); michael@0: } else { michael@0: nsCString uri; michael@0: f.GetURIString(uri); michael@0: LogMessage("Could not read '%s'.", uri.get()); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsComponentManagerImpl::ManifestComponent(ManifestProcessingContext& cx, int lineno, char *const * argv) michael@0: { michael@0: mLock.AssertNotCurrentThreadOwns(); michael@0: michael@0: char* id = argv[0]; michael@0: char* file = argv[1]; michael@0: michael@0: nsID cid; michael@0: if (!cid.Parse(id)) { michael@0: LogMessageWithContext(cx.mFile, lineno, michael@0: "Malformed CID: '%s'.", id); michael@0: return; michael@0: } michael@0: michael@0: // Precompute the hash/file data outside of the lock michael@0: FileLocation fl(cx.mFile, file); michael@0: nsCString hash; michael@0: fl.GetURIString(hash); michael@0: michael@0: MutexLock lock(mLock); michael@0: nsFactoryEntry* f = mFactories.Get(cid); michael@0: if (f) { michael@0: char idstr[NSID_LENGTH]; michael@0: cid.ToProvidedString(idstr); michael@0: michael@0: nsCString existing; michael@0: if (f->mModule) michael@0: existing = f->mModule->Description(); michael@0: else michael@0: existing = ""; michael@0: michael@0: lock.Unlock(); michael@0: michael@0: LogMessageWithContext(cx.mFile, lineno, michael@0: "Trying to re-register CID '%s' already registered by %s.", michael@0: idstr, michael@0: existing.get()); michael@0: return; michael@0: } michael@0: michael@0: KnownModule* km; michael@0: michael@0: km = mKnownModules.Get(hash); michael@0: if (!km) { michael@0: km = new KnownModule(fl); michael@0: mKnownModules.Put(hash, km); michael@0: } michael@0: michael@0: void* place; michael@0: michael@0: PL_ARENA_ALLOCATE(place, &mArena, sizeof(nsCID)); michael@0: nsID* permanentCID = static_cast(place); michael@0: *permanentCID = cid; michael@0: michael@0: PL_ARENA_ALLOCATE(place, &mArena, sizeof(mozilla::Module::CIDEntry)); michael@0: mozilla::Module::CIDEntry* e = new (place) mozilla::Module::CIDEntry(); michael@0: e->cid = permanentCID; michael@0: michael@0: f = new nsFactoryEntry(e, km); michael@0: mFactories.Put(cid, f); michael@0: } michael@0: michael@0: void michael@0: nsComponentManagerImpl::ManifestContract(ManifestProcessingContext& cx, int lineno, char *const * argv) michael@0: { michael@0: mLock.AssertNotCurrentThreadOwns(); michael@0: michael@0: char* contract = argv[0]; michael@0: char* id = argv[1]; michael@0: michael@0: nsID cid; michael@0: if (!cid.Parse(id)) { michael@0: LogMessageWithContext(cx.mFile, lineno, michael@0: "Malformed CID: '%s'.", id); michael@0: return; michael@0: } michael@0: michael@0: MutexLock lock(mLock); michael@0: nsFactoryEntry* f = mFactories.Get(cid); michael@0: if (!f) { michael@0: lock.Unlock(); michael@0: LogMessageWithContext(cx.mFile, lineno, michael@0: "Could not map contract ID '%s' to CID %s because no implementation of the CID is registered.", michael@0: contract, id); michael@0: return; michael@0: } michael@0: michael@0: mContractIDs.Put(nsDependentCString(contract), f); michael@0: } michael@0: michael@0: void michael@0: nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext& cx, int lineno, char *const * argv) michael@0: { michael@0: char* category = argv[0]; michael@0: char* key = argv[1]; michael@0: char* value = argv[2]; michael@0: michael@0: nsCategoryManager::GetSingleton()-> michael@0: AddCategoryEntry(category, key, value); michael@0: } michael@0: michael@0: void michael@0: nsComponentManagerImpl::RereadChromeManifests(bool aChromeOnly) michael@0: { michael@0: for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) { michael@0: ComponentLocation& l = sModuleLocations->ElementAt(i); michael@0: RegisterManifest(l.type, l.location, aChromeOnly); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsComponentManagerImpl::KnownModule::EnsureLoader() michael@0: { michael@0: if (!mLoader) { michael@0: nsCString extension; michael@0: mFile.GetURIString(extension); michael@0: CutExtension(extension); michael@0: mLoader = nsComponentManagerImpl::gComponentManager->LoaderForExtension(extension); michael@0: } michael@0: return !!mLoader; michael@0: } michael@0: michael@0: bool michael@0: nsComponentManagerImpl::KnownModule::Load() michael@0: { michael@0: if (mFailed) michael@0: return false; michael@0: if (!mModule) { michael@0: if (!EnsureLoader()) michael@0: return false; michael@0: michael@0: mModule = mLoader->LoadModule(mFile); michael@0: michael@0: if (!mModule) { michael@0: mFailed = true; michael@0: return false; michael@0: } michael@0: } michael@0: if (!mLoaded) { michael@0: if (mModule->loadProc) { michael@0: nsresult rv = mModule->loadProc(); michael@0: if (NS_FAILED(rv)) { michael@0: mFailed = true; michael@0: return false; michael@0: } michael@0: } michael@0: mLoaded = true; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: nsCString michael@0: nsComponentManagerImpl::KnownModule::Description() const michael@0: { michael@0: nsCString s; michael@0: if (mFile) michael@0: mFile.GetURIString(s); michael@0: else michael@0: s = ""; michael@0: return s; michael@0: } michael@0: michael@0: nsresult nsComponentManagerImpl::Shutdown(void) michael@0: { michael@0: PR_ASSERT(NORMAL == mStatus); michael@0: michael@0: mStatus = SHUTDOWN_IN_PROGRESS; michael@0: michael@0: // Shutdown the component manager michael@0: PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown.")); michael@0: michael@0: UnregisterWeakMemoryReporter(this); michael@0: michael@0: // Release all cached factories michael@0: mContractIDs.Clear(); michael@0: mFactories.Clear(); // XXX release the objects, don't just clear michael@0: mLoaderMap.Clear(); michael@0: mKnownModules.Clear(); michael@0: mKnownStaticModules.Clear(); michael@0: michael@0: delete sStaticModules; michael@0: delete sModuleLocations; michael@0: michael@0: // Unload libraries michael@0: mNativeModuleLoader.UnloadLibraries(); michael@0: michael@0: // delete arena for strings and small objects michael@0: PL_FinishArenaPool(&mArena); michael@0: michael@0: mStatus = SHUTDOWN_COMPLETE; michael@0: michael@0: PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Shutdown complete.")); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsComponentManagerImpl::~nsComponentManagerImpl() michael@0: { michael@0: PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning destruction.")); michael@0: michael@0: if (SHUTDOWN_COMPLETE != mStatus) michael@0: Shutdown(); michael@0: michael@0: PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Destroyed.")); michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS( michael@0: nsComponentManagerImpl, michael@0: nsIComponentManager, michael@0: nsIServiceManager, michael@0: nsIComponentRegistrar, michael@0: nsISupportsWeakReference, michael@0: nsIInterfaceRequestor, michael@0: nsIMemoryReporter) michael@0: michael@0: nsresult michael@0: nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result) michael@0: { michael@0: NS_WARNING("This isn't supported"); michael@0: // fall through to QI as anything QIable is a superset of what can be michael@0: // got via the GetInterface() michael@0: return QueryInterface(uuid, result); michael@0: } michael@0: michael@0: nsFactoryEntry * michael@0: nsComponentManagerImpl::GetFactoryEntry(const char *aContractID, michael@0: uint32_t aContractIDLen) michael@0: { michael@0: SafeMutexAutoLock lock(mLock); michael@0: return mContractIDs.Get(nsDependentCString(aContractID, aContractIDLen)); michael@0: } michael@0: michael@0: michael@0: nsFactoryEntry * michael@0: nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass) michael@0: { michael@0: SafeMutexAutoLock lock(mLock); michael@0: return mFactories.Get(aClass); michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsComponentManagerImpl::FindFactory(const nsCID& aClass) michael@0: { michael@0: nsFactoryEntry* e = GetFactoryEntry(aClass); michael@0: if (!e) michael@0: return nullptr; michael@0: michael@0: return e->GetFactory(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsComponentManagerImpl::FindFactory(const char *contractID, michael@0: uint32_t aContractIDLen) michael@0: { michael@0: nsFactoryEntry *entry = GetFactoryEntry(contractID, aContractIDLen); michael@0: if (!entry) michael@0: return nullptr; michael@0: michael@0: return entry->GetFactory(); michael@0: } michael@0: michael@0: /** michael@0: * GetClassObject() michael@0: * michael@0: * Given a classID, this finds the singleton ClassObject that implements the CID. michael@0: * Returns an interface of type aIID off the singleton classobject. michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID, michael@0: void **aResult) michael@0: { michael@0: nsresult rv; michael@0: michael@0: #ifdef PR_LOGGING michael@0: if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG)) michael@0: { michael@0: char *buf = aClass.ToString(); michael@0: PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf); michael@0: if (buf) michael@0: NS_Free(buf); michael@0: } michael@0: #endif michael@0: michael@0: PR_ASSERT(aResult != nullptr); michael@0: michael@0: nsCOMPtr factory = FindFactory(aClass); michael@0: if (!factory) michael@0: return NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: michael@0: rv = factory->QueryInterface(aIID, aResult); michael@0: michael@0: PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, michael@0: ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID, michael@0: const nsIID &aIID, michael@0: void **aResult) michael@0: { michael@0: if (NS_WARN_IF(!aResult) || michael@0: NS_WARN_IF(!contractID)) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: nsresult rv; michael@0: michael@0: michael@0: #ifdef PR_LOGGING michael@0: if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG)) michael@0: { michael@0: PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID); michael@0: } michael@0: #endif michael@0: michael@0: nsCOMPtr factory = FindFactory(contractID, strlen(contractID)); michael@0: if (!factory) michael@0: return NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: michael@0: rv = factory->QueryInterface(aIID, aResult); michael@0: michael@0: PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, michael@0: ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /** michael@0: * CreateInstance() michael@0: * michael@0: * Create an instance of an object that implements an interface and belongs michael@0: * to the implementation aClass using the factory. The factory is immediately michael@0: * released and not held onto for any longer. michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::CreateInstance(const nsCID &aClass, michael@0: nsISupports *aDelegate, michael@0: const nsIID &aIID, michael@0: void **aResult) michael@0: { michael@0: // test this first, since there's no point in creating a component during michael@0: // shutdown -- whether it's available or not would depend on the order it michael@0: // occurs in the list michael@0: if (gXPCOMShuttingDown) { michael@0: // When processing shutdown, don't process new GetService() requests michael@0: #ifdef SHOW_DENIED_ON_SHUTDOWN michael@0: nsXPIDLCString cid, iid; michael@0: cid.Adopt(aClass.ToString()); michael@0: iid.Adopt(aIID.ToString()); michael@0: fprintf(stderr, "Creating new instance on shutdown. Denied.\n" michael@0: " CID: %s\n IID: %s\n", cid.get(), iid.get()); michael@0: #endif /* SHOW_DENIED_ON_SHUTDOWN */ michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: if (aResult == nullptr) michael@0: { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: *aResult = nullptr; michael@0: michael@0: nsFactoryEntry *entry = GetFactoryEntry(aClass); michael@0: michael@0: if (!entry) michael@0: return NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: michael@0: #ifdef SHOW_CI_ON_EXISTING_SERVICE michael@0: if (entry->mServiceObject) { michael@0: nsXPIDLCString cid; michael@0: cid.Adopt(aClass.ToString()); michael@0: nsAutoCString message; michael@0: message = NS_LITERAL_CSTRING("You are calling CreateInstance \"") + michael@0: cid + NS_LITERAL_CSTRING("\" when a service for this CID already exists!"); michael@0: NS_ERROR(message.get()); michael@0: } michael@0: #endif michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr factory = entry->GetFactory(); michael@0: if (factory) michael@0: { michael@0: rv = factory->CreateInstance(aDelegate, aIID, aResult); michael@0: if (NS_SUCCEEDED(rv) && !*aResult) { michael@0: NS_ERROR("Factory did not return an object but returned success!"); michael@0: rv = NS_ERROR_SERVICE_NOT_FOUND; michael@0: } michael@0: } michael@0: else { michael@0: // Translate error values michael@0: rv = NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: } michael@0: michael@0: #ifdef PR_LOGGING michael@0: if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) michael@0: { michael@0: char *buf = aClass.ToString(); michael@0: PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, michael@0: ("nsComponentManager: CreateInstance(%s) %s", buf, michael@0: NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); michael@0: if (buf) michael@0: NS_Free(buf); michael@0: } michael@0: #endif michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /** michael@0: * CreateInstanceByContractID() michael@0: * michael@0: * A variant of CreateInstance() that creates an instance of the object that michael@0: * implements the interface aIID and whose implementation has a contractID aContractID. michael@0: * michael@0: * This is only a convenience routine that turns around can calls the michael@0: * CreateInstance() with classid and iid. michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID, michael@0: nsISupports *aDelegate, michael@0: const nsIID &aIID, michael@0: void **aResult) michael@0: { michael@0: if (NS_WARN_IF(!aContractID)) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: // test this first, since there's no point in creating a component during michael@0: // shutdown -- whether it's available or not would depend on the order it michael@0: // occurs in the list michael@0: if (gXPCOMShuttingDown) { michael@0: // When processing shutdown, don't process new GetService() requests michael@0: #ifdef SHOW_DENIED_ON_SHUTDOWN michael@0: nsXPIDLCString iid; michael@0: iid.Adopt(aIID.ToString()); michael@0: fprintf(stderr, "Creating new instance on shutdown. Denied.\n" michael@0: " ContractID: %s\n IID: %s\n", aContractID, iid.get()); michael@0: #endif /* SHOW_DENIED_ON_SHUTDOWN */ michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: if (aResult == nullptr) michael@0: { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: *aResult = nullptr; michael@0: michael@0: nsFactoryEntry *entry = GetFactoryEntry(aContractID, strlen(aContractID)); michael@0: michael@0: if (!entry) michael@0: return NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: michael@0: #ifdef SHOW_CI_ON_EXISTING_SERVICE michael@0: if (entry->mServiceObject) { michael@0: nsAutoCString message; michael@0: message = michael@0: NS_LITERAL_CSTRING("You are calling CreateInstance \"") + michael@0: nsDependentCString(aContractID) + michael@0: NS_LITERAL_CSTRING("\" when a service for this CID already exists! " michael@0: "Add it to abusedContracts to track down the service consumer."); michael@0: NS_ERROR(message.get()); michael@0: } michael@0: #endif michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr factory = entry->GetFactory(); michael@0: if (factory) michael@0: { michael@0: michael@0: rv = factory->CreateInstance(aDelegate, aIID, aResult); michael@0: if (NS_SUCCEEDED(rv) && !*aResult) { michael@0: NS_ERROR("Factory did not return an object but returned success!"); michael@0: rv = NS_ERROR_SERVICE_NOT_FOUND; michael@0: } michael@0: } michael@0: else { michael@0: // Translate error values michael@0: rv = NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: } michael@0: michael@0: PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, michael@0: ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID, michael@0: NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: static PLDHashOperator michael@0: FreeFactoryEntries(const nsID& aCID, michael@0: nsFactoryEntry* aEntry, michael@0: void* arg) michael@0: { michael@0: aEntry->mFactory = nullptr; michael@0: aEntry->mServiceObject = nullptr; michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: nsresult michael@0: nsComponentManagerImpl::FreeServices() michael@0: { michael@0: NS_ASSERTION(gXPCOMShuttingDown, "Must be shutting down in order to free all services"); michael@0: michael@0: if (!gXPCOMShuttingDown) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: mFactories.EnumerateRead(FreeFactoryEntries, nullptr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // This should only ever be called within the monitor! michael@0: nsComponentManagerImpl::PendingServiceInfo* michael@0: nsComponentManagerImpl::AddPendingService(const nsCID& aServiceCID, michael@0: PRThread* aThread) michael@0: { michael@0: PendingServiceInfo* newInfo = mPendingServices.AppendElement(); michael@0: if (newInfo) { michael@0: newInfo->cid = &aServiceCID; michael@0: newInfo->thread = aThread; michael@0: } michael@0: return newInfo; michael@0: } michael@0: michael@0: // This should only ever be called within the monitor! michael@0: void michael@0: nsComponentManagerImpl::RemovePendingService(const nsCID& aServiceCID) michael@0: { michael@0: uint32_t pendingCount = mPendingServices.Length(); michael@0: for (uint32_t index = 0; index < pendingCount; ++index) { michael@0: const PendingServiceInfo& info = mPendingServices.ElementAt(index); michael@0: if (info.cid->Equals(aServiceCID)) { michael@0: mPendingServices.RemoveElementAt(index); michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // This should only ever be called within the monitor! michael@0: PRThread* michael@0: nsComponentManagerImpl::GetPendingServiceThread(const nsCID& aServiceCID) const michael@0: { michael@0: uint32_t pendingCount = mPendingServices.Length(); michael@0: for (uint32_t index = 0; index < pendingCount; ++index) { michael@0: const PendingServiceInfo& info = mPendingServices.ElementAt(index); michael@0: if (info.cid->Equals(aServiceCID)) { michael@0: return info.thread; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::GetService(const nsCID& aClass, michael@0: const nsIID& aIID, michael@0: void* *result) michael@0: { michael@0: // test this first, since there's no point in returning a service during michael@0: // shutdown -- whether it's available or not would depend on the order it michael@0: // occurs in the list michael@0: if (gXPCOMShuttingDown) { michael@0: // When processing shutdown, don't process new GetService() requests michael@0: #ifdef SHOW_DENIED_ON_SHUTDOWN michael@0: nsXPIDLCString cid, iid; michael@0: cid.Adopt(aClass.ToString()); michael@0: iid.Adopt(aIID.ToString()); michael@0: fprintf(stderr, "Getting service on shutdown. Denied.\n" michael@0: " CID: %s\n IID: %s\n", cid.get(), iid.get()); michael@0: #endif /* SHOW_DENIED_ON_SHUTDOWN */ michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: // `service` must be released after the lock is released, so it must be michael@0: // declared before the lock in this C++ block. michael@0: nsCOMPtr service; michael@0: MutexLock lock(mLock); michael@0: michael@0: nsFactoryEntry* entry = mFactories.Get(aClass); michael@0: if (!entry) michael@0: return NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: michael@0: if (entry->mServiceObject) { michael@0: lock.Unlock(); michael@0: return entry->mServiceObject->QueryInterface(aIID, result); michael@0: } michael@0: michael@0: PRThread* currentPRThread = PR_GetCurrentThread(); michael@0: MOZ_ASSERT(currentPRThread, "This should never be null!"); michael@0: michael@0: // Needed to optimize the event loop below. michael@0: nsIThread* currentThread = nullptr; michael@0: michael@0: PRThread* pendingPRThread; michael@0: while ((pendingPRThread = GetPendingServiceThread(aClass))) { michael@0: if (pendingPRThread == currentPRThread) { michael@0: NS_ERROR("Recursive GetService!"); michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: michael@0: SafeMutexAutoUnlock unlockPending(mLock); michael@0: michael@0: if (!currentThread) { michael@0: currentThread = NS_GetCurrentThread(); michael@0: MOZ_ASSERT(currentThread, "This should never be null!"); michael@0: } michael@0: michael@0: // This will process a single event or yield the thread if no event is michael@0: // pending. michael@0: if (!NS_ProcessNextEvent(currentThread, false)) { michael@0: PR_Sleep(PR_INTERVAL_NO_WAIT); michael@0: } michael@0: } michael@0: michael@0: // It's still possible that the other thread failed to create the michael@0: // service so we're not guaranteed to have an entry or service yet. michael@0: if (entry->mServiceObject) { michael@0: lock.Unlock(); michael@0: return entry->mServiceObject->QueryInterface(aIID, result); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: PendingServiceInfo* newInfo = michael@0: #endif michael@0: AddPendingService(aClass, currentPRThread); michael@0: NS_ASSERTION(newInfo, "Failed to add info to the array!"); michael@0: michael@0: // We need to not be holding the service manager's lock while calling michael@0: // CreateInstance, because it invokes user code which could try to re-enter michael@0: // the service manager: michael@0: michael@0: nsresult rv; michael@0: { michael@0: SafeMutexAutoUnlock unlock(mLock); michael@0: rv = CreateInstance(aClass, nullptr, aIID, getter_AddRefs(service)); michael@0: } michael@0: if (NS_SUCCEEDED(rv) && !service) { michael@0: NS_ERROR("Factory did not return an object but returned success"); michael@0: return NS_ERROR_SERVICE_NOT_FOUND; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: pendingPRThread = GetPendingServiceThread(aClass); michael@0: MOZ_ASSERT(pendingPRThread == currentPRThread, michael@0: "Pending service array has been changed!"); michael@0: #endif michael@0: RemovePendingService(aClass); michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: NS_ASSERTION(!entry->mServiceObject, "Created two instances of a service!"); michael@0: michael@0: entry->mServiceObject = service.forget(); michael@0: michael@0: lock.Unlock(); michael@0: nsISupports** sresult = reinterpret_cast(result); michael@0: *sresult = entry->mServiceObject; michael@0: (*sresult)->AddRef(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass, michael@0: const nsIID& aIID, michael@0: bool *result) michael@0: { michael@0: // Now we want to get the service if we already got it. If not, we don't want michael@0: // to create an instance of it. mmh! michael@0: michael@0: // test this first, since there's no point in returning a service during michael@0: // shutdown -- whether it's available or not would depend on the order it michael@0: // occurs in the list michael@0: if (gXPCOMShuttingDown) { michael@0: // When processing shutdown, don't process new GetService() requests michael@0: #ifdef SHOW_DENIED_ON_SHUTDOWN michael@0: nsXPIDLCString cid, iid; michael@0: cid.Adopt(aClass.ToString()); michael@0: iid.Adopt(aIID.ToString()); michael@0: fprintf(stderr, "Checking for service on shutdown. Denied.\n" michael@0: " CID: %s\n IID: %s\n", cid.get(), iid.get()); michael@0: #endif /* SHOW_DENIED_ON_SHUTDOWN */ michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE; michael@0: nsFactoryEntry* entry; michael@0: michael@0: { michael@0: SafeMutexAutoLock lock(mLock); michael@0: entry = mFactories.Get(aClass); michael@0: } michael@0: michael@0: if (entry && entry->mServiceObject) { michael@0: nsCOMPtr service; michael@0: rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service)); michael@0: *result = (service!=nullptr); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID, michael@0: const nsIID& aIID, michael@0: bool *result) michael@0: { michael@0: // Now we want to get the service if we already got it. If not, we don't want michael@0: // to create an instance of it. mmh! michael@0: michael@0: // test this first, since there's no point in returning a service during michael@0: // shutdown -- whether it's available or not would depend on the order it michael@0: // occurs in the list michael@0: if (gXPCOMShuttingDown) { michael@0: // When processing shutdown, don't process new GetService() requests michael@0: #ifdef SHOW_DENIED_ON_SHUTDOWN michael@0: nsXPIDLCString iid; michael@0: iid.Adopt(aIID.ToString()); michael@0: fprintf(stderr, "Checking for service on shutdown. Denied.\n" michael@0: " ContractID: %s\n IID: %s\n", aContractID, iid.get()); michael@0: #endif /* SHOW_DENIED_ON_SHUTDOWN */ michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE; michael@0: nsFactoryEntry *entry; michael@0: { michael@0: SafeMutexAutoLock lock(mLock); michael@0: entry = mContractIDs.Get(nsDependentCString(aContractID)); michael@0: } michael@0: michael@0: if (entry && entry->mServiceObject) { michael@0: nsCOMPtr service; michael@0: rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service)); michael@0: *result = (service!=nullptr); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::GetServiceByContractID(const char* aContractID, michael@0: const nsIID& aIID, michael@0: void* *result) michael@0: { michael@0: // test this first, since there's no point in returning a service during michael@0: // shutdown -- whether it's available or not would depend on the order it michael@0: // occurs in the list michael@0: if (gXPCOMShuttingDown) { michael@0: // When processing shutdown, don't process new GetService() requests michael@0: #ifdef SHOW_DENIED_ON_SHUTDOWN michael@0: nsXPIDLCString iid; michael@0: iid.Adopt(aIID.ToString()); michael@0: fprintf(stderr, "Getting service on shutdown. Denied.\n" michael@0: " ContractID: %s\n IID: %s\n", aContractID, iid.get()); michael@0: #endif /* SHOW_DENIED_ON_SHUTDOWN */ michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: // `service` must be released after the lock is released, so it must be michael@0: // declared before the lock in this C++ block. michael@0: nsCOMPtr service; michael@0: MutexLock lock(mLock); michael@0: michael@0: nsFactoryEntry *entry = mContractIDs.Get(nsDependentCString(aContractID)); michael@0: if (!entry) michael@0: return NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: michael@0: if (entry->mServiceObject) { michael@0: // We need to not be holding the service manager's monitor while calling michael@0: // QueryInterface, because it invokes user code which could try to re-enter michael@0: // the service manager, or try to grab some other lock/monitor/condvar michael@0: // and deadlock, e.g. bug 282743. michael@0: // `entry` is valid until XPCOM shutdown, so we can safely use it after michael@0: // exiting the lock. michael@0: lock.Unlock(); michael@0: return entry->mServiceObject->QueryInterface(aIID, result); michael@0: } michael@0: michael@0: PRThread* currentPRThread = PR_GetCurrentThread(); michael@0: MOZ_ASSERT(currentPRThread, "This should never be null!"); michael@0: michael@0: // Needed to optimize the event loop below. michael@0: nsIThread* currentThread = nullptr; michael@0: michael@0: PRThread* pendingPRThread; michael@0: while ((pendingPRThread = GetPendingServiceThread(*entry->mCIDEntry->cid))) { michael@0: if (pendingPRThread == currentPRThread) { michael@0: NS_ERROR("Recursive GetService!"); michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: SafeMutexAutoUnlock unlockPending(mLock); michael@0: michael@0: if (!currentThread) { michael@0: currentThread = NS_GetCurrentThread(); michael@0: MOZ_ASSERT(currentThread, "This should never be null!"); michael@0: } michael@0: michael@0: // This will process a single event or yield the thread if no event is michael@0: // pending. michael@0: if (!NS_ProcessNextEvent(currentThread, false)) { michael@0: PR_Sleep(PR_INTERVAL_NO_WAIT); michael@0: } michael@0: } michael@0: michael@0: if (currentThread && entry->mServiceObject) { michael@0: // If we have a currentThread then we must have waited on another thread michael@0: // to create the service. Grab it now if that succeeded. michael@0: lock.Unlock(); michael@0: return entry->mServiceObject->QueryInterface(aIID, result); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: PendingServiceInfo* newInfo = michael@0: #endif michael@0: AddPendingService(*entry->mCIDEntry->cid, currentPRThread); michael@0: NS_ASSERTION(newInfo, "Failed to add info to the array!"); michael@0: michael@0: // We need to not be holding the service manager's lock while calling michael@0: // CreateInstance, because it invokes user code which could try to re-enter michael@0: // the service manager: michael@0: michael@0: nsresult rv; michael@0: { michael@0: SafeMutexAutoUnlock unlock(mLock); michael@0: rv = CreateInstanceByContractID(aContractID, nullptr, aIID, michael@0: getter_AddRefs(service)); michael@0: } michael@0: if (NS_SUCCEEDED(rv) && !service) { michael@0: NS_ERROR("Factory did not return an object but returned success"); michael@0: return NS_ERROR_SERVICE_NOT_FOUND; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: pendingPRThread = GetPendingServiceThread(*entry->mCIDEntry->cid); michael@0: MOZ_ASSERT(pendingPRThread == currentPRThread, michael@0: "Pending service array has been changed!"); michael@0: #endif michael@0: RemovePendingService(*entry->mCIDEntry->cid); michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: NS_ASSERTION(!entry->mServiceObject, "Created two instances of a service!"); michael@0: michael@0: entry->mServiceObject = service.forget(); michael@0: michael@0: lock.Unlock(); michael@0: michael@0: nsISupports** sresult = reinterpret_cast(result); michael@0: *sresult = entry->mServiceObject; michael@0: (*sresult)->AddRef(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsComponentManagerImpl::LoaderForExtension(const nsACString& aExt) michael@0: { michael@0: nsCOMPtr loader = mLoaderMap.Get(aExt); michael@0: if (!loader) { michael@0: loader = do_GetServiceFromCategory("module-loader", michael@0: PromiseFlatCString(aExt).get()); michael@0: if (!loader) michael@0: return nullptr; michael@0: michael@0: mLoaderMap.Put(aExt, loader); michael@0: } michael@0: michael@0: return loader.forget(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::RegisterFactory(const nsCID& aClass, michael@0: const char* aName, michael@0: const char* aContractID, michael@0: nsIFactory* aFactory) michael@0: { michael@0: if (!aFactory) { michael@0: // If a null factory is passed in, this call just wants to reset michael@0: // the contract ID to point to an existing CID entry. michael@0: if (!aContractID) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: SafeMutexAutoLock lock(mLock); michael@0: nsFactoryEntry* oldf = mFactories.Get(aClass); michael@0: if (!oldf) michael@0: return NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: michael@0: mContractIDs.Put(nsDependentCString(aContractID), oldf); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsAutoPtr f(new nsFactoryEntry(aClass, aFactory)); michael@0: michael@0: SafeMutexAutoLock lock(mLock); michael@0: nsFactoryEntry* oldf = mFactories.Get(aClass); michael@0: if (oldf) michael@0: return NS_ERROR_FACTORY_EXISTS; michael@0: michael@0: if (aContractID) michael@0: mContractIDs.Put(nsDependentCString(aContractID), f); michael@0: michael@0: mFactories.Put(aClass, f.forget()); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass, michael@0: nsIFactory* aFactory) michael@0: { michael@0: // Don't release the dying factory or service object until releasing michael@0: // the component manager monitor. michael@0: nsCOMPtr dyingFactory; michael@0: nsCOMPtr dyingServiceObject; michael@0: michael@0: { michael@0: SafeMutexAutoLock lock(mLock); michael@0: nsFactoryEntry* f = mFactories.Get(aClass); michael@0: if (!f || f->mFactory != aFactory) michael@0: return NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: michael@0: mFactories.Remove(aClass); michael@0: michael@0: // This might leave a stale contractid -> factory mapping in michael@0: // place, so null out the factory entry (see michael@0: // nsFactoryEntry::GetFactory) michael@0: f->mFactory.swap(dyingFactory); michael@0: f->mServiceObject.swap(dyingServiceObject); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::AutoRegister(nsIFile* aLocation) michael@0: { michael@0: XRE_AddManifestLocation(NS_COMPONENT_LOCATION, aLocation); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::AutoUnregister(nsIFile* aLocation) michael@0: { michael@0: NS_ERROR("AutoUnregister not implemented."); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::RegisterFactoryLocation(const nsCID& aCID, michael@0: const char* aClassName, michael@0: const char* aContractID, michael@0: nsIFile* aFile, michael@0: const char* aLoaderStr, michael@0: const char* aType) michael@0: { michael@0: NS_ERROR("RegisterFactoryLocation not implemented."); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID& aCID, michael@0: nsIFile* aFile) michael@0: { michael@0: NS_ERROR("UnregisterFactoryLocation not implemented."); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::IsCIDRegistered(const nsCID & aClass, michael@0: bool *_retval) michael@0: { michael@0: *_retval = (nullptr != GetFactoryEntry(aClass)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::IsContractIDRegistered(const char *aClass, michael@0: bool *_retval) michael@0: { michael@0: if (NS_WARN_IF(!aClass)) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass)); michael@0: michael@0: if (entry) michael@0: *_retval = true; michael@0: else michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: static PLDHashOperator michael@0: EnumerateCIDHelper(const nsID& id, nsFactoryEntry* entry, void* closure) michael@0: { michael@0: nsCOMArray *array = static_cast*>(closure); michael@0: nsCOMPtr wrapper = new nsSupportsIDImpl(); michael@0: wrapper->SetData(&id); michael@0: array->AppendObject(wrapper); michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator **aEnumerator) michael@0: { michael@0: nsCOMArray array; michael@0: mFactories.EnumerateRead(EnumerateCIDHelper, &array); michael@0: michael@0: return NS_NewArrayEnumerator(aEnumerator, array); michael@0: } michael@0: michael@0: static PLDHashOperator michael@0: EnumerateContractsHelper(const nsACString& contract, nsFactoryEntry* entry, void* closure) michael@0: { michael@0: nsTArray* array = static_cast*>(closure); michael@0: array->AppendElement(contract); michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator **aEnumerator) michael@0: { michael@0: nsTArray* array = new nsTArray; michael@0: mContractIDs.EnumerateRead(EnumerateContractsHelper, array); michael@0: michael@0: nsCOMPtr e; michael@0: nsresult rv = NS_NewAdoptingUTF8StringEnumerator(getter_AddRefs(e), array); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: return CallQueryInterface(e, aEnumerator); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::CIDToContractID(const nsCID & aClass, michael@0: char **_retval) michael@0: { michael@0: NS_ERROR("CIDTOContractID not implemented"); michael@0: return NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::ContractIDToCID(const char *aContractID, michael@0: nsCID * *_retval) michael@0: { michael@0: { michael@0: SafeMutexAutoLock lock(mLock); michael@0: nsFactoryEntry* entry = mContractIDs.Get(nsDependentCString(aContractID)); michael@0: if (entry) { michael@0: *_retval = (nsCID*) NS_Alloc(sizeof(nsCID)); michael@0: **_retval = *entry->mCIDEntry->cid; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: *_retval = nullptr; michael@0: return NS_ERROR_FACTORY_NOT_REGISTERED; michael@0: } michael@0: michael@0: static size_t michael@0: SizeOfFactoriesEntryExcludingThis(nsIDHashKey::KeyType aKey, michael@0: nsFactoryEntry* const &aData, michael@0: MallocSizeOf aMallocSizeOf, michael@0: void* aUserArg) michael@0: { michael@0: return aData->SizeOfIncludingThis(aMallocSizeOf); michael@0: } michael@0: michael@0: static size_t michael@0: SizeOfContractIDsEntryExcludingThis(nsCStringHashKey::KeyType aKey, michael@0: nsFactoryEntry* const &aData, michael@0: MallocSizeOf aMallocSizeOf, michael@0: void* aUserArg) michael@0: { michael@0: // We don't measure the nsFactoryEntry data because its owned by mFactories michael@0: // (which measures them in SizeOfFactoriesEntryExcludingThis). michael@0: return aKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf); michael@0: } michael@0: michael@0: MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf) michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::CollectReports(nsIHandleReportCallback* aHandleReport, michael@0: nsISupports* aData) michael@0: { michael@0: return MOZ_COLLECT_REPORT( michael@0: "explicit/xpcom/component-manager", KIND_HEAP, UNITS_BYTES, michael@0: SizeOfIncludingThis(ComponentManagerMallocSizeOf), michael@0: "Memory used for the XPCOM component manager."); michael@0: } michael@0: michael@0: size_t michael@0: nsComponentManagerImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) michael@0: { michael@0: size_t n = aMallocSizeOf(this); michael@0: n += mLoaderMap.SizeOfExcludingThis(nullptr, aMallocSizeOf); michael@0: n += mFactories.SizeOfExcludingThis(SizeOfFactoriesEntryExcludingThis, aMallocSizeOf); michael@0: n += mContractIDs.SizeOfExcludingThis(SizeOfContractIDsEntryExcludingThis, aMallocSizeOf); michael@0: michael@0: n += sStaticModules->SizeOfIncludingThis(aMallocSizeOf); michael@0: n += sModuleLocations->SizeOfIncludingThis(aMallocSizeOf); michael@0: michael@0: n += mKnownStaticModules.SizeOfExcludingThis(aMallocSizeOf); michael@0: n += mKnownModules.SizeOfExcludingThis(nullptr, aMallocSizeOf); michael@0: michael@0: n += PL_SizeOfArenaPoolExcludingPool(&mArena, aMallocSizeOf); michael@0: michael@0: n += mPendingServices.SizeOfExcludingThis(aMallocSizeOf); michael@0: michael@0: // Measurement of the following members may be added later if DMD finds it is michael@0: // worthwhile: michael@0: // - mLoaderMap's keys and values michael@0: // - mMon michael@0: // - sStaticModules' entries michael@0: // - sModuleLocations' entries michael@0: // - mNativeModuleLoader michael@0: // - mKnownStaticModules' entries? michael@0: // - mKnownModules' keys and values? michael@0: michael@0: return n; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsFactoryEntry michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: nsFactoryEntry::nsFactoryEntry(const mozilla::Module::CIDEntry* entry, michael@0: nsComponentManagerImpl::KnownModule* module) michael@0: : mCIDEntry(entry) michael@0: , mModule(module) michael@0: { michael@0: } michael@0: michael@0: nsFactoryEntry::nsFactoryEntry(const nsCID& aCID, nsIFactory* factory) michael@0: : mCIDEntry(nullptr) michael@0: , mModule(nullptr) michael@0: , mFactory(factory) michael@0: { michael@0: mozilla::Module::CIDEntry* e = new mozilla::Module::CIDEntry(); michael@0: nsCID* cid = new nsCID; michael@0: *cid = aCID; michael@0: e->cid = cid; michael@0: mCIDEntry = e; michael@0: } michael@0: michael@0: nsFactoryEntry::~nsFactoryEntry() michael@0: { michael@0: // If this was a RegisterFactory entry, we own the CIDEntry/CID michael@0: if (!mModule) { michael@0: delete mCIDEntry->cid; michael@0: delete mCIDEntry; michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsFactoryEntry::GetFactory() michael@0: { michael@0: nsComponentManagerImpl::gComponentManager->mLock.AssertNotCurrentThreadOwns(); michael@0: michael@0: if (!mFactory) { michael@0: // RegisterFactory then UnregisterFactory can leave an entry in mContractIDs michael@0: // pointing to an unusable nsFactoryEntry. michael@0: if (!mModule) michael@0: return nullptr; michael@0: michael@0: if (!mModule->Load()) michael@0: return nullptr; michael@0: michael@0: // Don't set mFactory directly, it needs to be locked michael@0: nsCOMPtr factory; michael@0: michael@0: if (mModule->Module()->getFactoryProc) { michael@0: factory = mModule->Module()->getFactoryProc(*mModule->Module(), michael@0: *mCIDEntry); michael@0: } michael@0: else if (mCIDEntry->getFactoryProc) { michael@0: factory = mCIDEntry->getFactoryProc(*mModule->Module(), *mCIDEntry); michael@0: } michael@0: else { michael@0: NS_ASSERTION(mCIDEntry->constructorProc, "no getfactory or constructor"); michael@0: factory = new mozilla::GenericFactory(mCIDEntry->constructorProc); michael@0: } michael@0: if (!factory) michael@0: return nullptr; michael@0: michael@0: SafeMutexAutoLock lock(nsComponentManagerImpl::gComponentManager->mLock); michael@0: // Threads can race to set mFactory michael@0: if (!mFactory) { michael@0: factory.swap(mFactory); michael@0: } michael@0: } michael@0: nsCOMPtr factory = mFactory; michael@0: return factory.forget(); michael@0: } michael@0: michael@0: size_t michael@0: nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) michael@0: { michael@0: size_t n = aMallocSizeOf(this); michael@0: michael@0: // Measurement of the following members may be added later if DMD finds it is michael@0: // worthwhile: michael@0: // - mCIDEntry; michael@0: // - mModule; michael@0: // - mFactory; michael@0: // - mServiceObject; michael@0: michael@0: return n; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Static Access Functions michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: nsresult michael@0: NS_GetComponentManager(nsIComponentManager* *result) michael@0: { michael@0: if (!nsComponentManagerImpl::gComponentManager) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: NS_GetServiceManager(nsIServiceManager* *result) michael@0: { michael@0: if (!nsComponentManagerImpl::gComponentManager) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: NS_GetComponentRegistrar(nsIComponentRegistrar* *result) michael@0: { michael@0: if (!nsComponentManagerImpl::gComponentManager) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager); michael@0: return NS_OK; michael@0: } michael@0: michael@0: EXPORT_XPCOM_API(nsresult) michael@0: XRE_AddStaticComponent(const mozilla::Module* aComponent) michael@0: { michael@0: nsComponentManagerImpl::InitializeStaticModules(); michael@0: nsComponentManagerImpl::sStaticModules->AppendElement(aComponent); michael@0: michael@0: if (nsComponentManagerImpl::gComponentManager && michael@0: nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus) michael@0: nsComponentManagerImpl::gComponentManager->RegisterModule(aComponent, nullptr); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation) michael@0: { michael@0: nsString path; michael@0: nsresult rv = aLocation->GetPath(path); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (Substring(path, path.Length() - 4).Equals(NS_LITERAL_STRING(".xpi"))) { michael@0: return XRE_AddJarManifestLocation(NS_BOOTSTRAPPED_LOCATION, aLocation); michael@0: } michael@0: michael@0: nsCOMPtr manifest = michael@0: CloneAndAppend(aLocation, NS_LITERAL_CSTRING("chrome.manifest")); michael@0: return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION, manifest); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation) michael@0: { michael@0: nsCOMPtr cr = mozilla::services::GetChromeRegistryService(); michael@0: if (!cr) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr manifest; michael@0: nsString path; michael@0: nsresult rv = aLocation->GetPath(path); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsComponentManagerImpl::ComponentLocation elem; michael@0: elem.type = NS_BOOTSTRAPPED_LOCATION; michael@0: michael@0: if (Substring(path, path.Length() - 4).Equals(NS_LITERAL_STRING(".xpi"))) { michael@0: elem.location.Init(aLocation, "chrome.manifest"); michael@0: } else { michael@0: nsCOMPtr lf = CloneAndAppend(aLocation, NS_LITERAL_CSTRING("chrome.manifest")); michael@0: elem.location.Init(lf); michael@0: } michael@0: michael@0: // Remove reference. michael@0: nsComponentManagerImpl::sModuleLocations->RemoveElement(elem, ComponentLocationComparator()); michael@0: michael@0: rv = cr->CheckForNewChrome(); michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComponentManagerImpl::GetManifestLocations(nsIArray **aLocations) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aLocations); michael@0: *aLocations = nullptr; michael@0: michael@0: if (!sModuleLocations) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: nsCOMPtr locations = nsArray::Create(); michael@0: nsresult rv; michael@0: for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) { michael@0: ComponentLocation& l = sModuleLocations->ElementAt(i); michael@0: FileLocation loc = l.location; michael@0: nsCString uriString; michael@0: loc.GetURIString(uriString); michael@0: nsCOMPtr uri; michael@0: rv = NS_NewURI(getter_AddRefs(uri), uriString); michael@0: if (NS_SUCCEEDED(rv)) michael@0: locations->AppendElement(uri, false); michael@0: } michael@0: michael@0: locations.forget(aLocations); michael@0: return NS_OK; michael@0: } michael@0: michael@0: EXPORT_XPCOM_API(nsresult) michael@0: XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation) michael@0: { michael@0: nsComponentManagerImpl::InitializeModuleLocations(); michael@0: nsComponentManagerImpl::ComponentLocation* c = michael@0: nsComponentManagerImpl::sModuleLocations->AppendElement(); michael@0: c->type = aType; michael@0: c->location.Init(aLocation); michael@0: michael@0: if (nsComponentManagerImpl::gComponentManager && michael@0: nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus) michael@0: nsComponentManagerImpl::gComponentManager->RegisterManifest(aType, c->location, false); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: EXPORT_XPCOM_API(nsresult) michael@0: XRE_AddJarManifestLocation(NSLocationType aType, nsIFile* aLocation) michael@0: { michael@0: nsComponentManagerImpl::InitializeModuleLocations(); michael@0: nsComponentManagerImpl::ComponentLocation* c = michael@0: nsComponentManagerImpl::sModuleLocations->AppendElement(); michael@0: michael@0: c->type = aType; michael@0: c->location.Init(aLocation, "chrome.manifest"); michael@0: michael@0: if (nsComponentManagerImpl::gComponentManager && michael@0: nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus) michael@0: nsComponentManagerImpl::gComponentManager->RegisterManifest(aType, c->location, false); michael@0: michael@0: return NS_OK; michael@0: } michael@0: