Bug 977026 - part 3: preload XPT before calling fork. r=bsmedberg

This commit is contained in:
Thinker K.F. Li 2014-07-25 20:52:00 +02:00
parent fbe3632a77
commit 86aa764e48
8 changed files with 360 additions and 35 deletions

View File

@ -5,6 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsXULAppAPI.h"
#include "application.ini.h"
#include "nsXPCOMGlue.h"
#include "nsStringGlue.h"
#include "nsCOMPtr.h"
@ -29,10 +30,16 @@
// Functions being loaded by XPCOMGlue
XRE_ProcLoaderServiceRunType XRE_ProcLoaderServiceRun;
XRE_ProcLoaderClientInitType XRE_ProcLoaderClientInit;
XRE_ProcLoaderPreloadType XRE_ProcLoaderPreload;
extern XRE_CreateAppDataType XRE_CreateAppData;
extern XRE_GetFileFromPathType XRE_GetFileFromPath;
static const nsDynamicFunctionLoad kXULFuncs[] = {
{ "XRE_ProcLoaderServiceRun", (NSFuncPtr*) &XRE_ProcLoaderServiceRun },
{ "XRE_ProcLoaderClientInit", (NSFuncPtr*) &XRE_ProcLoaderClientInit },
{ "XRE_ProcLoaderPreload", (NSFuncPtr*) &XRE_ProcLoaderPreload },
{ "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
{ "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
{ nullptr, nullptr }
};
@ -83,15 +90,89 @@ LoadLibxul(const char *aXPCOMPath)
return true;
}
/**
* Return true if |arg| matches the given argument name.
*/
static bool
LoadStaticData(const char *aProgram)
IsArg(const char* arg, const char* s)
{
if (*arg == '-') {
if (*++arg == '-') {
++arg;
}
return !strcasecmp(arg, s);
}
#if defined(XP_WIN)
if (*arg == '/') {
return !strcasecmp(++arg, s);
}
#endif
return false;
}
static already_AddRefed<nsIFile>
GetAppIni(int argc, const char *argv[])
{
nsCOMPtr<nsIFile> appini;
nsresult rv;
// Allow firefox.exe to launch XULRunner apps via -app <application.ini>
// Note that -app must be the *first* argument.
const char *appDataFile = getenv("XUL_APP_FILE");
if (appDataFile && *appDataFile) {
rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini));
NS_ENSURE_SUCCESS(rv, nullptr);
} else if (argc > 1 && IsArg(argv[1], "app")) {
if (argc == 2) {
return nullptr;
}
rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini));
NS_ENSURE_SUCCESS(rv, nullptr);
char appEnv[MAXPATHLEN];
snprintf(appEnv, MAXPATHLEN, "XUL_APP_FILE=%s", argv[2]);
if (putenv(appEnv)) {
return nullptr;
}
}
return appini.forget();
}
static bool
LoadStaticData(int argc, const char *argv[])
{
char xpcomPath[MAXPATHLEN];
bool ok = GetXPCOMPath(aProgram, xpcomPath, MAXPATHLEN);
bool ok = GetXPCOMPath(argv[0], xpcomPath, MAXPATHLEN);
NS_ENSURE_TRUE(ok, false);
ok = LoadLibxul(xpcomPath);
return ok;
NS_ENSURE_TRUE(ok, false);
char progDir[MAXPATHLEN];
ok = GetDirnameSlash(xpcomPath, progDir, MAXPATHLEN);
NS_ENSURE_TRUE(ok, false);
nsCOMPtr<nsIFile> appini = GetAppIni(argc, argv);
const nsXREAppData *appData;
if (appini) {
nsresult rv =
XRE_CreateAppData(appini, const_cast<nsXREAppData**>(&appData));
NS_ENSURE_SUCCESS(rv, false);
} else {
appData = &sAppData;
}
XRE_ProcLoaderPreload(progDir, appData);
if (appini) {
XRE_FreeAppData(const_cast<nsXREAppData*>(appData));
}
return true;
}
/**
@ -158,7 +239,7 @@ main(int argc, const char* argv[])
* Before fork(), libxul and static data of Gecko are loaded for
* sharing.
*/
bool ok = LoadStaticData(program);
bool ok = LoadStaticData(argc, argv);
if (!ok) {
return 255;
}

View File

@ -160,3 +160,5 @@ if CONFIG['MOZ_ENABLE_XREMOTE']:
'/widget/xremoteclient',
]
if CONFIG['MOZ_B2G_LOADER']:
DEFINES['OMNIJAR_NAME'] = CONFIG['OMNIJAR_NAME']

View File

@ -81,6 +81,11 @@
using mozilla::_ipdltest::IPDLUnitTestProcessChild;
#endif // ifdef MOZ_IPDL_TESTS
#ifdef MOZ_B2G_LOADER
#include "nsLocalFile.h"
#include "nsXREAppData.h"
#endif
using namespace mozilla;
using mozilla::ipc::BrowserProcessSubThread;
@ -815,3 +820,38 @@ XRE_GetWindowsEnvironment()
}
#endif // XP_WIN
#ifdef MOZ_B2G_LOADER
extern const nsXREAppData* gAppData;
/**
* Preload static data of Gecko for B2G loader.
*
* This function is supposed to be called before XPCOM is initialized.
* For now, this function preloads
* - XPT interface Information
*/
void
XRE_ProcLoaderPreload(const char* aProgramDir, const nsXREAppData* aAppData)
{
void PreloadXPT(nsIFile *);
nsresult rv;
nsCOMPtr<nsIFile> omnijarFile;
rv = NS_NewNativeLocalFile(nsCString(aProgramDir),
true,
getter_AddRefs(omnijarFile));
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = omnijarFile->AppendNative(NS_LITERAL_CSTRING(NS_STRINGIFY(OMNIJAR_NAME)));
MOZ_ASSERT(NS_SUCCEEDED(rv));
/*
* gAppData is required by nsXULAppInfo. The manifest parser
* evaluate flags with the information from nsXULAppInfo.
*/
gAppData = aAppData;
PreloadXPT(omnijarFile);
gAppData = nullptr;
}
#endif /* MOZ_B2G_LOADER */

View File

@ -472,6 +472,9 @@ XRE_API(int,
XRE_ProcLoaderServiceRun, (pid_t, int, int argc, const char *argv[]));
XRE_API(void,
XRE_ProcLoaderClientInit, (pid_t, int));
XRE_API(void,
XRE_ProcLoaderPreload, (const char* aProgramDir,
const nsXREAppData* aAppData));
#endif // MOZ_B2G_LOADER
XRE_API(int,

View File

@ -36,6 +36,18 @@
#include "nsIScriptError.h"
#include "nsIXULAppInfo.h"
#include "nsIXULRuntime.h"
#ifdef MOZ_B2G_LOADER
#include "mozilla/XPTInterfaceInfoManager.h"
#endif
#ifdef MOZ_B2G_LOADER
#define XPTONLY_MANIFEST &nsComponentManagerImpl::XPTOnlyManifestManifest
#define XPTONLY_XPT &nsComponentManagerImpl::XPTOnlyManifestXPT
#else
#define XPTONLY_MANIFEST nullptr
#define XPTONLY_XPT nullptr
#endif
using namespace mozilla;
@ -64,36 +76,43 @@ struct ManifestDirective
(nsChromeRegistry::ManifestProcessingContext& cx,
int lineno, char *const *argv,
bool platform, bool contentaccessible);
#ifdef MOZ_B2G_LOADER
// The function to handle the directive for XPT Only parsing.
void (*xptonlyfunc)(nsComponentManagerImpl::XPTOnlyManifestProcessingContext& cx,
int lineno, char *const * argv);
#else
void *xptonlyfunc;
#endif
bool isContract;
};
static const ManifestDirective kParsingTable[] = {
{ "manifest", 1, false, true, true, false,
&nsComponentManagerImpl::ManifestManifest, nullptr },
&nsComponentManagerImpl::ManifestManifest, nullptr, XPTONLY_MANIFEST },
{ "binary-component", 1, true, false, false, false,
&nsComponentManagerImpl::ManifestBinaryComponent, nullptr },
&nsComponentManagerImpl::ManifestBinaryComponent, nullptr, nullptr },
{ "interfaces", 1, true, false, false, false,
&nsComponentManagerImpl::ManifestXPT, nullptr },
&nsComponentManagerImpl::ManifestXPT, nullptr, XPTONLY_XPT },
{ "component", 2, true, false, false, false,
&nsComponentManagerImpl::ManifestComponent, nullptr },
&nsComponentManagerImpl::ManifestComponent, nullptr, nullptr },
{ "contract", 2, true, false, false, false,
&nsComponentManagerImpl::ManifestContract, nullptr, true},
&nsComponentManagerImpl::ManifestContract, nullptr, nullptr, true},
{ "category", 3, true, false, false, false,
&nsComponentManagerImpl::ManifestCategory, nullptr },
&nsComponentManagerImpl::ManifestCategory, nullptr, nullptr },
{ "content", 2, true, true, true, true,
nullptr, &nsChromeRegistry::ManifestContent },
nullptr, &nsChromeRegistry::ManifestContent, nullptr },
{ "locale", 3, true, true, true, false,
nullptr, &nsChromeRegistry::ManifestLocale },
nullptr, &nsChromeRegistry::ManifestLocale, nullptr },
{ "skin", 3, false, true, true, false,
nullptr, &nsChromeRegistry::ManifestSkin },
nullptr, &nsChromeRegistry::ManifestSkin, nullptr },
{ "overlay", 2, true, true, false, false,
nullptr, &nsChromeRegistry::ManifestOverlay },
nullptr, &nsChromeRegistry::ManifestOverlay, nullptr },
{ "style", 2, false, true, false, false,
nullptr, &nsChromeRegistry::ManifestStyle },
nullptr, &nsChromeRegistry::ManifestStyle, nullptr },
{ "override", 2, true, true, true, false,
nullptr, &nsChromeRegistry::ManifestOverride },
nullptr, &nsChromeRegistry::ManifestOverride, nullptr },
{ "resource", 2, true, true, false, false,
nullptr, &nsChromeRegistry::ManifestResource }
nullptr, &nsChromeRegistry::ManifestResource, nullptr }
};
static const char kWhitespace[] = "\t ";
@ -126,8 +145,16 @@ struct AutoPR_smprintf_free
} // anonymous 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)
@ -143,6 +170,10 @@ void LogMessage(const char* aMsg, ...)
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, ...)
{
@ -153,6 +184,10 @@ void LogMessageWithContext(FileLocation &aFile,
if (!formatted)
return;
if (!nsComponentManagerImpl::gComponentManager) {
return;
}
nsCString file;
aFile.GetURIString(file);
@ -388,11 +423,23 @@ struct CachedDirective
} // anonymous 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 type, FileLocation &file, char* buf, bool aChromeOnly)
ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOnly, bool aXPTOnly)
{
nsComponentManagerImpl::ManifestProcessingContext mgrcx(type, file, aChromeOnly);
nsChromeRegistry::ManifestProcessingContext chromecx(type, file);
#ifdef MOZ_B2G_LOADER
nsComponentManagerImpl::XPTOnlyManifestProcessingContext xptonlycx(file);
#endif
nsresult rv;
NS_NAMED_LITERAL_STRING(kPlatform, "platform");
@ -416,7 +463,12 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn
nsAutoString osTarget;
nsAutoString abi;
nsCOMPtr<nsIXULAppInfo> xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
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);
@ -516,9 +568,10 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn
for (const ManifestDirective* d = kParsingTable;
d < ArrayEnd(kParsingTable);
++d) {
if (!strcmp(d->directive, token)) {
directive = d;
break;
if (!strcmp(d->directive, token) &&
(!aXPTOnly || d->xptonlyfunc)) {
directive = d;
break;
}
}
@ -577,8 +630,9 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn
CheckStringFlag(kABI, wtoken, abi, stABI) ||
CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion))
CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion)) {
continue;
}
#if defined(MOZ_WIDGET_ANDROID)
bool tablet = false;
@ -619,6 +673,11 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn
stABI == eBad)
continue;
#ifdef MOZ_B2G_LOADER
if (aXPTOnly) {
directive->xptonlyfunc(xptonlycx, line, argv);
} else
#endif /* MOZ_B2G_LOADER */
if (directive->regfunc) {
if (GeckoProcessType_Default != XRE_GetProcessType())
continue;
@ -636,7 +695,7 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn
(nsChromeRegistry::gChromeRegistry->*(directive->regfunc))
(chromecx, line, argv, platform, contentAccessible);
}
else if (directive->ischrome || !aChromeOnly) {
else if (directive->mgrfunc && (directive->ischrome || !aChromeOnly)) {
if (directive->isContract) {
CachedDirective* cd = contracts.AppendElement();
cd->lineno = line;
@ -646,6 +705,9 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn
else
(nsComponentManagerImpl::gComponentManager->*(directive->mgrfunc))
(mgrcx, line, argv);
} else {
LogMessageWithContext(file, line,
"No valid manifest directive.");
}
}

View File

@ -13,7 +13,7 @@
class nsIFile;
void ParseManifest(NSLocationType type, mozilla::FileLocation &file,
char* buf, bool aChromeOnly);
char* buf, bool aChromeOnly, bool aXPTOnly=false);
void LogMessage(const char* aMsg, ...);

View File

@ -69,6 +69,7 @@
#include "nsStringEnumerator.h"
#include "mozilla/FileUtils.h"
#include "nsNetUtil.h"
#include "nsDataHashtable.h"
#include <new> // for placement new
@ -104,6 +105,36 @@ NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID);
#define UID_STRING_LENGTH 39
#ifdef MOZ_B2G_LOADER
typedef nsDataHashtable<nsCStringHashKey, bool> XPTIInfosBookType;
static XPTIInfosBookType *sXPTIInfosBook = nullptr;
static XPTIInfosBookType *
GetXPTIInfosBook()
{
if (sXPTIInfosBook == nullptr) {
sXPTIInfosBook = new XPTIInfosBookType;
}
return sXPTIInfosBook;
}
static bool
IsRegisteredXPTIInfo(FileLocation &aFile)
{
nsAutoCString uri;
aFile.GetURIString(uri);
return GetXPTIInfosBook()->Get(uri);
}
static void
MarkRegisteredXPTIInfo(FileLocation &aFile)
{
nsAutoCString uri;
aFile.GetURIString(uri);
GetXPTIInfosBook()->Put(uri, true);
}
#endif /* MOZ_B2G_LOADER */
nsresult
nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
{
@ -524,11 +555,14 @@ CutExtension(nsCString& path)
path.Cut(0, dotPos + 1);
}
void
nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
FileLocation &aFile,
bool aChromeOnly)
static void
DoRegisterManifest(NSLocationType aType,
FileLocation &aFile,
bool aChromeOnly,
bool aXPTOnly)
{
MOZ_ASSERT(!aXPTOnly ||
nsComponentManagerImpl::gComponentManager == nullptr);
uint32_t len;
FileLocation::Data data;
nsAutoArrayPtr<char> buf;
@ -542,7 +576,7 @@ nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
}
if (NS_SUCCEEDED(rv)) {
buf[len] = '\0';
ParseManifest(aType, aFile, buf, aChromeOnly);
ParseManifest(aType, aFile, buf, aChromeOnly, aXPTOnly);
} else if (NS_BOOTSTRAPPED_LOCATION != aType) {
nsCString uri;
aFile.GetURIString(uri);
@ -550,6 +584,14 @@ nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
}
}
void
nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
FileLocation &aFile,
bool aChromeOnly)
{
DoRegisterManifest(aType, aFile, aChromeOnly, false);
}
void
nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& cx, int lineno, char *const * argv)
{
@ -587,14 +629,19 @@ nsComponentManagerImpl::ManifestBinaryComponent(ManifestProcessingContext& cx, i
RegisterModule(m, &f);
}
void
nsComponentManagerImpl::ManifestXPT(ManifestProcessingContext& cx, int lineno, char *const * argv)
static void
DoRegisterXPT(FileLocation &aFile)
{
FileLocation f(cx.mFile, argv[0]);
#ifdef MOZ_B2G_LOADER
if (IsRegisteredXPTIInfo(aFile)) {
return;
}
#endif
uint32_t len;
FileLocation::Data data;
nsAutoArrayPtr<char> buf;
nsresult rv = f.GetData(data);
nsresult rv = aFile.GetData(data);
if (NS_SUCCEEDED(rv)) {
rv = data.GetSize(&len);
}
@ -604,13 +651,23 @@ nsComponentManagerImpl::ManifestXPT(ManifestProcessingContext& cx, int lineno, c
}
if (NS_SUCCEEDED(rv)) {
XPTInterfaceInfoManager::GetSingleton()->RegisterBuffer(buf, len);
#ifdef MOZ_B2G_LOADER
MarkRegisteredXPTIInfo(aFile);
#endif
} else {
nsCString uri;
f.GetURIString(uri);
aFile.GetURIString(uri);
LogMessage("Could not read '%s'.", uri.get());
}
}
void
nsComponentManagerImpl::ManifestXPT(ManifestProcessingContext& cx, int lineno, char *const * argv)
{
FileLocation f(cx.mFile, argv[0]);
DoRegisterXPT(f);
}
void
nsComponentManagerImpl::ManifestComponent(ManifestProcessingContext& cx, int lineno, char *const * argv)
{
@ -794,6 +851,10 @@ nsresult nsComponentManagerImpl::Shutdown(void)
delete sStaticModules;
delete sModuleLocations;
#ifdef MOZ_B2G_LOADER
delete sXPTIInfosBook;
sXPTIInfosBook = nullptr;
#endif
// Unload libraries
mNativeModuleLoader.UnloadLibraries();
@ -1942,6 +2003,54 @@ nsComponentManagerImpl::GetManifestLocations(nsIArray **aLocations)
return NS_OK;
}
#ifdef MOZ_B2G_LOADER
/* static */
void
nsComponentManagerImpl::XPTOnlyManifestManifest(XPTOnlyManifestProcessingContext &aCx,
int aLineno,
char * const * aArgv)
{
char* file = aArgv[0];
FileLocation f(aCx.mFile, file);
DoRegisterManifest(NS_COMPONENT_LOCATION, f, false, true);
}
/* static */
void
nsComponentManagerImpl::XPTOnlyManifestXPT(XPTOnlyManifestProcessingContext &aCx,
int aLineno,
char * const * aArgv)
{
FileLocation f(aCx.mFile, aArgv[0]);
DoRegisterXPT(f);
}
/**
* To load XPT Interface Information before the component manager is ready.
*
* With this function, B2G loader could XPT interface info. as earier
* as possible to gain benefit of shared memory model of the kernel.
*/
/* static */ void
nsComponentManagerImpl::PreloadXPT(nsIFile *aFile)
{
MOZ_ASSERT(nsComponentManagerImpl::gComponentManager == nullptr);
FileLocation location(aFile, "chrome.manifest");
DoRegisterManifest(NS_COMPONENT_LOCATION, location,
false, true /* aXPTOnly */);
}
void
PreloadXPT(nsIFile *aOmnijarFile)
{
nsComponentManagerImpl::PreloadXPT(aOmnijarFile);
}
#endif /* MOZ_B2G_LOADER */
EXPORT_XPCOM_API(nsresult)
XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation)
{

View File

@ -38,6 +38,10 @@
#include "mozilla/Omnijar.h"
#include "mozilla/Attributes.h"
#ifdef MOZ_B2G_LOADER
#include "mozilla/FileLocation.h"
#endif
struct nsFactoryEntry;
class nsIServiceManager;
struct PRThread;
@ -316,6 +320,30 @@ public:
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
#ifdef MOZ_B2G_LOADER
// Preload XPT interface info for B2G loader.
// This function is called before XPCOM has been initialized.
static void PreloadXPT(nsIFile *aFile);
#endif
#ifdef MOZ_B2G_LOADER
// Parsing functions of directives of manifest for XPT only parsing.
struct XPTOnlyManifestProcessingContext
{
XPTOnlyManifestProcessingContext(mozilla::FileLocation &aFile)
: mFile(aFile)
{ }
~XPTOnlyManifestProcessingContext() { }
mozilla::FileLocation mFile;
};
static void XPTOnlyManifestManifest(XPTOnlyManifestProcessingContext& aCx,
int aLineno, char * const *aArgv);
static void XPTOnlyManifestXPT(XPTOnlyManifestProcessingContext& aCx,
int aLineno, char * const *aArgv);
#endif
private:
~nsComponentManagerImpl();
};