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/. */
4
5 #include "mozilla/DebugOnly.h"
6
7 #include "base/basictypes.h"
8
9 #include "nsXULAppAPI.h"
10
11 #include <stdlib.h>
12 #if defined(MOZ_WIDGET_GTK)
13 #include <glib.h>
14 #endif
15
16 #include "prenv.h"
17
18 #include "nsIAppShell.h"
19 #include "nsIAppStartupNotifier.h"
20 #include "nsIDirectoryService.h"
21 #include "nsIFile.h"
22 #include "nsIToolkitChromeRegistry.h"
23 #include "nsIToolkitProfile.h"
24
25 #ifdef XP_WIN
26 #include <process.h>
27 #include <shobjidl.h>
28 #include "mozilla/ipc/WindowsMessageLoop.h"
29 #endif
30
31 #include "nsAppDirectoryServiceDefs.h"
32 #include "nsAppRunner.h"
33 #include "nsAutoRef.h"
34 #include "nsDirectoryServiceDefs.h"
35 #include "nsExceptionHandler.h"
36 #include "nsString.h"
37 #include "nsThreadUtils.h"
38 #include "nsJSUtils.h"
39 #include "nsWidgetsCID.h"
40 #include "nsXREDirProvider.h"
41 #include "ThreadAnnotation.h"
42
43 #include "mozilla/Omnijar.h"
44 #if defined(XP_MACOSX)
45 #include "nsVersionComparator.h"
46 #include "chrome/common/mach_ipc_mac.h"
47 #endif
48 #include "nsX11ErrorHandler.h"
49 #include "nsGDKErrorHandler.h"
50 #include "base/at_exit.h"
51 #include "base/command_line.h"
52 #include "base/message_loop.h"
53 #include "base/process_util.h"
54 #include "chrome/common/child_process.h"
55 #if defined(MOZ_WIDGET_ANDROID)
56 #include "chrome/common/ipc_channel.h"
57 #include "mozilla/jni/Utils.h"
58 #endif // defined(MOZ_WIDGET_ANDROID)
59
60 #include "mozilla/AbstractThread.h"
61 #include "mozilla/FilePreferences.h"
62
63 #include "mozilla/ipc/BrowserProcessSubThread.h"
64 #include "mozilla/ipc/GeckoChildProcessHost.h"
65 #include "mozilla/ipc/IOThreadChild.h"
66 #include "mozilla/ipc/ProcessChild.h"
67 #include "ScopedXREEmbed.h"
68
69 #include "mozilla/plugins/PluginProcessChild.h"
70 #include "mozilla/dom/ContentProcess.h"
71 #include "mozilla/dom/ContentParent.h"
72 #include "mozilla/dom/ContentChild.h"
73
74 #include "mozilla/ipc/TestShellParent.h"
75 #include "mozilla/ipc/XPCShellEnvironment.h"
76 #include "mozilla/Scheduler.h"
77 #include "mozilla/WindowsDllBlocklist.h"
78
79 #include "GMPProcessChild.h"
80 #include "mozilla/gfx/GPUProcessImpl.h"
81
82 #include "GeckoProfiler.h"
83
84 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
85 #include "mozilla/sandboxTarget.h"
86 #include "mozilla/sandboxing/loggingCallbacks.h"
87 #endif
88
89 #if defined(MOZ_CONTENT_SANDBOX)
90 #include "mozilla/SandboxSettings.h"
91 #include "mozilla/Preferences.h"
92 #endif
93
94 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
95 #include "mozilla/Sandbox.h"
96 #endif
97
98 #if defined(XP_LINUX)
99 #include <sys/prctl.h>
100 #ifndef PR_SET_PTRACER
101 #define PR_SET_PTRACER 0x59616d61
102 #endif
103 #ifndef PR_SET_PTRACER_ANY
104 #define PR_SET_PTRACER_ANY ((unsigned long)-1)
105 #endif
106 #endif
107
108 #ifdef MOZ_IPDL_TESTS
109 #include "mozilla/_ipdltest/IPDLUnitTests.h"
110 #include "mozilla/_ipdltest/IPDLUnitTestProcessChild.h"
111
112 using mozilla::_ipdltest::IPDLUnitTestProcessChild;
113 #endif // ifdef MOZ_IPDL_TESTS
114
115 #ifdef MOZ_JPROF
116 #include "jprof.h"
117 #endif
118
119 #if defined(XP_WIN) && defined(MOZ_ENABLE_SKIA_PDF)
120 #include "mozilla/widget/PDFiumProcessChild.h"
121 #endif
122
123 using namespace mozilla;
124
125 using mozilla::ipc::BrowserProcessSubThread;
126 using mozilla::ipc::GeckoChildProcessHost;
127 using mozilla::ipc::IOThreadChild;
128 using mozilla::ipc::ProcessChild;
129 using mozilla::ipc::ScopedXREEmbed;
130
131 using mozilla::dom::ContentChild;
132 using mozilla::dom::ContentParent;
133 using mozilla::dom::ContentProcess;
134 using mozilla::plugins::PluginProcessChild;
135
136 using mozilla::gmp::GMPProcessChild;
137
138 using mozilla::ipc::TestShellCommandParent;
139 using mozilla::ipc::TestShellParent;
140 using mozilla::ipc::XPCShellEnvironment;
141
142 using mozilla::startup::sChildProcessType;
143
144 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
145
XRE_LockProfileDirectory(nsIFile * aDirectory,nsISupports ** aLockObject)146 nsresult XRE_LockProfileDirectory(nsIFile* aDirectory,
147 nsISupports** aLockObject) {
148 nsCOMPtr<nsIProfileLock> lock;
149
150 nsresult rv =
151 NS_LockProfilePath(aDirectory, nullptr, nullptr, getter_AddRefs(lock));
152 if (NS_SUCCEEDED(rv)) NS_ADDREF(*aLockObject = lock);
153
154 return rv;
155 }
156
157 static int32_t sInitCounter;
158
XRE_InitEmbedding2(nsIFile * aLibXULDirectory,nsIFile * aAppDirectory,nsIDirectoryServiceProvider * aAppDirProvider)159 nsresult XRE_InitEmbedding2(nsIFile* aLibXULDirectory, nsIFile* aAppDirectory,
160 nsIDirectoryServiceProvider* aAppDirProvider) {
161 // Initialize some globals to make nsXREDirProvider happy
162 static char* kNullCommandLine[] = {nullptr};
163 gArgv = kNullCommandLine;
164 gArgc = 0;
165
166 NS_ENSURE_ARG(aLibXULDirectory);
167
168 if (++sInitCounter > 1) // XXXbsmedberg is this really the right solution?
169 return NS_OK;
170
171 if (!aAppDirectory) aAppDirectory = aLibXULDirectory;
172
173 nsresult rv;
174
175 new nsXREDirProvider; // This sets gDirServiceProvider
176 if (!gDirServiceProvider) return NS_ERROR_OUT_OF_MEMORY;
177
178 rv = gDirServiceProvider->Initialize(aAppDirectory, aLibXULDirectory,
179 aAppDirProvider);
180 if (NS_FAILED(rv)) return rv;
181
182 rv = NS_InitXPCOM2(nullptr, aAppDirectory, gDirServiceProvider);
183 if (NS_FAILED(rv)) return rv;
184
185 // We do not need to autoregister components here. The CheckCompatibility()
186 // bits in nsAppRunner.cpp check for an invalidation flag in
187 // compatibility.ini.
188 // If the app wants to autoregister every time (for instance, if it's debug),
189 // it can do so after we return from this function.
190
191 nsCOMPtr<nsIObserver> startupNotifier(
192 do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID));
193 if (!startupNotifier) return NS_ERROR_FAILURE;
194
195 startupNotifier->Observe(nullptr, APPSTARTUP_TOPIC, nullptr);
196
197 return NS_OK;
198 }
199
XRE_NotifyProfile()200 void XRE_NotifyProfile() {
201 NS_ASSERTION(gDirServiceProvider, "XRE_InitEmbedding was not called!");
202 gDirServiceProvider->DoStartup();
203 }
204
XRE_TermEmbedding()205 void XRE_TermEmbedding() {
206 if (--sInitCounter != 0) return;
207
208 NS_ASSERTION(gDirServiceProvider,
209 "XRE_TermEmbedding without XRE_InitEmbedding");
210
211 gDirServiceProvider->DoShutdown();
212 NS_ShutdownXPCOM(nullptr);
213 delete gDirServiceProvider;
214 }
215
XRE_ChildProcessTypeToString(GeckoProcessType aProcessType)216 const char* XRE_ChildProcessTypeToString(GeckoProcessType aProcessType) {
217 return (aProcessType < GeckoProcessType_End)
218 ? kGeckoProcessTypeString[aProcessType]
219 : "invalid";
220 }
221
222 namespace mozilla {
223 namespace startup {
224 GeckoProcessType sChildProcessType = GeckoProcessType_Default;
225 } // namespace startup
226 } // namespace mozilla
227
228 #if defined(MOZ_WIDGET_ANDROID)
XRE_SetAndroidChildFds(JNIEnv * env,int ipcFd,int crashFd,int crashAnnotationFd)229 void XRE_SetAndroidChildFds(JNIEnv* env, int ipcFd, int crashFd,
230 int crashAnnotationFd) {
231 mozilla::jni::SetGeckoThreadEnv(env);
232 IPC::Channel::SetClientChannelFd(ipcFd);
233 CrashReporter::SetNotificationPipeForChild(crashFd);
234 CrashReporter::SetCrashAnnotationPipeForChild(crashAnnotationFd);
235 }
236 #endif // defined(MOZ_WIDGET_ANDROID)
237
XRE_SetProcessType(const char * aProcessTypeString)238 void XRE_SetProcessType(const char* aProcessTypeString) {
239 static bool called = false;
240 if (called) {
241 MOZ_CRASH();
242 }
243 called = true;
244
245 sChildProcessType = GeckoProcessType_Invalid;
246 for (int i = 0; i < (int)ArrayLength(kGeckoProcessTypeString); ++i) {
247 if (!strcmp(kGeckoProcessTypeString[i], aProcessTypeString)) {
248 sChildProcessType = static_cast<GeckoProcessType>(i);
249 return;
250 }
251 }
252 }
253
254 // FIXME/bug 539522: this out-of-place function is stuck here because
255 // IPDL wants access to this crashreporter interface, and
256 // crashreporter is built in such a way to make that awkward
XRE_TakeMinidumpForChild(uint32_t aChildPid,nsIFile ** aDump,uint32_t * aSequence)257 bool XRE_TakeMinidumpForChild(uint32_t aChildPid, nsIFile** aDump,
258 uint32_t* aSequence) {
259 return CrashReporter::TakeMinidumpForChild(aChildPid, aDump, aSequence);
260 }
261
262 bool
263 #if defined(XP_WIN)
XRE_SetRemoteExceptionHandler(const char * aPipe,uintptr_t aCrashTimeAnnotationFile)264 XRE_SetRemoteExceptionHandler(const char* aPipe /*= 0*/,
265 uintptr_t aCrashTimeAnnotationFile)
266 #else
267 XRE_SetRemoteExceptionHandler(const char* aPipe /*= 0*/)
268 #endif
269 {
270 #if defined(XP_WIN)
271 return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe),
272 aCrashTimeAnnotationFile);
273 #elif defined(XP_MACOSX)
274 return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe));
275 #else
276 return CrashReporter::SetRemoteExceptionHandler();
277 #endif
278 }
279
280 #if defined(XP_WIN)
SetTaskbarGroupId(const nsString & aId)281 void SetTaskbarGroupId(const nsString& aId) {
282 if (FAILED(SetCurrentProcessExplicitAppUserModelID(aId.get()))) {
283 NS_WARNING(
284 "SetCurrentProcessExplicitAppUserModelID failed for child process.");
285 }
286 }
287 #endif
288
289 #if defined(MOZ_CONTENT_SANDBOX)
AddContentSandboxLevelAnnotation()290 void AddContentSandboxLevelAnnotation() {
291 if (XRE_GetProcessType() == GeckoProcessType_Content) {
292 int level = GetEffectiveContentSandboxLevel();
293 nsAutoCString levelString;
294 levelString.AppendInt(level);
295 CrashReporter::AnnotateCrashReport(
296 NS_LITERAL_CSTRING("ContentSandboxLevel"), levelString);
297 }
298 }
299 #endif /* MOZ_CONTENT_SANDBOX */
300
301 namespace {
302
GetDebugChildPauseTime()303 int GetDebugChildPauseTime() {
304 auto pauseStr = PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE");
305 if (pauseStr && *pauseStr) {
306 int pause = atoi(pauseStr);
307 if (pause != 1) { // must be !=1 since =1 enables the default pause time
308 #if defined(OS_WIN)
309 pause *= 1000; // convert to ms
310 #endif
311 return pause;
312 }
313 }
314 #ifdef OS_POSIX
315 return 30; // seconds
316 #elif defined(OS_WIN)
317 return 10000; // milliseconds
318 #else
319 return 0;
320 #endif
321 }
322
323 } // namespace
324
XRE_InitChildProcess(int aArgc,char * aArgv[],const XREChildData * aChildData)325 nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
326 const XREChildData* aChildData) {
327 NS_ENSURE_ARG_MIN(aArgc, 2);
328 NS_ENSURE_ARG_POINTER(aArgv);
329 NS_ENSURE_ARG_POINTER(aArgv[0]);
330 MOZ_ASSERT(aChildData);
331
332 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
333 // This has to happen before glib thread pools are started.
334 mozilla::SandboxEarlyInit();
335 #endif
336
337 #ifdef MOZ_JPROF
338 // Call the code to install our handler
339 setupProfilingStuff();
340 #endif
341
342 #if defined(XP_WIN)
343 // From the --attach-console support in nsNativeAppSupportWin.cpp, but
344 // here we are a content child process, so we always attempt to attach
345 // to the parent's (ie, the browser's) console.
346 // Try to attach console to the parent process.
347 // It will succeed when the parent process is a command line,
348 // so that stdio will be displayed in it.
349 if (AttachConsole(ATTACH_PARENT_PROCESS)) {
350 // Change std handles to refer to new console handles.
351 // Before doing so, ensure that stdout/stderr haven't been
352 // redirected to a valid file
353 if (_fileno(stdout) == -1 || _get_osfhandle(fileno(stdout)) == -1)
354 freopen("CONOUT$", "w", stdout);
355 // Merge stderr into CONOUT$ since there isn't any `CONERR$`.
356 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
357 if (_fileno(stderr) == -1 || _get_osfhandle(fileno(stderr)) == -1)
358 freopen("CONOUT$", "w", stderr);
359 if (_fileno(stdin) == -1 || _get_osfhandle(fileno(stdin)) == -1)
360 freopen("CONIN$", "r", stdin);
361 }
362
363 #if defined(MOZ_SANDBOX)
364 if (aChildData->sandboxTargetServices) {
365 SandboxTarget::Instance()->SetTargetServices(
366 aChildData->sandboxTargetServices);
367 }
368 #endif
369 #endif
370
371 // NB: This must be called before profiler_init
372 ScopedLogging logger;
373
374 mozilla::LogModule::Init();
375
376 AUTO_PROFILER_INIT;
377 AUTO_PROFILER_LABEL("XRE_InitChildProcess", OTHER);
378
379 // Ensure AbstractThread is minimally setup, so async IPC messages
380 // work properly.
381 AbstractThread::InitTLS();
382
383 // Complete 'task_t' exchange for Mac OS X. This structure has the same size
384 // regardless of architecture so we don't have any cross-arch issues here.
385 #ifdef XP_MACOSX
386 if (aArgc < 1) return NS_ERROR_FAILURE;
387 const char* const mach_port_name = aArgv[--aArgc];
388
389 const int kTimeoutMs = 1000;
390
391 MachSendMessage child_message(0);
392 if (!child_message.AddDescriptor(MachMsgPortDescriptor(mach_task_self()))) {
393 NS_WARNING("child AddDescriptor(mach_task_self()) failed.");
394 return NS_ERROR_FAILURE;
395 }
396
397 ReceivePort child_recv_port;
398 mach_port_t raw_child_recv_port = child_recv_port.GetPort();
399 if (!child_message.AddDescriptor(
400 MachMsgPortDescriptor(raw_child_recv_port))) {
401 NS_WARNING("Adding descriptor to message failed");
402 return NS_ERROR_FAILURE;
403 }
404
405 ReceivePort* ports_out_receiver = new ReceivePort();
406 if (!child_message.AddDescriptor(
407 MachMsgPortDescriptor(ports_out_receiver->GetPort()))) {
408 NS_WARNING("Adding descriptor to message failed");
409 return NS_ERROR_FAILURE;
410 }
411
412 ReceivePort* ports_in_receiver = new ReceivePort();
413 if (!child_message.AddDescriptor(
414 MachMsgPortDescriptor(ports_in_receiver->GetPort()))) {
415 NS_WARNING("Adding descriptor to message failed");
416 return NS_ERROR_FAILURE;
417 }
418
419 MachPortSender child_sender(mach_port_name);
420 kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs);
421 if (err != KERN_SUCCESS) {
422 NS_WARNING("child SendMessage() failed");
423 return NS_ERROR_FAILURE;
424 }
425
426 MachReceiveMessage parent_message;
427 err = child_recv_port.WaitForMessage(&parent_message, kTimeoutMs);
428 if (err != KERN_SUCCESS) {
429 NS_WARNING("child WaitForMessage() failed");
430 return NS_ERROR_FAILURE;
431 }
432
433 if (parent_message.GetTranslatedPort(0) == MACH_PORT_NULL) {
434 NS_WARNING("child GetTranslatedPort(0) failed");
435 return NS_ERROR_FAILURE;
436 }
437
438 err = task_set_bootstrap_port(mach_task_self(),
439 parent_message.GetTranslatedPort(0));
440
441 if (parent_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
442 NS_WARNING("child GetTranslatedPort(1) failed");
443 return NS_ERROR_FAILURE;
444 }
445 MachPortSender* ports_out_sender =
446 new MachPortSender(parent_message.GetTranslatedPort(1));
447
448 if (parent_message.GetTranslatedPort(2) == MACH_PORT_NULL) {
449 NS_WARNING("child GetTranslatedPort(2) failed");
450 return NS_ERROR_FAILURE;
451 }
452 MachPortSender* ports_in_sender =
453 new MachPortSender(parent_message.GetTranslatedPort(2));
454
455 if (err != KERN_SUCCESS) {
456 NS_WARNING("child task_set_bootstrap_port() failed");
457 return NS_ERROR_FAILURE;
458 }
459
460 #endif
461
462 SetupErrorHandling(aArgv[0]);
463
464 if (!CrashReporter::IsDummy()) {
465 #if defined(XP_WIN)
466 if (aArgc < 1) {
467 return NS_ERROR_FAILURE;
468 }
469 const char* const crashTimeAnnotationArg = aArgv[--aArgc];
470 uintptr_t crashTimeAnnotationFile =
471 static_cast<uintptr_t>(std::stoul(std::string(crashTimeAnnotationArg)));
472 #endif
473
474 if (aArgc < 1) return NS_ERROR_FAILURE;
475 const char* const crashReporterArg = aArgv[--aArgc];
476
477 #if defined(XP_MACOSX)
478 // on windows and mac, |crashReporterArg| is the named pipe on which the
479 // server is listening for requests, or "-" if crash reporting is
480 // disabled.
481 if (0 != strcmp("-", crashReporterArg) &&
482 !XRE_SetRemoteExceptionHandler(crashReporterArg)) {
483 // Bug 684322 will add better visibility into this condition
484 NS_WARNING("Could not setup crash reporting\n");
485 }
486 #elif defined(XP_WIN)
487 if (0 != strcmp("-", crashReporterArg) &&
488 !XRE_SetRemoteExceptionHandler(crashReporterArg,
489 crashTimeAnnotationFile)) {
490 // Bug 684322 will add better visibility into this condition
491 NS_WARNING("Could not setup crash reporting\n");
492 }
493 #else
494 // on POSIX, |crashReporterArg| is "true" if crash reporting is
495 // enabled, false otherwise
496 if (0 != strcmp("false", crashReporterArg) &&
497 !XRE_SetRemoteExceptionHandler(nullptr)) {
498 // Bug 684322 will add better visibility into this condition
499 NS_WARNING("Could not setup crash reporting\n");
500 }
501 #endif
502 }
503
504 // For Init/Shutdown thread name annotations in the crash reporter.
505 CrashReporter::InitThreadAnnotationRAII annotation;
506
507 gArgv = aArgv;
508 gArgc = aArgc;
509
510 #ifdef MOZ_X11
511 XInitThreads();
512 #endif
513 #ifdef MOZ_WIDGET_GTK
514 // Setting the name here avoids the need to pass this through to gtk_init().
515 g_set_prgname(aArgv[0]);
516 #endif
517
518 #ifdef OS_POSIX
519 if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS") ||
520 PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
521 #if defined(XP_LINUX) && defined(DEBUG)
522 if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0) != 0) {
523 printf_stderr("Could not allow ptrace from any process.\n");
524 }
525 #endif
526 printf_stderr(
527 "\n\nCHILDCHILDCHILDCHILD (process type %s)\n debug me @ %d\n\n",
528 XRE_ChildProcessTypeToString(XRE_GetProcessType()),
529 base::GetCurrentProcId());
530 sleep(GetDebugChildPauseTime());
531 }
532 #elif defined(OS_WIN)
533 if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS")) {
534 NS_DebugBreak(NS_DEBUG_BREAK,
535 "Invoking NS_DebugBreak() to debug child process", nullptr,
536 __FILE__, __LINE__);
537 } else if (PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
538 printf_stderr(
539 "\n\nCHILDCHILDCHILDCHILD (process type %s)\n debug me @ %d\n\n",
540 XRE_ChildProcessTypeToString(XRE_GetProcessType()),
541 base::GetCurrentProcId());
542 ::Sleep(GetDebugChildPauseTime());
543 }
544 #endif
545
546 // child processes launched by GeckoChildProcessHost get this magic
547 // argument appended to their command lines
548 const char* const parentPIDString = aArgv[aArgc - 1];
549 MOZ_ASSERT(parentPIDString, "NULL parent PID");
550 --aArgc;
551
552 char* end = 0;
553 base::ProcessId parentPID = strtol(parentPIDString, &end, 10);
554 MOZ_ASSERT(!*end, "invalid parent PID");
555
556 nsCOMPtr<nsIFile> crashReportTmpDir;
557 if (XRE_GetProcessType() == GeckoProcessType_GPU) {
558 aArgc--;
559 if (strlen(aArgv[aArgc])) { // if it's empty, ignore it
560 nsresult rv =
561 XRE_GetFileFromPath(aArgv[aArgc], getter_AddRefs(crashReportTmpDir));
562 if (NS_FAILED(rv)) {
563 // If we don't have a valid tmp dir we can probably still run ok, but
564 // crash report .extra files might not get picked up by the parent
565 // process. Debug-assert because this shouldn't happen in practice.
566 MOZ_ASSERT(false, "GPU process started without valid tmp dir!");
567 }
568 }
569 }
570
571 #ifdef XP_MACOSX
572 mozilla::ipc::SharedMemoryBasic::SetupMachMemory(
573 parentPID, ports_in_receiver, ports_in_sender, ports_out_sender,
574 ports_out_receiver, true);
575 #endif
576
577 #if defined(XP_WIN)
578 // On Win7+, register the application user model id passed in by
579 // parent. This insures windows created by the container properly
580 // group with the parent app on the Win7 taskbar.
581 const char* const appModelUserId = aArgv[--aArgc];
582 if (appModelUserId) {
583 // '-' implies no support
584 if (*appModelUserId != '-') {
585 nsString appId;
586 CopyASCIItoUTF16(nsDependentCString(appModelUserId), appId);
587 // The version string is encased in quotes
588 appId.Trim("\"");
589 // Set the id
590 SetTaskbarGroupId(appId);
591 }
592 }
593 #endif
594
595 base::AtExitManager exitManager;
596
597 nsresult rv = XRE_InitCommandLine(aArgc, aArgv);
598 if (NS_FAILED(rv)) {
599 return NS_ERROR_FAILURE;
600 }
601
602 MessageLoop::Type uiLoopType;
603 switch (XRE_GetProcessType()) {
604 case GeckoProcessType_Content:
605 case GeckoProcessType_GPU:
606 // Content processes need the XPCOM/chromium frankenventloop
607 uiLoopType = MessageLoop::TYPE_MOZILLA_CHILD;
608 break;
609 case GeckoProcessType_GMPlugin:
610 case GeckoProcessType_PDFium:
611 uiLoopType = MessageLoop::TYPE_DEFAULT;
612 break;
613 default:
614 uiLoopType = MessageLoop::TYPE_UI;
615 break;
616 }
617
618 {
619 // This is a lexical scope for the MessageLoop below. We want it
620 // to go out of scope before NS_LogTerm() so that we don't get
621 // spurious warnings about XPCOM objects being destroyed from a
622 // static context.
623
624 // Associate this thread with a UI MessageLoop
625 MessageLoop uiMessageLoop(uiLoopType);
626 {
627 nsAutoPtr<ProcessChild> process;
628
629 #ifdef XP_WIN
630 mozilla::ipc::windows::InitUIThread();
631 #endif
632
633 switch (XRE_GetProcessType()) {
634 case GeckoProcessType_Default:
635 MOZ_CRASH("This makes no sense");
636 break;
637
638 case GeckoProcessType_Plugin:
639 process = new PluginProcessChild(parentPID);
640 break;
641
642 case GeckoProcessType_Content:
643 process = new ContentProcess(parentPID);
644 break;
645
646 case GeckoProcessType_IPDLUnitTest:
647 #ifdef MOZ_IPDL_TESTS
648 process = new IPDLUnitTestProcessChild(parentPID);
649 #else
650 MOZ_CRASH("rebuild with --enable-ipdl-tests");
651 #endif
652 break;
653
654 case GeckoProcessType_GMPlugin:
655 process = new gmp::GMPProcessChild(parentPID);
656 break;
657
658 #if defined(XP_WIN) && defined(MOZ_ENABLE_SKIA_PDF)
659 case GeckoProcessType_PDFium:
660 process = new widget::PDFiumProcessChild(parentPID);
661 break;
662 #endif
663 case GeckoProcessType_GPU:
664 process = new gfx::GPUProcessImpl(parentPID);
665 break;
666
667 default:
668 MOZ_CRASH("Unknown main thread class");
669 }
670
671 if (!process->Init(aArgc, aArgv)) {
672 return NS_ERROR_FAILURE;
673 }
674
675 #if defined(XP_WIN)
676 // Set child processes up such that they will get killed after the
677 // chrome process is killed in cases where the user shuts the system
678 // down or logs off.
679 ::SetProcessShutdownParameters(0x280 - 1, SHUTDOWN_NORETRY);
680 #endif
681
682 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
683 // We need to do this after the process has been initialised, as
684 // InitLoggingIfRequired may need access to prefs.
685 mozilla::sandboxing::InitLoggingIfRequired(
686 aChildData->ProvideLogFunction);
687 #endif
688 mozilla::FilePreferences::InitDirectoriesWhitelist();
689 mozilla::FilePreferences::InitPrefs();
690
691 OverrideDefaultLocaleIfNeeded();
692
693 #if defined(MOZ_CONTENT_SANDBOX)
694 AddContentSandboxLevelAnnotation();
695 #endif
696
697 // Run the UI event loop on the main thread.
698 uiMessageLoop.MessageLoop::Run();
699
700 // Allow ProcessChild to clean up after itself before going out of
701 // scope and being deleted
702 process->CleanUp();
703 mozilla::Omnijar::CleanUp();
704
705 #if defined(XP_MACOSX)
706 // Everybody should be done using shared memory by now.
707 mozilla::ipc::SharedMemoryBasic::Shutdown();
708 #endif
709 }
710 }
711
712 return XRE_DeinitCommandLine();
713 }
714
XRE_GetIOMessageLoop()715 MessageLoop* XRE_GetIOMessageLoop() {
716 if (sChildProcessType == GeckoProcessType_Default) {
717 return BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO);
718 }
719 return IOThreadChild::message_loop();
720 }
721
722 namespace {
723
724 class MainFunctionRunnable : public Runnable {
725 public:
726 NS_DECL_NSIRUNNABLE
727
MainFunctionRunnable(MainFunction aFunction,void * aData)728 MainFunctionRunnable(MainFunction aFunction, void* aData)
729 : mozilla::Runnable("MainFunctionRunnable"),
730 mFunction(aFunction),
731 mData(aData) {
732 NS_ASSERTION(aFunction, "Don't give me a null pointer!");
733 }
734
735 private:
736 MainFunction mFunction;
737 void* mData;
738 };
739
740 } /* anonymous namespace */
741
742 NS_IMETHODIMP
Run()743 MainFunctionRunnable::Run() {
744 mFunction(mData);
745 return NS_OK;
746 }
747
XRE_InitParentProcess(int aArgc,char * aArgv[],MainFunction aMainFunction,void * aMainFunctionData)748 nsresult XRE_InitParentProcess(int aArgc, char* aArgv[],
749 MainFunction aMainFunction,
750 void* aMainFunctionData) {
751 NS_ENSURE_ARG_MIN(aArgc, 1);
752 NS_ENSURE_ARG_POINTER(aArgv);
753 NS_ENSURE_ARG_POINTER(aArgv[0]);
754
755 // Set main thread before we initialize the profiler
756 NS_SetMainThread();
757
758 mozilla::LogModule::Init();
759
760 AUTO_PROFILER_INIT;
761
762 ScopedXREEmbed embed;
763
764 gArgc = aArgc;
765 gArgv = aArgv;
766 nsresult rv = XRE_InitCommandLine(gArgc, gArgv);
767 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
768
769 {
770 embed.Start();
771
772 nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
773 NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
774
775 if (aMainFunction) {
776 nsCOMPtr<nsIRunnable> runnable =
777 new MainFunctionRunnable(aMainFunction, aMainFunctionData);
778 NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
779
780 nsresult rv = NS_DispatchToCurrentThread(runnable);
781 NS_ENSURE_SUCCESS(rv, rv);
782 }
783
784 // Do event loop
785 if (NS_FAILED(appShell->Run())) {
786 NS_WARNING("Failed to run appshell");
787 return NS_ERROR_FAILURE;
788 }
789 }
790
791 return XRE_DeinitCommandLine();
792 }
793
794 #ifdef MOZ_IPDL_TESTS
795 //-----------------------------------------------------------------------------
796 // IPDL unit test
797
XRE_RunIPDLTest(int aArgc,char ** aArgv)798 int XRE_RunIPDLTest(int aArgc, char** aArgv) {
799 if (aArgc < 2) {
800 fprintf(
801 stderr,
802 "TEST-UNEXPECTED-FAIL | <---> | insufficient #args, need at least 2\n");
803 return 1;
804 }
805
806 void* data = reinterpret_cast<void*>(aArgv[aArgc - 1]);
807
808 nsresult rv = XRE_InitParentProcess(
809 --aArgc, aArgv, mozilla::_ipdltest::IPDLUnitTestMain, data);
810 NS_ENSURE_SUCCESS(rv, 1);
811
812 return 0;
813 }
814 #endif // ifdef MOZ_IPDL_TESTS
815
XRE_RunAppShell()816 nsresult XRE_RunAppShell() {
817 nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
818 NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
819 #if defined(XP_MACOSX)
820 if (XRE_UseNativeEventProcessing()) {
821 // In content processes that want XPCOM (and hence want
822 // AppShell), we usually run our hybrid event loop through
823 // MessagePump::Run(), by way of nsBaseAppShell::Run(). The
824 // Cocoa nsAppShell impl, however, implements its own Run()
825 // that's unaware of MessagePump. That's all rather suboptimal,
826 // but oddly enough not a problem... usually.
827 //
828 // The problem with this setup comes during startup.
829 // XPCOM-in-subprocesses depends on IPC, e.g. to init the pref
830 // service, so we have to init IPC first. But, IPC also
831 // indirectly kinda-depends on XPCOM, because MessagePump
832 // schedules work from off-main threads (e.g. IO thread) by
833 // using NS_DispatchToMainThread(). If the IO thread receives a
834 // Message from the parent before nsThreadManager is
835 // initialized, then DispatchToMainThread() will fail, although
836 // MessagePump will remember the task. This race condition
837 // isn't a problem when appShell->Run() ends up in
838 // MessagePump::Run(), because MessagePump will immediate see it
839 // has work to do. It *is* a problem when we end up in [NSApp
840 // run], because it's not aware that MessagePump has work that
841 // needs to be processed; that was supposed to be signaled by
842 // nsIRunnable(s).
843 //
844 // So instead of hacking Cocoa nsAppShell or rewriting the
845 // event-loop system, we compromise here by processing any tasks
846 // that might have been enqueued on MessagePump, *before*
847 // MessagePump::ScheduleWork was able to successfully
848 // DispatchToMainThread().
849 MessageLoop* loop = MessageLoop::current();
850 bool couldNest = loop->NestableTasksAllowed();
851
852 loop->SetNestableTasksAllowed(true);
853 RefPtr<Runnable> task = new MessageLoop::QuitTask();
854 loop->PostTask(task.forget());
855 loop->Run();
856
857 loop->SetNestableTasksAllowed(couldNest);
858 }
859 #endif // XP_MACOSX
860 return appShell->Run();
861 }
862
XRE_ShutdownChildProcess()863 void XRE_ShutdownChildProcess() {
864 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
865
866 mozilla::DebugOnly<MessageLoop*> ioLoop = XRE_GetIOMessageLoop();
867 MOZ_ASSERT(!!ioLoop, "Bad shutdown order");
868
869 Scheduler::Shutdown();
870
871 // Quit() sets off the following chain of events
872 // (1) UI loop starts quitting
873 // (2) UI loop returns from Run() in XRE_InitChildProcess()
874 // (3) ProcessChild goes out of scope and terminates the IO thread
875 // (4) ProcessChild joins the IO thread
876 // (5) exit()
877 MessageLoop::current()->Quit();
878
879 #if defined(XP_MACOSX)
880 nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
881 if (appShell) {
882 // On Mac, we might be only above nsAppShell::Run(), not
883 // MessagePump::Run(). See XRE_RunAppShell(). To account for
884 // that case, we fire off an Exit() here. If we were indeed
885 // above MessagePump::Run(), this Exit() is just superfluous.
886 appShell->Exit();
887 }
888 #endif // XP_MACOSX
889 }
890
891 namespace {
892 ContentParent* gContentParent; // long-lived, manually refcounted
GetOrCreateTestShellParent()893 TestShellParent* GetOrCreateTestShellParent() {
894 if (!gContentParent) {
895 // Use a "web" child process by default. File a bug if you don't like
896 // this and you're sure you wouldn't be better off writing a "browser"
897 // chrome mochitest where you can have multiple types of content
898 // processes.
899 RefPtr<ContentParent> parent = ContentParent::GetNewOrUsedBrowserProcess(
900 NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
901 parent.forget(&gContentParent);
902 } else if (!gContentParent->IsAlive()) {
903 return nullptr;
904 }
905 TestShellParent* tsp = gContentParent->GetTestShellSingleton();
906 if (!tsp) {
907 tsp = gContentParent->CreateTestShell();
908 }
909 return tsp;
910 }
911
912 } // namespace
913
XRE_SendTestShellCommand(JSContext * aCx,JSString * aCommand,void * aCallback)914 bool XRE_SendTestShellCommand(JSContext* aCx, JSString* aCommand,
915 void* aCallback) {
916 JS::RootedString cmd(aCx, aCommand);
917 TestShellParent* tsp = GetOrCreateTestShellParent();
918 NS_ENSURE_TRUE(tsp, false);
919
920 nsAutoJSString command;
921 NS_ENSURE_TRUE(command.init(aCx, cmd), false);
922
923 if (!aCallback) {
924 return tsp->SendExecuteCommand(command);
925 }
926
927 TestShellCommandParent* callback = static_cast<TestShellCommandParent*>(
928 tsp->SendPTestShellCommandConstructor(command));
929 NS_ENSURE_TRUE(callback, false);
930
931 JS::Value callbackVal = *reinterpret_cast<JS::Value*>(aCallback);
932 NS_ENSURE_TRUE(callback->SetCallback(aCx, callbackVal), false);
933
934 return true;
935 }
936
XRE_ShutdownTestShell()937 bool XRE_ShutdownTestShell() {
938 if (!gContentParent) {
939 return true;
940 }
941 bool ret = true;
942 if (gContentParent->IsAlive()) {
943 ret = gContentParent->DestroyTestShell(
944 gContentParent->GetTestShellSingleton());
945 }
946 NS_RELEASE(gContentParent);
947 return ret;
948 }
949
950 #ifdef MOZ_X11
XRE_InstallX11ErrorHandler()951 void XRE_InstallX11ErrorHandler() {
952 #ifdef MOZ_WIDGET_GTK
953 InstallGdkErrorHandler();
954 #else
955 InstallX11ErrorHandler();
956 #endif
957 }
958 #endif
959