Coverage Report

Created: 2018-09-25 14:53

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