xpcom/components/nsComponentManager.cpp

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

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

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial