summaryrefslogtreecommitdiffstats
path: root/toolkit/xre/nsEmbedFunctions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/xre/nsEmbedFunctions.cpp')
-rw-r--r--toolkit/xre/nsEmbedFunctions.cpp821
1 files changed, 821 insertions, 0 deletions
diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp
new file mode 100644
index 0000000000..72077d6ddf
--- /dev/null
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -0,0 +1,821 @@
+/* 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/DebugOnly.h"
+
+#include "nsXULAppAPI.h"
+
+#include <stdlib.h>
+#if defined(MOZ_WIDGET_GTK)
+# include <glib.h>
+#endif
+
+#include "prenv.h"
+
+#include "nsIAppShell.h"
+#include "nsIToolkitProfile.h"
+
+#ifdef XP_WIN
+# include <process.h>
+# include <shobjidl.h>
+# include "mozilla/ipc/WindowsMessageLoop.h"
+# ifdef MOZ_SANDBOX
+# include "mozilla/RandomNum.h"
+# endif
+# include "mozilla/ScopeExit.h"
+# include "mozilla/WinDllServices.h"
+# include "mozilla/WindowsBCryptInitialization.h"
+# include "WinUtils.h"
+#endif
+
+#include "nsAppRunner.h"
+#include "nsExceptionHandler.h"
+#include "mozilla/RuntimeExceptionModule.h"
+#include "nsThreadUtils.h"
+#include "nsJSUtils.h"
+#include "nsWidgetsCID.h"
+#include "nsXREDirProvider.h"
+#ifdef MOZ_ASAN_REPORTER
+# include "CmdLineAndEnvUtils.h"
+# include "nsIFile.h"
+#endif
+
+#include "mozilla/Omnijar.h"
+#if defined(XP_MACOSX)
+# include <mach/mach.h>
+# include <servers/bootstrap.h>
+# include "nsVersionComparator.h"
+# include "chrome/common/mach_ipc_mac.h"
+# include "gfxPlatformMac.h"
+#endif
+#include "nsX11ErrorHandler.h"
+#include "nsGDKErrorHandler.h"
+#include "base/at_exit.h"
+#include "base/message_loop.h"
+#include "base/process_util.h"
+#if defined(MOZ_WIDGET_ANDROID)
+# include "chrome/common/ipc_channel.h"
+# include "mozilla/jni/Utils.h"
+# include "mozilla/ipc/ProcessUtils.h"
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+#include "mozilla/AbstractThread.h"
+#include "mozilla/FilePreferences.h"
+#include "mozilla/IOInterposer.h"
+#include "mozilla/ProcessType.h"
+#include "mozilla/RDDProcessImpl.h"
+#include "mozilla/ipc/UtilityProcessImpl.h"
+#include "mozilla/UniquePtr.h"
+
+#include "mozilla/ipc/BrowserProcessSubThread.h"
+#include "mozilla/ipc/IOThreadChild.h"
+#include "mozilla/ipc/ProcessChild.h"
+
+#include "mozilla/dom/ContentProcess.h"
+#include "mozilla/dom/ContentParent.h"
+
+#include "mozilla/ipc/TestShellParent.h"
+#if defined(XP_WIN)
+# include "mozilla/WindowsConsole.h"
+# include "mozilla/WindowsDllBlocklist.h"
+#endif
+
+#include "GMPProcessChild.h"
+#include "mozilla/gfx/GPUProcessImpl.h"
+#include "mozilla/net/SocketProcessImpl.h"
+
+#include "ProfilerControl.h"
+
+#if defined(MOZ_SANDBOX) && defined(XP_WIN)
+# include "mozilla/sandboxTarget.h"
+# include "mozilla/sandboxing/loggingCallbacks.h"
+# include "mozilla/RemoteSandboxBrokerProcessChild.h"
+#endif
+
+#if defined(MOZ_SANDBOX)
+# include "XREChildData.h"
+# include "mozilla/SandboxSettings.h"
+#endif
+
+#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+# include "mozilla/Sandbox.h"
+#endif
+
+#if defined(XP_LINUX)
+# include <sys/prctl.h>
+# ifndef PR_SET_PTRACER
+# define PR_SET_PTRACER 0x59616d61
+# endif
+# ifndef PR_SET_PTRACER_ANY
+# define PR_SET_PTRACER_ANY ((unsigned long)-1)
+# endif
+#endif
+
+#ifdef MOZ_JPROF
+# include "jprof.h"
+#endif
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+# include "mozilla/sandboxing/SandboxInitialization.h"
+# include "mozilla/sandboxing/sandboxLogging.h"
+#endif
+
+#if defined(MOZ_ENABLE_FORKSERVER)
+# include "mozilla/ipc/ForkServer.h"
+#endif
+
+#if defined(MOZ_X11)
+# include <X11/Xlib.h>
+#endif
+
+#include "VRProcessChild.h"
+
+using namespace mozilla;
+
+using mozilla::ipc::BrowserProcessSubThread;
+using mozilla::ipc::GeckoChildProcessHost;
+using mozilla::ipc::IOThreadChild;
+using mozilla::ipc::ProcessChild;
+
+using mozilla::dom::ContentParent;
+using mozilla::dom::ContentProcess;
+
+using mozilla::gmp::GMPProcessChild;
+
+using mozilla::ipc::TestShellCommandParent;
+using mozilla::ipc::TestShellParent;
+
+namespace mozilla::_ipdltest {
+// Set in IPDLUnitTest.cpp when running gtests.
+UniquePtr<mozilla::ipc::ProcessChild> (*gMakeIPDLUnitTestProcessChild)(
+ base::ProcessId, const nsID&) = nullptr;
+} // namespace mozilla::_ipdltest
+
+static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
+
+const char* XRE_GeckoProcessTypeToString(GeckoProcessType aProcessType) {
+ switch (aProcessType) {
+#define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
+ process_bin_type, procinfo_typename, \
+ webidl_typename, allcaps_name) \
+ case GeckoProcessType::GeckoProcessType_##enum_name: \
+ return string_name;
+#include "mozilla/GeckoProcessTypes.h"
+#undef GECKO_PROCESS_TYPE
+ default:
+ return "invalid";
+ }
+}
+
+const char* XRE_ChildProcessTypeToAnnotation(GeckoProcessType aProcessType) {
+ switch (aProcessType) {
+ case GeckoProcessType_GMPlugin:
+ return "plugin";
+ case GeckoProcessType_Default:
+ return "";
+ case GeckoProcessType_Content:
+ return "content";
+ default:
+ return XRE_GeckoProcessTypeToString(aProcessType);
+ }
+}
+
+#if defined(MOZ_WIDGET_ANDROID)
+void XRE_SetAndroidChildFds(JNIEnv* env, const XRE_AndroidChildFds& fds) {
+ mozilla::jni::SetGeckoThreadEnv(env);
+ mozilla::ipc::SetPrefsFd(fds.mPrefsFd);
+ mozilla::ipc::SetPrefMapFd(fds.mPrefMapFd);
+ IPC::Channel::SetClientChannelFd(fds.mIpcFd);
+ CrashReporter::SetNotificationPipeForChild(fds.mCrashFd);
+}
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+void XRE_SetProcessType(const char* aProcessTypeString) {
+ SetGeckoProcessType(aProcessTypeString);
+}
+
+#if defined(XP_WIN)
+void SetTaskbarGroupId(const nsString& aId) {
+ if (FAILED(SetCurrentProcessExplicitAppUserModelID(aId.get()))) {
+ NS_WARNING(
+ "SetCurrentProcessExplicitAppUserModelID failed for child process.");
+ }
+}
+#endif
+
+#if defined(MOZ_SANDBOX)
+void AddContentSandboxLevelAnnotation() {
+ if (XRE_GetProcessType() == GeckoProcessType_Content) {
+ int level = GetEffectiveContentSandboxLevel();
+ CrashReporter::AnnotateCrashReport(
+ CrashReporter::Annotation::ContentSandboxLevel, level);
+ } else if (XRE_GetProcessType() == GeckoProcessType_GPU) {
+ int level = GetEffectiveGpuSandboxLevel();
+ CrashReporter::AnnotateCrashReport(
+ CrashReporter::Annotation::GpuSandboxLevel, level);
+ }
+}
+#endif /* MOZ_SANDBOX */
+
+namespace {
+
+int GetDebugChildPauseTime() {
+ auto pauseStr = PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE");
+ if (pauseStr && *pauseStr) {
+ int pause = atoi(pauseStr);
+ if (pause != 1) { // must be !=1 since =1 enables the default pause time
+#if defined(XP_WIN)
+ pause *= 1000; // convert to ms
+#endif
+ return pause;
+ }
+ }
+#ifdef XP_UNIX
+ return 30; // seconds
+#elif defined(XP_WIN)
+ return 10000; // milliseconds
+#else
+ return 0;
+#endif
+}
+
+static bool IsCrashReporterEnabled(const char* aArg) {
+ // on windows and mac, |aArg| is the named pipe on which the server is
+ // listening for requests, or "-" if crash reporting is disabled.
+#if defined(XP_MACOSX) || defined(XP_WIN)
+ return 0 != strcmp("-", aArg);
+#else
+ // on POSIX, |aArg| is "true" if crash reporting is enabled, false otherwise
+ return 0 != strcmp("false", aArg);
+#endif
+}
+
+} // namespace
+
+nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
+ const XREChildData* aChildData) {
+ NS_ENSURE_ARG_MIN(aArgc, 2);
+ NS_ENSURE_ARG_POINTER(aArgv);
+ NS_ENSURE_ARG_POINTER(aArgv[0]);
+ MOZ_ASSERT(aChildData);
+
+ NS_SetCurrentThreadName("MainThread");
+
+#ifdef MOZ_ASAN_REPORTER
+ // In ASan reporter builds, we need to set ASan's log_path as early as
+ // possible, so it dumps its errors into files there instead of using
+ // the default stderr location. Since this is crucial for ASan reporter
+ // to work at all (and we don't want people to use a non-functional
+ // ASan reporter build), all failures while setting log_path are fatal.
+ //
+ // We receive this log_path via the ASAN_REPORTER_PATH environment variable
+ // because there is no other way to generically get the necessary profile
+ // directory in all child types without adding support for that in each
+ // child process type class (at the risk of missing this in a child).
+ //
+ // In certain cases (e.g. child startup through xpcshell or gtests), this
+ // code needs to remain disabled, as no ASAN_REPORTER_PATH would be available.
+ if (!PR_GetEnv("MOZ_DISABLE_ASAN_REPORTER") && !PR_GetEnv("MOZ_RUN_GTEST")) {
+ nsCOMPtr<nsIFile> asanReporterPath = GetFileFromEnv("ASAN_REPORTER_PATH");
+ if (!asanReporterPath) {
+ MOZ_CRASH("Child did not receive ASAN_REPORTER_PATH!");
+ }
+ setASanReporterPath(asanReporterPath);
+ }
+#endif
+
+#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+ // This has to happen before glib thread pools are started.
+ mozilla::SandboxEarlyInit();
+ // This just needs to happen before sandboxing, to initialize the
+ // cached value, but libmozsandbox can't see this symbol.
+ mozilla::GetNumberOfProcessors();
+#endif
+
+#ifdef MOZ_JPROF
+ // Call the code to install our handler
+ setupProfilingStuff();
+#endif
+
+#if defined(XP_WIN)
+ // From the --attach-console support in nsNativeAppSupportWin.cpp, but
+ // here we are a content child process, so we always attempt to attach
+ // to the parent's (ie, the browser's) console.
+ // Try to attach console to the parent process.
+ // It will succeed when the parent process is a command line,
+ // so that stdio will be displayed in it.
+ UseParentConsole();
+
+# if defined(MOZ_SANDBOX)
+ if (aChildData->sandboxTargetServices) {
+ SandboxTarget::Instance()->SetTargetServices(
+ aChildData->sandboxTargetServices);
+ }
+# endif
+#endif
+
+ // NB: This must be called before profiler_init
+ ScopedLogging logger;
+
+ mozilla::LogModule::Init(aArgc, aArgv);
+
+ AUTO_BASE_PROFILER_LABEL("XRE_InitChildProcess (around Gecko Profiler)",
+ OTHER);
+ AUTO_PROFILER_INIT;
+ AUTO_PROFILER_LABEL("XRE_InitChildProcess", OTHER);
+
+#ifdef XP_MACOSX
+ gfxPlatformMac::RegisterSupplementalFonts();
+#endif
+
+ // Ensure AbstractThread is minimally setup, so async IPC messages
+ // work properly.
+ AbstractThread::InitTLS();
+
+ // Complete 'task_t' exchange for Mac OS X. This structure has the same size
+ // regardless of architecture so we don't have any cross-arch issues here.
+#ifdef XP_MACOSX
+ if (aArgc < 1) return NS_ERROR_FAILURE;
+
+# if defined(MOZ_SANDBOX)
+ // Save the original number of arguments to pass to the sandbox
+ // setup routine which also uses the crash server argument.
+ int allArgc = aArgc;
+# endif /* MOZ_SANDBOX */
+
+ // Acquire the mach bootstrap port name from our command line, and send our
+ // task_t to the parent process.
+ const char* const mach_port_name = aArgv[--aArgc];
+
+ const int kTimeoutMs = 1000;
+
+ UniqueMachSendRight task_sender;
+ kern_return_t kr = bootstrap_look_up(bootstrap_port, mach_port_name,
+ getter_Transfers(task_sender));
+ if (kr != KERN_SUCCESS) {
+ NS_WARNING(nsPrintfCString("child bootstrap_look_up failed: %s",
+ mach_error_string(kr))
+ .get());
+ return NS_ERROR_FAILURE;
+ }
+
+ kr = MachSendPortSendRight(task_sender.get(), mach_task_self(),
+ Some(kTimeoutMs));
+ if (kr != KERN_SUCCESS) {
+ NS_WARNING(nsPrintfCString("child MachSendPortSendRight failed: %s",
+ mach_error_string(kr))
+ .get());
+ return NS_ERROR_FAILURE;
+ }
+
+# if defined(MOZ_SANDBOX)
+ std::string sandboxError;
+ if (!GeckoChildProcessHost::StartMacSandbox(allArgc, aArgv, sandboxError)) {
+ printf_stderr("Sandbox error: %s\n", sandboxError.c_str());
+ MOZ_CRASH("Sandbox initialization failed");
+ }
+# endif /* MOZ_SANDBOX */
+
+#endif /* XP_MACOSX */
+
+ SetupErrorHandling(aArgv[0]);
+
+ bool exceptionHandlerIsSet = false;
+ if (!CrashReporter::IsDummy()) {
+ if (aArgc < 1) return NS_ERROR_FAILURE;
+ const char* const crashReporterArg = aArgv[--aArgc];
+
+ if (IsCrashReporterEnabled(crashReporterArg)) {
+ exceptionHandlerIsSet =
+ CrashReporter::SetRemoteExceptionHandler(crashReporterArg);
+ MOZ_ASSERT(exceptionHandlerIsSet,
+ "Should have been able to set remote exception handler");
+
+ if (!exceptionHandlerIsSet) {
+ // Bug 684322 will add better visibility into this condition
+ NS_WARNING("Could not setup crash reporting\n");
+ }
+ } else {
+ // We might have registered a runtime exception module very early in
+ // process startup to catch early crashes. This is before we process the
+ // crash reporter arg, so unregister here if it turns out the crash
+ // reporter is disabled.
+ CrashReporter::UnregisterRuntimeExceptionModule();
+ }
+ }
+
+ gArgv = aArgv;
+ gArgc = aArgc;
+
+#ifdef MOZ_X11
+ XInitThreads();
+#endif
+#ifdef MOZ_WIDGET_GTK
+ // Setting the name here avoids the need to pass this through to gtk_init().
+ g_set_prgname(aArgv[0]);
+#endif
+
+#ifdef XP_UNIX
+ if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS") ||
+ PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
+# if defined(XP_LINUX) && defined(DEBUG)
+ if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0) != 0) {
+ printf_stderr("Could not allow ptrace from any process.\n");
+ }
+# endif
+ printf_stderr(
+ "\n\nCHILDCHILDCHILDCHILD (process type %s)\n debug me @ %d\n\n",
+ XRE_GetProcessTypeString(), base::GetCurrentProcId());
+ sleep(GetDebugChildPauseTime());
+ }
+#elif defined(XP_WIN)
+ if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS")) {
+ NS_DebugBreak(NS_DEBUG_BREAK,
+ "Invoking NS_DebugBreak() to debug child process", nullptr,
+ __FILE__, __LINE__);
+ } else if (PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
+ printf_stderr(
+ "\n\nCHILDCHILDCHILDCHILD (process type %s)\n debug me @ %lu\n\n",
+ XRE_GetProcessTypeString(), base::GetCurrentProcId());
+ ::Sleep(GetDebugChildPauseTime());
+ }
+#endif
+
+#ifdef MOZ_WIDGET_ANDROID
+ // The parent process already did this, but Gecko child processes on
+ // Android aren't descendants of the parent process, so they don't
+ // inherit its rlimits.
+ mozilla::startup::IncreaseDescriptorLimits();
+#endif
+
+ // child processes launched by GeckoChildProcessHost get this magic
+ // argument appended to their command lines
+ const char* const parentPIDString = aArgv[aArgc - 1];
+ MOZ_ASSERT(parentPIDString, "NULL parent PID");
+ --aArgc;
+
+ char* end = 0;
+ base::ProcessId parentPID = strtol(parentPIDString, &end, 10);
+ MOZ_ASSERT(!*end, "invalid parent PID");
+
+ // They also get the initial message channel ID passed in the same manner.
+ const char* const messageChannelIdString = aArgv[aArgc - 1];
+ MOZ_ASSERT(messageChannelIdString, "NULL MessageChannel Id");
+ --aArgc;
+
+ nsID messageChannelId{};
+ if (!messageChannelId.Parse(messageChannelIdString)) {
+ return NS_ERROR_FAILURE;
+ }
+
+#if defined(XP_WIN)
+ // On Win7+, when not running as an MSIX package, register the application
+ // user model id passed in by parent. This ensures windows created by the
+ // container properly group with the parent app on the Win7 taskbar.
+ // MSIX packages explicitly do not support setting the appid from within
+ // the app, as it is set in the package manifest instead.
+ const char* const appModelUserId = aArgv[--aArgc];
+ if (appModelUserId && !mozilla::widget::WinUtils::HasPackageIdentity()) {
+ // '-' implies no support
+ if (*appModelUserId != '-') {
+ nsString appId;
+ CopyASCIItoUTF16(nsDependentCString(appModelUserId), appId);
+ // The version string is encased in quotes
+ appId.Trim("\"");
+ // Set the id
+ SetTaskbarGroupId(appId);
+ }
+ }
+#endif
+
+ base::AtExitManager exitManager;
+
+ nsresult rv = XRE_InitCommandLine(aArgc, aArgv);
+ if (NS_FAILED(rv)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ MessageLoop::Type uiLoopType;
+ switch (XRE_GetProcessType()) {
+ case GeckoProcessType_Content:
+ case GeckoProcessType_GPU:
+ case GeckoProcessType_IPDLUnitTest:
+ case GeckoProcessType_VR:
+ case GeckoProcessType_RDD:
+ case GeckoProcessType_Socket:
+ case GeckoProcessType_Utility:
+ // Content processes need the XPCOM/chromium frankenventloop
+ uiLoopType = MessageLoop::TYPE_MOZILLA_CHILD;
+ break;
+ case GeckoProcessType_GMPlugin:
+ gmp::GMPProcessChild::InitStatics(aArgc, aArgv);
+ uiLoopType = gmp::GMPProcessChild::UseXPCOM()
+ ? MessageLoop::TYPE_MOZILLA_CHILD
+ : MessageLoop::TYPE_DEFAULT;
+ break;
+ case GeckoProcessType_RemoteSandboxBroker:
+ uiLoopType = MessageLoop::TYPE_DEFAULT;
+ break;
+ default:
+ uiLoopType = MessageLoop::TYPE_UI;
+ break;
+ }
+
+#if defined(XP_WIN)
+# if defined(MOZ_SANDBOX)
+ if (aChildData->sandboxBrokerServices) {
+ SandboxBroker::Initialize(aChildData->sandboxBrokerServices);
+ SandboxBroker::GeckoDependentInitialize();
+ }
+# endif // defined(MOZ_SANDBOX)
+
+ {
+ DebugOnly<bool> result = mozilla::WindowsBCryptInitialization();
+ MOZ_ASSERT(result);
+ }
+#endif // defined(XP_WIN)
+
+ {
+ // This is a lexical scope for the MessageLoop below. We want it
+ // to go out of scope before NS_LogTerm() so that we don't get
+ // spurious warnings about XPCOM objects being destroyed from a
+ // static context.
+
+ AutoIOInterposer ioInterposerGuard;
+
+ // Associate this thread with a UI MessageLoop
+ MessageLoop uiMessageLoop(uiLoopType);
+ {
+ UniquePtr<ProcessChild> process;
+ switch (XRE_GetProcessType()) {
+ case GeckoProcessType_Default:
+ MOZ_CRASH("This makes no sense");
+ break;
+
+ case GeckoProcessType_Content:
+ ioInterposerGuard.Init();
+ process = MakeUnique<ContentProcess>(parentPID, messageChannelId);
+ break;
+
+ case GeckoProcessType_IPDLUnitTest:
+ MOZ_RELEASE_ASSERT(mozilla::_ipdltest::gMakeIPDLUnitTestProcessChild,
+ "xul-gtest not loaded!");
+ process = mozilla::_ipdltest::gMakeIPDLUnitTestProcessChild(
+ parentPID, messageChannelId);
+ break;
+
+ case GeckoProcessType_GMPlugin:
+ process =
+ MakeUnique<gmp::GMPProcessChild>(parentPID, messageChannelId);
+ break;
+
+ case GeckoProcessType_GPU:
+ process =
+ MakeUnique<gfx::GPUProcessImpl>(parentPID, messageChannelId);
+ break;
+
+ case GeckoProcessType_VR:
+ process =
+ MakeUnique<gfx::VRProcessChild>(parentPID, messageChannelId);
+ break;
+
+ case GeckoProcessType_RDD:
+ process = MakeUnique<RDDProcessImpl>(parentPID, messageChannelId);
+ break;
+
+ case GeckoProcessType_Socket:
+ ioInterposerGuard.Init();
+ process =
+ MakeUnique<net::SocketProcessImpl>(parentPID, messageChannelId);
+ break;
+
+ case GeckoProcessType_Utility:
+ process =
+ MakeUnique<ipc::UtilityProcessImpl>(parentPID, messageChannelId);
+ break;
+
+#if defined(MOZ_SANDBOX) && defined(XP_WIN)
+ case GeckoProcessType_RemoteSandboxBroker:
+ process = MakeUnique<RemoteSandboxBrokerProcessChild>(
+ parentPID, messageChannelId);
+ break;
+#endif
+
+#if defined(MOZ_ENABLE_FORKSERVER)
+ case GeckoProcessType_ForkServer:
+ MOZ_CRASH("Fork server should not go here");
+ break;
+#endif
+ default:
+ MOZ_CRASH("Unknown main thread class");
+ }
+
+ if (!process->Init(aArgc, aArgv)) {
+ return NS_ERROR_FAILURE;
+ }
+
+#if defined(XP_WIN)
+ // Set child processes up such that they will get killed after the
+ // chrome process is killed in cases where the user shuts the system
+ // down or logs off.
+ ::SetProcessShutdownParameters(0x280 - 1, SHUTDOWN_NORETRY);
+
+ RefPtr<DllServices> dllSvc(DllServices::Get());
+ auto dllSvcDisable =
+ MakeScopeExit([&dllSvc]() { dllSvc->DisableFull(); });
+#endif
+
+#if defined(MOZ_SANDBOX) && defined(XP_WIN)
+ // We need to do this after the process has been initialised, as
+ // InitLoggingIfRequired may need access to prefs.
+ mozilla::sandboxing::InitLoggingIfRequired(
+ aChildData->ProvideLogFunction);
+#endif
+ if (XRE_GetProcessType() != GeckoProcessType_RemoteSandboxBroker) {
+ // Remote sandbox launcher process doesn't have prerequisites for
+ // these...
+ mozilla::FilePreferences::InitDirectoriesAllowlist();
+ mozilla::FilePreferences::InitPrefs();
+ }
+
+#if defined(MOZ_SANDBOX)
+ AddContentSandboxLevelAnnotation();
+#endif
+
+ // Run the UI event loop on the main thread.
+ uiMessageLoop.MessageLoop::Run();
+
+ // Allow ProcessChild to clean up after itself before going out of
+ // scope and being deleted
+ process->CleanUp();
+ mozilla::Omnijar::CleanUp();
+ }
+ }
+
+ CrashReporter::UnsetRemoteExceptionHandler(exceptionHandlerIsSet);
+
+ return XRE_DeinitCommandLine();
+}
+
+MessageLoop* XRE_GetIOMessageLoop() {
+ if (GetGeckoProcessType() == GeckoProcessType_Default) {
+ return BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO);
+ }
+ return IOThreadChild::message_loop();
+}
+
+nsresult XRE_RunAppShell() {
+ nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
+ NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
+#if defined(XP_MACOSX)
+ if (XRE_UseNativeEventProcessing()) {
+ // In content processes that want XPCOM (and hence want
+ // AppShell), we usually run our hybrid event loop through
+ // MessagePump::Run(), by way of nsBaseAppShell::Run(). The
+ // Cocoa nsAppShell impl, however, implements its own Run()
+ // that's unaware of MessagePump. That's all rather suboptimal,
+ // but oddly enough not a problem... usually.
+ //
+ // The problem with this setup comes during startup.
+ // XPCOM-in-subprocesses depends on IPC, e.g. to init the pref
+ // service, so we have to init IPC first. But, IPC also
+ // indirectly kinda-depends on XPCOM, because MessagePump
+ // schedules work from off-main threads (e.g. IO thread) by
+ // using NS_DispatchToMainThread(). If the IO thread receives a
+ // Message from the parent before nsThreadManager is
+ // initialized, then DispatchToMainThread() will fail, although
+ // MessagePump will remember the task. This race condition
+ // isn't a problem when appShell->Run() ends up in
+ // MessagePump::Run(), because MessagePump will immediate see it
+ // has work to do. It *is* a problem when we end up in [NSApp
+ // run], because it's not aware that MessagePump has work that
+ // needs to be processed; that was supposed to be signaled by
+ // nsIRunnable(s).
+ //
+ // So instead of hacking Cocoa nsAppShell or rewriting the
+ // event-loop system, we compromise here by processing any tasks
+ // that might have been enqueued on MessagePump, *before*
+ // MessagePump::ScheduleWork was able to successfully
+ // DispatchToMainThread().
+ MessageLoop* loop = MessageLoop::current();
+ bool couldNest = loop->NestableTasksAllowed();
+
+ loop->SetNestableTasksAllowed(true);
+ RefPtr<Runnable> task = new MessageLoop::QuitTask();
+ loop->PostTask(task.forget());
+ loop->Run();
+
+ loop->SetNestableTasksAllowed(couldNest);
+ }
+#endif // XP_MACOSX
+ return appShell->Run();
+}
+
+void XRE_ShutdownChildProcess() {
+ MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+ mozilla::DebugOnly<MessageLoop*> ioLoop = XRE_GetIOMessageLoop();
+ MOZ_ASSERT(!!ioLoop, "Bad shutdown order");
+
+ // Quit() sets off the following chain of events
+ // (1) UI loop starts quitting
+ // (2) UI loop returns from Run() in XRE_InitChildProcess()
+ // (3) ProcessChild goes out of scope and terminates the IO thread
+ // (4) ProcessChild joins the IO thread
+ // (5) exit()
+ MessageLoop::current()->Quit();
+
+#if defined(XP_MACOSX)
+ nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
+ if (appShell) {
+ // On Mac, we might be only above nsAppShell::Run(), not
+ // MessagePump::Run(). See XRE_RunAppShell(). To account for
+ // that case, we fire off an Exit() here. If we were indeed
+ // above MessagePump::Run(), this Exit() is just superfluous.
+ appShell->Exit();
+ }
+#endif // XP_MACOSX
+}
+
+namespace {
+ContentParent* gContentParent; // long-lived, manually refcounted
+TestShellParent* GetOrCreateTestShellParent() {
+ if (!gContentParent) {
+ // Use a "web" child process by default. File a bug if you don't like
+ // this and you're sure you wouldn't be better off writing a "browser"
+ // chrome mochitest where you can have multiple types of content
+ // processes.
+ RefPtr<ContentParent> parent =
+ ContentParent::GetNewOrUsedBrowserProcess(DEFAULT_REMOTE_TYPE);
+ parent.forget(&gContentParent);
+ } else if (gContentParent->IsShuttingDown()) {
+ return nullptr;
+ }
+ TestShellParent* tsp = gContentParent->GetTestShellSingleton();
+ if (!tsp) {
+ tsp = gContentParent->CreateTestShell();
+ }
+ return tsp;
+}
+
+} // namespace
+
+bool XRE_SendTestShellCommand(JSContext* aCx, JSString* aCommand,
+ JS::Value* aCallback) {
+ JS::Rooted<JSString*> cmd(aCx, aCommand);
+ TestShellParent* tsp = GetOrCreateTestShellParent();
+ NS_ENSURE_TRUE(tsp, false);
+
+ nsAutoJSString command;
+ NS_ENSURE_TRUE(command.init(aCx, cmd), false);
+
+ if (!aCallback) {
+ return tsp->SendExecuteCommand(command);
+ }
+
+ TestShellCommandParent* callback = static_cast<TestShellCommandParent*>(
+ tsp->SendPTestShellCommandConstructor(command));
+ NS_ENSURE_TRUE(callback, false);
+
+ NS_ENSURE_TRUE(callback->SetCallback(aCx, *aCallback), false);
+
+ return true;
+}
+
+bool XRE_ShutdownTestShell() {
+ if (!gContentParent) {
+ return true;
+ }
+ bool ret = true;
+ if (gContentParent->IsAlive()) {
+ ret = gContentParent->DestroyTestShell(
+ gContentParent->GetTestShellSingleton());
+ }
+ NS_RELEASE(gContentParent);
+ return ret;
+}
+
+#ifdef MOZ_X11
+void XRE_InstallX11ErrorHandler() {
+# ifdef MOZ_WIDGET_GTK
+ InstallGdkErrorHandler();
+# endif
+
+ // Ensure our X11 error handler overrides the default GDK error handler such
+ // that errors are ignored by default. GDK will install its own error handler
+ // temporarily when pushing error traps internally as needed. This avoids us
+ // otherwise having to frequently override the error handler merely to trap
+ // errors in multiple places that would otherwise contend with GDK or other
+ // libraries that might also override the handler.
+ InstallX11ErrorHandler();
+}
+
+void XRE_CleanupX11ErrorHandler() { CleanupX11ErrorHandler(); }
+#endif
+
+#ifdef MOZ_ENABLE_FORKSERVER
+int XRE_ForkServer(int* aArgc, char*** aArgv) {
+ return mozilla::ipc::ForkServer::RunForkServer(aArgc, aArgv) ? 1 : 0;
+}
+#endif