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