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