Coverage Report

Created: 2018-09-25 14:53

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