mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-01 04:47:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
792
xpcom/components/ManifestParser.cpp
Normal file
792
xpcom/components/ManifestParser.cpp
Normal file
|
|
@ -0,0 +1,792 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "ManifestParser.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "prio.h"
|
||||
#include "prprf.h"
|
||||
#if defined(XP_WIN)
|
||||
#include <windows.h>
|
||||
#elif defined(MOZ_WIDGET_COCOA)
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include "nsCocoaFeatures.h"
|
||||
#elif defined(MOZ_WIDGET_GTK)
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
#include "AndroidBridge.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#include "nsCRT.h"
|
||||
#include "nsConsoleMessage.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "nsVersionComparator.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIXULAppInfo.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
struct ManifestDirective
|
||||
{
|
||||
const char* directive;
|
||||
int argc;
|
||||
|
||||
// Binary components are only allowed for APP locations.
|
||||
bool apponly;
|
||||
|
||||
// Some directives should only be delivered for APP or EXTENSION locations.
|
||||
bool componentonly;
|
||||
|
||||
bool ischrome;
|
||||
|
||||
bool allowbootstrap;
|
||||
|
||||
// The platform/contentaccessible flags only apply to content directives.
|
||||
bool contentflags;
|
||||
|
||||
// Function to handle this directive. This isn't a union because C++ still
|
||||
// hasn't learned how to initialize unions in a sane way.
|
||||
void (nsComponentManagerImpl::*mgrfunc)(
|
||||
nsComponentManagerImpl::ManifestProcessingContext& aCx,
|
||||
int aLineNo, char* const* aArgv);
|
||||
void (nsChromeRegistry::*regfunc)(
|
||||
nsChromeRegistry::ManifestProcessingContext& aCx,
|
||||
int aLineNo, char* const* aArgv, int aFlags);
|
||||
void* xptonlyfunc;
|
||||
|
||||
bool isContract;
|
||||
};
|
||||
static const ManifestDirective kParsingTable[] = {
|
||||
{
|
||||
"manifest", 1, false, false, true, true, false,
|
||||
&nsComponentManagerImpl::ManifestManifest, nullptr, nullptr
|
||||
},
|
||||
{
|
||||
"binary-component", 1, true, true, false, false, false,
|
||||
&nsComponentManagerImpl::ManifestBinaryComponent, nullptr, nullptr
|
||||
},
|
||||
{
|
||||
"interfaces", 1, false, true, false, false, false,
|
||||
&nsComponentManagerImpl::ManifestXPT, nullptr, nullptr
|
||||
},
|
||||
{
|
||||
"component", 2, false, true, false, false, false,
|
||||
&nsComponentManagerImpl::ManifestComponent, nullptr, nullptr
|
||||
},
|
||||
{
|
||||
"contract", 2, false, true, false, false, false,
|
||||
&nsComponentManagerImpl::ManifestContract, nullptr, nullptr, true
|
||||
},
|
||||
{
|
||||
"category", 3, false, true, false, false, false,
|
||||
&nsComponentManagerImpl::ManifestCategory, nullptr, nullptr
|
||||
},
|
||||
{
|
||||
"content", 2, false, true, true, true, true,
|
||||
nullptr, &nsChromeRegistry::ManifestContent, nullptr
|
||||
},
|
||||
{
|
||||
"locale", 3, false, true, true, true, false,
|
||||
nullptr, &nsChromeRegistry::ManifestLocale, nullptr
|
||||
},
|
||||
{
|
||||
"skin", 3, false, false, true, true, false,
|
||||
nullptr, &nsChromeRegistry::ManifestSkin, nullptr
|
||||
},
|
||||
{
|
||||
"overlay", 2, false, true, true, false, false,
|
||||
nullptr, &nsChromeRegistry::ManifestOverlay, nullptr
|
||||
},
|
||||
{
|
||||
"style", 2, false, false, true, false, false,
|
||||
nullptr, &nsChromeRegistry::ManifestStyle, nullptr
|
||||
},
|
||||
{
|
||||
// NB: note that while skin manifests can use this, they are only allowed
|
||||
// to use it for chrome://../skin/ URLs
|
||||
"override", 2, false, false, true, true, false,
|
||||
nullptr, &nsChromeRegistry::ManifestOverride, nullptr
|
||||
},
|
||||
{
|
||||
"resource", 2, false, true, true, true, false,
|
||||
nullptr, &nsChromeRegistry::ManifestResource, nullptr
|
||||
}
|
||||
};
|
||||
|
||||
static const char kWhitespace[] = "\t ";
|
||||
|
||||
static bool
|
||||
IsNewline(char aChar)
|
||||
{
|
||||
return aChar == '\n' || aChar == '\r';
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct AutoPR_smprintf_free
|
||||
{
|
||||
explicit AutoPR_smprintf_free(char* aBuf) : mBuf(aBuf) {}
|
||||
|
||||
~AutoPR_smprintf_free()
|
||||
{
|
||||
if (mBuf) {
|
||||
PR_smprintf_free(mBuf);
|
||||
}
|
||||
}
|
||||
|
||||
operator char*() const { return mBuf; }
|
||||
|
||||
char* mBuf;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* If we are pre-loading XPTs, this method may do nothing because the
|
||||
* console service is not initialized.
|
||||
*/
|
||||
void
|
||||
LogMessage(const char* aMsg, ...)
|
||||
{
|
||||
if (!nsComponentManagerImpl::gComponentManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIConsoleService> console =
|
||||
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
if (!console) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, aMsg);
|
||||
AutoPR_smprintf_free formatted(PR_vsmprintf(aMsg, args));
|
||||
va_end(args);
|
||||
|
||||
nsCOMPtr<nsIConsoleMessage> error =
|
||||
new nsConsoleMessage(NS_ConvertUTF8toUTF16(formatted).get());
|
||||
console->LogMessage(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* If we are pre-loading XPTs, this method may do nothing because the
|
||||
* console service is not initialized.
|
||||
*/
|
||||
void
|
||||
LogMessageWithContext(FileLocation& aFile,
|
||||
uint32_t aLineNumber, const char* aMsg, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, aMsg);
|
||||
AutoPR_smprintf_free formatted(PR_vsmprintf(aMsg, args));
|
||||
va_end(args);
|
||||
if (!formatted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nsComponentManagerImpl::gComponentManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCString file;
|
||||
aFile.GetURIString(file);
|
||||
|
||||
nsCOMPtr<nsIScriptError> error =
|
||||
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
|
||||
if (!error) {
|
||||
// This can happen early in component registration. Fall back to a
|
||||
// generic console message.
|
||||
LogMessage("Warning: in '%s', line %i: %s", file.get(),
|
||||
aLineNumber, (char*)formatted);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIConsoleService> console =
|
||||
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
if (!console) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = error->Init(NS_ConvertUTF8toUTF16(formatted),
|
||||
NS_ConvertUTF8toUTF16(file), EmptyString(),
|
||||
aLineNumber, 0, nsIScriptError::warningFlag,
|
||||
"chrome registration");
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
console->LogMessage(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a modifier flag of the following forms:
|
||||
* "flag" (same as "true")
|
||||
* "flag=yes|true|1"
|
||||
* "flag="no|false|0"
|
||||
* @param aFlag The flag to compare.
|
||||
* @param aData The tokenized data to check; this is lowercased
|
||||
* before being passed in.
|
||||
* @param aResult If the flag is found, the value is assigned here.
|
||||
* @return Whether the flag was handled.
|
||||
*/
|
||||
static bool
|
||||
CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, bool& aResult)
|
||||
{
|
||||
if (!StringBeginsWith(aData, aFlag)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aFlag.Length() == aData.Length()) {
|
||||
// the data is simply "flag", which is the same as "flag=yes"
|
||||
aResult = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aData.CharAt(aFlag.Length()) != '=') {
|
||||
// the data is "flag2=", which is not anything we care about
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aData.Length() == aFlag.Length() + 1) {
|
||||
aResult = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (aData.CharAt(aFlag.Length() + 1)) {
|
||||
case '1':
|
||||
case 't': //true
|
||||
case 'y': //yes
|
||||
aResult = true;
|
||||
return true;
|
||||
|
||||
case '0':
|
||||
case 'f': //false
|
||||
case 'n': //no
|
||||
aResult = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
enum TriState
|
||||
{
|
||||
eUnspecified,
|
||||
eBad,
|
||||
eOK
|
||||
};
|
||||
|
||||
/**
|
||||
* Check for a modifier flag of the following form:
|
||||
* "flag=string"
|
||||
* "flag!=string"
|
||||
* @param aFlag The flag to compare.
|
||||
* @param aData The tokenized data to check; this is lowercased
|
||||
* before being passed in.
|
||||
* @param aValue The value that is expected.
|
||||
* @param aResult If this is "ok" when passed in, this is left alone.
|
||||
* Otherwise if the flag is found it is set to eBad or eOK.
|
||||
* @return Whether the flag was handled.
|
||||
*/
|
||||
static bool
|
||||
CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData,
|
||||
const nsSubstring& aValue, TriState& aResult)
|
||||
{
|
||||
if (aData.Length() < aFlag.Length() + 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!StringBeginsWith(aData, aFlag)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool comparison = true;
|
||||
if (aData[aFlag.Length()] != '=') {
|
||||
if (aData[aFlag.Length()] == '!' &&
|
||||
aData.Length() >= aFlag.Length() + 2 &&
|
||||
aData[aFlag.Length() + 1] == '=') {
|
||||
comparison = false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (aResult != eOK) {
|
||||
nsDependentSubstring testdata =
|
||||
Substring(aData, aFlag.Length() + (comparison ? 1 : 2));
|
||||
if (testdata.Equals(aValue)) {
|
||||
aResult = comparison ? eOK : eBad;
|
||||
} else {
|
||||
aResult = comparison ? eBad : eOK;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a modifier flag of the following form:
|
||||
* "flag=version"
|
||||
* "flag<=version"
|
||||
* "flag<version"
|
||||
* "flag>=version"
|
||||
* "flag>version"
|
||||
* @param aFlag The flag to compare.
|
||||
* @param aData The tokenized data to check; this is lowercased
|
||||
* before being passed in.
|
||||
* @param aValue The value that is expected. If this is empty then no
|
||||
* comparison will match.
|
||||
* @param aResult If this is eOK when passed in, this is left alone.
|
||||
* Otherwise if the flag is found it is set to eBad or eOK.
|
||||
* @return Whether the flag was handled.
|
||||
*/
|
||||
|
||||
#define COMPARE_EQ 1 << 0
|
||||
#define COMPARE_LT 1 << 1
|
||||
#define COMPARE_GT 1 << 2
|
||||
|
||||
static bool
|
||||
CheckVersionFlag(const nsString& aFlag, const nsString& aData,
|
||||
const nsString& aValue, TriState& aResult)
|
||||
{
|
||||
if (aData.Length() < aFlag.Length() + 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!StringBeginsWith(aData, aFlag)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aValue.Length() == 0) {
|
||||
if (aResult != eOK) {
|
||||
aResult = eBad;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t comparison;
|
||||
nsAutoString testdata;
|
||||
|
||||
switch (aData[aFlag.Length()]) {
|
||||
case '=':
|
||||
comparison = COMPARE_EQ;
|
||||
testdata = Substring(aData, aFlag.Length() + 1);
|
||||
break;
|
||||
|
||||
case '<':
|
||||
if (aData[aFlag.Length() + 1] == '=') {
|
||||
comparison = COMPARE_EQ | COMPARE_LT;
|
||||
testdata = Substring(aData, aFlag.Length() + 2);
|
||||
} else {
|
||||
comparison = COMPARE_LT;
|
||||
testdata = Substring(aData, aFlag.Length() + 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case '>':
|
||||
if (aData[aFlag.Length() + 1] == '=') {
|
||||
comparison = COMPARE_EQ | COMPARE_GT;
|
||||
testdata = Substring(aData, aFlag.Length() + 2);
|
||||
} else {
|
||||
comparison = COMPARE_GT;
|
||||
testdata = Substring(aData, aFlag.Length() + 1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (testdata.Length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aResult != eOK) {
|
||||
int32_t c = mozilla::CompareVersions(NS_ConvertUTF16toUTF8(aValue).get(),
|
||||
NS_ConvertUTF16toUTF8(testdata).get());
|
||||
if ((c == 0 && comparison & COMPARE_EQ) ||
|
||||
(c < 0 && comparison & COMPARE_LT) ||
|
||||
(c > 0 && comparison & COMPARE_GT)) {
|
||||
aResult = eOK;
|
||||
} else {
|
||||
aResult = eBad;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// In-place conversion of ascii characters to lower case
|
||||
static void
|
||||
ToLowerCase(char* aToken)
|
||||
{
|
||||
for (; *aToken; ++aToken) {
|
||||
*aToken = NS_ToLower(*aToken);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct CachedDirective
|
||||
{
|
||||
int lineno;
|
||||
char* argv[4];
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
/**
|
||||
* For XPT-Only mode, the parser handles only directives of "manifest"
|
||||
* and "interfaces", and always call the function given by |xptonlyfunc|
|
||||
* variable of struct |ManifestDirective|.
|
||||
*
|
||||
* This function is safe to be called before the component manager is
|
||||
* ready if aXPTOnly is true for it don't invoke any component during
|
||||
* parsing.
|
||||
*/
|
||||
void
|
||||
ParseManifest(NSLocationType aType, FileLocation& aFile, char* aBuf,
|
||||
bool aChromeOnly, bool aXPTOnly)
|
||||
{
|
||||
nsComponentManagerImpl::ManifestProcessingContext mgrcx(aType, aFile,
|
||||
aChromeOnly);
|
||||
nsChromeRegistry::ManifestProcessingContext chromecx(aType, aFile);
|
||||
nsresult rv;
|
||||
|
||||
NS_NAMED_LITERAL_STRING(kPlatform, "platform");
|
||||
NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
|
||||
NS_NAMED_LITERAL_STRING(kRemoteEnabled, "remoteenabled");
|
||||
NS_NAMED_LITERAL_STRING(kRemoteRequired, "remoterequired");
|
||||
NS_NAMED_LITERAL_STRING(kApplication, "application");
|
||||
NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
|
||||
NS_NAMED_LITERAL_STRING(kGeckoVersion, "platformversion");
|
||||
NS_NAMED_LITERAL_STRING(kOs, "os");
|
||||
NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
|
||||
NS_NAMED_LITERAL_STRING(kABI, "abi");
|
||||
NS_NAMED_LITERAL_STRING(kProcess, "process");
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
NS_NAMED_LITERAL_STRING(kTablet, "tablet");
|
||||
#endif
|
||||
|
||||
NS_NAMED_LITERAL_STRING(kMain, "main");
|
||||
NS_NAMED_LITERAL_STRING(kContent, "content");
|
||||
|
||||
// Obsolete
|
||||
NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
|
||||
|
||||
nsAutoString appID;
|
||||
nsAutoString appVersion;
|
||||
nsAutoString geckoVersion;
|
||||
nsAutoString osTarget;
|
||||
nsAutoString abi;
|
||||
nsAutoString process;
|
||||
|
||||
nsCOMPtr<nsIXULAppInfo> xapp;
|
||||
if (!aXPTOnly) {
|
||||
// Avoid to create any component for XPT only mode.
|
||||
// No xapp means no ID, version, ..., modifiers checking.
|
||||
xapp = do_GetService(XULAPPINFO_SERVICE_CONTRACTID);
|
||||
}
|
||||
if (xapp) {
|
||||
nsAutoCString s;
|
||||
rv = xapp->GetID(s);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
CopyUTF8toUTF16(s, appID);
|
||||
}
|
||||
|
||||
rv = xapp->GetVersion(s);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
CopyUTF8toUTF16(s, appVersion);
|
||||
}
|
||||
|
||||
rv = xapp->GetPlatformVersion(s);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
CopyUTF8toUTF16(s, geckoVersion);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXULRuntime> xruntime(do_QueryInterface(xapp));
|
||||
if (xruntime) {
|
||||
rv = xruntime->GetOS(s);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
ToLowerCase(s);
|
||||
CopyUTF8toUTF16(s, osTarget);
|
||||
}
|
||||
|
||||
rv = xruntime->GetXPCOMABI(s);
|
||||
if (NS_SUCCEEDED(rv) && osTarget.Length()) {
|
||||
ToLowerCase(s);
|
||||
CopyUTF8toUTF16(s, abi);
|
||||
abi.Insert(char16_t('_'), 0);
|
||||
abi.Insert(osTarget, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoString osVersion;
|
||||
#if defined(XP_WIN)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996) // VC12+ deprecates GetVersionEx
|
||||
OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
|
||||
if (GetVersionEx(&info)) {
|
||||
nsTextFormatter::ssprintf(osVersion, u"%ld.%ld",
|
||||
info.dwMajorVersion,
|
||||
info.dwMinorVersion);
|
||||
}
|
||||
#pragma warning(pop)
|
||||
#elif defined(MOZ_WIDGET_COCOA)
|
||||
SInt32 majorVersion = nsCocoaFeatures::OSXVersionMajor();
|
||||
SInt32 minorVersion = nsCocoaFeatures::OSXVersionMinor();
|
||||
nsTextFormatter::ssprintf(osVersion, u"%ld.%ld",
|
||||
majorVersion,
|
||||
minorVersion);
|
||||
#elif defined(MOZ_WIDGET_GTK)
|
||||
nsTextFormatter::ssprintf(osVersion, u"%ld.%ld",
|
||||
gtk_major_version,
|
||||
gtk_minor_version);
|
||||
#elif defined(MOZ_WIDGET_ANDROID)
|
||||
bool isTablet = false;
|
||||
if (mozilla::AndroidBridge::Bridge()) {
|
||||
mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION",
|
||||
"RELEASE",
|
||||
osVersion);
|
||||
isTablet = java::GeckoAppShell::IsTablet();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
process = kContent;
|
||||
} else {
|
||||
process = kMain;
|
||||
}
|
||||
|
||||
// Because contracts must be registered after CIDs, we save and process them
|
||||
// at the end.
|
||||
nsTArray<CachedDirective> contracts;
|
||||
|
||||
char* token;
|
||||
char* newline = aBuf;
|
||||
uint32_t line = 0;
|
||||
|
||||
// outer loop tokenizes by newline
|
||||
while (*newline) {
|
||||
while (*newline && IsNewline(*newline)) {
|
||||
++newline;
|
||||
++line;
|
||||
}
|
||||
if (!*newline) {
|
||||
break;
|
||||
}
|
||||
|
||||
token = newline;
|
||||
while (*newline && !IsNewline(*newline)) {
|
||||
++newline;
|
||||
}
|
||||
|
||||
if (*newline) {
|
||||
*newline = '\0';
|
||||
++newline;
|
||||
}
|
||||
++line;
|
||||
|
||||
if (*token == '#') { // ignore lines that begin with # as comments
|
||||
continue;
|
||||
}
|
||||
|
||||
char* whitespace = token;
|
||||
token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
|
||||
if (!token) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ManifestDirective* directive = nullptr;
|
||||
for (const ManifestDirective* d = kParsingTable;
|
||||
d < ArrayEnd(kParsingTable);
|
||||
++d) {
|
||||
if (!strcmp(d->directive, token) &&
|
||||
(!aXPTOnly || d->xptonlyfunc)) {
|
||||
directive = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!directive) {
|
||||
LogMessageWithContext(aFile, line,
|
||||
"Ignoring unrecognized chrome manifest directive '%s'.",
|
||||
token);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!directive->allowbootstrap && NS_BOOTSTRAPPED_LOCATION == aType) {
|
||||
LogMessageWithContext(aFile, line,
|
||||
"Bootstrapped manifest not allowed to use '%s' directive.",
|
||||
token);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifndef MOZ_BINARY_EXTENSIONS
|
||||
if (directive->apponly && NS_APP_LOCATION != aType) {
|
||||
LogMessageWithContext(aFile, line,
|
||||
"Only application manifests may use the '%s' directive.", token);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (directive->componentonly && NS_SKIN_LOCATION == aType) {
|
||||
LogMessageWithContext(aFile, line,
|
||||
"Skin manifest not allowed to use '%s' directive.",
|
||||
token);
|
||||
continue;
|
||||
}
|
||||
|
||||
NS_ASSERTION(directive->argc < 4, "Need to reset argv array length");
|
||||
char* argv[4];
|
||||
for (int i = 0; i < directive->argc; ++i) {
|
||||
argv[i] = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
|
||||
}
|
||||
|
||||
if (!argv[directive->argc - 1]) {
|
||||
LogMessageWithContext(aFile, line,
|
||||
"Not enough arguments for chrome manifest directive '%s', expected %i.",
|
||||
token, directive->argc);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
TriState stAppVersion = eUnspecified;
|
||||
TriState stGeckoVersion = eUnspecified;
|
||||
TriState stApp = eUnspecified;
|
||||
TriState stOsVersion = eUnspecified;
|
||||
TriState stOs = eUnspecified;
|
||||
TriState stABI = eUnspecified;
|
||||
TriState stProcess = eUnspecified;
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
TriState stTablet = eUnspecified;
|
||||
#endif
|
||||
int flags = 0;
|
||||
|
||||
while ((token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
|
||||
ok) {
|
||||
ToLowerCase(token);
|
||||
NS_ConvertASCIItoUTF16 wtoken(token);
|
||||
|
||||
if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
|
||||
CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
|
||||
CheckStringFlag(kABI, wtoken, abi, stABI) ||
|
||||
CheckStringFlag(kProcess, wtoken, process, stProcess) ||
|
||||
CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
|
||||
CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
|
||||
CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
bool tablet = false;
|
||||
if (CheckFlag(kTablet, wtoken, tablet)) {
|
||||
stTablet = (tablet == isTablet) ? eOK : eBad;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (directive->contentflags) {
|
||||
bool flag;
|
||||
if (CheckFlag(kPlatform, wtoken, flag)) {
|
||||
if (flag)
|
||||
flags |= nsChromeRegistry::PLATFORM_PACKAGE;
|
||||
continue;
|
||||
}
|
||||
if (CheckFlag(kContentAccessible, wtoken, flag)) {
|
||||
if (flag)
|
||||
flags |= nsChromeRegistry::CONTENT_ACCESSIBLE;
|
||||
continue;
|
||||
}
|
||||
if (CheckFlag(kRemoteEnabled, wtoken, flag)) {
|
||||
if (flag)
|
||||
flags |= nsChromeRegistry::REMOTE_ALLOWED;
|
||||
continue;
|
||||
}
|
||||
if (CheckFlag(kRemoteRequired, wtoken, flag)) {
|
||||
if (flag)
|
||||
flags |= nsChromeRegistry::REMOTE_REQUIRED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool xpcNativeWrappers = true; // Dummy for CheckFlag.
|
||||
if (CheckFlag(kXPCNativeWrappers, wtoken, xpcNativeWrappers)) {
|
||||
LogMessageWithContext(aFile, line,
|
||||
"Ignoring obsolete chrome registration modifier '%s'.",
|
||||
token);
|
||||
continue;
|
||||
}
|
||||
|
||||
LogMessageWithContext(aFile, line,
|
||||
"Unrecognized chrome manifest modifier '%s'.",
|
||||
token);
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!ok ||
|
||||
stApp == eBad ||
|
||||
stAppVersion == eBad ||
|
||||
stGeckoVersion == eBad ||
|
||||
stOs == eBad ||
|
||||
stOsVersion == eBad ||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
stTablet == eBad ||
|
||||
#endif
|
||||
stABI == eBad ||
|
||||
stProcess == eBad) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (directive->regfunc) {
|
||||
if (GeckoProcessType_Default != XRE_GetProcessType()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!nsChromeRegistry::gChromeRegistry) {
|
||||
nsCOMPtr<nsIChromeRegistry> cr =
|
||||
mozilla::services::GetChromeRegistryService();
|
||||
if (!nsChromeRegistry::gChromeRegistry) {
|
||||
LogMessageWithContext(aFile, line,
|
||||
"Chrome registry isn't available yet.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
(nsChromeRegistry::gChromeRegistry->*(directive->regfunc))(
|
||||
chromecx, line, argv, flags);
|
||||
} else if (directive->ischrome || !aChromeOnly) {
|
||||
if (directive->isContract) {
|
||||
CachedDirective* cd = contracts.AppendElement();
|
||||
cd->lineno = line;
|
||||
cd->argv[0] = argv[0];
|
||||
cd->argv[1] = argv[1];
|
||||
} else {
|
||||
(nsComponentManagerImpl::gComponentManager->*(directive->mgrfunc))(
|
||||
mgrcx, line, argv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < contracts.Length(); ++i) {
|
||||
CachedDirective& d = contracts[i];
|
||||
nsComponentManagerImpl::gComponentManager->ManifestContract(mgrcx,
|
||||
d.lineno,
|
||||
d.argv);
|
||||
}
|
||||
}
|
||||
22
xpcom/components/ManifestParser.h
Normal file
22
xpcom/components/ManifestParser.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef ManifestParser_h
|
||||
#define ManifestParser_h
|
||||
|
||||
#include "nsComponentManager.h"
|
||||
#include "nsChromeRegistry.h"
|
||||
#include "mozilla/FileLocation.h"
|
||||
|
||||
void ParseManifest(NSLocationType aType, mozilla::FileLocation& aFile,
|
||||
char* aBuf, bool aChromeOnly, bool aXPTOnly = false);
|
||||
|
||||
void LogMessage(const char* aMsg, ...);
|
||||
|
||||
void LogMessageWithContext(mozilla::FileLocation& aFile,
|
||||
uint32_t aLineNumber, const char* aMsg, ...);
|
||||
|
||||
#endif // ManifestParser_h
|
||||
157
xpcom/components/Module.h
Normal file
157
xpcom/components/Module.h
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_Module_h
|
||||
#define mozilla_Module_h
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsID.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* A module implements one or more XPCOM components. This structure is used
|
||||
* for both binary and script modules, but the registration members
|
||||
* (cids/contractids/categoryentries) are unused for modules which are loaded
|
||||
* via a module loader.
|
||||
*/
|
||||
struct Module
|
||||
{
|
||||
static const unsigned int kVersion = 52;
|
||||
|
||||
struct CIDEntry;
|
||||
|
||||
typedef already_AddRefed<nsIFactory> (*GetFactoryProcPtr)(
|
||||
const Module& module, const CIDEntry& entry);
|
||||
|
||||
typedef nsresult (*ConstructorProcPtr)(nsISupports* aOuter,
|
||||
const nsIID& aIID,
|
||||
void** aResult);
|
||||
|
||||
typedef nsresult (*LoadFuncPtr)();
|
||||
typedef void (*UnloadFuncPtr)();
|
||||
|
||||
/**
|
||||
* This selector allows CIDEntrys to be marked so that they're only loaded
|
||||
* into certain kinds of processes. Selectors can be combined.
|
||||
*/
|
||||
enum ProcessSelector
|
||||
{
|
||||
ANY_PROCESS = 0x0,
|
||||
MAIN_PROCESS_ONLY = 0x1,
|
||||
CONTENT_PROCESS_ONLY = 0x2,
|
||||
|
||||
/**
|
||||
* By default, modules are not loaded in the GPU process, even if
|
||||
* ANY_PROCESS is specified. This flag enables a module in the
|
||||
* GPU process.
|
||||
*/
|
||||
ALLOW_IN_GPU_PROCESS = 0x4
|
||||
};
|
||||
|
||||
/**
|
||||
* The constructor callback is an implementation detail of the default binary
|
||||
* loader and may be null.
|
||||
*/
|
||||
struct CIDEntry
|
||||
{
|
||||
const nsCID* cid;
|
||||
bool service;
|
||||
GetFactoryProcPtr getFactoryProc;
|
||||
ConstructorProcPtr constructorProc;
|
||||
ProcessSelector processSelector;
|
||||
};
|
||||
|
||||
struct ContractIDEntry
|
||||
{
|
||||
const char* contractid;
|
||||
nsID const* cid;
|
||||
ProcessSelector processSelector;
|
||||
};
|
||||
|
||||
struct CategoryEntry
|
||||
{
|
||||
const char* category;
|
||||
const char* entry;
|
||||
const char* value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Binary compatibility check, should be kModuleVersion.
|
||||
*/
|
||||
unsigned int mVersion;
|
||||
|
||||
/**
|
||||
* An array of CIDs (class IDs) implemented by this module. The final entry
|
||||
* should be { nullptr }.
|
||||
*/
|
||||
const CIDEntry* mCIDs;
|
||||
|
||||
/**
|
||||
* An array of mappings from contractid to CID. The final entry should
|
||||
* be { nullptr }.
|
||||
*/
|
||||
const ContractIDEntry* mContractIDs;
|
||||
|
||||
/**
|
||||
* An array of category manager entries. The final entry should be
|
||||
* { nullptr }.
|
||||
*/
|
||||
const CategoryEntry* mCategoryEntries;
|
||||
|
||||
/**
|
||||
* When the component manager tries to get the factory for a CID, it first
|
||||
* checks for this module-level getfactory callback. If this function is
|
||||
* not implemented, it checks the CIDEntry getfactory callback. If that is
|
||||
* also nullptr, a generic factory is generated using the CIDEntry
|
||||
* constructor callback which must be non-nullptr.
|
||||
*/
|
||||
GetFactoryProcPtr getFactoryProc;
|
||||
|
||||
/**
|
||||
* Optional Function which are called when this module is loaded and
|
||||
* at shutdown. These are not C++ constructor/destructors to avoid
|
||||
* calling them too early in startup or too late in shutdown.
|
||||
*/
|
||||
LoadFuncPtr loadProc;
|
||||
UnloadFuncPtr unloadProc;
|
||||
|
||||
/**
|
||||
* Optional flags which control whether the module loads on a process-type
|
||||
* basis.
|
||||
*/
|
||||
ProcessSelector selector;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
# define NSMODULE_NAME(_name) _name##_NSModule
|
||||
# if defined(_MSC_VER)
|
||||
# pragma section(".kPStaticModules$M", read)
|
||||
# pragma comment(linker, "/merge:.kPStaticModules=.rdata")
|
||||
# define NSMODULE_SECTION __declspec(allocate(".kPStaticModules$M"), dllexport)
|
||||
# elif defined(__GNUC__)
|
||||
# if defined(__ELF__)
|
||||
# define NSMODULE_SECTION __attribute__((section(".kPStaticModules"), visibility("default")))
|
||||
# elif defined(__MACH__)
|
||||
# define NSMODULE_SECTION __attribute__((section("__DATA, .kPStaticModules"), visibility("default")))
|
||||
# elif defined (_WIN32)
|
||||
# define NSMODULE_SECTION __attribute__((section(".kPStaticModules"), dllexport))
|
||||
# endif
|
||||
# endif
|
||||
# if !defined(NSMODULE_SECTION)
|
||||
# error Do not know how to define sections.
|
||||
# endif
|
||||
# define NSMODULE_DEFN(_name) extern NSMODULE_SECTION mozilla::Module const *const NSMODULE_NAME(_name)
|
||||
#else
|
||||
# define NSMODULE_NAME(_name) NSModule
|
||||
# define NSMODULE_DEFN(_name) extern "C" NS_EXPORT mozilla::Module const *const NSModule
|
||||
#endif
|
||||
|
||||
#endif // mozilla_Module_h
|
||||
44
xpcom/components/ModuleLoader.h
Normal file
44
xpcom/components/ModuleLoader.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ModuleLoader_h
|
||||
#define mozilla_ModuleLoader_h
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "mozilla/Module.h"
|
||||
#include "mozilla/FileLocation.h"
|
||||
|
||||
#define MOZILLA_MODULELOADER_PSEUDO_IID \
|
||||
{ 0xD951A8CE, 0x6E9F, 0x464F, \
|
||||
{ 0x8A, 0xC8, 0x14, 0x61, 0xC0, 0xD3, 0x63, 0xC8 } }
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Module loaders are responsible for loading a component file. The static
|
||||
* component loader is special and does not use this abstract interface.
|
||||
*
|
||||
* @note Implementations of this interface should be threadsafe,
|
||||
* methods may be called from any thread.
|
||||
*/
|
||||
class ModuleLoader : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_MODULELOADER_PSEUDO_IID)
|
||||
|
||||
/**
|
||||
* Return the module for a specified file. The caller should cache
|
||||
* the module: the implementer should not expect for the same file
|
||||
* to be loaded multiple times. The Module object should either be
|
||||
* statically or permanently allocated; it will not be freed.
|
||||
*/
|
||||
virtual const Module* LoadModule(mozilla::FileLocation& aFile) = 0;
|
||||
};
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(ModuleLoader, MOZILLA_MODULELOADER_PSEUDO_IID)
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ModuleLoader_h
|
||||
98
xpcom/components/ModuleUtils.h
Normal file
98
xpcom/components/ModuleUtils.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_GenericModule_h
|
||||
#define mozilla_GenericModule_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Module.h"
|
||||
|
||||
#define NS_GENERIC_FACTORY_CONSTRUCTOR(_InstanceClass) \
|
||||
static nsresult \
|
||||
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \
|
||||
void **aResult) \
|
||||
{ \
|
||||
RefPtr<_InstanceClass> inst; \
|
||||
\
|
||||
*aResult = nullptr; \
|
||||
if (nullptr != aOuter) { \
|
||||
return NS_ERROR_NO_AGGREGATION; \
|
||||
} \
|
||||
\
|
||||
inst = new _InstanceClass(); \
|
||||
return inst->QueryInterface(aIID, aResult); \
|
||||
}
|
||||
|
||||
#define NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(_InstanceClass, _InitMethod) \
|
||||
static nsresult \
|
||||
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \
|
||||
void **aResult) \
|
||||
{ \
|
||||
nsresult rv; \
|
||||
\
|
||||
RefPtr<_InstanceClass> inst; \
|
||||
\
|
||||
*aResult = nullptr; \
|
||||
if (nullptr != aOuter) { \
|
||||
return NS_ERROR_NO_AGGREGATION; \
|
||||
} \
|
||||
\
|
||||
inst = new _InstanceClass(); \
|
||||
rv = inst->_InitMethod(); \
|
||||
if (NS_SUCCEEDED(rv)) { \
|
||||
rv = inst->QueryInterface(aIID, aResult); \
|
||||
} \
|
||||
\
|
||||
return rv; \
|
||||
}
|
||||
|
||||
// 'Constructor' that uses an existing getter function that gets a singleton.
|
||||
// NOTE: assumes that getter does an AddRef - so additional AddRef is not done.
|
||||
#define NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(_InstanceClass, _GetterProc) \
|
||||
static nsresult \
|
||||
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \
|
||||
void **aResult) \
|
||||
{ \
|
||||
RefPtr<_InstanceClass> inst; \
|
||||
\
|
||||
*aResult = nullptr; \
|
||||
if (nullptr != aOuter) { \
|
||||
return NS_ERROR_NO_AGGREGATION; \
|
||||
} \
|
||||
\
|
||||
inst = already_AddRefed<_InstanceClass>(_GetterProc()); \
|
||||
if (nullptr == inst) { \
|
||||
return NS_ERROR_OUT_OF_MEMORY; \
|
||||
} \
|
||||
return inst->QueryInterface(aIID, aResult); \
|
||||
}
|
||||
|
||||
#ifndef MOZILLA_INTERNAL_API
|
||||
|
||||
#include "nsIModule.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class GenericModule final : public nsIModule
|
||||
{
|
||||
~GenericModule() {}
|
||||
|
||||
public:
|
||||
explicit GenericModule(const mozilla::Module* aData) : mData(aData) {}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIMODULE
|
||||
|
||||
private:
|
||||
const mozilla::Module* mData;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
||||
#endif // mozilla_GenericModule_h
|
||||
55
xpcom/components/moz.build
Normal file
55
xpcom/components/moz.build
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsICategoryManager.idl',
|
||||
'nsIClassInfo.idl',
|
||||
'nsIComponentManager.idl',
|
||||
'nsIComponentRegistrar.idl',
|
||||
'nsIFactory.idl',
|
||||
'nsIModule.idl',
|
||||
'nsIServiceManager.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'xpcom_components'
|
||||
|
||||
EXPORTS += [
|
||||
'nsCategoryManagerUtils.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'Module.h',
|
||||
'ModuleLoader.h',
|
||||
'ModuleUtils.h',
|
||||
]
|
||||
|
||||
# nsCategoryManager.cpp and nsComponentManager.cpp cannot be built in
|
||||
# unified mode because they use thea PL_ARENA_CONST_ALIGN_MASK macro
|
||||
# with plarena.h.
|
||||
SOURCES += [
|
||||
'nsCategoryManager.cpp',
|
||||
'nsComponentManager.cpp',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'ManifestParser.cpp',
|
||||
'nsNativeModuleLoader.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'!..',
|
||||
'../base',
|
||||
'../build',
|
||||
'../ds',
|
||||
'../reflect/xptinfo',
|
||||
'/chrome',
|
||||
'/modules/libjar',
|
||||
]
|
||||
|
||||
if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
832
xpcom/components/nsCategoryManager.cpp
Normal file
832
xpcom/components/nsCategoryManager.cpp
Normal file
|
|
@ -0,0 +1,832 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#define PL_ARENA_CONST_ALIGN_MASK 7
|
||||
|
||||
#include "nsICategoryManager.h"
|
||||
#include "nsCategoryManager.h"
|
||||
|
||||
#include "plarena.h"
|
||||
#include "prio.h"
|
||||
#include "prprf.h"
|
||||
#include "prlock.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsIStringEnumerator.h"
|
||||
#include "nsSupportsPrimitives.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsQuickSort.h"
|
||||
#include "nsEnumeratorUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#include "ManifestParser.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
using namespace mozilla;
|
||||
class nsIComponentLoaderManager;
|
||||
|
||||
/*
|
||||
CategoryDatabase
|
||||
contains 0 or more 1-1 mappings of string to Category
|
||||
each Category contains 0 or more 1-1 mappings of string keys to string values
|
||||
|
||||
In other words, the CategoryDatabase is a tree, whose root is a hashtable.
|
||||
Internal nodes (or Categories) are hashtables. Leaf nodes are strings.
|
||||
|
||||
The leaf strings are allocated in an arena, because we assume they're not
|
||||
going to change much ;)
|
||||
*/
|
||||
|
||||
#define NS_CATEGORYMANAGER_ARENA_SIZE (1024 * 8)
|
||||
|
||||
// pulled in from nsComponentManager.cpp
|
||||
char* ArenaStrdup(const char* aStr, PLArenaPool* aArena);
|
||||
|
||||
//
|
||||
// BaseStringEnumerator is subclassed by EntryEnumerator and
|
||||
// CategoryEnumerator
|
||||
//
|
||||
class BaseStringEnumerator
|
||||
: public nsISimpleEnumerator
|
||||
, private nsIUTF8StringEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
NS_DECL_NSIUTF8STRINGENUMERATOR
|
||||
|
||||
protected:
|
||||
// Callback function for NS_QuickSort to sort mArray
|
||||
static int SortCallback(const void*, const void*, void*);
|
||||
|
||||
BaseStringEnumerator()
|
||||
: mArray(nullptr)
|
||||
, mCount(0)
|
||||
, mSimpleCurItem(0)
|
||||
, mStringCurItem(0)
|
||||
{
|
||||
}
|
||||
|
||||
// A virtual destructor is needed here because subclasses of
|
||||
// BaseStringEnumerator do not implement their own Release() method.
|
||||
|
||||
virtual ~BaseStringEnumerator()
|
||||
{
|
||||
delete [] mArray;
|
||||
}
|
||||
|
||||
void Sort();
|
||||
|
||||
const char** mArray;
|
||||
uint32_t mCount;
|
||||
uint32_t mSimpleCurItem;
|
||||
uint32_t mStringCurItem;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(BaseStringEnumerator, nsISimpleEnumerator,
|
||||
nsIUTF8StringEnumerator)
|
||||
|
||||
NS_IMETHODIMP
|
||||
BaseStringEnumerator::HasMoreElements(bool* aResult)
|
||||
{
|
||||
*aResult = (mSimpleCurItem < mCount);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BaseStringEnumerator::GetNext(nsISupports** aResult)
|
||||
{
|
||||
if (mSimpleCurItem >= mCount) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsSupportsDependentCString* str =
|
||||
new nsSupportsDependentCString(mArray[mSimpleCurItem++]);
|
||||
if (!str) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
*aResult = str;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BaseStringEnumerator::HasMore(bool* aResult)
|
||||
{
|
||||
*aResult = (mStringCurItem < mCount);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BaseStringEnumerator::GetNext(nsACString& aResult)
|
||||
{
|
||||
if (mStringCurItem >= mCount) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aResult = nsDependentCString(mArray[mStringCurItem++]);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
BaseStringEnumerator::SortCallback(const void* aE1, const void* aE2,
|
||||
void* /*unused*/)
|
||||
{
|
||||
char const* const* s1 = reinterpret_cast<char const* const*>(aE1);
|
||||
char const* const* s2 = reinterpret_cast<char const* const*>(aE2);
|
||||
|
||||
return strcmp(*s1, *s2);
|
||||
}
|
||||
|
||||
void
|
||||
BaseStringEnumerator::Sort()
|
||||
{
|
||||
NS_QuickSort(mArray, mCount, sizeof(mArray[0]), SortCallback, nullptr);
|
||||
}
|
||||
|
||||
//
|
||||
// EntryEnumerator is the wrapper that allows nsICategoryManager::EnumerateCategory
|
||||
//
|
||||
class EntryEnumerator
|
||||
: public BaseStringEnumerator
|
||||
{
|
||||
public:
|
||||
static EntryEnumerator* Create(nsTHashtable<CategoryLeaf>& aTable);
|
||||
};
|
||||
|
||||
|
||||
EntryEnumerator*
|
||||
EntryEnumerator::Create(nsTHashtable<CategoryLeaf>& aTable)
|
||||
{
|
||||
EntryEnumerator* enumObj = new EntryEnumerator();
|
||||
if (!enumObj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
enumObj->mArray = new char const* [aTable.Count()];
|
||||
if (!enumObj->mArray) {
|
||||
delete enumObj;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (auto iter = aTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
CategoryLeaf* leaf = iter.Get();
|
||||
if (leaf->value) {
|
||||
enumObj->mArray[enumObj->mCount++] = leaf->GetKey();
|
||||
}
|
||||
}
|
||||
|
||||
enumObj->Sort();
|
||||
|
||||
return enumObj;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CategoryNode implementations
|
||||
//
|
||||
|
||||
CategoryNode*
|
||||
CategoryNode::Create(PLArenaPool* aArena)
|
||||
{
|
||||
return new (aArena) CategoryNode();
|
||||
}
|
||||
|
||||
CategoryNode::~CategoryNode()
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
CategoryNode::operator new(size_t aSize, PLArenaPool* aArena)
|
||||
{
|
||||
void* p;
|
||||
PL_ARENA_ALLOCATE(p, aArena, aSize);
|
||||
return p;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CategoryNode::GetLeaf(const char* aEntryName,
|
||||
char** aResult)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
CategoryLeaf* ent = mTable.GetEntry(aEntryName);
|
||||
|
||||
if (ent && ent->value) {
|
||||
*aResult = NS_strdup(ent->value);
|
||||
if (*aResult) {
|
||||
rv = NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CategoryNode::AddLeaf(const char* aEntryName,
|
||||
const char* aValue,
|
||||
bool aReplace,
|
||||
char** aResult,
|
||||
PLArenaPool* aArena)
|
||||
{
|
||||
if (aResult) {
|
||||
*aResult = nullptr;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mLock);
|
||||
CategoryLeaf* leaf = mTable.GetEntry(aEntryName);
|
||||
|
||||
if (!leaf) {
|
||||
const char* arenaEntryName = ArenaStrdup(aEntryName, aArena);
|
||||
if (!arenaEntryName) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
leaf = mTable.PutEntry(arenaEntryName);
|
||||
if (!leaf) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if (leaf->value && !aReplace) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
const char* arenaValue = ArenaStrdup(aValue, aArena);
|
||||
if (!arenaValue) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (aResult && leaf->value) {
|
||||
*aResult = ToNewCString(nsDependentCString(leaf->value));
|
||||
if (!*aResult) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
leaf->value = arenaValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
CategoryNode::DeleteLeaf(const char* aEntryName)
|
||||
{
|
||||
// we don't throw any errors, because it normally doesn't matter
|
||||
// and it makes JS a lot cleaner
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
// we can just remove the entire hash entry without introspection
|
||||
mTable.RemoveEntry(aEntryName);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CategoryNode::Enumerate(nsISimpleEnumerator** aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!aResult)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mLock);
|
||||
EntryEnumerator* enumObj = EntryEnumerator::Create(mTable);
|
||||
|
||||
if (!enumObj) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
*aResult = enumObj;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
size_t
|
||||
CategoryNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf)
|
||||
{
|
||||
// We don't measure the strings pointed to by the entries because the
|
||||
// pointers are non-owning.
|
||||
return mTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
//
|
||||
// CategoryEnumerator class
|
||||
//
|
||||
|
||||
class CategoryEnumerator
|
||||
: public BaseStringEnumerator
|
||||
{
|
||||
public:
|
||||
static CategoryEnumerator* Create(nsClassHashtable<nsDepCharHashKey,
|
||||
CategoryNode>& aTable);
|
||||
};
|
||||
|
||||
CategoryEnumerator*
|
||||
CategoryEnumerator::Create(nsClassHashtable<nsDepCharHashKey, CategoryNode>&
|
||||
aTable)
|
||||
{
|
||||
CategoryEnumerator* enumObj = new CategoryEnumerator();
|
||||
if (!enumObj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
enumObj->mArray = new const char* [aTable.Count()];
|
||||
if (!enumObj->mArray) {
|
||||
delete enumObj;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (auto iter = aTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
// if a category has no entries, we pretend it doesn't exist
|
||||
CategoryNode* aNode = iter.UserData();
|
||||
if (aNode->Count()) {
|
||||
const char* str = iter.Key();
|
||||
enumObj->mArray[enumObj->mCount++] = str;
|
||||
}
|
||||
}
|
||||
|
||||
return enumObj;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// nsCategoryManager implementations
|
||||
//
|
||||
|
||||
NS_IMPL_QUERY_INTERFACE(nsCategoryManager, nsICategoryManager, nsIMemoryReporter)
|
||||
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
nsCategoryManager::AddRef()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
nsCategoryManager::Release()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
nsCategoryManager* nsCategoryManager::gCategoryManager;
|
||||
|
||||
/* static */ nsCategoryManager*
|
||||
nsCategoryManager::GetSingleton()
|
||||
{
|
||||
if (!gCategoryManager) {
|
||||
gCategoryManager = new nsCategoryManager();
|
||||
}
|
||||
return gCategoryManager;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsCategoryManager::Destroy()
|
||||
{
|
||||
// The nsMemoryReporterManager gets destroyed before the nsCategoryManager,
|
||||
// so we don't need to unregister the nsCategoryManager as a memory reporter.
|
||||
// In debug builds we assert that unregistering fails, as a way (imperfect
|
||||
// but better than nothing) of testing the "destroyed before" part.
|
||||
MOZ_ASSERT(NS_FAILED(UnregisterWeakMemoryReporter(gCategoryManager)));
|
||||
|
||||
delete gCategoryManager;
|
||||
gCategoryManager = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCategoryManager::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||
{
|
||||
if (aOuter) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
|
||||
return GetSingleton()->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
nsCategoryManager::nsCategoryManager()
|
||||
: mLock("nsCategoryManager")
|
||||
, mSuppressNotifications(false)
|
||||
{
|
||||
PL_INIT_ARENA_POOL(&mArena, "CategoryManagerArena",
|
||||
NS_CATEGORYMANAGER_ARENA_SIZE);
|
||||
}
|
||||
|
||||
void
|
||||
nsCategoryManager::InitMemoryReporter()
|
||||
{
|
||||
RegisterWeakMemoryReporter(this);
|
||||
}
|
||||
|
||||
nsCategoryManager::~nsCategoryManager()
|
||||
{
|
||||
// the hashtable contains entries that must be deleted before the arena is
|
||||
// destroyed, or else you will have PRLocks undestroyed and other Really
|
||||
// Bad Stuff (TM)
|
||||
mTable.Clear();
|
||||
|
||||
PL_FinishArenaPool(&mArena);
|
||||
}
|
||||
|
||||
inline CategoryNode*
|
||||
nsCategoryManager::get_category(const char* aName)
|
||||
{
|
||||
CategoryNode* node;
|
||||
if (!mTable.Get(aName, &node)) {
|
||||
return nullptr;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(CategoryManagerMallocSizeOf)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCategoryManager::CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData, bool aAnonymize)
|
||||
{
|
||||
MOZ_COLLECT_REPORT(
|
||||
"explicit/xpcom/category-manager", KIND_HEAP, UNITS_BYTES,
|
||||
SizeOfIncludingThis(CategoryManagerMallocSizeOf),
|
||||
"Memory used for the XPCOM category manager.");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
size_t
|
||||
nsCategoryManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
{
|
||||
size_t n = aMallocSizeOf(this);
|
||||
|
||||
n += PL_SizeOfArenaPoolExcludingPool(&mArena, aMallocSizeOf);
|
||||
|
||||
n += mTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
// We don't measure the key string because it's a non-owning pointer.
|
||||
n += iter.Data()->SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class CategoryNotificationRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
CategoryNotificationRunnable(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char* aData)
|
||||
: mSubject(aSubject)
|
||||
, mTopic(aTopic)
|
||||
, mData(aData)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISupports> mSubject;
|
||||
const char* mTopic;
|
||||
NS_ConvertUTF8toUTF16 mData;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
CategoryNotificationRunnable::Run()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (observerService) {
|
||||
observerService->NotifyObservers(mSubject, mTopic, mData.get());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
void
|
||||
nsCategoryManager::NotifyObservers(const char* aTopic,
|
||||
const char* aCategoryName,
|
||||
const char* aEntryName)
|
||||
{
|
||||
if (mSuppressNotifications) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<CategoryNotificationRunnable> r;
|
||||
|
||||
if (aEntryName) {
|
||||
nsCOMPtr<nsISupportsCString> entry =
|
||||
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = entry->SetData(nsDependentCString(aEntryName));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
r = new CategoryNotificationRunnable(entry, aTopic, aCategoryName);
|
||||
} else {
|
||||
r = new CategoryNotificationRunnable(NS_ISUPPORTS_CAST(nsICategoryManager*,
|
||||
this),
|
||||
aTopic, aCategoryName);
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCategoryManager::GetCategoryEntry(const char* aCategoryName,
|
||||
const char* aEntryName,
|
||||
char** aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!aCategoryName) ||
|
||||
NS_WARN_IF(!aEntryName) ||
|
||||
NS_WARN_IF(!aResult)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsresult status = NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
CategoryNode* category;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
category = get_category(aCategoryName);
|
||||
}
|
||||
|
||||
if (category) {
|
||||
status = category->GetLeaf(aEntryName, aResult);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCategoryManager::AddCategoryEntry(const char* aCategoryName,
|
||||
const char* aEntryName,
|
||||
const char* aValue,
|
||||
bool aPersist,
|
||||
bool aReplace,
|
||||
char** aResult)
|
||||
{
|
||||
if (aPersist) {
|
||||
NS_ERROR("Category manager doesn't support persistence.");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
AddCategoryEntry(aCategoryName, aEntryName, aValue, aReplace, aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsCategoryManager::AddCategoryEntry(const char* aCategoryName,
|
||||
const char* aEntryName,
|
||||
const char* aValue,
|
||||
bool aReplace,
|
||||
char** aOldValue)
|
||||
{
|
||||
if (aOldValue) {
|
||||
*aOldValue = nullptr;
|
||||
}
|
||||
|
||||
// Before we can insert a new entry, we'll need to
|
||||
// find the |CategoryNode| to put it in...
|
||||
CategoryNode* category;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
category = get_category(aCategoryName);
|
||||
|
||||
if (!category) {
|
||||
// That category doesn't exist yet; let's make it.
|
||||
category = CategoryNode::Create(&mArena);
|
||||
|
||||
char* categoryName = ArenaStrdup(aCategoryName, &mArena);
|
||||
mTable.Put(categoryName, category);
|
||||
}
|
||||
}
|
||||
|
||||
if (!category) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We will need the return value of AddLeaf even if the called doesn't want it
|
||||
char* oldEntry = nullptr;
|
||||
|
||||
nsresult rv = category->AddLeaf(aEntryName,
|
||||
aValue,
|
||||
aReplace,
|
||||
&oldEntry,
|
||||
&mArena);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (oldEntry) {
|
||||
NotifyObservers(NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID,
|
||||
aCategoryName, aEntryName);
|
||||
}
|
||||
NotifyObservers(NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID,
|
||||
aCategoryName, aEntryName);
|
||||
|
||||
if (aOldValue) {
|
||||
*aOldValue = oldEntry;
|
||||
} else {
|
||||
free(oldEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCategoryManager::DeleteCategoryEntry(const char* aCategoryName,
|
||||
const char* aEntryName,
|
||||
bool aDontPersist)
|
||||
{
|
||||
if (NS_WARN_IF(!aCategoryName) ||
|
||||
NS_WARN_IF(!aEntryName)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/*
|
||||
Note: no errors are reported since failure to delete
|
||||
probably won't hurt you, and returning errors seriously
|
||||
inconveniences JS clients
|
||||
*/
|
||||
|
||||
CategoryNode* category;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
category = get_category(aCategoryName);
|
||||
}
|
||||
|
||||
if (category) {
|
||||
category->DeleteLeaf(aEntryName);
|
||||
|
||||
NotifyObservers(NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID,
|
||||
aCategoryName, aEntryName);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCategoryManager::DeleteCategory(const char* aCategoryName)
|
||||
{
|
||||
if (NS_WARN_IF(!aCategoryName)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// the categories are arena-allocated, so we don't
|
||||
// actually delete them. We just remove all of the
|
||||
// leaf nodes.
|
||||
|
||||
CategoryNode* category;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
category = get_category(aCategoryName);
|
||||
}
|
||||
|
||||
if (category) {
|
||||
category->Clear();
|
||||
NotifyObservers(NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID,
|
||||
aCategoryName, nullptr);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCategoryManager::EnumerateCategory(const char* aCategoryName,
|
||||
nsISimpleEnumerator** aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!aCategoryName) ||
|
||||
NS_WARN_IF(!aResult)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
CategoryNode* category;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
category = get_category(aCategoryName);
|
||||
}
|
||||
|
||||
if (!category) {
|
||||
return NS_NewEmptyEnumerator(aResult);
|
||||
}
|
||||
|
||||
return category->Enumerate(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCategoryManager::EnumerateCategories(nsISimpleEnumerator** aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!aResult)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mLock);
|
||||
CategoryEnumerator* enumObj = CategoryEnumerator::Create(mTable);
|
||||
|
||||
if (!enumObj) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
*aResult = enumObj;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct writecat_struct
|
||||
{
|
||||
PRFileDesc* fd;
|
||||
bool success;
|
||||
};
|
||||
|
||||
nsresult
|
||||
nsCategoryManager::SuppressNotifications(bool aSuppress)
|
||||
{
|
||||
mSuppressNotifications = aSuppress;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* CreateServicesFromCategory()
|
||||
*
|
||||
* Given a category, this convenience functions enumerates the category and
|
||||
* creates a service of every CID or ContractID registered under the category.
|
||||
* If observerTopic is non null and the service implements nsIObserver,
|
||||
* this will attempt to notify the observer with the origin, observerTopic string
|
||||
* as parameter.
|
||||
*/
|
||||
void
|
||||
NS_CreateServicesFromCategory(const char* aCategory,
|
||||
nsISupports* aOrigin,
|
||||
const char* aObserverTopic,
|
||||
const char16_t* aObserverData)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsICategoryManager> categoryManager =
|
||||
do_GetService("@mozilla.org/categorymanager;1");
|
||||
if (!categoryManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> enumerator;
|
||||
rv = categoryManager->EnumerateCategory(aCategory,
|
||||
getter_AddRefs(enumerator));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIUTF8StringEnumerator> senumerator =
|
||||
do_QueryInterface(enumerator);
|
||||
if (!senumerator) {
|
||||
NS_WARNING("Category enumerator doesn't support nsIUTF8StringEnumerator.");
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasMore;
|
||||
while (NS_SUCCEEDED(senumerator->HasMore(&hasMore)) && hasMore) {
|
||||
// From here on just skip any error we get.
|
||||
nsAutoCString entryString;
|
||||
if (NS_FAILED(senumerator->GetNext(entryString))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsXPIDLCString contractID;
|
||||
rv = categoryManager->GetCategoryEntry(aCategory, entryString.get(),
|
||||
getter_Copies(contractID));
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> instance = do_GetService(contractID);
|
||||
if (!instance) {
|
||||
LogMessage("While creating services from category '%s', could not create service for entry '%s', contract ID '%s'",
|
||||
aCategory, entryString.get(), contractID.get());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aObserverTopic) {
|
||||
// try an observer, if it implements it.
|
||||
nsCOMPtr<nsIObserver> observer = do_QueryInterface(instance);
|
||||
if (observer) {
|
||||
observer->Observe(aOrigin, aObserverTopic,
|
||||
aObserverData ? aObserverData : u"");
|
||||
} else {
|
||||
LogMessage("While creating services from category '%s', service for entry '%s', contract ID '%s' does not implement nsIObserver.",
|
||||
aCategory, entryString.get(), contractID.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
146
xpcom/components/nsCategoryManager.h
Normal file
146
xpcom/components/nsCategoryManager.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
#ifndef NSCATEGORYMANAGER_H
|
||||
#define NSCATEGORYMANAGER_H
|
||||
|
||||
#include "prio.h"
|
||||
#include "plarena.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsICategoryManager.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsIMemoryReporter;
|
||||
|
||||
/* 16d222a6-1dd2-11b2-b693-f38b02c021b2 */
|
||||
#define NS_CATEGORYMANAGER_CID \
|
||||
{ 0x16d222a6, 0x1dd2, 0x11b2, \
|
||||
{0xb6, 0x93, 0xf3, 0x8b, 0x02, 0xc0, 0x21, 0xb2} }
|
||||
|
||||
/**
|
||||
* a "leaf-node", managed by the nsCategoryNode hashtable.
|
||||
*
|
||||
* we need to keep a "persistent value" (which will be written to the registry)
|
||||
* and a non-persistent value (for the current runtime): these are usually
|
||||
* the same, except when aPersist==false. The strings are permanently arena-
|
||||
* allocated, and will never go away.
|
||||
*/
|
||||
class CategoryLeaf : public nsDepCharHashKey
|
||||
{
|
||||
public:
|
||||
explicit CategoryLeaf(const char* aKey) : nsDepCharHashKey(aKey), value(nullptr) {}
|
||||
const char* value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* CategoryNode keeps a hashtable of its entries.
|
||||
* the CategoryNode itself is permanently allocated in
|
||||
* the arena.
|
||||
*/
|
||||
class CategoryNode
|
||||
{
|
||||
public:
|
||||
nsresult GetLeaf(const char* aEntryName,
|
||||
char** aResult);
|
||||
|
||||
nsresult AddLeaf(const char* aEntryName,
|
||||
const char* aValue,
|
||||
bool aReplace,
|
||||
char** aResult,
|
||||
PLArenaPool* aArena);
|
||||
|
||||
void DeleteLeaf(const char* aEntryName);
|
||||
|
||||
void Clear()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(mLock);
|
||||
mTable.Clear();
|
||||
}
|
||||
|
||||
uint32_t Count()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(mLock);
|
||||
uint32_t tCount = mTable.Count();
|
||||
return tCount;
|
||||
}
|
||||
|
||||
nsresult Enumerate(nsISimpleEnumerator** aResult);
|
||||
|
||||
// CategoryNode is arena-allocated, with the strings
|
||||
static CategoryNode* Create(PLArenaPool* aArena);
|
||||
~CategoryNode();
|
||||
void operator delete(void*) {}
|
||||
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
|
||||
|
||||
private:
|
||||
CategoryNode() : mLock("CategoryLeaf") {}
|
||||
|
||||
void* operator new(size_t aSize, PLArenaPool* aArena);
|
||||
|
||||
nsTHashtable<CategoryLeaf> mTable;
|
||||
mozilla::Mutex mLock;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The main implementation of nsICategoryManager.
|
||||
*
|
||||
* This implementation is thread-safe.
|
||||
*/
|
||||
class nsCategoryManager final
|
||||
: public nsICategoryManager
|
||||
, public nsIMemoryReporter
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICATEGORYMANAGER
|
||||
NS_DECL_NSIMEMORYREPORTER
|
||||
|
||||
/**
|
||||
* Suppress or unsuppress notifications of category changes to the
|
||||
* observer service. This is to be used by nsComponentManagerImpl
|
||||
* on startup while reading the stored category list.
|
||||
*/
|
||||
nsresult SuppressNotifications(bool aSuppress);
|
||||
|
||||
void AddCategoryEntry(const char* aCategory,
|
||||
const char* aKey,
|
||||
const char* aValue,
|
||||
bool aReplace = true,
|
||||
char** aOldValue = nullptr);
|
||||
|
||||
static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
void InitMemoryReporter();
|
||||
|
||||
static nsCategoryManager* GetSingleton();
|
||||
static void Destroy();
|
||||
|
||||
private:
|
||||
static nsCategoryManager* gCategoryManager;
|
||||
|
||||
nsCategoryManager();
|
||||
~nsCategoryManager();
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
|
||||
|
||||
CategoryNode* get_category(const char* aName);
|
||||
void NotifyObservers(const char* aTopic,
|
||||
const char* aCategoryName, // must be a static string
|
||||
const char* aEntryName);
|
||||
|
||||
PLArenaPool mArena;
|
||||
nsClassHashtable<nsDepCharHashKey, CategoryNode> mTable;
|
||||
mozilla::Mutex mLock;
|
||||
bool mSuppressNotifications;
|
||||
};
|
||||
|
||||
#endif
|
||||
18
xpcom/components/nsCategoryManagerUtils.h
Normal file
18
xpcom/components/nsCategoryManagerUtils.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsCategoryManagerUtils_h__
|
||||
#define nsCategoryManagerUtils_h__
|
||||
|
||||
#include "nsICategoryManager.h"
|
||||
|
||||
void
|
||||
NS_CreateServicesFromCategory(const char* aCategory,
|
||||
nsISupports* aOrigin,
|
||||
const char* aObserverTopic,
|
||||
const char16_t* aObserverData = nullptr);
|
||||
|
||||
#endif
|
||||
2083
xpcom/components/nsComponentManager.cpp
Normal file
2083
xpcom/components/nsComponentManager.cpp
Normal file
File diff suppressed because it is too large
Load diff
363
xpcom/components/nsComponentManager.h
Normal file
363
xpcom/components/nsComponentManager.h
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsComponentManager_h__
|
||||
#define nsComponentManager_h__
|
||||
|
||||
#include "nsXPCOM.h"
|
||||
|
||||
#include "xpcom-private.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIComponentRegistrar.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIFile.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Module.h"
|
||||
#include "mozilla/ModuleLoader.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsNativeModuleLoader.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "PLDHashTable.h"
|
||||
#include "prtime.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "plarena.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "mozilla/Omnijar.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
struct nsFactoryEntry;
|
||||
class nsIServiceManager;
|
||||
struct PRThread;
|
||||
|
||||
#define NS_COMPONENTMANAGER_CID \
|
||||
{ /* 91775d60-d5dc-11d2-92fb-00e09805570f */ \
|
||||
0x91775d60, \
|
||||
0xd5dc, \
|
||||
0x11d2, \
|
||||
{0x92, 0xfb, 0x00, 0xe0, 0x98, 0x05, 0x57, 0x0f} \
|
||||
}
|
||||
|
||||
/* keys for registry use */
|
||||
extern const char xpcomKeyName[];
|
||||
extern const char xpcomComponentsKeyName[];
|
||||
extern const char lastModValueName[];
|
||||
extern const char fileSizeValueName[];
|
||||
extern const char nativeComponentType[];
|
||||
extern const char staticComponentType[];
|
||||
|
||||
#ifdef DEBUG
|
||||
#define XPCOM_CHECK_PENDING_CIDS
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern const mozilla::Module kXPCOMModule;
|
||||
|
||||
/**
|
||||
* This is a wrapper around mozilla::Mutex which provides runtime
|
||||
* checking for a deadlock where the same thread tries to lock a mutex while
|
||||
* it is already locked. This checking is present in both debug and release
|
||||
* builds.
|
||||
*/
|
||||
class SafeMutex
|
||||
{
|
||||
public:
|
||||
explicit SafeMutex(const char* aName)
|
||||
: mMutex(aName)
|
||||
, mOwnerThread(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
~SafeMutex() {}
|
||||
|
||||
void Lock()
|
||||
{
|
||||
AssertNotCurrentThreadOwns();
|
||||
mMutex.Lock();
|
||||
MOZ_ASSERT(mOwnerThread == nullptr);
|
||||
mOwnerThread = PR_GetCurrentThread();
|
||||
}
|
||||
|
||||
void Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mOwnerThread == PR_GetCurrentThread());
|
||||
mOwnerThread = nullptr;
|
||||
mMutex.Unlock();
|
||||
}
|
||||
|
||||
void AssertCurrentThreadOwns() const
|
||||
{
|
||||
// This method is a debug-only check
|
||||
MOZ_ASSERT(mOwnerThread == PR_GetCurrentThread());
|
||||
}
|
||||
|
||||
MOZ_NEVER_INLINE void AssertNotCurrentThreadOwns() const
|
||||
{
|
||||
// This method is a release-mode check
|
||||
if (PR_GetCurrentThread() == mOwnerThread) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mozilla::Mutex mMutex;
|
||||
mozilla::Atomic<PRThread*, mozilla::Relaxed> mOwnerThread;
|
||||
};
|
||||
|
||||
typedef mozilla::BaseAutoLock<SafeMutex> SafeMutexAutoLock;
|
||||
typedef mozilla::BaseAutoUnlock<SafeMutex> SafeMutexAutoUnlock;
|
||||
|
||||
class nsComponentManagerImpl final
|
||||
: public nsIComponentManager
|
||||
, public nsIServiceManager
|
||||
, public nsSupportsWeakReference
|
||||
, public nsIComponentRegistrar
|
||||
, public nsIInterfaceRequestor
|
||||
, public nsIMemoryReporter
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSICOMPONENTMANAGER
|
||||
NS_DECL_NSICOMPONENTREGISTRAR
|
||||
NS_DECL_NSIMEMORYREPORTER
|
||||
|
||||
static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
|
||||
nsresult RegistryLocationForFile(nsIFile* aFile,
|
||||
nsCString& aResult);
|
||||
nsresult FileForRegistryLocation(const nsCString& aLocation,
|
||||
nsIFile** aSpec);
|
||||
|
||||
NS_DECL_NSISERVICEMANAGER
|
||||
|
||||
// nsComponentManagerImpl methods:
|
||||
nsComponentManagerImpl();
|
||||
|
||||
static nsComponentManagerImpl* gComponentManager;
|
||||
nsresult Init();
|
||||
|
||||
nsresult Shutdown(void);
|
||||
|
||||
nsresult FreeServices();
|
||||
|
||||
already_AddRefed<mozilla::ModuleLoader> LoaderForExtension(const nsACString& aExt);
|
||||
nsInterfaceHashtable<nsCStringHashKey, mozilla::ModuleLoader> mLoaderMap;
|
||||
|
||||
already_AddRefed<nsIFactory> FindFactory(const nsCID& aClass);
|
||||
already_AddRefed<nsIFactory> FindFactory(const char* aContractID,
|
||||
uint32_t aContractIDLen);
|
||||
|
||||
already_AddRefed<nsIFactory> LoadFactory(nsFactoryEntry* aEntry);
|
||||
|
||||
nsFactoryEntry* GetFactoryEntry(const char* aContractID,
|
||||
uint32_t aContractIDLen);
|
||||
nsFactoryEntry* GetFactoryEntry(const nsCID& aClass);
|
||||
|
||||
nsDataHashtable<nsIDHashKey, nsFactoryEntry*> mFactories;
|
||||
nsDataHashtable<nsCStringHashKey, nsFactoryEntry*> mContractIDs;
|
||||
|
||||
SafeMutex mLock;
|
||||
|
||||
static void InitializeStaticModules();
|
||||
static void InitializeModuleLocations();
|
||||
|
||||
struct ComponentLocation
|
||||
{
|
||||
NSLocationType type;
|
||||
mozilla::FileLocation location;
|
||||
};
|
||||
|
||||
class ComponentLocationComparator
|
||||
{
|
||||
public:
|
||||
bool Equals(const ComponentLocation& aA, const ComponentLocation& aB) const
|
||||
{
|
||||
return (aA.type == aB.type && aA.location.Equals(aB.location));
|
||||
}
|
||||
};
|
||||
|
||||
static nsTArray<const mozilla::Module*>* sStaticModules;
|
||||
static nsTArray<ComponentLocation>* sModuleLocations;
|
||||
|
||||
nsNativeModuleLoader mNativeModuleLoader;
|
||||
|
||||
class KnownModule
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Static or binary module.
|
||||
*/
|
||||
KnownModule(const mozilla::Module* aModule, mozilla::FileLocation& aFile)
|
||||
: mModule(aModule)
|
||||
, mFile(aFile)
|
||||
, mLoaded(false)
|
||||
, mFailed(false)
|
||||
{
|
||||
}
|
||||
|
||||
explicit KnownModule(const mozilla::Module* aModule)
|
||||
: mModule(aModule)
|
||||
, mLoaded(false)
|
||||
, mFailed(false)
|
||||
{
|
||||
}
|
||||
|
||||
explicit KnownModule(mozilla::FileLocation& aFile)
|
||||
: mModule(nullptr)
|
||||
, mFile(aFile)
|
||||
, mLoader(nullptr)
|
||||
, mLoaded(false)
|
||||
, mFailed(false)
|
||||
{
|
||||
}
|
||||
|
||||
~KnownModule()
|
||||
{
|
||||
if (mLoaded && mModule->unloadProc) {
|
||||
mModule->unloadProc();
|
||||
}
|
||||
}
|
||||
|
||||
bool EnsureLoader();
|
||||
bool Load();
|
||||
|
||||
const mozilla::Module* Module() const { return mModule; }
|
||||
|
||||
/**
|
||||
* For error logging, get a description of this module, either the
|
||||
* file path, or <static module>.
|
||||
*/
|
||||
nsCString Description() const;
|
||||
|
||||
private:
|
||||
const mozilla::Module* mModule;
|
||||
mozilla::FileLocation mFile;
|
||||
nsCOMPtr<mozilla::ModuleLoader> mLoader;
|
||||
bool mLoaded;
|
||||
bool mFailed;
|
||||
};
|
||||
|
||||
// The KnownModule is kept alive by these members, it is
|
||||
// referenced by pointer from the factory entries.
|
||||
nsTArray<nsAutoPtr<KnownModule>> mKnownStaticModules;
|
||||
// The key is the URI string of the module
|
||||
nsClassHashtable<nsCStringHashKey, KnownModule> mKnownModules;
|
||||
|
||||
// Mutex not held
|
||||
void RegisterModule(const mozilla::Module* aModule,
|
||||
mozilla::FileLocation* aFile);
|
||||
|
||||
|
||||
// Mutex held
|
||||
void RegisterCIDEntryLocked(const mozilla::Module::CIDEntry* aEntry,
|
||||
KnownModule* aModule);
|
||||
void RegisterContractIDLocked(const mozilla::Module::ContractIDEntry* aEntry);
|
||||
|
||||
// Mutex not held
|
||||
void RegisterManifest(NSLocationType aType, mozilla::FileLocation& aFile,
|
||||
bool aChromeOnly);
|
||||
|
||||
struct ManifestProcessingContext
|
||||
{
|
||||
ManifestProcessingContext(NSLocationType aType,
|
||||
mozilla::FileLocation& aFile, bool aChromeOnly)
|
||||
: mType(aType)
|
||||
, mFile(aFile)
|
||||
, mChromeOnly(aChromeOnly)
|
||||
{
|
||||
}
|
||||
|
||||
~ManifestProcessingContext() {}
|
||||
|
||||
NSLocationType mType;
|
||||
mozilla::FileLocation mFile;
|
||||
bool mChromeOnly;
|
||||
};
|
||||
|
||||
void ManifestManifest(ManifestProcessingContext& aCx, int aLineNo,
|
||||
char* const* aArgv);
|
||||
void ManifestBinaryComponent(ManifestProcessingContext& aCx, int aLineNo,
|
||||
char* const* aArgv);
|
||||
void ManifestXPT(ManifestProcessingContext& aCx, int aLineNo,
|
||||
char* const* aArgv);
|
||||
void ManifestComponent(ManifestProcessingContext& aCx, int aLineNo,
|
||||
char* const* aArgv);
|
||||
void ManifestContract(ManifestProcessingContext& aCx, int aLineNo,
|
||||
char* const* aArgv);
|
||||
void ManifestCategory(ManifestProcessingContext& aCx, int aLineNo,
|
||||
char* const* aArgv);
|
||||
|
||||
void RereadChromeManifests(bool aChromeOnly = true);
|
||||
|
||||
// Shutdown
|
||||
enum
|
||||
{
|
||||
NOT_INITIALIZED,
|
||||
NORMAL,
|
||||
SHUTDOWN_IN_PROGRESS,
|
||||
SHUTDOWN_COMPLETE
|
||||
} mStatus;
|
||||
|
||||
PLArenaPool mArena;
|
||||
|
||||
struct PendingServiceInfo
|
||||
{
|
||||
const nsCID* cid;
|
||||
PRThread* thread;
|
||||
};
|
||||
|
||||
inline PendingServiceInfo* AddPendingService(const nsCID& aServiceCID,
|
||||
PRThread* aThread);
|
||||
inline void RemovePendingService(const nsCID& aServiceCID);
|
||||
inline PRThread* GetPendingServiceThread(const nsCID& aServiceCID) const;
|
||||
|
||||
nsTArray<PendingServiceInfo> mPendingServices;
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
private:
|
||||
~nsComponentManagerImpl();
|
||||
};
|
||||
|
||||
|
||||
#define NS_MAX_FILENAME_LEN 1024
|
||||
|
||||
#define NS_ERROR_IS_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 24)
|
||||
|
||||
struct nsFactoryEntry
|
||||
{
|
||||
nsFactoryEntry(const mozilla::Module::CIDEntry* aEntry,
|
||||
nsComponentManagerImpl::KnownModule* aModule);
|
||||
|
||||
// nsIComponentRegistrar.registerFactory support
|
||||
nsFactoryEntry(const nsCID& aClass, nsIFactory* aFactory);
|
||||
|
||||
~nsFactoryEntry();
|
||||
|
||||
already_AddRefed<nsIFactory> GetFactory();
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
|
||||
|
||||
const mozilla::Module::CIDEntry* mCIDEntry;
|
||||
nsComponentManagerImpl::KnownModule* mModule;
|
||||
|
||||
nsCOMPtr<nsIFactory> mFactory;
|
||||
nsCOMPtr<nsISupports> mServiceObject;
|
||||
};
|
||||
|
||||
#endif // nsComponentManager_h__
|
||||
69
xpcom/components/nsICategoryManager.idl
Normal file
69
xpcom/components/nsICategoryManager.idl
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsISimpleEnumerator;
|
||||
|
||||
/*
|
||||
* nsICategoryManager
|
||||
*/
|
||||
|
||||
[scriptable, uuid(3275b2cd-af6d-429a-80d7-f0c5120342ac)]
|
||||
interface nsICategoryManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* Get the value for the given category's entry.
|
||||
* @param aCategory The name of the category ("protocol")
|
||||
* @param aEntry The entry you're looking for ("http")
|
||||
* @return The value.
|
||||
*/
|
||||
string getCategoryEntry(in string aCategory, in string aEntry);
|
||||
|
||||
/**
|
||||
* Add an entry to a category.
|
||||
* @param aCategory The name of the category ("protocol")
|
||||
* @param aEntry The entry to be added ("http")
|
||||
* @param aValue The value for the entry ("moz.httprulez.1")
|
||||
* @param aPersist Should this data persist between invocations?
|
||||
* @param aReplace Should we replace an existing entry?
|
||||
* @return Previous entry, if any
|
||||
*/
|
||||
string addCategoryEntry(in string aCategory, in string aEntry,
|
||||
in string aValue, in boolean aPersist,
|
||||
in boolean aReplace);
|
||||
|
||||
/**
|
||||
* Delete an entry from the category.
|
||||
* @param aCategory The name of the category ("protocol")
|
||||
* @param aEntry The entry to be added ("http")
|
||||
* @param aPersist Delete persistent data from registry, if present?
|
||||
*/
|
||||
void deleteCategoryEntry(in string aCategory, in string aEntry,
|
||||
in boolean aPersist);
|
||||
|
||||
/**
|
||||
* Delete a category and all entries.
|
||||
* @param aCategory The category to be deleted.
|
||||
*/
|
||||
void deleteCategory(in string aCategory);
|
||||
|
||||
/**
|
||||
* Enumerate the entries in a category.
|
||||
* @param aCategory The category to be enumerated.
|
||||
* @return a simple enumerator, each result QIs to
|
||||
* nsISupportsCString.
|
||||
*/
|
||||
nsISimpleEnumerator enumerateCategory(in string aCategory);
|
||||
|
||||
/**
|
||||
* Enumerate all existing categories
|
||||
* @param aCategory The category to be enumerated.
|
||||
* @return a simple enumerator, each result QIs to
|
||||
* nsISupportsCString.
|
||||
*/
|
||||
nsISimpleEnumerator enumerateCategories();
|
||||
};
|
||||
|
||||
87
xpcom/components/nsIClassInfo.idl
Normal file
87
xpcom/components/nsIClassInfo.idl
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIXPCScriptable;
|
||||
|
||||
/**
|
||||
* Provides information about a specific implementation class. If you want
|
||||
* your class to implement nsIClassInfo, see nsIClassInfoImpl.h for
|
||||
* instructions--you most likely do not want to inherit from nsIClassInfo.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(a60569d7-d401-4677-ba63-2aa5971af25d)]
|
||||
interface nsIClassInfo : nsISupports
|
||||
{
|
||||
/**
|
||||
* Get an ordered list of the interface ids that instances of the class
|
||||
* promise to implement. Note that nsISupports is an implicit member
|
||||
* of any such list and need not be included.
|
||||
*
|
||||
* Should set *count = 0 and *array = null and return NS_OK if getting the
|
||||
* list is not supported.
|
||||
*/
|
||||
void getInterfaces(out uint32_t count,
|
||||
[array, size_is(count), retval] out nsIIDPtr array);
|
||||
|
||||
/**
|
||||
* Return an object to assist XPConnect in supplying JavaScript-specific
|
||||
* behavior to callers of the instance object, or null if not needed.
|
||||
*/
|
||||
nsIXPCScriptable getScriptableHelper();
|
||||
|
||||
/**
|
||||
* A contract ID through which an instance of this class can be created
|
||||
* (or accessed as a service, if |flags & SINGLETON|), or null.
|
||||
*/
|
||||
readonly attribute string contractID;
|
||||
|
||||
/**
|
||||
* A human readable string naming the class, or null.
|
||||
*/
|
||||
readonly attribute string classDescription;
|
||||
|
||||
/**
|
||||
* A class ID through which an instance of this class can be created
|
||||
* (or accessed as a service, if |flags & SINGLETON|), or null.
|
||||
*/
|
||||
readonly attribute nsCIDPtr classID;
|
||||
|
||||
/**
|
||||
* Bitflags for 'flags' attribute.
|
||||
*/
|
||||
const uint32_t SINGLETON = 1 << 0;
|
||||
const uint32_t THREADSAFE = 1 << 1;
|
||||
const uint32_t MAIN_THREAD_ONLY = 1 << 2;
|
||||
const uint32_t DOM_OBJECT = 1 << 3;
|
||||
const uint32_t PLUGIN_OBJECT = 1 << 4;
|
||||
const uint32_t SINGLETON_CLASSINFO = 1 << 5;
|
||||
|
||||
/**
|
||||
* 'flags' attribute bitflag: whether objects of this type implement
|
||||
* nsIContent.
|
||||
*/
|
||||
const uint32_t CONTENT_NODE = 1 << 6;
|
||||
|
||||
// The high order bit is RESERVED for consumers of these flags.
|
||||
// No implementor of this interface should ever return flags
|
||||
// with this bit set.
|
||||
const uint32_t RESERVED = 1 << 31;
|
||||
|
||||
|
||||
readonly attribute uint32_t flags;
|
||||
|
||||
/**
|
||||
* Also a class ID through which an instance of this class can be created
|
||||
* (or accessed as a service, if |flags & SINGLETON|). If the class does
|
||||
* not have a CID, it should return NS_ERROR_NOT_AVAILABLE. This attribute
|
||||
* exists so C++ callers can avoid allocating and freeing a CID, as would
|
||||
* happen if they used classID.
|
||||
*/
|
||||
[noscript] readonly attribute nsCID classIDNoAlloc;
|
||||
|
||||
};
|
||||
106
xpcom/components/nsIComponentManager.idl
Normal file
106
xpcom/components/nsIComponentManager.idl
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* The nsIComponentManager interface.
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIFile;
|
||||
interface nsIFactory;
|
||||
interface nsIArray;
|
||||
|
||||
[scriptable, uuid(d604ffc3-1ba3-4f6c-b65f-1ed4199364c3)]
|
||||
interface nsIComponentManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* getClassObject
|
||||
*
|
||||
* Returns the factory object that can be used to create instances of
|
||||
* CID aClass
|
||||
*
|
||||
* @param aClass The classid of the factory that is being requested
|
||||
*/
|
||||
void getClassObject(in nsCIDRef aClass,
|
||||
in nsIIDRef aIID,
|
||||
[iid_is(aIID),retval] out nsQIResult result);
|
||||
|
||||
/**
|
||||
* getClassObjectByContractID
|
||||
*
|
||||
* Returns the factory object that can be used to create instances of
|
||||
* CID aClass
|
||||
*
|
||||
* @param aClass The classid of the factory that is being requested
|
||||
*/
|
||||
void getClassObjectByContractID(in string aContractID,
|
||||
in nsIIDRef aIID,
|
||||
[iid_is(aIID),retval] out nsQIResult result);
|
||||
|
||||
|
||||
/**
|
||||
* createInstance
|
||||
*
|
||||
* Create an instance of the CID aClass and return the interface aIID.
|
||||
*
|
||||
* @param aClass : ClassID of object instance requested
|
||||
* @param aDelegate : Used for aggregation
|
||||
* @param aIID : IID of interface requested
|
||||
*/
|
||||
void createInstance(in nsCIDRef aClass,
|
||||
in nsISupports aDelegate,
|
||||
in nsIIDRef aIID,
|
||||
[iid_is(aIID),retval] out nsQIResult result);
|
||||
|
||||
/**
|
||||
* createInstanceByContractID
|
||||
*
|
||||
* Create an instance of the CID that implements aContractID and return the
|
||||
* interface aIID.
|
||||
*
|
||||
* @param aContractID : aContractID of object instance requested
|
||||
* @param aDelegate : Used for aggregation
|
||||
* @param aIID : IID of interface requested
|
||||
*/
|
||||
void createInstanceByContractID(in string aContractID,
|
||||
in nsISupports aDelegate,
|
||||
in nsIIDRef aIID,
|
||||
[iid_is(aIID),retval] out nsQIResult result);
|
||||
|
||||
/**
|
||||
* addBootstrappedManifestLocation
|
||||
*
|
||||
* Adds a bootstrapped manifest location on runtime.
|
||||
*
|
||||
* @param aLocation : A directory where chrome.manifest resides,
|
||||
* or an XPI with it on the root.
|
||||
*/
|
||||
void addBootstrappedManifestLocation(in nsIFile aLocation);
|
||||
|
||||
/**
|
||||
* removeBootstrappedManifestLocation
|
||||
*
|
||||
* Removes a bootstrapped manifest location on runtime.
|
||||
*
|
||||
* @param aLocation : A directory where chrome.manifest resides,
|
||||
* or an XPI with it on the root.
|
||||
*/
|
||||
void removeBootstrappedManifestLocation(in nsIFile aLocation);
|
||||
|
||||
/**
|
||||
* getManifestLocations
|
||||
*
|
||||
* Get an array of nsIURIs of all registered and builtin manifest locations.
|
||||
*/
|
||||
nsIArray getManifestLocations();
|
||||
};
|
||||
|
||||
|
||||
%{ C++
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#endif
|
||||
%} C++
|
||||
163
xpcom/components/nsIComponentRegistrar.idl
Normal file
163
xpcom/components/nsIComponentRegistrar.idl
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* The nsIComponentRegistrar interface.
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIFile;
|
||||
interface nsIFactory;
|
||||
interface nsISimpleEnumerator;
|
||||
|
||||
[scriptable, uuid(2417cbfe-65ad-48a6-b4b6-eb84db174392)]
|
||||
interface nsIComponentRegistrar : nsISupports
|
||||
{
|
||||
/**
|
||||
* autoRegister
|
||||
*
|
||||
* Register a .manifest file, or an entire directory containing
|
||||
* these files. Registration lasts for this run only, and is not cached.
|
||||
*
|
||||
* @note Formerly this method would register component files directly. This
|
||||
* is no longer supported.
|
||||
*/
|
||||
void autoRegister(in nsIFile aSpec);
|
||||
|
||||
/**
|
||||
* autoUnregister
|
||||
* @status OBSOLETE: This method is no longer implemented, but preserved
|
||||
* in this interface for binary compatibility with
|
||||
* Mozilla 1.9.2.
|
||||
*/
|
||||
void autoUnregister(in nsIFile aSpec);
|
||||
|
||||
|
||||
/**
|
||||
* registerFactory
|
||||
*
|
||||
* Register a factory with a given ContractID, CID and Class Name.
|
||||
*
|
||||
* @param aClass : CID of object
|
||||
* @param aClassName : Class Name of CID (unused)
|
||||
* @param aContractID : ContractID associated with CID aClass. May be null
|
||||
* if no contract ID is needed.
|
||||
* @param aFactory : Factory that will be registered for CID aClass.
|
||||
* If aFactory is null, the contract will be associated
|
||||
* with a previously registered CID.
|
||||
*/
|
||||
void registerFactory(in nsCIDRef aClass,
|
||||
in string aClassName,
|
||||
in string aContractID,
|
||||
in nsIFactory aFactory);
|
||||
|
||||
/**
|
||||
* unregisterFactory
|
||||
*
|
||||
* Unregister a factory associated with CID aClass.
|
||||
*
|
||||
* @param aClass : CID being unregistered
|
||||
* @param aFactory : Factory previously registered to create instances of
|
||||
* CID aClass.
|
||||
*
|
||||
* @throws NS_ERROR* Method failure.
|
||||
*/
|
||||
void unregisterFactory(in nsCIDRef aClass,
|
||||
in nsIFactory aFactory);
|
||||
|
||||
/**
|
||||
* registerFactoryLocation
|
||||
* @status OBSOLETE: This method is no longer implemented, but preserved
|
||||
* in this interface for binary compatibility with
|
||||
* Mozilla 1.9.2.
|
||||
*/
|
||||
void registerFactoryLocation(in nsCIDRef aClass,
|
||||
in string aClassName,
|
||||
in string aContractID,
|
||||
in nsIFile aFile,
|
||||
in string aLoaderStr,
|
||||
in string aType);
|
||||
|
||||
/**
|
||||
* unregisterFactoryLocation
|
||||
* @status OBSOLETE: This method is no longer implemented, but preserved
|
||||
* in this interface for binary compatibility with
|
||||
* Mozilla 1.9.2.
|
||||
*/
|
||||
void unregisterFactoryLocation(in nsCIDRef aClass,
|
||||
in nsIFile aFile);
|
||||
|
||||
/**
|
||||
* isCIDRegistered
|
||||
*
|
||||
* Returns true if a factory is registered for the CID.
|
||||
*
|
||||
* @param aClass : CID queried for registeration
|
||||
* @return : true if a factory is registered for CID
|
||||
* false otherwise.
|
||||
*/
|
||||
boolean isCIDRegistered(in nsCIDRef aClass);
|
||||
|
||||
/**
|
||||
* isContractIDRegistered
|
||||
*
|
||||
* Returns true if a factory is registered for the contract id.
|
||||
*
|
||||
* @param aClass : contract id queried for registeration
|
||||
* @return : true if a factory is registered for contract id
|
||||
* false otherwise.
|
||||
*/
|
||||
boolean isContractIDRegistered(in string aContractID);
|
||||
|
||||
/**
|
||||
* enumerateCIDs
|
||||
*
|
||||
* Enumerate the list of all registered CIDs.
|
||||
*
|
||||
* @return : enumerator for CIDs. Elements of the enumeration can be QI'ed
|
||||
* for the nsISupportsID interface. From the nsISupportsID, you
|
||||
* can obtain the actual CID.
|
||||
*/
|
||||
nsISimpleEnumerator enumerateCIDs();
|
||||
|
||||
/**
|
||||
* enumerateContractIDs
|
||||
*
|
||||
* Enumerate the list of all registered ContractIDs.
|
||||
*
|
||||
* @return : enumerator for ContractIDs. Elements of the enumeration can be
|
||||
* QI'ed for the nsISupportsCString interface. From the
|
||||
* nsISupportsCString interface, you can obtain the actual
|
||||
* Contract ID string.
|
||||
*/
|
||||
nsISimpleEnumerator enumerateContractIDs();
|
||||
|
||||
/**
|
||||
* CIDToContractID
|
||||
* @status OBSOLETE: This method is no longer implemented, but preserved
|
||||
* in this interface for binary compatibility with
|
||||
* Mozilla 1.9.2.
|
||||
*/
|
||||
string CIDToContractID(in nsCIDRef aClass);
|
||||
|
||||
/**
|
||||
* contractIDToCID
|
||||
*
|
||||
* Returns the CID for a given Contract ID, if one exists and is registered.
|
||||
*
|
||||
* @return : Contract ID.
|
||||
*/
|
||||
nsCIDPtr contractIDToCID(in string aContractID);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
42
xpcom/components/nsIFactory.idl
Normal file
42
xpcom/components/nsIFactory.idl
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* A class factory allows the creation of nsISupports derived
|
||||
* components without specifying a concrete base class.
|
||||
*/
|
||||
|
||||
[scriptable, object, uuid(00000001-0000-0000-c000-000000000046)]
|
||||
interface nsIFactory : nsISupports {
|
||||
/**
|
||||
* Creates an instance of a component.
|
||||
*
|
||||
* @param aOuter Pointer to a component that wishes to be aggregated
|
||||
* in the resulting instance. This will be nullptr if no
|
||||
* aggregation is requested.
|
||||
* @param iid The IID of the interface being requested in
|
||||
* the component which is being currently created.
|
||||
* @param result [out] Pointer to the newly created instance, if successful.
|
||||
* @throws NS_NOINTERFACE - Interface not accessible.
|
||||
* @throws NS_ERROR_NO_AGGREGATION - if an 'outer' object is supplied, but the
|
||||
* component is not aggregatable.
|
||||
* NS_ERROR* - Method failure.
|
||||
*/
|
||||
void createInstance(in nsISupports aOuter, in nsIIDRef iid,
|
||||
[retval, iid_is(iid)] out nsQIResult result);
|
||||
|
||||
/**
|
||||
* LockFactory provides the client a way to keep the component
|
||||
* in memory until it is finished with it. The client can call
|
||||
* LockFactory(PR_TRUE) to lock the factory and LockFactory(PR_FALSE)
|
||||
* to release the factory.
|
||||
*
|
||||
* @param lock - Must be PR_TRUE or PR_FALSE
|
||||
* @throws NS_ERROR* - Method failure.
|
||||
*/
|
||||
void lockFactory(in boolean lock);
|
||||
};
|
||||
82
xpcom/components/nsIModule.idl
Normal file
82
xpcom/components/nsIModule.idl
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIFile;
|
||||
interface nsIComponentManager;
|
||||
|
||||
/**
|
||||
* The nsIModule interface.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(7392D032-5371-11d3-994E-00805FD26FEE)]
|
||||
interface nsIModule : nsISupports
|
||||
{
|
||||
/**
|
||||
* Object Instance Creation
|
||||
*
|
||||
* Obtains a Class Object from a nsIModule for a given CID and IID pair.
|
||||
* This class object can either be query to a nsIFactory or a may be
|
||||
* query to a nsIClassInfo.
|
||||
*
|
||||
* @param aCompMgr : The global component manager
|
||||
* @param aClass : ClassID of object instance requested
|
||||
* @param aIID : IID of interface requested
|
||||
*
|
||||
*/
|
||||
void getClassObject(in nsIComponentManager aCompMgr,
|
||||
in nsCIDRef aClass,
|
||||
in nsIIDRef aIID,
|
||||
[retval, iid_is(aIID)] out nsQIResult aResult);
|
||||
|
||||
|
||||
/**
|
||||
* One time registration callback
|
||||
*
|
||||
* When the nsIModule is discovered, this method will be
|
||||
* called so that any setup registration can be preformed.
|
||||
*
|
||||
* @param aCompMgr : The global component manager
|
||||
* @param aLocation : The location of the nsIModule on disk
|
||||
* @param aLoaderStr: Opaque loader specific string
|
||||
* @param aType : Loader Type being used to load this module
|
||||
*/
|
||||
void registerSelf(in nsIComponentManager aCompMgr,
|
||||
in nsIFile aLocation,
|
||||
in string aLoaderStr,
|
||||
in string aType);
|
||||
/**
|
||||
* One time unregistration callback
|
||||
*
|
||||
* When the nsIModule is being unregistered, this method will be
|
||||
* called so that any unregistration can be preformed
|
||||
*
|
||||
* @param aCompMgr : The global component manager
|
||||
* @param aLocation : The location of the nsIModule on disk
|
||||
* @param aLoaderStr : Opaque loader specific string
|
||||
*
|
||||
*/
|
||||
void unregisterSelf(in nsIComponentManager aCompMgr,
|
||||
in nsIFile aLocation,
|
||||
in string aLoaderStr);
|
||||
|
||||
/**
|
||||
* Module load management
|
||||
*
|
||||
* @param aCompMgr : The global component manager
|
||||
*
|
||||
* @return indicates to the caller if the module can be unloaded.
|
||||
* Returning PR_TRUE isn't a guarantee that the module will be
|
||||
* unloaded. It constitues only willingness of the module to be
|
||||
* unloaded. It is very important to ensure that no outstanding
|
||||
* references to the module's code/data exist before returning
|
||||
* PR_TRUE.
|
||||
* Returning PR_FALSE guaratees that the module won't be unloaded.
|
||||
*/
|
||||
boolean canUnload(in nsIComponentManager aCompMgr);
|
||||
};
|
||||
|
||||
|
||||
72
xpcom/components/nsIServiceManager.idl
Normal file
72
xpcom/components/nsIServiceManager.idl
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* The nsIServiceManager manager interface provides a means to obtain
|
||||
* global services in an application. The service manager depends on the
|
||||
* repository to find and instantiate factories to obtain services.
|
||||
*
|
||||
* Users of the service manager must first obtain a pointer to the global
|
||||
* service manager by calling NS_GetServiceManager. After that,
|
||||
* they can request specific services by calling GetService. When they are
|
||||
* finished they can NS_RELEASE() the service as usual.
|
||||
*
|
||||
* A user of a service may keep references to particular services indefinitely
|
||||
* and only must call Release when it shuts down.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(8bb35ed9-e332-462d-9155-4a002ab5c958)]
|
||||
interface nsIServiceManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* getServiceByContractID
|
||||
*
|
||||
* Returns the instance that implements aClass or aContractID and the
|
||||
* interface aIID. This may result in the instance being created.
|
||||
*
|
||||
* @param aClass or aContractID : aClass or aContractID of object
|
||||
* instance requested
|
||||
* @param aIID : IID of interface requested
|
||||
* @param result : resulting service
|
||||
*/
|
||||
void getService(in nsCIDRef aClass,
|
||||
in nsIIDRef aIID,
|
||||
[iid_is(aIID),retval] out nsQIResult result);
|
||||
|
||||
void getServiceByContractID(in string aContractID,
|
||||
in nsIIDRef aIID,
|
||||
[iid_is(aIID),retval] out nsQIResult result);
|
||||
|
||||
/**
|
||||
* isServiceInstantiated
|
||||
*
|
||||
* isServiceInstantiated will return a true if the service has already
|
||||
* been created, or throw otherwise
|
||||
*
|
||||
* @param aClass or aContractID : aClass or aContractID of object
|
||||
* instance requested
|
||||
* @param aIID : IID of interface requested
|
||||
* @throws NS_ERROR_SERVICE_NOT_AVAILABLE if the service hasn't been
|
||||
* instantiated
|
||||
* @throws NS_NOINTERFACE if the IID given isn't supported by the object
|
||||
*/
|
||||
boolean isServiceInstantiated(in nsCIDRef aClass, in nsIIDRef aIID);
|
||||
boolean isServiceInstantiatedByContractID(in string aContractID, in nsIIDRef aIID);
|
||||
};
|
||||
|
||||
|
||||
%{C++
|
||||
// Observing xpcom autoregistration. Topics will be 'start' and 'stop'.
|
||||
#define NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID "xpcom-autoregistration"
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#endif
|
||||
%}
|
||||
|
||||
220
xpcom/components/nsNativeModuleLoader.cpp
Normal file
220
xpcom/components/nsNativeModuleLoader.cpp
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
* This Original Code has been modified by IBM Corporation.
|
||||
* Modifications made by IBM described herein are
|
||||
* Copyright (c) International Business Machines
|
||||
* Corporation, 2000
|
||||
*
|
||||
* Modifications to Mozilla code or documentation
|
||||
* identified per MPL Section 3.3
|
||||
*
|
||||
* Date Modified by Description of modification
|
||||
* 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
|
||||
*/
|
||||
|
||||
#include "nsNativeModuleLoader.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "prinit.h"
|
||||
#include "prerror.h"
|
||||
|
||||
#include "nsComponentManager.h"
|
||||
#include "ManifestParser.h" // for LogMessage
|
||||
#include "nsCRTGlue.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsTraceRefcnt.h"
|
||||
|
||||
#include "nsIFile.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define IMPLEMENT_BREAK_AFTER_LOAD
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static LazyLogModule sNativeModuleLoaderLog("nsNativeModuleLoader");
|
||||
#define LOG(level, args) MOZ_LOG(sNativeModuleLoaderLog, level, args)
|
||||
|
||||
nsresult
|
||||
nsNativeModuleLoader::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Startup not on main thread?");
|
||||
LOG(LogLevel::Debug, ("nsNativeModuleLoader::Init()"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class LoadModuleMainThreadRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
LoadModuleMainThreadRunnable(nsNativeModuleLoader* aLoader,
|
||||
FileLocation& aFile)
|
||||
: mManager(nsComponentManagerImpl::gComponentManager)
|
||||
, mLoader(aLoader)
|
||||
, mFile(aFile)
|
||||
, mResult(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mResult = mLoader->LoadModule(mFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<nsComponentManagerImpl> mManager;
|
||||
nsNativeModuleLoader* mLoader;
|
||||
FileLocation mFile;
|
||||
const mozilla::Module* mResult;
|
||||
};
|
||||
|
||||
const mozilla::Module*
|
||||
nsNativeModuleLoader::LoadModule(FileLocation& aFile)
|
||||
{
|
||||
if (aFile.IsZip()) {
|
||||
NS_ERROR("Binary components cannot be loaded from JARs");
|
||||
return nullptr;
|
||||
}
|
||||
nsCOMPtr<nsIFile> file = aFile.GetBaseFile();
|
||||
nsresult rv;
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
// If this call is off the main thread, synchronously proxy it
|
||||
// to the main thread.
|
||||
RefPtr<LoadModuleMainThreadRunnable> r =
|
||||
new LoadModuleMainThreadRunnable(this, aFile);
|
||||
NS_DispatchToMainThread(r, NS_DISPATCH_SYNC);
|
||||
return r->mResult;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHashable> hashedFile(do_QueryInterface(file));
|
||||
if (!hashedFile) {
|
||||
NS_ERROR("nsIFile is not nsIHashable");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoCString filePath;
|
||||
file->GetNativePath(filePath);
|
||||
|
||||
NativeLoadData data;
|
||||
|
||||
if (mLibraries.Get(hashedFile, &data)) {
|
||||
NS_ASSERTION(data.mModule, "Corrupt mLibraries hash");
|
||||
LOG(LogLevel::Debug,
|
||||
("nsNativeModuleLoader::LoadModule(\"%s\") - found in cache",
|
||||
filePath.get()));
|
||||
return data.mModule;
|
||||
}
|
||||
|
||||
// We haven't loaded this module before
|
||||
{
|
||||
#ifdef HAS_DLL_BLOCKLIST
|
||||
AutoSetXPCOMLoadOnMainThread guard;
|
||||
#endif
|
||||
rv = file->Load(&data.mLibrary);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
char errorMsg[1024] = "<unknown; can't get error from NSPR>";
|
||||
|
||||
if (PR_GetErrorTextLength() < (int)sizeof(errorMsg)) {
|
||||
PR_GetErrorText(errorMsg);
|
||||
}
|
||||
|
||||
LogMessage("Failed to load native module at path '%s': (%lx) %s",
|
||||
filePath.get(), rv, errorMsg);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef IMPLEMENT_BREAK_AFTER_LOAD
|
||||
nsAutoCString leafName;
|
||||
file->GetNativeLeafName(leafName);
|
||||
|
||||
char* env = getenv("XPCOM_BREAK_ON_LOAD");
|
||||
char* blist;
|
||||
if (env && *env && (blist = strdup(env))) {
|
||||
char* nextTok = blist;
|
||||
while (char* token = NS_strtok(":", &nextTok)) {
|
||||
if (leafName.Find(token, true) != kNotFound) {
|
||||
NS_BREAK();
|
||||
}
|
||||
}
|
||||
|
||||
free(blist);
|
||||
}
|
||||
#endif
|
||||
|
||||
void* module = PR_FindSymbol(data.mLibrary, "NSModule");
|
||||
if (!module) {
|
||||
LogMessage("Native module at path '%s' doesn't export symbol `NSModule`.",
|
||||
filePath.get());
|
||||
PR_UnloadLibrary(data.mLibrary);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
data.mModule = *(mozilla::Module const* const*)module;
|
||||
if (mozilla::Module::kVersion != data.mModule->mVersion) {
|
||||
LogMessage("Native module at path '%s' is incompatible with this version of Firefox, has version %i, expected %i.",
|
||||
filePath.get(), data.mModule->mVersion,
|
||||
mozilla::Module::kVersion);
|
||||
PR_UnloadLibrary(data.mLibrary);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mLibraries.Put(hashedFile, data); // infallible
|
||||
return data.mModule;
|
||||
}
|
||||
|
||||
void
|
||||
nsNativeModuleLoader::UnloadLibraries()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Shutdown not on main thread?");
|
||||
|
||||
for (auto iter = mLibraries.Iter(); !iter.Done(); iter.Next()) {
|
||||
NativeLoadData& loadData = iter.Data();
|
||||
loadData.mModule = nullptr;
|
||||
}
|
||||
|
||||
for (auto iter = mLibraries.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (MOZ_LOG_TEST(sNativeModuleLoaderLog, LogLevel::Debug)) {
|
||||
nsIHashable* hashedFile = iter.Key();
|
||||
nsCOMPtr<nsIFile> file(do_QueryInterface(hashedFile));
|
||||
|
||||
nsAutoCString filePath;
|
||||
file->GetNativePath(filePath);
|
||||
|
||||
LOG(LogLevel::Debug,
|
||||
("nsNativeModuleLoader::UnloaderFunc(\"%s\")", filePath.get()));
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
nsTraceRefcnt::SetActivityIsLegal(false);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// XXXbsmedberg: do this as soon as the static-destructor crash(es)
|
||||
// are fixed
|
||||
NativeLoadData& loadData = iter.Data();
|
||||
PRStatus ret = PR_UnloadLibrary(loadData.mLibrary);
|
||||
NS_ASSERTION(ret == PR_SUCCESS, "Failed to unload library");
|
||||
#endif
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
nsTraceRefcnt::SetActivityIsLegal(true);
|
||||
#endif
|
||||
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
39
xpcom/components/nsNativeModuleLoader.h
Normal file
39
xpcom/components/nsNativeModuleLoader.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsNativeModuleLoader_h__
|
||||
#define nsNativeModuleLoader_h__
|
||||
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "prlink.h"
|
||||
|
||||
namespace mozilla {
|
||||
class FileLocation;
|
||||
} // namespace mozilla
|
||||
|
||||
class nsNativeModuleLoader final
|
||||
{
|
||||
public:
|
||||
const mozilla::Module* LoadModule(mozilla::FileLocation& aFile);
|
||||
|
||||
nsresult Init();
|
||||
|
||||
void UnloadLibraries();
|
||||
|
||||
private:
|
||||
struct NativeLoadData
|
||||
{
|
||||
NativeLoadData() : mModule(nullptr), mLibrary(nullptr) {}
|
||||
|
||||
const mozilla::Module* mModule;
|
||||
PRLibrary* mLibrary;
|
||||
};
|
||||
|
||||
nsDataHashtable<nsHashableHashKey, NativeLoadData> mLibraries;
|
||||
};
|
||||
|
||||
#endif /* nsNativeModuleLoader_h__ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue