1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "mozilla/DebugOnly.h"
7 #include "nsXULAppAPI.h"
10 #if defined(MOZ_WIDGET_GTK)
16 #include "nsIAppShell.h"
17 #include "nsIToolkitProfile.h"
21 # include <shobjidl.h>
22 # include "mozilla/ipc/WindowsMessageLoop.h"
24 # include "mozilla/RandomNum.h"
26 # include "mozilla/ScopeExit.h"
27 # include "mozilla/WinDllServices.h"
28 # include "mozilla/WindowsBCryptInitialization.h"
29 # include "WinUtils.h"
32 #include "nsAppRunner.h"
33 #include "nsExceptionHandler.h"
34 #include "mozilla/RuntimeExceptionModule.h"
35 #include "nsThreadUtils.h"
36 #include "nsJSUtils.h"
37 #include "nsWidgetsCID.h"
38 #include "nsXREDirProvider.h"
39 #ifdef MOZ_ASAN_REPORTER
40 # include "CmdLineAndEnvUtils.h"
44 #include "mozilla/Omnijar.h"
45 #if defined(XP_MACOSX)
46 # include <mach/mach.h>
47 # include <servers/bootstrap.h>
48 # include "nsVersionComparator.h"
49 # include "chrome/common/mach_ipc_mac.h"
50 # include "gfxPlatformMac.h"
52 #include "nsX11ErrorHandler.h"
53 #include "nsGDKErrorHandler.h"
54 #include "base/at_exit.h"
55 #include "base/message_loop.h"
56 #include "base/process_util.h"
57 #if defined(MOZ_WIDGET_ANDROID)
58 # include "chrome/common/ipc_channel.h"
59 # include "mozilla/jni/Utils.h"
60 # include "mozilla/ipc/ProcessUtils.h"
61 #endif // defined(MOZ_WIDGET_ANDROID)
63 #include "mozilla/AbstractThread.h"
64 #include "mozilla/FilePreferences.h"
65 #include "mozilla/IOInterposer.h"
66 #include "mozilla/ProcessType.h"
67 #include "mozilla/RDDProcessImpl.h"
68 #include "mozilla/ipc/UtilityProcessImpl.h"
69 #include "mozilla/UniquePtr.h"
71 #include "mozilla/ipc/BrowserProcessSubThread.h"
72 #include "mozilla/ipc/IOThreadChild.h"
73 #include "mozilla/ipc/ProcessChild.h"
75 #include "mozilla/dom/ContentProcess.h"
76 #include "mozilla/dom/ContentParent.h"
78 #include "mozilla/ipc/TestShellParent.h"
80 # include "mozilla/WindowsConsole.h"
81 # include "mozilla/WindowsDllBlocklist.h"
84 #include "GMPProcessChild.h"
85 #include "mozilla/gfx/GPUProcessImpl.h"
86 #include "mozilla/net/SocketProcessImpl.h"
88 #include "ProfilerControl.h"
90 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
91 # include "mozilla/sandboxTarget.h"
92 # include "mozilla/sandboxing/loggingCallbacks.h"
93 # include "mozilla/RemoteSandboxBrokerProcessChild.h"
96 #if defined(MOZ_SANDBOX)
97 # include "XREChildData.h"
98 # include "mozilla/SandboxSettings.h"
101 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
102 # include "mozilla/Sandbox.h"
105 #if defined(XP_LINUX)
106 # include <sys/prctl.h>
107 # ifndef PR_SET_PTRACER
108 # define PR_SET_PTRACER 0x59616d61
110 # ifndef PR_SET_PTRACER_ANY
111 # define PR_SET_PTRACER_ANY ((unsigned long)-1)
119 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
120 # include "mozilla/sandboxing/SandboxInitialization.h"
121 # include "mozilla/sandboxing/sandboxLogging.h"
124 #if defined(MOZ_ENABLE_FORKSERVER)
125 # include "mozilla/ipc/ForkServer.h"
129 # include <X11/Xlib.h>
132 #include "VRProcessChild.h"
134 using namespace mozilla
;
136 using mozilla::ipc::BrowserProcessSubThread
;
137 using mozilla::ipc::GeckoChildProcessHost
;
138 using mozilla::ipc::IOThreadChild
;
139 using mozilla::ipc::ProcessChild
;
141 using mozilla::dom::ContentParent
;
142 using mozilla::dom::ContentProcess
;
144 using mozilla::gmp::GMPProcessChild
;
146 using mozilla::ipc::TestShellCommandParent
;
147 using mozilla::ipc::TestShellParent
;
149 namespace mozilla::_ipdltest
{
150 // Set in IPDLUnitTest.cpp when running gtests.
151 UniquePtr
<mozilla::ipc::ProcessChild
> (*gMakeIPDLUnitTestProcessChild
)(
152 base::ProcessId
, const nsID
&) = nullptr;
153 } // namespace mozilla::_ipdltest
155 static NS_DEFINE_CID(kAppShellCID
, NS_APPSHELL_CID
);
157 const char* XRE_GeckoProcessTypeToString(GeckoProcessType aProcessType
) {
158 switch (aProcessType
) {
159 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
160 process_bin_type, procinfo_typename, \
161 webidl_typename, allcaps_name) \
162 case GeckoProcessType::GeckoProcessType_##enum_name: \
164 #include "mozilla/GeckoProcessTypes.h"
165 #undef GECKO_PROCESS_TYPE
171 const char* XRE_ChildProcessTypeToAnnotation(GeckoProcessType aProcessType
) {
172 switch (aProcessType
) {
173 case GeckoProcessType_GMPlugin
:
175 case GeckoProcessType_Default
:
177 case GeckoProcessType_Content
:
180 return XRE_GeckoProcessTypeToString(aProcessType
);
184 #if defined(MOZ_WIDGET_ANDROID)
185 void XRE_SetAndroidChildFds(JNIEnv
* env
, const XRE_AndroidChildFds
& fds
) {
186 mozilla::jni::SetGeckoThreadEnv(env
);
187 mozilla::ipc::SetPrefsFd(fds
.mPrefsFd
);
188 mozilla::ipc::SetPrefMapFd(fds
.mPrefMapFd
);
189 IPC::Channel::SetClientChannelFd(fds
.mIpcFd
);
190 CrashReporter::SetNotificationPipeForChild(fds
.mCrashFd
);
192 #endif // defined(MOZ_WIDGET_ANDROID)
194 void XRE_SetProcessType(const char* aProcessTypeString
) {
195 SetGeckoProcessType(aProcessTypeString
);
199 void SetTaskbarGroupId(const nsString
& aId
) {
200 if (FAILED(SetCurrentProcessExplicitAppUserModelID(aId
.get()))) {
202 "SetCurrentProcessExplicitAppUserModelID failed for child process.");
207 #if defined(MOZ_SANDBOX)
208 void AddContentSandboxLevelAnnotation() {
209 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
210 int level
= GetEffectiveContentSandboxLevel();
211 CrashReporter::AnnotateCrashReport(
212 CrashReporter::Annotation::ContentSandboxLevel
, level
);
213 } else if (XRE_GetProcessType() == GeckoProcessType_GPU
) {
214 int level
= GetEffectiveGpuSandboxLevel();
215 CrashReporter::AnnotateCrashReport(
216 CrashReporter::Annotation::GpuSandboxLevel
, level
);
219 #endif /* MOZ_SANDBOX */
223 int GetDebugChildPauseTime() {
224 auto pauseStr
= PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE");
225 if (pauseStr
&& *pauseStr
) {
226 int pause
= atoi(pauseStr
);
227 if (pause
!= 1) { // must be !=1 since =1 enables the default pause time
229 pause
*= 1000; // convert to ms
235 return 30; // seconds
236 #elif defined(XP_WIN)
237 return 10000; // milliseconds
243 static bool IsCrashReporterEnabled(const char* aArg
) {
244 // on windows and mac, |aArg| is the named pipe on which the server is
245 // listening for requests, or "-" if crash reporting is disabled.
246 #if defined(XP_MACOSX) || defined(XP_WIN)
247 return 0 != strcmp("-", aArg
);
249 // on POSIX, |aArg| is "true" if crash reporting is enabled, false otherwise
250 return 0 != strcmp("false", aArg
);
256 nsresult
XRE_InitChildProcess(int aArgc
, char* aArgv
[],
257 const XREChildData
* aChildData
) {
258 NS_ENSURE_ARG_MIN(aArgc
, 2);
259 NS_ENSURE_ARG_POINTER(aArgv
);
260 NS_ENSURE_ARG_POINTER(aArgv
[0]);
261 MOZ_ASSERT(aChildData
);
263 NS_SetCurrentThreadName("MainThread");
265 #ifdef MOZ_ASAN_REPORTER
266 // In ASan reporter builds, we need to set ASan's log_path as early as
267 // possible, so it dumps its errors into files there instead of using
268 // the default stderr location. Since this is crucial for ASan reporter
269 // to work at all (and we don't want people to use a non-functional
270 // ASan reporter build), all failures while setting log_path are fatal.
272 // We receive this log_path via the ASAN_REPORTER_PATH environment variable
273 // because there is no other way to generically get the necessary profile
274 // directory in all child types without adding support for that in each
275 // child process type class (at the risk of missing this in a child).
277 // In certain cases (e.g. child startup through xpcshell or gtests), this
278 // code needs to remain disabled, as no ASAN_REPORTER_PATH would be available.
279 if (!PR_GetEnv("MOZ_DISABLE_ASAN_REPORTER") && !PR_GetEnv("MOZ_RUN_GTEST")) {
280 nsCOMPtr
<nsIFile
> asanReporterPath
= GetFileFromEnv("ASAN_REPORTER_PATH");
281 if (!asanReporterPath
) {
282 MOZ_CRASH("Child did not receive ASAN_REPORTER_PATH!");
284 setASanReporterPath(asanReporterPath
);
288 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
289 // This has to happen before glib thread pools are started.
290 mozilla::SandboxEarlyInit();
291 // This just needs to happen before sandboxing, to initialize the
292 // cached value, but libmozsandbox can't see this symbol.
293 mozilla::GetNumberOfProcessors();
297 // Call the code to install our handler
298 setupProfilingStuff();
302 // From the --attach-console support in nsNativeAppSupportWin.cpp, but
303 // here we are a content child process, so we always attempt to attach
304 // to the parent's (ie, the browser's) console.
305 // Try to attach console to the parent process.
306 // It will succeed when the parent process is a command line,
307 // so that stdio will be displayed in it.
310 # if defined(MOZ_SANDBOX)
311 if (aChildData
->sandboxTargetServices
) {
312 SandboxTarget::Instance()->SetTargetServices(
313 aChildData
->sandboxTargetServices
);
318 // NB: This must be called before profiler_init
319 ScopedLogging logger
;
321 mozilla::LogModule::Init(aArgc
, aArgv
);
323 AUTO_BASE_PROFILER_LABEL("XRE_InitChildProcess (around Gecko Profiler)",
326 AUTO_PROFILER_LABEL("XRE_InitChildProcess", OTHER
);
329 gfxPlatformMac::RegisterSupplementalFonts();
332 // Ensure AbstractThread is minimally setup, so async IPC messages
334 AbstractThread::InitTLS();
336 // Complete 'task_t' exchange for Mac OS X. This structure has the same size
337 // regardless of architecture so we don't have any cross-arch issues here.
339 if (aArgc
< 1) return NS_ERROR_FAILURE
;
341 # if defined(MOZ_SANDBOX)
342 // Save the original number of arguments to pass to the sandbox
343 // setup routine which also uses the crash server argument.
345 # endif /* MOZ_SANDBOX */
347 // Acquire the mach bootstrap port name from our command line, and send our
348 // task_t to the parent process.
349 const char* const mach_port_name
= aArgv
[--aArgc
];
351 const int kTimeoutMs
= 1000;
353 UniqueMachSendRight task_sender
;
354 kern_return_t kr
= bootstrap_look_up(bootstrap_port
, mach_port_name
,
355 getter_Transfers(task_sender
));
356 if (kr
!= KERN_SUCCESS
) {
357 NS_WARNING(nsPrintfCString("child bootstrap_look_up failed: %s",
358 mach_error_string(kr
))
360 return NS_ERROR_FAILURE
;
363 kr
= MachSendPortSendRight(task_sender
.get(), mach_task_self(),
365 if (kr
!= KERN_SUCCESS
) {
366 NS_WARNING(nsPrintfCString("child MachSendPortSendRight failed: %s",
367 mach_error_string(kr
))
369 return NS_ERROR_FAILURE
;
372 # if defined(MOZ_SANDBOX)
373 std::string sandboxError
;
374 if (!GeckoChildProcessHost::StartMacSandbox(allArgc
, aArgv
, sandboxError
)) {
375 printf_stderr("Sandbox error: %s\n", sandboxError
.c_str());
376 MOZ_CRASH("Sandbox initialization failed");
378 # endif /* MOZ_SANDBOX */
380 #endif /* XP_MACOSX */
382 SetupErrorHandling(aArgv
[0]);
384 bool exceptionHandlerIsSet
= false;
385 if (!CrashReporter::IsDummy()) {
386 if (aArgc
< 1) return NS_ERROR_FAILURE
;
387 const char* const crashReporterArg
= aArgv
[--aArgc
];
389 if (IsCrashReporterEnabled(crashReporterArg
)) {
390 exceptionHandlerIsSet
=
391 CrashReporter::SetRemoteExceptionHandler(crashReporterArg
);
392 MOZ_ASSERT(exceptionHandlerIsSet
,
393 "Should have been able to set remote exception handler");
395 if (!exceptionHandlerIsSet
) {
396 // Bug 684322 will add better visibility into this condition
397 NS_WARNING("Could not setup crash reporting\n");
400 // We might have registered a runtime exception module very early in
401 // process startup to catch early crashes. This is before we process the
402 // crash reporter arg, so unregister here if it turns out the crash
403 // reporter is disabled.
404 CrashReporter::UnregisterRuntimeExceptionModule();
414 #ifdef MOZ_WIDGET_GTK
415 // Setting the name here avoids the need to pass this through to gtk_init().
416 g_set_prgname(aArgv
[0]);
420 if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS") ||
421 PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
422 # if defined(XP_LINUX) && defined(DEBUG)
423 if (prctl(PR_SET_PTRACER
, PR_SET_PTRACER_ANY
, 0, 0, 0) != 0) {
424 printf_stderr("Could not allow ptrace from any process.\n");
428 "\n\nCHILDCHILDCHILDCHILD (process type %s)\n debug me @ %d\n\n",
429 XRE_GetProcessTypeString(), base::GetCurrentProcId());
430 sleep(GetDebugChildPauseTime());
432 #elif defined(XP_WIN)
433 if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS")) {
434 NS_DebugBreak(NS_DEBUG_BREAK
,
435 "Invoking NS_DebugBreak() to debug child process", nullptr,
437 } else if (PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
439 "\n\nCHILDCHILDCHILDCHILD (process type %s)\n debug me @ %lu\n\n",
440 XRE_GetProcessTypeString(), base::GetCurrentProcId());
441 ::Sleep(GetDebugChildPauseTime());
445 #ifdef MOZ_WIDGET_ANDROID
446 // The parent process already did this, but Gecko child processes on
447 // Android aren't descendants of the parent process, so they don't
448 // inherit its rlimits.
449 mozilla::startup::IncreaseDescriptorLimits();
452 // child processes launched by GeckoChildProcessHost get this magic
453 // argument appended to their command lines
454 const char* const parentPIDString
= aArgv
[aArgc
- 1];
455 MOZ_ASSERT(parentPIDString
, "NULL parent PID");
459 base::ProcessId parentPID
= strtol(parentPIDString
, &end
, 10);
460 MOZ_ASSERT(!*end
, "invalid parent PID");
462 // They also get the initial message channel ID passed in the same manner.
463 const char* const messageChannelIdString
= aArgv
[aArgc
- 1];
464 MOZ_ASSERT(messageChannelIdString
, "NULL MessageChannel Id");
467 nsID messageChannelId
{};
468 if (!messageChannelId
.Parse(messageChannelIdString
)) {
469 return NS_ERROR_FAILURE
;
473 // On Win7+, when not running as an MSIX package, register the application
474 // user model id passed in by parent. This ensures windows created by the
475 // container properly group with the parent app on the Win7 taskbar.
476 // MSIX packages explicitly do not support setting the appid from within
477 // the app, as it is set in the package manifest instead.
478 const char* const appModelUserId
= aArgv
[--aArgc
];
479 if (appModelUserId
&& !mozilla::widget::WinUtils::HasPackageIdentity()) {
480 // '-' implies no support
481 if (*appModelUserId
!= '-') {
483 CopyASCIItoUTF16(nsDependentCString(appModelUserId
), appId
);
484 // The version string is encased in quotes
487 SetTaskbarGroupId(appId
);
492 base::AtExitManager exitManager
;
494 nsresult rv
= XRE_InitCommandLine(aArgc
, aArgv
);
496 return NS_ERROR_FAILURE
;
499 MessageLoop::Type uiLoopType
;
500 switch (XRE_GetProcessType()) {
501 case GeckoProcessType_Content
:
502 case GeckoProcessType_GPU
:
503 case GeckoProcessType_IPDLUnitTest
:
504 case GeckoProcessType_VR
:
505 case GeckoProcessType_RDD
:
506 case GeckoProcessType_Socket
:
507 case GeckoProcessType_Utility
:
508 // Content processes need the XPCOM/chromium frankenventloop
509 uiLoopType
= MessageLoop::TYPE_MOZILLA_CHILD
;
511 case GeckoProcessType_GMPlugin
:
512 gmp::GMPProcessChild::InitStatics(aArgc
, aArgv
);
513 uiLoopType
= gmp::GMPProcessChild::UseXPCOM()
514 ? MessageLoop::TYPE_MOZILLA_CHILD
515 : MessageLoop::TYPE_DEFAULT
;
517 case GeckoProcessType_RemoteSandboxBroker
:
518 uiLoopType
= MessageLoop::TYPE_DEFAULT
;
521 uiLoopType
= MessageLoop::TYPE_UI
;
526 # if defined(MOZ_SANDBOX)
527 if (aChildData
->sandboxBrokerServices
) {
528 SandboxBroker::Initialize(aChildData
->sandboxBrokerServices
);
529 SandboxBroker::GeckoDependentInitialize();
531 # endif // defined(MOZ_SANDBOX)
534 DebugOnly
<bool> result
= mozilla::WindowsBCryptInitialization();
537 #endif // defined(XP_WIN)
540 // This is a lexical scope for the MessageLoop below. We want it
541 // to go out of scope before NS_LogTerm() so that we don't get
542 // spurious warnings about XPCOM objects being destroyed from a
545 AutoIOInterposer ioInterposerGuard
;
547 // Associate this thread with a UI MessageLoop
548 MessageLoop
uiMessageLoop(uiLoopType
);
550 UniquePtr
<ProcessChild
> process
;
551 switch (XRE_GetProcessType()) {
552 case GeckoProcessType_Default
:
553 MOZ_CRASH("This makes no sense");
556 case GeckoProcessType_Content
:
557 ioInterposerGuard
.Init();
558 process
= MakeUnique
<ContentProcess
>(parentPID
, messageChannelId
);
561 case GeckoProcessType_IPDLUnitTest
:
562 MOZ_RELEASE_ASSERT(mozilla::_ipdltest::gMakeIPDLUnitTestProcessChild
,
563 "xul-gtest not loaded!");
564 process
= mozilla::_ipdltest::gMakeIPDLUnitTestProcessChild(
565 parentPID
, messageChannelId
);
568 case GeckoProcessType_GMPlugin
:
570 MakeUnique
<gmp::GMPProcessChild
>(parentPID
, messageChannelId
);
573 case GeckoProcessType_GPU
:
575 MakeUnique
<gfx::GPUProcessImpl
>(parentPID
, messageChannelId
);
578 case GeckoProcessType_VR
:
580 MakeUnique
<gfx::VRProcessChild
>(parentPID
, messageChannelId
);
583 case GeckoProcessType_RDD
:
584 process
= MakeUnique
<RDDProcessImpl
>(parentPID
, messageChannelId
);
587 case GeckoProcessType_Socket
:
588 ioInterposerGuard
.Init();
590 MakeUnique
<net::SocketProcessImpl
>(parentPID
, messageChannelId
);
593 case GeckoProcessType_Utility
:
595 MakeUnique
<ipc::UtilityProcessImpl
>(parentPID
, messageChannelId
);
598 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
599 case GeckoProcessType_RemoteSandboxBroker
:
600 process
= MakeUnique
<RemoteSandboxBrokerProcessChild
>(
601 parentPID
, messageChannelId
);
605 #if defined(MOZ_ENABLE_FORKSERVER)
606 case GeckoProcessType_ForkServer
:
607 MOZ_CRASH("Fork server should not go here");
611 MOZ_CRASH("Unknown main thread class");
614 if (!process
->Init(aArgc
, aArgv
)) {
615 return NS_ERROR_FAILURE
;
619 // Set child processes up such that they will get killed after the
620 // chrome process is killed in cases where the user shuts the system
622 ::SetProcessShutdownParameters(0x280 - 1, SHUTDOWN_NORETRY
);
624 RefPtr
<DllServices
> dllSvc(DllServices::Get());
626 MakeScopeExit([&dllSvc
]() { dllSvc
->DisableFull(); });
629 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
630 // We need to do this after the process has been initialised, as
631 // InitLoggingIfRequired may need access to prefs.
632 mozilla::sandboxing::InitLoggingIfRequired(
633 aChildData
->ProvideLogFunction
);
635 if (XRE_GetProcessType() != GeckoProcessType_RemoteSandboxBroker
) {
636 // Remote sandbox launcher process doesn't have prerequisites for
638 mozilla::FilePreferences::InitDirectoriesAllowlist();
639 mozilla::FilePreferences::InitPrefs();
642 #if defined(MOZ_SANDBOX)
643 AddContentSandboxLevelAnnotation();
646 // Run the UI event loop on the main thread.
647 uiMessageLoop
.MessageLoop::Run();
649 // Allow ProcessChild to clean up after itself before going out of
650 // scope and being deleted
652 mozilla::Omnijar::CleanUp();
656 CrashReporter::UnsetRemoteExceptionHandler(exceptionHandlerIsSet
);
658 return XRE_DeinitCommandLine();
661 MessageLoop
* XRE_GetIOMessageLoop() {
662 if (GetGeckoProcessType() == GeckoProcessType_Default
) {
663 return BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO
);
665 return IOThreadChild::message_loop();
668 nsresult
XRE_RunAppShell() {
669 nsCOMPtr
<nsIAppShell
> appShell(do_GetService(kAppShellCID
));
670 NS_ENSURE_TRUE(appShell
, NS_ERROR_FAILURE
);
671 #if defined(XP_MACOSX)
672 if (XRE_UseNativeEventProcessing()) {
673 // In content processes that want XPCOM (and hence want
674 // AppShell), we usually run our hybrid event loop through
675 // MessagePump::Run(), by way of nsBaseAppShell::Run(). The
676 // Cocoa nsAppShell impl, however, implements its own Run()
677 // that's unaware of MessagePump. That's all rather suboptimal,
678 // but oddly enough not a problem... usually.
680 // The problem with this setup comes during startup.
681 // XPCOM-in-subprocesses depends on IPC, e.g. to init the pref
682 // service, so we have to init IPC first. But, IPC also
683 // indirectly kinda-depends on XPCOM, because MessagePump
684 // schedules work from off-main threads (e.g. IO thread) by
685 // using NS_DispatchToMainThread(). If the IO thread receives a
686 // Message from the parent before nsThreadManager is
687 // initialized, then DispatchToMainThread() will fail, although
688 // MessagePump will remember the task. This race condition
689 // isn't a problem when appShell->Run() ends up in
690 // MessagePump::Run(), because MessagePump will immediate see it
691 // has work to do. It *is* a problem when we end up in [NSApp
692 // run], because it's not aware that MessagePump has work that
693 // needs to be processed; that was supposed to be signaled by
696 // So instead of hacking Cocoa nsAppShell or rewriting the
697 // event-loop system, we compromise here by processing any tasks
698 // that might have been enqueued on MessagePump, *before*
699 // MessagePump::ScheduleWork was able to successfully
700 // DispatchToMainThread().
701 MessageLoop
* loop
= MessageLoop::current();
702 bool couldNest
= loop
->NestableTasksAllowed();
704 loop
->SetNestableTasksAllowed(true);
705 RefPtr
<Runnable
> task
= new MessageLoop::QuitTask();
706 loop
->PostTask(task
.forget());
709 loop
->SetNestableTasksAllowed(couldNest
);
712 return appShell
->Run();
715 void XRE_ShutdownChildProcess() {
716 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
718 mozilla::DebugOnly
<MessageLoop
*> ioLoop
= XRE_GetIOMessageLoop();
719 MOZ_ASSERT(!!ioLoop
, "Bad shutdown order");
721 // Quit() sets off the following chain of events
722 // (1) UI loop starts quitting
723 // (2) UI loop returns from Run() in XRE_InitChildProcess()
724 // (3) ProcessChild goes out of scope and terminates the IO thread
725 // (4) ProcessChild joins the IO thread
727 MessageLoop::current()->Quit();
729 #if defined(XP_MACOSX)
730 nsCOMPtr
<nsIAppShell
> appShell(do_GetService(kAppShellCID
));
732 // On Mac, we might be only above nsAppShell::Run(), not
733 // MessagePump::Run(). See XRE_RunAppShell(). To account for
734 // that case, we fire off an Exit() here. If we were indeed
735 // above MessagePump::Run(), this Exit() is just superfluous.
742 ContentParent
* gContentParent
; // long-lived, manually refcounted
743 TestShellParent
* GetOrCreateTestShellParent() {
744 if (!gContentParent
) {
745 // Use a "web" child process by default. File a bug if you don't like
746 // this and you're sure you wouldn't be better off writing a "browser"
747 // chrome mochitest where you can have multiple types of content
749 RefPtr
<ContentParent
> parent
=
750 ContentParent::GetNewOrUsedBrowserProcess(DEFAULT_REMOTE_TYPE
);
751 parent
.forget(&gContentParent
);
752 } else if (gContentParent
->IsShuttingDown()) {
755 TestShellParent
* tsp
= gContentParent
->GetTestShellSingleton();
757 tsp
= gContentParent
->CreateTestShell();
764 bool XRE_SendTestShellCommand(JSContext
* aCx
, JSString
* aCommand
,
765 JS::Value
* aCallback
) {
766 JS::Rooted
<JSString
*> cmd(aCx
, aCommand
);
767 TestShellParent
* tsp
= GetOrCreateTestShellParent();
768 NS_ENSURE_TRUE(tsp
, false);
770 nsAutoJSString command
;
771 NS_ENSURE_TRUE(command
.init(aCx
, cmd
), false);
774 return tsp
->SendExecuteCommand(command
);
777 TestShellCommandParent
* callback
= static_cast<TestShellCommandParent
*>(
778 tsp
->SendPTestShellCommandConstructor(command
));
779 NS_ENSURE_TRUE(callback
, false);
781 NS_ENSURE_TRUE(callback
->SetCallback(aCx
, *aCallback
), false);
786 bool XRE_ShutdownTestShell() {
787 if (!gContentParent
) {
791 if (gContentParent
->IsAlive()) {
792 ret
= gContentParent
->DestroyTestShell(
793 gContentParent
->GetTestShellSingleton());
795 NS_RELEASE(gContentParent
);
800 void XRE_InstallX11ErrorHandler() {
801 # ifdef MOZ_WIDGET_GTK
802 InstallGdkErrorHandler();
805 // Ensure our X11 error handler overrides the default GDK error handler such
806 // that errors are ignored by default. GDK will install its own error handler
807 // temporarily when pushing error traps internally as needed. This avoids us
808 // otherwise having to frequently override the error handler merely to trap
809 // errors in multiple places that would otherwise contend with GDK or other
810 // libraries that might also override the handler.
811 InstallX11ErrorHandler();
814 void XRE_CleanupX11ErrorHandler() { CleanupX11ErrorHandler(); }
817 #ifdef MOZ_ENABLE_FORKSERVER
818 int XRE_ForkServer(int* aArgc
, char*** aArgv
) {
819 return mozilla::ipc::ForkServer::RunForkServer(aArgc
, aArgv
) ? 1 : 0;