Bug 1306327 - build a mozilla::Bootstrap API which is used by the various stubs to initialize gecko and run the main loop. Sandboxing init, which is statically linked, still runs in each stub separately. r?glandium draft
authorBenjamin Smedberg <benjamin@smedbergs.us>
Mon, 14 Nov 2016 09:44:47 -0500
changeset 441690 754bf8c90a86d4620def06d18c2263e898771c83
parent 441689 6b0073bf98f3ab3b694761730eb196b2c439c5b3
child 441691 e1c42db6dd0f245925ddc835306b5bb2f57398e0
push id36494
push userbmo:benjamin@smedbergs.us
push dateSun, 20 Nov 2016 20:48:29 +0000
reviewersglandium
bugs1306327
milestone53.0a1
Bug 1306327 - build a mozilla::Bootstrap API which is used by the various stubs to initialize gecko and run the main loop. Sandboxing init, which is statically linked, still runs in each stub separately. r?glandium UNRESOLVED ISSUES: * LIBFUZZER config is probably broken but I'm not sure how to test MozReview-Commit-ID: JsJEWy4pfLb
browser/app/nsBrowserApp.cpp
dom/media/gmp/GMPLoader.cpp
dom/media/gmp/GMPLoader.h
intl/lwbrk/gtest/moz.build
ipc/app/MozillaRuntimeMain.cpp
ipc/contentproc/moz.build
ipc/contentproc/plugin-container.cpp
ipc/moz.build
js/xpconnect/shell/xpcshell.cpp
toolkit/xre/Bootstrap.cpp
toolkit/xre/Bootstrap.h
toolkit/xre/moz.build
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsAppRunner.h
xpcom/build/BinaryPath.h
xpcom/glue/standalone/nsXPCOMGlue.cpp
xpcom/glue/standalone/nsXPCOMGlue.h
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -1,51 +1,43 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "nsXULAppAPI.h"
-#include "mozilla/AppData.h"
+#include "mozilla/Bootstrap.h"
+#include "mozilla/StartupTimeline.h"
 #include "application.ini.h"
 #include "nsXPCOMGlue.h"
+
 #if defined(XP_WIN)
 #include <windows.h>
 #include <stdlib.h>
 #elif defined(XP_UNIX)
 #include <sys/resource.h>
 #include <unistd.h>
 #endif
 
 #include <stdio.h>
 #include <stdarg.h>
 #include <time.h>
 
-#include "nsCOMPtr.h"
-#include "nsIFile.h"
-#include "nsStringGlue.h"
-
 #ifdef XP_WIN
-#ifdef MOZ_ASAN
-// ASAN requires firefox.exe to be built with -MD, and it's OK if we don't
-// support Windows XP SP2 in ASAN builds.
-#define XRE_DONT_SUPPORT_XPSP2
-#endif
 #define XRE_WANT_ENVIRON
+#include "nsWindowsWMain.cpp"
 #define strcasecmp _stricmp
 #ifdef MOZ_SANDBOX
 #include "mozilla/sandboxing/SandboxInitialization.h"
+#include "mozilla/sandboxing/sandboxLogging.h"
 #endif
 #endif
 #include "BinaryPath.h"
 
 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
 
-#include "mozilla/Sprintf.h"
-#include "mozilla/Telemetry.h"
 #include "mozilla/WindowsDllBlocklist.h"
 
 #ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR
 #include <cpuid.h>
 #include "mozilla/Unused.h"
 
 static bool
 IsSSE2Available()
@@ -84,29 +76,18 @@ SSE2Check()
   MOZ_UNUSED(write(STDERR_FILENO,
                    sSSE2Message,
                    MOZ_ARRAY_LENGTH(sSSE2Message) - 1));
   // _exit() instead of exit() to avoid running the usual "at exit" code.
   _exit(255);
 }
 #endif
 
-#if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID) \
-  && !(defined(XP_LINUX) && defined(MOZ_SANDBOX))
-#define MOZ_BROWSER_CAN_BE_CONTENTPROC
-#include "../../ipc/contentproc/plugin-container.cpp"
-#endif
-
 using namespace mozilla;
 
-#ifdef XP_MACOSX
-#define kOSXResourcesFolder "Resources"
-#endif
-#define kDesktopFolder "browser"
-
 static void Output(const char *fmt, ... )
 {
   va_list ap;
   va_start(ap, fmt);
 
 #ifndef XP_WIN
   vfprintf(stderr, fmt, ap);
 #else
@@ -137,16 +118,17 @@ static void Output(const char *fmt, ... 
     FreeLibrary(user32);
   }
 #endif
 #endif
 
   va_end(ap);
 }
 
+#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
 /**
  * Return true if |arg| matches the given argument name.
  */
 static bool IsArg(const char* arg, const char* s)
 {
   if (*arg == '-')
   {
     if (*++arg == '-')
@@ -156,254 +138,84 @@ static bool IsArg(const char* arg, const
 
 #if defined(XP_WIN)
   if (*arg == '/')
     return !strcasecmp(++arg, s);
 #endif
 
   return false;
 }
-
-XRE_GetFileFromPathType XRE_GetFileFromPath;
-XRE_CreateAppDataType XRE_CreateAppData;
-XRE_FreeAppDataType XRE_FreeAppData;
-XRE_TelemetryAccumulateType XRE_TelemetryAccumulate;
-XRE_StartupTimelineRecordType XRE_StartupTimelineRecord;
-XRE_mainType XRE_main;
-XRE_StopLateWriteChecksType XRE_StopLateWriteChecks;
-XRE_XPCShellMainType XRE_XPCShellMain;
-XRE_GetProcessTypeType XRE_GetProcessType;
-XRE_SetProcessTypeType XRE_SetProcessType;
-XRE_InitChildProcessType XRE_InitChildProcess;
-XRE_EnableSameExecutableForContentProcType XRE_EnableSameExecutableForContentProc;
-#ifdef LIBFUZZER
-XRE_LibFuzzerSetMainType XRE_LibFuzzerSetMain;
-XRE_LibFuzzerGetFuncsType XRE_LibFuzzerGetFuncs;
 #endif
 
-static const nsDynamicFunctionLoad kXULFuncs[] = {
-    { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
-    { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
-    { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
-    { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
-    { "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord },
-    { "XRE_main", (NSFuncPtr*) &XRE_main },
-    { "XRE_StopLateWriteChecks", (NSFuncPtr*) &XRE_StopLateWriteChecks },
-    { "XRE_XPCShellMain", (NSFuncPtr*) &XRE_XPCShellMain },
-    { "XRE_GetProcessType", (NSFuncPtr*) &XRE_GetProcessType },
-    { "XRE_SetProcessType", (NSFuncPtr*) &XRE_SetProcessType },
-    { "XRE_InitChildProcess", (NSFuncPtr*) &XRE_InitChildProcess },
-    { "XRE_EnableSameExecutableForContentProc", (NSFuncPtr*) &XRE_EnableSameExecutableForContentProc },
-#ifdef LIBFUZZER
-    { "XRE_LibFuzzerSetMain", (NSFuncPtr*) &XRE_LibFuzzerSetMain },
-    { "XRE_LibFuzzerGetFuncs", (NSFuncPtr*) &XRE_LibFuzzerGetFuncs },
-#endif
-    { nullptr, nullptr }
-};
-
 #ifdef LIBFUZZER
 int libfuzzer_main(int argc, char **argv);
 
 /* This wrapper is used by the libFuzzer main to call into libxul */
 
 void libFuzzerGetFuncs(const char* moduleName, LibFuzzerInitFunc* initFunc,
                        LibFuzzerTestingFunc* testingFunc) {
   return XRE_LibFuzzerGetFuncs(moduleName, initFunc, testingFunc);
 }
 #endif
 
-static int do_main(int argc, char* argv[], char* envp[], nsIFile *xreDirectory)
-{
-  nsCOMPtr<nsIFile> appini;
-  nsresult rv;
-  uint32_t mainFlags = 0;
-
-  // 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));
-    if (NS_FAILED(rv)) {
-      Output("Invalid path found: '%s'", appDataFile);
-      return 255;
-    }
-  }
-  else if (argc > 1 && IsArg(argv[1], "app")) {
-    if (argc == 2) {
-      Output("Incorrect number of arguments passed to -app");
-      return 255;
-    }
-
-    rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini));
-    if (NS_FAILED(rv)) {
-      Output("application.ini path not recognized: '%s'", argv[2]);
-      return 255;
-    }
-
-    char appEnv[MAXPATHLEN];
-    SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]);
-    if (putenv(strdup(appEnv))) {
-      Output("Couldn't set %s.\n", appEnv);
-      return 255;
-    }
-    argv[2] = argv[0];
-    argv += 2;
-    argc -= 2;
-  } else if (argc > 1 && IsArg(argv[1], "xpcshell")) {
-    for (int i = 1; i < argc; i++) {
-      argv[i] = argv[i + 1];
-    }
-
-    XREShellData shellData;
-#if defined(XP_WIN) && defined(MOZ_SANDBOX)
-    shellData.sandboxBrokerServices =
-      sandboxing::GetInitializedBrokerServices();
-#endif
-
-    return XRE_XPCShellMain(--argc, argv, envp, &shellData);
-  }
-
-  if (appini) {
-    nsXREAppData *appData;
-    rv = XRE_CreateAppData(appini, &appData);
-    if (NS_FAILED(rv)) {
-      Output("Couldn't read application.ini");
-      return 255;
-    }
-#if defined(HAS_DLL_BLOCKLIST)
-    // The dll blocklist operates in the exe vs. xullib. Pass a flag to
-    // xullib so automated tests can check the result once the browser
-    // is up and running.
-    appData->flags |=
-      DllBlocklist_CheckStatus() ? NS_XRE_DLL_BLOCKLIST_ENABLED : 0;
-#endif
-    // xreDirectory already has a refcount from NS_NewLocalFile
-    appData->xreDirectory = xreDirectory;
-    int result = XRE_main(argc, argv, appData, mainFlags);
-    XRE_FreeAppData(appData);
-    return result;
-  }
-
-  ScopedAppData appData(&sAppData);
-  nsCOMPtr<nsIFile> exeFile;
-  rv = mozilla::BinaryPath::GetFile(argv[0], getter_AddRefs(exeFile));
-  if (NS_FAILED(rv)) {
-    Output("Couldn't find the application directory.\n");
-    return 255;
-  }
-
-  nsCOMPtr<nsIFile> greDir;
-  exeFile->GetParent(getter_AddRefs(greDir));
-#ifdef XP_MACOSX
-  greDir->SetNativeLeafName(NS_LITERAL_CSTRING(kOSXResourcesFolder));
-#endif
-  nsCOMPtr<nsIFile> appSubdir;
-  greDir->Clone(getter_AddRefs(appSubdir));
-  appSubdir->Append(NS_LITERAL_STRING(kDesktopFolder));
-
-  SetStrongPtr(appData.directory, static_cast<nsIFile*>(appSubdir.get()));
-  // xreDirectory already has a refcount from NS_NewLocalFile
-  appData.xreDirectory = xreDirectory;
-
-#if defined(HAS_DLL_BLOCKLIST)
-  appData.flags |=
-    DllBlocklist_CheckStatus() ? NS_XRE_DLL_BLOCKLIST_ENABLED : 0;
-#endif
-
-#if defined(XP_WIN) && defined(MOZ_SANDBOX)
-  sandbox::BrokerServices* brokerServices =
-    sandboxing::GetInitializedBrokerServices();
-#if defined(MOZ_CONTENT_SANDBOX)
-  if (!brokerServices) {
-    Output("Couldn't initialize the broker services.\n");
-    return 255;
-  }
-#endif
-  appData.sandboxBrokerServices = brokerServices;
-#endif
-
-#ifdef LIBFUZZER
-  if (getenv("LIBFUZZER"))
-    XRE_LibFuzzerSetMain(argc, argv, libfuzzer_main);
-#endif
-
-  return XRE_main(argc, argv, &appData, mainFlags);
-}
 
 static bool
 FileExists(const char *path)
 {
 #ifdef XP_WIN
   wchar_t wideDir[MAX_PATH];
   MultiByteToWideChar(CP_UTF8, 0, path, -1, wideDir, MAX_PATH);
   DWORD fileAttrs = GetFileAttributesW(wideDir);
   return fileAttrs != INVALID_FILE_ATTRIBUTES;
 #else
   return access(path, R_OK) == 0;
 #endif
 }
 
-static nsresult
-InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory)
+static Bootstrap::UniquePtr
+InitXPCOMGlue(const char *argv0)
 {
   char exePath[MAXPATHLEN];
 
   nsresult rv = mozilla::BinaryPath::Get(argv0, exePath);
   if (NS_FAILED(rv)) {
     Output("Couldn't find the application directory.\n");
-    return rv;
+    return nullptr;
   }
 
   char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
   if (!lastSlash ||
       (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_DLL) - 1))
-    return NS_ERROR_FAILURE;
+    return nullptr;
 
   strcpy(lastSlash + 1, XPCOM_DLL);
 
   if (!FileExists(exePath)) {
     Output("Could not find the Mozilla runtime.\n");
-    return NS_ERROR_FAILURE;
+    return nullptr;
   }
 
   // We do this because of data in bug 771745
   XPCOMGlueEnablePreload();
 
-  rv = XPCOMGlueStartup(exePath);
-  if (NS_FAILED(rv)) {
+  Bootstrap::UniquePtr b = XPCOMGlueStartup(exePath);
+  if (!b) {
     Output("Couldn't load XPCOM.\n");
-    return rv;
-  }
-
-  rv = XPCOMGlueLoadXULFunctions(kXULFuncs);
-  if (NS_FAILED(rv)) {
-    Output("Couldn't load XRE functions.\n");
-    return rv;
+    return nullptr;
   }
 
-  // This will set this thread as the main thread.
-  NS_LogInit();
-
-  if (xreDirectory) {
-    // chop XPCOM_DLL off exePath
-    *lastSlash = '\0';
+  // chop XPCOM_DLL off exePath
+  *lastSlash = '\0';
 #ifdef XP_MACOSX
-    lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
-    strcpy(lastSlash + 1, kOSXResourcesFolder);
+  lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
+  strcpy(lastSlash + 1, kOSXResourcesFolder);
 #endif
-#ifdef XP_WIN
-    rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(exePath), false,
-                         xreDirectory);
-#else
-    rv = NS_NewNativeLocalFile(nsDependentCString(exePath), false,
-                               xreDirectory);
-#endif
-  }
 
-  return rv;
+  b->SetXREDirectory(exePath);
+  return b;
 }
 
 int main(int argc, char* argv[], char* envp[])
 {
   mozilla::TimeStamp start = mozilla::TimeStamp::Now();
 
 #ifdef HAS_DLL_BLOCKLIST
   DllBlocklist_Initialize();
@@ -412,64 +224,59 @@ int main(int argc, char* argv[], char* e
   // In order to be effective against AppInit DLLs, the blocklist must be
   // initialized before user32.dll is loaded into the process (bug 932100).
   if (GetModuleHandleA("user32.dll")) {
     fprintf(stderr, "DLL blocklist was unable to intercept AppInit DLLs.\n");
   }
 #endif
 #endif
 
+  bool contentproc = false;
+
 #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
-  // We are launching as a content process, delegate to the appropriate
-  // main
-  if (argc > 1 && IsArg(argv[1], "contentproc")) {
+  contentproc = argc > 1 && IsArg(argv[1], "contentproc");
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  sandbox::TargetServices* targetServices = nullptr;
+  if (contentproc) {
     // We need to initialize the sandbox TargetServices before InitXPCOMGlue
     // because we might need the sandbox broker to give access to some files.
-    if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) {
-      Output("Failed to initialize the sandbox target services.");
-      return 255;
+    if (IsSandboxedProcess()) {
+      targetServices = sandboxing::GetInitializedTargetServices();
+      if (!targetServices) {
+        Output("Failed to initialize the sandbox target services.");
+        return 255;
+      }
     }
+  }
+#endif
 #endif
 
-    nsresult rv = InitXPCOMGlue(argv[0], nullptr);
-    if (NS_FAILED(rv)) {
-      return 255;
-    }
-
-    int result = content_process_main(argc, argv);
-
-    // InitXPCOMGlue calls NS_LogInit, so we need to balance it here.
-    NS_LogTerm();
+  // We are launching as a content process, delegate to the appropriate
+  // main
 
-    return result;
-  }
-#endif
-
-
-  nsIFile *xreDirectory;
-
-  nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory);
-  if (NS_FAILED(rv)) {
+  Bootstrap::UniquePtr bootstrap = InitXPCOMGlue(argv[0]);
+  if (!bootstrap) {
     return 255;
   }
 
-  XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
+  bootstrap->SetDefaultAppData(sAppData);
+  bootstrap->StartupTimelineRecord(mozilla::StartupTimeline::START, start);
 
-#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
-  XRE_EnableSameExecutableForContentProc();
+#ifdef HAS_DLL_BLOCKLIST
+  bootstrap->SetBlocklistEnabled(DllBlocklist_CheckStatus());
 #endif
 
-  int result = do_main(argc, argv, envp, xreDirectory);
-
-  NS_LogTerm();
-
-#ifdef XP_MACOSX
-  // Allow writes again. While we would like to catch writes from static
-  // destructors to allow early exits to use _exit, we know that there is
-  // at least one such write that we don't control (see bug 826029). For
-  // now we enable writes again and early exits will have to use exit instead
-  // of _exit.
-  XRE_StopLateWriteChecks();
+  int result;
+  if (contentproc) {
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+    bootstrap->SetSandboxTarget(targetServices);
+    bootstrap->SetSandboxLogger(mozilla::sandboxing::ProvideLogFunction);
 #endif
+    result = bootstrap->ContentProcessMain(argc, argv);
+  } else {
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+    bootstrap->SetSandboxBroker(sandboxing::GetInitializedBrokerServices());
+#endif
+    result = bootstrap->AppMain(argc, argv, envp);
+  }
 
   return result;
 }
--- a/dom/media/gmp/GMPLoader.cpp
+++ b/dom/media/gmp/GMPLoader.cpp
@@ -19,18 +19,18 @@
 
 #include "GMPDeviceBinding.h"
 
 namespace mozilla {
 namespace gmp {
 
 class GMPLoaderImpl : public GMPLoader {
 public:
-  explicit GMPLoaderImpl(SandboxStarter* aStarter)
-    : mSandboxStarter(aStarter)
+  explicit GMPLoaderImpl(UniquePtr<SandboxStarter> aStarter)
+    : mSandboxStarter(Move(aStarter))
     , mAdapter(nullptr)
   {}
   ~GMPLoaderImpl() override = default;
 
   bool Load(const char* aUTF8LibPath,
             uint32_t aUTF8LibPathLen,
             char* aOriginSalt,
             uint32_t aOriginSaltLen,
@@ -44,22 +44,22 @@ public:
 
   void Shutdown() override;
 
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override;
 #endif
 
 private:
-  SandboxStarter* mSandboxStarter;
+  UniquePtr<SandboxStarter> mSandboxStarter;
   UniquePtr<GMPAdapter> mAdapter;
 };
 
-UniquePtr<GMPLoader> CreateGMPLoader(SandboxStarter* aStarter) {
-  return MakeUnique<GMPLoaderImpl>(aStarter);
+UniquePtr<GMPLoader> CreateGMPLoader(UniquePtr<SandboxStarter> aStarter) {
+  return MakeUnique<GMPLoaderImpl>(Move(aStarter));
 }
 
 class PassThroughGMPAdapter : public GMPAdapter {
 public:
   ~PassThroughGMPAdapter() override {
     // Ensure we're always shutdown, even if caller forgets to call GMPShutdown().
     GMPShutdown();
   }
--- a/dom/media/gmp/GMPLoader.h
+++ b/dom/media/gmp/GMPLoader.h
@@ -100,14 +100,14 @@ public:
   // sandbox, which we don't yet know when the GMPLoader and SandboxStarter
   // objects are created.
   virtual void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) = 0;
 #endif
 };
 
 // On Desktop, this function resides in plugin-container.
 // On Mobile, this function resides in XUL.
-UniquePtr<GMPLoader> CreateGMPLoader(SandboxStarter* aStarter);
+UniquePtr<GMPLoader> CreateGMPLoader(UniquePtr<SandboxStarter> aStarter);
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMP_LOADER_H__
--- a/intl/lwbrk/gtest/moz.build
+++ b/intl/lwbrk/gtest/moz.build
@@ -4,9 +4,8 @@
 # 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/.
 
 UNIFIED_SOURCES += [
     'TestLineBreak.cpp',
 ]
 
 FINAL_LIBRARY = 'xul-gtest'
-
--- a/ipc/app/MozillaRuntimeMain.cpp
+++ b/ipc/app/MozillaRuntimeMain.cpp
@@ -1,19 +1,131 @@
 /* -*- 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 "../contentproc/plugin-container.cpp"
+#include "GMPLoader.h"
+#include "mozilla/Bootstrap.h"
+#include "mozilla/WindowsDllBlocklist.h"
+
+#ifdef XP_WIN
+#include <windows.h>
+// we want a wmain entry point
+// but we don't want its DLL load protection, because some plugins can't do it;
+// we'll handle that in ContentProcessMain.
+#define XRE_DONT_PROTECT_DLL_LOAD
+#include "nsWindowsWMain.cpp"
+#else
+#include <unistd.h>
+#endif
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+#include "mozilla/sandboxing/SandboxInitialization.h"
+#include "mozilla/sandboxing/sandboxLogging.h"
+#endif
+
+#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+#include "mozilla/Sandbox.h"
+#include "mozilla/SandboxInfo.h"
+#endif
+
+using namespace mozilla;
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+class WinSandboxStarter : public mozilla::gmp::SandboxStarter {
+public:
+    virtual bool Start(const char *aLibPath) override {
+        if (IsSandboxedProcess()) {
+            mozilla::sandboxing::LowerSandbox();
+        }
+        return true;
+    }
+};
+#endif
 
-#include "mozilla/WindowsDllBlocklist.h"
+#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+class LinuxSandboxStarter : public mozilla::gmp::SandboxStarter {
+    LinuxSandboxStarter() { }
+public:
+    static UniquePtr<SandboxStarter> Make() {
+        if (mozilla::SandboxInfo::Get().CanSandboxMedia()) {
+            return UniquePtr<SandboxStarter>(new LinuxSandboxStarter());
+        } else {
+            // Sandboxing isn't possible, but the parent has already
+            // checked that this plugin doesn't require it.  (Bug 1074561)
+            return nullptr;
+        }
+    }
+    virtual bool Start(const char *aLibPath) override {
+        mozilla::SetMediaPluginSandbox(aLibPath);
+        return true;
+    }
+};
+#endif
+
+#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
+class MacSandboxStarter : public mozilla::gmp::SandboxStarter {
+public:
+    virtual bool Start(const char *aLibPath) override {
+      std::string err;
+      bool rv = mozilla::StartMacSandbox(mInfo, err);
+      if (!rv) {
+        fprintf(stderr, "sandbox_init() failed! Error \"%s\"\n", err.c_str());
+      }
+      return rv;
+    }
+    virtual void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override {
+      mInfo = *aSandboxInfo;
+    }
+private:
+  MacSandboxInfo mInfo;
+};
+#endif
+
+UniquePtr<mozilla::gmp::SandboxStarter>
+MakeSandboxStarter()
+{
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+    return MakeUnique<WinSandboxStarter>();
+#elif defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+    return LinuxSandboxStarter::Make();
+#elif defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
+    return MakeUnique<MacSandboxStarter>();
+#else
+    return nullptr;
+#endif
+}
 
 int
 main(int argc, char *argv[])
 {
 #ifdef HAS_DLL_BLOCKLIST
   DllBlocklist_Initialize();
 #endif
 
-  return content_process_main(argc, argv);
+  Bootstrap::UniquePtr bootstrap;
+  XRE_GetBootstrap(bootstrap);
+  if (!bootstrap) {
+    return 1;
+  }
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  // We need to initialize the sandbox TargetServices before InitXPCOMGlue
+  // because we might need the sandbox broker to give access to some files.
+  if (IsSandboxedProcess()) {
+    sandbox::TargetServices* targetServices = sandboxing::GetInitializedTargetServices();
+    if (!targetServices) {
+      return 255;
+    }
+    bootstrap->SetSandboxTarget(targetServices);
+    bootstrap->SetSandboxLogger(mozilla::sandboxing::ProvideLogFunction);
+  }
+#endif
+#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK) && defined(MOZ_PLUGIN_CONTAINER)
+  // On desktop, the GMPLoader lives in plugin-container, so that its
+  // code can be covered by an EME/GMP vendor's voucher.
+  bootstrap->SetGMPLoader(mozilla::gmp::CreateGMPLoader(MakeSandboxStarter()));
+#endif
+
+  return bootstrap->ContentProcessMain(argc, argv);
 }
deleted file mode 100644
--- a/ipc/contentproc/moz.build
+++ /dev/null
@@ -1,25 +0,0 @@
-# -*- 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/.
-
-Library('plugin-container')
-
-SOURCES += [
-    'plugin-container.cpp',
-]
-
-include('/ipc/chromium/chromium-config.mozbuild')
-
-if CONFIG['OS_ARCH'] == 'WINNT':
-    LOCAL_INCLUDES += [
-        '/toolkit/xre',
-        '/xpcom/base',
-    ]
-
-if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
-    LOCAL_INCLUDES += [
-        '/security/sandbox/chromium',
-        '/security/sandbox/chromium-shim',
-    ]
deleted file mode 100644
--- a/ipc/contentproc/plugin-container.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: sw=4 ts=4 et :
- * 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 "nsXPCOM.h"
-#include "nsXULAppAPI.h"
-#include "nsAutoPtr.h"
-
-#ifdef XP_WIN
-#include <windows.h>
-// we want a wmain entry point
-// but we don't want its DLL load protection, because we'll handle it here
-#define XRE_DONT_PROTECT_DLL_LOAD
-#include "nsWindowsWMain.cpp"
-#include "nsSetDllDirectory.h"
-#else
-// FIXME/cjones testing
-#include <unistd.h>
-#endif
-
-#include "GMPLoader.h"
-
-#if defined(XP_WIN) && defined(MOZ_SANDBOX)
-#include "mozilla/sandboxing/SandboxInitialization.h"
-#include "mozilla/sandboxing/sandboxLogging.h"
-#endif
-
-#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
-#include "mozilla/Sandbox.h"
-#include "mozilla/SandboxInfo.h"
-#endif
-
-#ifdef MOZ_WIDGET_GONK
-# include <sys/time.h>
-# include <sys/resource.h> 
-
-# include <binder/ProcessState.h>
-
-# ifdef LOGE_IF
-#  undef LOGE_IF
-# endif
-
-# include <android/log.h>
-# define LOGE_IF(cond, ...) \
-     ( (CONDITION(cond)) \
-     ? ((void)__android_log_print(ANDROID_LOG_ERROR, \
-       "Gecko:MozillaRntimeMain", __VA_ARGS__)) \
-     : (void)0 )
-
-# ifdef MOZ_CONTENT_SANDBOX
-# include "mozilla/Sandbox.h"
-# endif
-
-#endif // MOZ_WIDGET_GONK
-
-#ifdef MOZ_WIDGET_GONK
-static void
-InitializeBinder(void *aDummy) {
-    // Change thread priority to 0 only during calling ProcessState::self().
-    // The priority is registered to binder driver and used for default Binder
-    // Thread's priority. 
-    // To change the process's priority to small value need's root permission.
-    int curPrio = getpriority(PRIO_PROCESS, 0);
-    int err = setpriority(PRIO_PROCESS, 0, 0);
-    MOZ_ASSERT(!err);
-    LOGE_IF(err, "setpriority failed. Current process needs root permission.");
-    android::ProcessState::self()->startThreadPool();
-    setpriority(PRIO_PROCESS, 0, curPrio);
-}
-#endif
-
-#if defined(XP_WIN) && defined(MOZ_SANDBOX)
-class WinSandboxStarter : public mozilla::gmp::SandboxStarter {
-public:
-    virtual bool Start(const char *aLibPath) override {
-        if (IsSandboxedProcess()) {
-            mozilla::sandboxing::LowerSandbox();
-        }
-        return true;
-    }
-};
-#endif
-
-#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
-class LinuxSandboxStarter : public mozilla::gmp::SandboxStarter {
-    LinuxSandboxStarter() { }
-public:
-    static SandboxStarter* Make() {
-        if (mozilla::SandboxInfo::Get().CanSandboxMedia()) {
-            return new LinuxSandboxStarter();
-        } else {
-            // Sandboxing isn't possible, but the parent has already
-            // checked that this plugin doesn't require it.  (Bug 1074561)
-            return nullptr;
-        }
-    }
-    virtual bool Start(const char *aLibPath) override {
-        mozilla::SetMediaPluginSandbox(aLibPath);
-        return true;
-    }
-};
-#endif
-
-#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
-class MacSandboxStarter : public mozilla::gmp::SandboxStarter {
-public:
-    virtual bool Start(const char *aLibPath) override {
-      std::string err;
-      bool rv = mozilla::StartMacSandbox(mInfo, err);
-      if (!rv) {
-        fprintf(stderr, "sandbox_init() failed! Error \"%s\"\n", err.c_str());
-      }
-      return rv;
-    }
-    virtual void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override {
-      mInfo = *aSandboxInfo;
-    }
-private:
-  MacSandboxInfo mInfo;
-};
-#endif
-
-mozilla::gmp::SandboxStarter*
-MakeSandboxStarter()
-{
-#if defined(XP_WIN) && defined(MOZ_SANDBOX)
-    return new WinSandboxStarter();
-#elif defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
-    return LinuxSandboxStarter::Make();
-#elif defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
-    return new MacSandboxStarter();
-#else
-    return nullptr;
-#endif
-}
-
-int
-content_process_main(int argc, char* argv[])
-{
-    // Check for the absolute minimum number of args we need to move
-    // forward here. We expect the last arg to be the child process type.
-    if (argc < 1) {
-      return 3;
-    }
-
-    XREChildData childData;
-
-#if defined(XP_WIN) && defined(MOZ_SANDBOX)
-    if (IsSandboxedProcess()) {
-        childData.sandboxTargetServices =
-            mozilla::sandboxing::GetInitializedTargetServices();
-        if (!childData.sandboxTargetServices) {
-            return 1;
-        }
-
-        childData.ProvideLogFunction = mozilla::sandboxing::ProvideLogFunction;
-    }
-#endif
-
-    XRE_SetProcessType(argv[--argc]);
-
-#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
-    // This has to happen while we're still single-threaded, and on
-    // B2G that means before the Android Binder library is
-    // initialized.
-    mozilla::SandboxEarlyInit(XRE_GetProcessType());
-#endif
-
-#ifdef MOZ_WIDGET_GONK
-    // This creates a ThreadPool for binder ipc. A ThreadPool is necessary to
-    // receive binder calls, though not necessary to send binder calls.
-    // ProcessState::Self() also needs to be called once on the main thread to
-    // register the main thread with the binder driver.
-
-    InitializeBinder(nullptr);
-#endif
-
-#ifdef XP_WIN
-    // For plugins, this is done in PluginProcessChild::Init, as we need to
-    // avoid it for unsupported plugins.  See PluginProcessChild::Init for
-    // the details.
-    if (XRE_GetProcessType() != GeckoProcessType_Plugin) {
-        mozilla::SanitizeEnvironmentVariables();
-        SetDllDirectoryW(L"");
-    }
-#endif
-#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK) && defined(MOZ_PLUGIN_CONTAINER)
-    // On desktop, the GMPLoader lives in plugin-container, so that its
-    // code can be covered by an EME/GMP vendor's voucher.
-    nsAutoPtr<mozilla::gmp::SandboxStarter> starter(MakeSandboxStarter());
-    if (XRE_GetProcessType() == GeckoProcessType_GMPlugin) {
-        childData.gmpLoader = mozilla::gmp::CreateGMPLoader(starter);
-    }
-#endif
-    nsresult rv = XRE_InitChildProcess(argc, argv, &childData);
-    NS_ENSURE_SUCCESS(rv, 1);
-
-    return 0;
-}
--- a/ipc/moz.build
+++ b/ipc/moz.build
@@ -15,15 +15,12 @@ if CONFIG['MOZ_ENABLE_DBUS']:
     DIRS += ['dbus']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     DIRS += ['unixfd', 'unixsocket']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     DIRS += ['hal', 'keystore', 'netd']
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
-    DIRS += ['contentproc']
-
 if CONFIG['OS_ARCH'] == 'WINNT':
     DIRS += ['mscom']
 
 DIRS += ['app']
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -3,19 +3,19 @@
 /* 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/. */
 
 /* XPConnect JavaScript interactive shell. */
 
 #include <stdio.h>
 
+#include "mozilla/Bootstrap.h"
 #include "mozilla/WindowsDllBlocklist.h"
 
-#include "nsXULAppAPI.h"
 #ifdef XP_MACOSX
 #include "xpcshellMacUtils.h"
 #endif
 #ifdef XP_WIN
 #include <windows.h>
 #include <shlobj.h>
 
 // we want a wmain entry point
@@ -26,16 +26,18 @@
 #include "mozilla/sandboxing/SandboxInitialization.h"
 #endif
 #endif
 
 #ifdef MOZ_WIDGET_GTK
 #include <gtk/gtk.h>
 #endif
 
+using namespace mozilla;
+
 int
 main(int argc, char** argv, char** envp)
 {
 #ifdef MOZ_WIDGET_GTK
     // A default display may or may not be required for xpcshell tests, and so
     // is not created here. Instead we set the command line args, which is a
     // fairly cheap operation.
     gtk_parse_args(&argc, &argv);
@@ -48,22 +50,26 @@ main(int argc, char** argv, char** envp)
     // unbuffer stdout so that output is in the correct order; note that stderr
     // is unbuffered by default
     setbuf(stdout, 0);
 
 #ifdef HAS_DLL_BLOCKLIST
     DllBlocklist_Initialize();
 #endif
 
-    XREShellData shellData;
+    Bootstrap::UniquePtr bootstrap;
+    XRE_GetBootstrap(bootstrap);
+    if (!bootstrap) {
+        fprintf(stderr, "Error: unable to initialize XUL bootstrap.");
+        return 1;
+    }
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
-    shellData.sandboxBrokerServices =
-      mozilla::sandboxing::GetInitializedBrokerServices();
+    bootstrap->SetSandboxBroker(mozilla::sandboxing::GetInitializedBrokerServices());
 #endif
 
-    int result = XRE_XPCShellMain(argc, argv, envp, &shellData);
+    int result = bootstrap->XPCShellMain(argc, argv, envp);
 
 #ifdef XP_MACOSX
     FinishAutoreleasePool();
 #endif
 
     return result;
 }
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/Bootstrap.cpp
@@ -0,0 +1,320 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/Bootstrap.h"
+
+#include "BinaryPath.h"
+#include "mozilla/AppData.h"
+#include "mozilla/Sprintf.h"
+#include "nsAppRunner.h"
+#include "nsCOMPtr.h"
+#include "nsIFile.h"
+#include "nsString.h"
+#include "nsXULAppAPI.h"
+
+#ifdef XP_WIN
+#include "nsSetDllDirectory.h"
+#endif
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+#include "mozilla/sandboxing/SandboxInitialization.h"
+#endif
+
+#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+#include "mozilla/Sandbox.h"
+#include "mozilla/SandboxInfo.h"
+#endif
+
+#define kDesktopFolder "browser"
+
+#ifdef XP_WIN
+#define strcasecmp _stricmp
+#endif
+
+namespace mozilla {
+
+class BootstrapImpl final : public Bootstrap
+{
+public:
+  BootstrapImpl()
+    : mStaticAppData(nullptr)
+    , mBlocklistEnabled(false)
+  {
+    NS_LogInit();
+  }
+  ~BootstrapImpl()
+  {
+  }
+
+  virtual void Dispose() override
+  {
+    delete this;
+
+    // Terminate logging here instead of the destructor because there are
+    // logged members that are cleaned up.
+    NS_LogTerm();
+
+#ifdef XP_MACOSX
+    // Allow writes again. While we would like to catch writes from static
+    // destructors to allow early exits to use _exit, we know that there is
+    // at least one such write that we don't control (see bug 826029). For
+    // now we enable writes again and early exits will have to use exit instead
+    // of _exit.
+    XRE_StopLateWriteChecks();
+#endif
+  }
+
+  virtual void SetDefaultAppData(const nsXREAppData& staticAppData) override
+  {
+    mStaticAppData = &staticAppData;
+  }
+
+  virtual void SetXREDirectory(const char* directory) override;
+  virtual void SetBlocklistEnabled(bool enabled) override
+  {
+    mBlocklistEnabled = enabled;
+  }
+  virtual void StartupTimelineRecord(int event, mozilla::TimeStamp when) override
+  {
+    XRE_StartupTimelineRecord(event, when);
+  }
+
+#ifdef BOOTSTRAP_HAS_GMPLOADER
+  virtual void SetGMPLoader(mozilla::UniquePtr<mozilla::gmp::GMPLoader> gmpLoader) override
+  {
+    mChildData.gmpLoader = Move(gmpLoader);
+  }
+#endif
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  virtual void SetSandboxTarget(sandbox::TargetServices* target) override
+  {
+    mChildData.sandboxTargetServices = target;
+  }
+  virtual void SetSandboxLogger(mozilla::sandboxing::ProvideLogFunctionCb callback) override
+  {
+    mChildData.ProvideLogFunction = callback;
+  }
+
+  virtual void SetSandboxBroker(sandbox::BrokerServices* broker) override
+  {
+    mSandboxBroker = broker;
+  }
+#endif
+
+  virtual int AppMain(int argc, char* argv[], char* envp[]) override;
+  virtual int ContentProcessMain(int argc, char* argv[]) override;
+  virtual int XPCShellMain(int argc, char* argv[], char* envp[]) override;
+
+private:
+  const nsXREAppData* mStaticAppData;
+  nsCOMPtr<nsIFile> mXREDirectory;
+  XREChildData mChildData;
+  bool mBlocklistEnabled;
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  sandbox::BrokerServices* mSandboxBroker = nullptr;
+#endif
+};
+
+void
+BootstrapImpl::SetXREDirectory(const char* directory)
+{
+#ifdef XP_WIN
+  NS_NewLocalFile(NS_ConvertUTF8toUTF16(directory), false,
+                  getter_AddRefs(mXREDirectory));
+#else
+  NS_NewNativeLocalFile(nsDependentCString(directory), false,
+                        getter_AddRefs(mXREDirectory));
+#endif
+}
+
+/**
+ * Return true if |arg| matches the given argument name.
+ */
+static bool 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;
+}
+
+int
+BootstrapImpl::AppMain(int argc, char* argv[], char* envp[])
+{
+  nsCOMPtr<nsIFile> appini;
+  nsresult rv;
+  uint32_t mainFlags = 0;
+
+#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
+  XRE_EnableSameExecutableForContentProc();
+#endif
+
+  // 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));
+    if (NS_FAILED(rv)) {
+      Output(false, "Invalid path found: '%s'", appDataFile);
+      return 255;
+    }
+  }
+  else if (argc > 1 && IsArg(argv[1], "app")) {
+    if (argc == 2) {
+      Output(false, "Incorrect number of arguments passed to -app");
+      return 255;
+    }
+
+    rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini));
+    if (NS_FAILED(rv)) {
+      Output(false, "application.ini path not recognized: '%s'", argv[2]);
+      return 255;
+    }
+
+    char appEnv[MAXPATHLEN];
+    SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]);
+    if (putenv(strdup(appEnv))) {
+      Output(false, "Couldn't set %s.\n", appEnv);
+      return 255;
+    }
+    argv[2] = argv[0];
+    argv += 2;
+    argc -= 2;
+  } else if (argc > 1 && IsArg(argv[1], "xpcshell")) {
+    for (int i = 1; i < argc; i++) {
+      argv[i] = argv[i + 1];
+    }
+
+    return XPCShellMain(--argc, argv, envp);
+  }
+
+  if (appini) {
+    nsXREAppData *appData;
+    rv = XRE_CreateAppData(appini, &appData);
+    if (NS_FAILED(rv)) {
+      Output(false, "Couldn't read application.ini");
+      return 255;
+    }
+    if (mBlocklistEnabled) {
+      appData->flags |= NS_XRE_DLL_BLOCKLIST_ENABLED;
+    }
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+    appData->sandboxBrokerServices = mSandboxBroker;
+#endif
+
+    SetStrongPtr(appData->xreDirectory, mXREDirectory.get());
+    int result = XRE_main(argc, argv, appData, mainFlags);
+    XRE_FreeAppData(appData);
+    return result;
+  }
+
+  ScopedAppData appData(mStaticAppData);
+  nsCOMPtr<nsIFile> exeFile;
+  rv = mozilla::BinaryPath::GetFile(argv[0], getter_AddRefs(exeFile));
+  if (NS_FAILED(rv)) {
+    Output(false, "Couldn't find the application directory.\n");
+    return 255;
+  }
+
+  nsCOMPtr<nsIFile> greDir;
+  exeFile->GetParent(getter_AddRefs(greDir));
+#ifdef XP_MACOSX
+  greDir->SetNativeLeafName(NS_LITERAL_CSTRING(kOSXResourcesFolder));
+#endif
+  nsCOMPtr<nsIFile> appSubdir;
+  greDir->Clone(getter_AddRefs(appSubdir));
+  appSubdir->Append(NS_LITERAL_STRING(kDesktopFolder));
+
+  SetStrongPtr(appData.directory, appSubdir.get());
+  SetStrongPtr(appData.xreDirectory, mXREDirectory.get());
+
+  if (mBlocklistEnabled) {
+    appData.flags |= NS_XRE_DLL_BLOCKLIST_ENABLED;
+  }
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  appData.sandboxBrokerServices = mSandboxBroker;
+#endif
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
+  if (!mSandboxBroker) {
+    Output(false, "Couldn't initialize the broker services.\n");
+    return 255;
+  }
+#endif
+
+#ifdef LIBFUZZER
+  if (getenv("LIBFUZZER"))
+    XRE_LibFuzzerSetMain(argc, argv, libfuzzer_main);
+#endif
+
+  return XRE_main(argc, argv, &appData, mainFlags);
+}
+
+int
+BootstrapImpl::ContentProcessMain(int argc, char* argv[])
+{
+  // Check for the absolute minimum number of args we need to move
+  // forward here. We expect the last arg to be the child process type.
+  if (argc < 1) {
+    return 3;
+  }
+
+  XRE_SetProcessType(argv[--argc]);
+
+#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+  // This has to happen while we're still single-threaded, and on
+  // B2G that means before the Android Binder library is
+  // initialized.
+  mozilla::SandboxEarlyInit(XRE_GetProcessType());
+#endif
+
+#ifdef XP_WIN
+  // For plugins, this is done in PluginProcessChild::Init, as we need to
+  // avoid it for unsupported plugins.  See PluginProcessChild::Init for
+  // the details.
+  if (XRE_GetProcessType() != GeckoProcessType_Plugin) {
+    mozilla::SanitizeEnvironmentVariables();
+    SetDllDirectoryW(L"");
+  }
+#endif
+  nsresult rv = XRE_InitChildProcess(argc, argv, &mChildData);
+  NS_ENSURE_SUCCESS(rv, 1);
+
+  return 0;
+}
+
+int
+BootstrapImpl::XPCShellMain(int argc, char* argv[], char* envp[])
+{
+  XREShellData shellData;
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  shellData.sandboxBrokerServices = mSandboxBroker;
+#endif
+  return XRE_XPCShellMain(argc, argv, envp, &shellData);
+}
+
+static bool gBootstrapInitialized;
+
+extern "C" NS_EXPORT void NS_FROZENCALL
+XRE_GetBootstrap(Bootstrap::UniquePtr& b)
+{
+  MOZ_RELEASE_ASSERT(!gBootstrapInitialized);
+  gBootstrapInitialized = true;
+  b.reset(new BootstrapImpl());
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/Bootstrap.h
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 file represents the only external interface exposed from libxul. It
+ * is used by the various stub binaries (nsBrowserApp, xpcshell,
+ * plugin-container) to initialize XPCOM and start their main loop.
+ */
+
+#ifndef mozilla_Bootstrap_h
+#define mozilla_Bootstrap_h
+
+#include "GMPLoader.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/UniquePtr.h"
+#include "nscore.h"
+#include "nsXREAppData.h"
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+#include "mozilla/sandboxing/SandboxInitialization.h"
+#include "mozilla/sandboxing/loggingTypes.h"
+#endif
+
+#if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID) \
+  && !(defined(XP_LINUX) && defined(MOZ_SANDBOX))
+#define MOZ_BROWSER_CAN_BE_CONTENTPROC
+#endif
+
+#ifdef XP_MACOSX
+#define kOSXResourcesFolder "Resources"
+#endif
+
+#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK)
+#define BOOTSTRAP_HAS_GMPLOADER
+#endif
+
+namespace mozilla {
+
+/**
+ * This class is virtual abstract so that using it does not require linking
+ * any symbols. The singleton instance of this class is obtained from the
+ * exported method XRE_GetBootstrap.
+ */
+class Bootstrap
+{
+protected:
+  Bootstrap() { }
+
+  // Because of allocator mismatches, code outside libxul shouldn't delete a
+  // Bootstrap instance. Use Dispose().
+  virtual ~Bootstrap() { }
+
+public:
+  /**
+   * Destroy and deallocate this Bootstrap instance.
+   */
+  virtual void Dispose() = 0;
+
+  /**
+   * Helper class to use with UniquePtr.
+   */
+  class BootstrapDelete
+  {
+  public:
+    constexpr BootstrapDelete() { }
+    void operator()(Bootstrap* aPtr) const
+    {
+      aPtr->Dispose();
+    }
+  };
+  typedef mozilla::UniquePtr<Bootstrap, BootstrapDelete> UniquePtr;
+
+  /**
+   * Set the default (compiled-in) browser app data that is used if the command
+   * line doens't contain an -app override.
+   */
+  virtual void SetDefaultAppData(const nsXREAppData& staticAppData) = 0;
+
+  /**
+   * The calling app has to let us know where it found the platform DLLs.
+   */
+  virtual void SetXREDirectory(const char* directory) = 0;
+
+  /**
+   * For later telemetry and unit testing, we record whether the blocklist
+   * was enabled successfully.
+   */
+  virtual void SetBlocklistEnabled(bool enabled) = 0;
+
+  /**
+   * Record startup timeline events that happened before XUL loaded.
+   */
+  virtual void StartupTimelineRecord(int event, mozilla::TimeStamp when) = 0;
+
+#ifdef BOOTSTRAP_HAS_GMPLOADER
+  /**
+   * On desktop, the GMPLoader lives in plugin-container, so that its code
+   * can be covered by an EME/GMP vendor's voucher.
+   */
+  virtual void SetGMPLoader(mozilla::UniquePtr<mozilla::gmp::GMPLoader> gmpLoader) = 0;
+#endif
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  /**
+   * For sandboxed child processes, the sandbox target services and logging
+   * are initialized before XUL is loaded and passed in here.
+   */
+  virtual void SetSandboxTarget(sandbox::TargetServices*) = 0;
+  virtual void SetSandboxLogger(mozilla::sandboxing::ProvideLogFunctionCb callback) = 0;
+
+  /**
+   * For parent (main/xpcshell) processes, the sandbox broker services are
+   * initialized before XUL is loaded and passed in here.
+   */
+  virtual void SetSandboxBroker(sandbox::BrokerServices*) = 0;
+#endif
+
+  /**
+   * The guts of starting up the main browser app.
+   */
+  virtual int AppMain(int argc, char* argv[], char* envp[]) = 0;
+  virtual int ContentProcessMain(int argc, char* argv[]) = 0;
+  virtual int XPCShellMain(int argc, char* argv[], char* envp[]) = 0;
+};
+
+/**
+ * Creates and returns the singleton instnace of the bootstrap object.
+ * @param `b` is an outparam. We use a parameter and not a return value
+ *        because MSVC doesn't let us return a c++ class from a function with
+ *        "C" linkage. On failure this will be null.
+ * @note This function may only be called once and will crash if called again.
+ * @note this function will initialize logging and set the XPCOM "main thread".
+ * @note Use the virtual destructor on the returned object before exiting
+ *       the process.
+ */
+extern "C" NS_EXPORT void NS_FROZENCALL
+XRE_GetBootstrap(Bootstrap::UniquePtr& b);
+typedef void (*GetBootstrapType)(Bootstrap::UniquePtr&);
+
+} // namespace mozilla
+
+#endif // mozilla_Bootstrap_h
--- a/toolkit/xre/moz.build
+++ b/toolkit/xre/moz.build
@@ -17,16 +17,17 @@ XPIDL_SOURCES += [
 if CONFIG['OS_ARCH'] == 'WINNT':
     XPIDL_SOURCES += [
         'nsIWinAppHelper.idl',
     ]
 
 XPIDL_MODULE = 'xulapp'
 
 EXPORTS += ['nsAppRunner.h']
+EXPORTS.mozilla += ['Bootstrap.h']
 
 if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']:
     EXPORTS += ['EventTracer.h']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     UNIFIED_SOURCES += [
         'nsNativeAppSupportWin.cpp',
     ]
@@ -64,16 +65,17 @@ if CONFIG['MOZ_X11']:
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     UNIFIED_SOURCES += [
         'nsAndroidStartup.cpp',
     ]
 
 UNIFIED_SOURCES += [
+    'Bootstrap.cpp',
     'CreateAppData.cpp',
     'nsConsoleWriter.cpp',
     'nsNativeAppSupportBase.cpp',
     'nsSigHandlers.cpp',
     'nsXREDirProvider.cpp',
 ]
 
 # nsAppRunner.cpp and ProfileReset.cpp cannot be built in unified mode because
@@ -140,16 +142,17 @@ if CONFIG['MOZ_BUILD_APP'] == 'browser':
 
 LOCAL_INCLUDES += [
     '../profile',
     '/config',
     '/dom/base',
     '/dom/ipc',
     '/testing/gtest/mozilla',
     '/toolkit/crashreporter',
+    '/xpcom/base',
     '/xpcom/build',
 ]
 
 if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
     LOCAL_INCLUDES += [
         '/security/sandbox/chromium',
         '/security/sandbox/chromium-shim',
     ]
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -410,26 +410,18 @@ void MozExpectedExit() {
  */
 static void UnexpectedExit() {
   if (!gIsExpectedExit) {
     gIsExpectedExit = true; // Don't risk re-entrency issues when crashing.
     MOZ_CRASH("Exit called by third party code.");
   }
 }
 
-/**
- * Output a string to the user.  This method is really only meant to be used to
- * output last-ditch error messages designed for developers NOT END USERS.
- *
- * @param isError
- *        Pass true to indicate severe errors.
- * @param fmt
- *        printf-style format string followed by arguments.
- */
-static void Output(bool isError, const char *fmt, ... )
+void
+Output(bool isError, const char *fmt, ... )
 {
   va_list ap;
   va_start(ap, fmt);
 
 #if defined(XP_WIN) && !MOZ_WINCONSOLE
   char *msg = PR_vsmprintf(fmt, ap);
   if (msg)
   {
--- a/toolkit/xre/nsAppRunner.h
+++ b/toolkit/xre/nsAppRunner.h
@@ -111,16 +111,27 @@ UseParentConsole();
 BOOL
 WinLaunchChild(const wchar_t *exePath, int argc,
                char **argv, HANDLE userToken = nullptr,
                HANDLE *hProcess = nullptr);
 #endif
 
 #define NS_NATIVEAPPSUPPORT_CONTRACTID "@mozilla.org/toolkit/native-app-support;1"
 
+/**
+ * Output a string to the user.  This method is really only meant to be used to
+ * output last-ditch error messages designed for developers NOT END USERS.
+ *
+ * @param isError
+ *        Pass true to indicate severe errors.
+ * @param fmt
+ *        printf-style format string followed by arguments.
+ */
+void Output(bool isError, const char* fmt, ...);
+
 namespace mozilla {
 namespace startup {
 extern GeckoProcessType sChildProcessType;
 } // namespace startup
 } // namespace mozilla
 
 /**
  * Set up platform specific error handling such as suppressing DLL load dialog
--- a/xpcom/build/BinaryPath.h
+++ b/xpcom/build/BinaryPath.h
@@ -12,16 +12,22 @@
 #include <windows.h>
 #elif defined(XP_MACOSX)
 #include <CoreFoundation/CoreFoundation.h>
 #elif defined(XP_UNIX)
 #include <sys/stat.h>
 #include <string.h>
 #endif
 
+#ifdef MOZILLA_INTERNAL_API
+#include "nsIFile.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#endif
+
 namespace mozilla {
 
 class BinaryPath
 {
 public:
 #ifdef XP_WIN
   static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
   {
@@ -150,16 +156,17 @@ private:
     return NS_ERROR_FAILURE;
   }
 
 #else
 #error Oops, you need platform-specific code here
 #endif
 
 public:
+#ifdef MOZILLA_INTERNAL_API
   static nsresult GetFile(const char* aArgv0, nsIFile** aResult)
   {
     nsCOMPtr<nsIFile> lf;
 #ifdef XP_WIN
     wchar_t exePath[MAXPATHLEN];
     nsresult rv = GetW(aArgv0, exePath);
 #else
     char exePath[MAXPATHLEN];
@@ -176,13 +183,14 @@ public:
                                getter_AddRefs(lf));
 #endif
     if (NS_FAILED(rv)) {
       return rv;
     }
     NS_ADDREF(*aResult = lf);
     return NS_OK;
   }
+#endif // MOZILLA_INTERNAL_API
 };
 
 } // namespace mozilla
 
 #endif /* mozilla_BinaryPath_h */
--- a/xpcom/glue/standalone/nsXPCOMGlue.cpp
+++ b/xpcom/glue/standalone/nsXPCOMGlue.cpp
@@ -12,33 +12,43 @@
 #include "nsXPCOMPrivate.h"
 #include "nsCOMPtr.h"
 #include <stdlib.h>
 #include <stdio.h>
 
 #include "mozilla/FileUtils.h"
 #include "mozilla/Sprintf.h"
 
-using namespace mozilla;
+#ifdef XP_WIN
+#include <windows.h>
+#include <mbstring.h>
+#else
+#include <dlfcn.h>
+#endif
+
+#if defined(MOZ_WIDGET_GTK) && (defined(MOZ_MEMORY) || defined(__FreeBSD__) || defined(__NetBSD__))
+#define MOZ_GSLICE_INIT
+#include <glib.h>
+#endif
+
+namespace mozilla {
+
+typedef void (*NSFuncPtr)();
 
 #define XPCOM_DEPENDENT_LIBS_LIST "dependentlibs.list"
 
-static XPCOMFunctions xpcomFunctions;
 static bool do_preload = false;
 
 #if defined(XP_WIN)
 #define READ_TEXTMODE L"rt"
 #else
 #define READ_TEXTMODE "r"
 #endif
 
 #if defined(XP_WIN)
-#include <windows.h>
-#include <mbstring.h>
-
 typedef HINSTANCE LibHandleType;
 
 static LibHandleType
 GetLibHandle(pathstr_t aDependentLib)
 {
   LibHandleType libHandle =
     LoadLibraryExW(aDependentLib, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
 
@@ -65,26 +75,17 @@ GetLibHandle(pathstr_t aDependentLib)
   return libHandle;
 }
 
 static NSFuncPtr
 GetSymbol(LibHandleType aLibHandle, const char* aSymbol)
 {
   return (NSFuncPtr)GetProcAddress(aLibHandle, aSymbol);
 }
-
-static void
-CloseLibHandle(LibHandleType aLibHandle)
-{
-  FreeLibrary(aLibHandle);
-}
-
 #else
-#include <dlfcn.h>
-
 #if defined(MOZ_LINKER) && !defined(ANDROID)
 extern "C" {
 NS_HIDDEN __typeof(dlopen) __wrap_dlopen;
 NS_HIDDEN __typeof(dlsym) __wrap_dlsym;
 NS_HIDDEN __typeof(dlclose) __wrap_dlclose;
 }
 
 #define dlopen __wrap_dlopen
@@ -110,22 +111,16 @@ GetLibHandle(pathstr_t aDependentLib)
   return libHandle;
 }
 
 static NSFuncPtr
 GetSymbol(LibHandleType aLibHandle, const char* aSymbol)
 {
   return (NSFuncPtr)dlsym(aLibHandle, aSymbol);
 }
-
-static void
-CloseLibHandle(LibHandleType aLibHandle)
-{
-  dlclose(aLibHandle);
-}
 #endif
 
 struct DependentLib
 {
   LibHandleType libHandle;
   DependentLib* next;
 };
 
@@ -192,29 +187,16 @@ struct ScopedCloseFileTraits
   {
     if (aFile) {
       fclose(aFile);
     }
   }
 };
 typedef Scoped<ScopedCloseFileTraits> ScopedCloseFile;
 
-static void
-XPCOMGlueUnload()
-{
-  while (sTop) {
-    CloseLibHandle(sTop->libHandle);
-
-    DependentLib* temp = sTop;
-    sTop = sTop->next;
-
-    delete temp;
-  }
-}
-
 #if defined(XP_WIN)
 // like strpbrk but finds the *last* char, not the first
 static const char*
 ns_strrpbrk(const char* string, const char* strCharSet)
 {
   const char* found = nullptr;
   for (; *string; ++string) {
     for (const char* search = strCharSet; *search; ++search) {
@@ -225,17 +207,17 @@ ns_strrpbrk(const char* string, const ch
       }
     }
   }
 
   return found;
 }
 #endif
 
-static GetFrozenFunctionsFunc
+static GetBootstrapType
 XPCOMGlueLoad(const char* aXPCOMFile)
 {
   char xpcomDir[MAXPATHLEN];
 #ifdef XP_WIN
   const char* lastSlash = ns_strrpbrk(aXPCOMFile, "/\\");
 #elif XP_MACOSX
   // On OSX, the dependentlibs.list file lives under Contents/Resources.
   // However, the actual libraries listed in dependentlibs.list live under
@@ -316,612 +298,64 @@ XPCOMGlueLoad(const char* aXPCOMFile)
     }
 
     if (l + size_t(cursor - xpcomDir) > MAXPATHLEN) {
       return nullptr;
     }
 
     strcpy(cursor, buffer);
     if (!ReadDependentCB(xpcomDir, do_preload)) {
-      XPCOMGlueUnload();
       return nullptr;
     }
   }
 
-  GetFrozenFunctionsFunc sym =
-    (GetFrozenFunctionsFunc)GetSymbol(sTop->libHandle,
-                                      "NS_GetFrozenFunctions");
-
-  if (!sym) { // No symbol found.
-    XPCOMGlueUnload();
-    return nullptr;
-  }
+  GetBootstrapType sym = reinterpret_cast<GetBootstrapType>(
+    GetSymbol(sTop->libHandle, "XRE_GetBootstrap"));
 
   return sym;
 }
 
-nsresult
-XPCOMGlueLoadXULFunctions(const nsDynamicFunctionLoad* aSymbols)
-{
-  // We don't null-check sXULLibHandle because this might work even
-  // if it is null (same as RTLD_DEFAULT)
-
-  nsresult rv = NS_OK;
-  while (aSymbols->functionName) {
-    char buffer[512];
-    SprintfLiteral(buffer, "%s", aSymbols->functionName);
-
-    *aSymbols->function = (NSFuncPtr)GetSymbol(sTop->libHandle, buffer);
-    if (!*aSymbols->function) {
-      rv = NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
-    }
-
-    ++aSymbols;
-  }
-  return rv;
-}
-
 void
 XPCOMGlueEnablePreload()
 {
   do_preload = true;
 }
 
-#if defined(MOZ_WIDGET_GTK) && (defined(MOZ_MEMORY) || defined(__FreeBSD__) || defined(__NetBSD__))
-#define MOZ_GSLICE_INIT
+#ifdef MOZ_GSLICE_INIT
+
+void
+GSliceInit()
+{
+  if (!bool(getenv("G_SLICE"))) {
+    // Disable the slice allocator, since jemalloc already uses similar layout
+    // algorithms, and using a sub-allocator tends to increase fragmentation.
+    // This must be done before g_thread_init() is called.
+    // glib >= 2.36 initializes g_slice as a side effect of its various static
+    // initializers, so this needs to happen before glib is loaded, which is
+    // this is hooked in XPCOMGlueStartup before libxul is loaded. This
+    // relies on the main executable not depending on glib.
+    setenv("G_SLICE", "always-malloc", 1);
+  }
+}
 #endif
 
-#ifdef MOZ_GSLICE_INIT
-#include <glib.h>
-
-class GSliceInit {
-public:
-  GSliceInit() {
-    mHadGSlice = bool(getenv("G_SLICE"));
-    if (!mHadGSlice) {
-      // Disable the slice allocator, since jemalloc already uses similar layout
-      // algorithms, and using a sub-allocator tends to increase fragmentation.
-      // This must be done before g_thread_init() is called.
-      // glib >= 2.36 initializes g_slice as a side effect of its various static
-      // initializers, so this needs to happen before glib is loaded, which is
-      // this is hooked in XPCOMGlueStartup before libxul is loaded. This
-      // relies on the main executable not depending on glib.
-      setenv("G_SLICE", "always-malloc", 1);
-    }
-  }
-
-  ~GSliceInit() {
-#if MOZ_WIDGET_GTK == 2
-    if (sTop) {
-      auto XRE_GlibInit = (void (*)(void)) GetSymbol(sTop->libHandle,
-        "XRE_GlibInit");
-      // Initialize glib enough for G_SLICE to have an effect before it is unset.
-      // unset.
-      XRE_GlibInit();
-    }
-#endif
-    if (!mHadGSlice) {
-      unsetenv("G_SLICE");
-    }
-  }
-
-private:
-  bool mHadGSlice;
-};
-#endif
-
-nsresult
+Bootstrap::UniquePtr
 XPCOMGlueStartup(const char* aXPCOMFile)
 {
 #ifdef MOZ_GSLICE_INIT
-  GSliceInit gSliceInit;
+  GSliceInit();
 #endif
-  xpcomFunctions.version = XPCOM_GLUE_VERSION;
-  xpcomFunctions.size    = sizeof(XPCOMFunctions);
 
   if (!aXPCOMFile) {
     aXPCOMFile = XPCOM_DLL;
   }
 
-  GetFrozenFunctionsFunc func = XPCOMGlueLoad(aXPCOMFile);
+  GetBootstrapType func = XPCOMGlueLoad(aXPCOMFile);
   if (!func) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  nsresult rv = (*func)(&xpcomFunctions, nullptr);
-  if (NS_FAILED(rv)) {
-    XPCOMGlueUnload();
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-XPCOM_API(nsresult)
-NS_InitXPCOM2(nsIServiceManager** aResult,
-              nsIFile* aBinDirectory,
-              nsIDirectoryServiceProvider* aAppFileLocationProvider)
-{
-  if (!xpcomFunctions.init) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.init(aResult, aBinDirectory, aAppFileLocationProvider);
-}
-
-XPCOM_API(nsresult)
-NS_ShutdownXPCOM(nsIServiceManager* aServMgr)
-{
-  if (!xpcomFunctions.shutdown) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.shutdown(aServMgr);
-}
-
-XPCOM_API(nsresult)
-NS_GetServiceManager(nsIServiceManager** aResult)
-{
-  if (!xpcomFunctions.getServiceManager) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.getServiceManager(aResult);
-}
-
-XPCOM_API(nsresult)
-NS_GetComponentManager(nsIComponentManager** aResult)
-{
-  if (!xpcomFunctions.getComponentManager) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.getComponentManager(aResult);
-}
-
-XPCOM_API(nsresult)
-NS_GetComponentRegistrar(nsIComponentRegistrar** aResult)
-{
-  if (!xpcomFunctions.getComponentRegistrar) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.getComponentRegistrar(aResult);
-}
-
-XPCOM_API(nsresult)
-NS_GetMemoryManager(nsIMemory** aResult)
-{
-  if (!xpcomFunctions.getMemoryManager) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.getMemoryManager(aResult);
-}
-
-XPCOM_API(nsresult)
-NS_NewLocalFile(const nsAString& aPath, bool aFollowLinks, nsIFile** aResult)
-{
-  if (!xpcomFunctions.newLocalFile) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.newLocalFile(aPath, aFollowLinks, aResult);
-}
-
-XPCOM_API(nsresult)
-NS_NewNativeLocalFile(const nsACString& aPath, bool aFollowLinks,
-                      nsIFile** aResult)
-{
-  if (!xpcomFunctions.newNativeLocalFile) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.newNativeLocalFile(aPath, aFollowLinks, aResult);
-}
-
-XPCOM_API(nsresult)
-NS_GetDebug(nsIDebug2** aResult)
-{
-  if (!xpcomFunctions.getDebug) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.getDebug(aResult);
-}
-
-
-XPCOM_API(nsresult)
-NS_StringContainerInit(nsStringContainer& aStr)
-{
-  if (!xpcomFunctions.stringContainerInit) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.stringContainerInit(aStr);
-}
-
-XPCOM_API(nsresult)
-NS_StringContainerInit2(nsStringContainer& aStr, const char16_t* aData,
-                        uint32_t aDataLength, uint32_t aFlags)
-{
-  if (!xpcomFunctions.stringContainerInit2) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.stringContainerInit2(aStr, aData, aDataLength, aFlags);
-}
-
-XPCOM_API(void)
-NS_StringContainerFinish(nsStringContainer& aStr)
-{
-  if (xpcomFunctions.stringContainerFinish) {
-    xpcomFunctions.stringContainerFinish(aStr);
-  }
-}
-
-XPCOM_API(uint32_t)
-NS_StringGetData(const nsAString& aStr, const char16_t** aBuf, bool* aTerm)
-{
-  if (!xpcomFunctions.stringGetData) {
-    *aBuf = nullptr;
-    return 0;
-  }
-  return xpcomFunctions.stringGetData(aStr, aBuf, aTerm);
-}
-
-XPCOM_API(uint32_t)
-NS_StringGetMutableData(nsAString& aStr, uint32_t aLen, char16_t** aBuf)
-{
-  if (!xpcomFunctions.stringGetMutableData) {
-    *aBuf = nullptr;
-    return 0;
-  }
-  return xpcomFunctions.stringGetMutableData(aStr, aLen, aBuf);
-}
-
-XPCOM_API(char16_t*)
-NS_StringCloneData(const nsAString& aStr)
-{
-  if (!xpcomFunctions.stringCloneData) {
-    return nullptr;
-  }
-  return xpcomFunctions.stringCloneData(aStr);
-}
-
-XPCOM_API(nsresult)
-NS_StringSetData(nsAString& aStr, const char16_t* aBuf, uint32_t aCount)
-{
-  if (!xpcomFunctions.stringSetData) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-
-  return xpcomFunctions.stringSetData(aStr, aBuf, aCount);
-}
-
-XPCOM_API(nsresult)
-NS_StringSetDataRange(nsAString& aStr, uint32_t aCutStart, uint32_t aCutLength,
-                      const char16_t* aBuf, uint32_t aCount)
-{
-  if (!xpcomFunctions.stringSetDataRange) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.stringSetDataRange(aStr, aCutStart, aCutLength, aBuf,
-                                           aCount);
-}
-
-XPCOM_API(nsresult)
-NS_StringCopy(nsAString& aDest, const nsAString& aSrc)
-{
-  if (!xpcomFunctions.stringCopy) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.stringCopy(aDest, aSrc);
-}
-
-XPCOM_API(void)
-NS_StringSetIsVoid(nsAString& aStr, const bool aIsVoid)
-{
-  if (xpcomFunctions.stringSetIsVoid) {
-    xpcomFunctions.stringSetIsVoid(aStr, aIsVoid);
-  }
-}
-
-XPCOM_API(bool)
-NS_StringGetIsVoid(const nsAString& aStr)
-{
-  if (!xpcomFunctions.stringGetIsVoid) {
-    return false;
-  }
-  return xpcomFunctions.stringGetIsVoid(aStr);
-}
-
-XPCOM_API(nsresult)
-NS_CStringContainerInit(nsCStringContainer& aStr)
-{
-  if (!xpcomFunctions.cstringContainerInit) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.cstringContainerInit(aStr);
-}
-
-XPCOM_API(nsresult)
-NS_CStringContainerInit2(nsCStringContainer& aStr, const char* aData,
-                         uint32_t aDataLength, uint32_t aFlags)
-{
-  if (!xpcomFunctions.cstringContainerInit2) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.cstringContainerInit2(aStr, aData, aDataLength, aFlags);
-}
-
-XPCOM_API(void)
-NS_CStringContainerFinish(nsCStringContainer& aStr)
-{
-  if (xpcomFunctions.cstringContainerFinish) {
-    xpcomFunctions.cstringContainerFinish(aStr);
-  }
-}
-
-XPCOM_API(uint32_t)
-NS_CStringGetData(const nsACString& aStr, const char** aBuf, bool* aTerm)
-{
-  if (!xpcomFunctions.cstringGetData) {
-    *aBuf = nullptr;
-    return 0;
-  }
-  return xpcomFunctions.cstringGetData(aStr, aBuf, aTerm);
-}
-
-XPCOM_API(uint32_t)
-NS_CStringGetMutableData(nsACString& aStr, uint32_t aLen, char** aBuf)
-{
-  if (!xpcomFunctions.cstringGetMutableData) {
-    *aBuf = nullptr;
-    return 0;
-  }
-  return xpcomFunctions.cstringGetMutableData(aStr, aLen, aBuf);
-}
-
-XPCOM_API(char*)
-NS_CStringCloneData(const nsACString& aStr)
-{
-  if (!xpcomFunctions.cstringCloneData) {
-    return nullptr;
-  }
-  return xpcomFunctions.cstringCloneData(aStr);
-}
-
-XPCOM_API(nsresult)
-NS_CStringSetData(nsACString& aStr, const char* aBuf, uint32_t aCount)
-{
-  if (!xpcomFunctions.cstringSetData) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.cstringSetData(aStr, aBuf, aCount);
-}
-
-XPCOM_API(nsresult)
-NS_CStringSetDataRange(nsACString& aStr, uint32_t aCutStart,
-                       uint32_t aCutLength, const char* aBuf, uint32_t aCount)
-{
-  if (!xpcomFunctions.cstringSetDataRange) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.cstringSetDataRange(aStr, aCutStart, aCutLength, aBuf,
-                                            aCount);
-}
-
-XPCOM_API(nsresult)
-NS_CStringCopy(nsACString& aDest, const nsACString& aSrc)
-{
-  if (!xpcomFunctions.cstringCopy) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.cstringCopy(aDest, aSrc);
-}
-
-XPCOM_API(void)
-NS_CStringSetIsVoid(nsACString& aStr, const bool aIsVoid)
-{
-  if (xpcomFunctions.cstringSetIsVoid) {
-    xpcomFunctions.cstringSetIsVoid(aStr, aIsVoid);
-  }
-}
-
-XPCOM_API(bool)
-NS_CStringGetIsVoid(const nsACString& aStr)
-{
-  if (!xpcomFunctions.cstringGetIsVoid) {
-    return false;
-  }
-  return xpcomFunctions.cstringGetIsVoid(aStr);
-}
-
-XPCOM_API(nsresult)
-NS_CStringToUTF16(const nsACString& aSrc, nsCStringEncoding aSrcEncoding,
-                  nsAString& aDest)
-{
-  if (!xpcomFunctions.cstringToUTF16) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.cstringToUTF16(aSrc, aSrcEncoding, aDest);
-}
-
-XPCOM_API(nsresult)
-NS_UTF16ToCString(const nsAString& aSrc, nsCStringEncoding aDestEncoding,
-                  nsACString& aDest)
-{
-  if (!xpcomFunctions.utf16ToCString) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  return xpcomFunctions.utf16ToCString(aSrc, aDestEncoding, aDest);
-}
-
-XPCOM_API(void*)
-NS_Alloc(size_t aSize)
-{
-  if (!xpcomFunctions.allocFunc) {
-    return nullptr;
-  }
-  return xpcomFunctions.allocFunc(aSize);
-}
-
-XPCOM_API(void*)
-NS_Realloc(void* aPtr, size_t aSize)
-{
-  if (!xpcomFunctions.reallocFunc) {
-    return nullptr;
-  }
-  return xpcomFunctions.reallocFunc(aPtr, aSize);
-}
-
-XPCOM_API(void)
-NS_Free(void* aPtr)
-{
-  if (xpcomFunctions.freeFunc) {
-    xpcomFunctions.freeFunc(aPtr);
-  }
-}
-
-XPCOM_API(void)
-NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr,
-              const char* aFile, int32_t aLine)
-{
-  if (xpcomFunctions.debugBreakFunc) {
-    xpcomFunctions.debugBreakFunc(aSeverity, aStr, aExpr, aFile, aLine);
-  }
-}
-
-XPCOM_API(void)
-NS_LogInit()
-{
-  if (xpcomFunctions.logInitFunc) {
-    xpcomFunctions.logInitFunc();
-  }
-}
-
-XPCOM_API(void)
-NS_LogTerm()
-{
-  if (xpcomFunctions.logTermFunc) {
-    xpcomFunctions.logTermFunc();
-  }
-}
-
-XPCOM_API(void)
-NS_LogAddRef(void* aPtr, nsrefcnt aNewRefCnt,
-             const char* aTypeName, uint32_t aInstanceSize)
-{
-  if (xpcomFunctions.logAddRefFunc)
-    xpcomFunctions.logAddRefFunc(aPtr, aNewRefCnt,
-                                 aTypeName, aInstanceSize);
-}
-
-XPCOM_API(void)
-NS_LogRelease(void* aPtr, nsrefcnt aNewRefCnt, const char* aTypeName)
-{
-  if (xpcomFunctions.logReleaseFunc) {
-    xpcomFunctions.logReleaseFunc(aPtr, aNewRefCnt, aTypeName);
-  }
-}
-
-XPCOM_API(void)
-NS_LogCtor(void* aPtr, const char* aTypeName, uint32_t aInstanceSize)
-{
-  if (xpcomFunctions.logCtorFunc) {
-    xpcomFunctions.logCtorFunc(aPtr, aTypeName, aInstanceSize);
-  }
-}
-
-XPCOM_API(void)
-NS_LogDtor(void* aPtr, const char* aTypeName, uint32_t aInstanceSize)
-{
-  if (xpcomFunctions.logDtorFunc) {
-    xpcomFunctions.logDtorFunc(aPtr, aTypeName, aInstanceSize);
-  }
-}
-
-XPCOM_API(void)
-NS_LogCOMPtrAddRef(void* aCOMPtr, nsISupports* aObject)
-{
-  if (xpcomFunctions.logCOMPtrAddRefFunc) {
-    xpcomFunctions.logCOMPtrAddRefFunc(aCOMPtr, aObject);
-  }
-}
-
-XPCOM_API(void)
-NS_LogCOMPtrRelease(void* aCOMPtr, nsISupports* aObject)
-{
-  if (xpcomFunctions.logCOMPtrReleaseFunc) {
-    xpcomFunctions.logCOMPtrReleaseFunc(aCOMPtr, aObject);
-  }
-}
-
-XPCOM_API(nsresult)
-NS_GetXPTCallStub(REFNSIID aIID, nsIXPTCProxy* aOuter,
-                  nsISomeInterface** aStub)
-{
-  if (!xpcomFunctions.getXPTCallStubFunc) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-
-  return xpcomFunctions.getXPTCallStubFunc(aIID, aOuter, aStub);
-}
-
-XPCOM_API(void)
-NS_DestroyXPTCallStub(nsISomeInterface* aStub)
-{
-  if (xpcomFunctions.destroyXPTCallStubFunc) {
-    xpcomFunctions.destroyXPTCallStubFunc(aStub);
-  }
-}
-
-XPCOM_API(nsresult)
-NS_InvokeByIndex(nsISupports* aThat, uint32_t aMethodIndex,
-                 uint32_t aParamCount, nsXPTCVariant* aParams)
-{
-  if (!xpcomFunctions.invokeByIndexFunc) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-
-  return xpcomFunctions.invokeByIndexFunc(aThat, aMethodIndex,
-                                          aParamCount, aParams);
-}
-
-XPCOM_API(bool)
-NS_CycleCollectorSuspect(nsISupports* aObj)
-{
-  if (!xpcomFunctions.cycleSuspectFunc) {
-    return false;
-  }
-
-  return xpcomFunctions.cycleSuspectFunc(aObj);
-}
-
-XPCOM_API(bool)
-NS_CycleCollectorForget(nsISupports* aObj)
-{
-  if (!xpcomFunctions.cycleForgetFunc) {
-    return false;
-  }
-
-  return xpcomFunctions.cycleForgetFunc(aObj);
-}
-
-XPCOM_API(nsPurpleBufferEntry*)
-NS_CycleCollectorSuspect2(void* aObj, nsCycleCollectionParticipant* aCp)
-{
-  if (!xpcomFunctions.cycleSuspect2Func) {
     return nullptr;
   }
 
-  return xpcomFunctions.cycleSuspect2Func(aObj, aCp);
+  Bootstrap::UniquePtr b;
+  (*func)(b);
+  return b;
 }
 
-XPCOM_API(void)
-NS_CycleCollectorSuspect3(void* aObj, nsCycleCollectionParticipant* aCp,
-                          nsCycleCollectingAutoRefCnt* aRefCnt,
-                          bool* aShouldDelete)
-{
-  if (xpcomFunctions.cycleSuspect3Func) {
-    xpcomFunctions.cycleSuspect3Func(aObj, aCp, aRefCnt, aShouldDelete);
-  }
-}
-
-XPCOM_API(bool)
-NS_CycleCollectorForget2(nsPurpleBufferEntry* aEntry)
-{
-  if (!xpcomFunctions.cycleForget2Func) {
-    return false;
-  }
-
-  return xpcomFunctions.cycleForget2Func(aEntry);
-}
+} // namespace mozilla
--- a/xpcom/glue/standalone/nsXPCOMGlue.h
+++ b/xpcom/glue/standalone/nsXPCOMGlue.h
@@ -2,48 +2,30 @@
 /* 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 nsXPCOMGlue_h__
 #define nsXPCOMGlue_h__
 
-#include "nscore.h"
-
-#ifdef XPCOM_GLUE
+#ifdef MOZILLA_INTERNAL_API
+#error This file only makes sense outside of xul.
+#endif
 
-/**
- * The following functions are only available in the standalone glue.
- */
+#include "mozilla/Bootstrap.h"
+
+namespace mozilla {
 
 /**
  * Enabled preloading of dynamically loaded libraries
  */
-extern "C" NS_HIDDEN_(void) XPCOMGlueEnablePreload();
+void XPCOMGlueEnablePreload();
 
 /**
  * Initialize the XPCOM glue by dynamically linking against the XPCOM
  * shared library indicated by xpcomFile.
  */
-extern "C" NS_HIDDEN_(nsresult) XPCOMGlueStartup(const char* aXPCOMFile);
-
-typedef void (*NSFuncPtr)();
-
-struct nsDynamicFunctionLoad
-{
-  const char* functionName;
-  NSFuncPtr* function;
-};
+Bootstrap::UniquePtr XPCOMGlueStartup(const char* aXPCOMFile);
 
-/**
- * Dynamically load functions from libxul.
- *
- * @throws NS_ERROR_NOT_INITIALIZED if XPCOMGlueStartup() was not called or
- *         if the libxul DLL was not found.
- * @throws NS_ERROR_LOSS_OF_SIGNIFICANT_DATA if only some of the required
- *         functions were found.
- */
-extern "C" NS_HIDDEN_(nsresult)
-XPCOMGlueLoadXULFunctions(const nsDynamicFunctionLoad* aSymbols);
+} // namespace mozilla
 
-#endif // XPCOM_GLUE
 #endif // nsXPCOMGlue_h__