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