Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / ipc / glue / GeckoChildProcessHost.cpp
blobaa3f58360ffd47a65425346a384345b0d2d104c9
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "GeckoChildProcessHost.h"
9 #include "base/command_line.h"
10 #include "base/process.h"
11 #include "base/process_util.h"
12 #include "base/string_util.h"
13 #include "base/task.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/process_watcher.h"
16 #ifdef XP_DARWIN
17 # include <mach/mach_traps.h>
18 # include "SharedMemory.h"
19 # include "base/rand_util.h"
20 # include "chrome/common/mach_ipc_mac.h"
21 # include "mozilla/StaticPrefs_media.h"
22 #endif
23 #ifdef MOZ_WIDGET_COCOA
24 # include <bsm/libbsm.h>
25 # include <servers/bootstrap.h>
26 # include "nsILocalFileMac.h"
27 #endif
29 #include "GeckoProfiler.h"
30 #include "MainThreadUtils.h"
31 #include "mozilla/Preferences.h"
32 #include "mozilla/Sprintf.h"
33 #include "nsXPCOMPrivate.h"
34 #include "prenv.h"
35 #include "prerror.h"
37 #if defined(MOZ_SANDBOX)
38 # include "mozilla/SandboxSettings.h"
39 # include "nsAppDirectoryServiceDefs.h"
40 #endif
42 #include <sys/stat.h>
44 #include "ProtocolUtils.h"
45 #include "mozilla/LinkedList.h"
46 #include "mozilla/Logging.h"
47 #include "mozilla/Maybe.h"
48 #include "mozilla/GeckoArgs.h"
49 #include "mozilla/Omnijar.h"
50 #include "mozilla/RDDProcessHost.h"
51 #include "mozilla/Services.h"
52 #include "mozilla/SharedThreadPool.h"
53 #include "mozilla/StaticMutex.h"
54 #include "mozilla/TaskQueue.h"
55 #include "mozilla/glean/DomMetrics.h"
56 #include "mozilla/Telemetry.h"
57 #include "mozilla/UniquePtrExtensions.h"
58 #include "mozilla/ipc/IOThread.h"
59 #include "mozilla/ipc/EnvironmentMap.h"
60 #include "mozilla/ipc/NodeController.h"
61 #include "mozilla/net/SocketProcessHost.h"
62 #include "nsDirectoryService.h"
63 #include "nsDirectoryServiceDefs.h"
64 #include "nsExceptionHandler.h"
65 #include "nsIFile.h"
66 #include "nsIObserverService.h"
67 #include "nsPrintfCString.h"
69 #ifdef XP_WIN
70 # include <stdlib.h>
72 # include "nsIWinTaskbar.h"
73 # define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
75 # if defined(MOZ_SANDBOX)
76 # include "WinUtils.h"
77 # include "mozilla/Preferences.h"
78 # include "mozilla/sandboxing/sandboxLogging.h"
79 # endif
81 # include "mozilla/NativeNt.h"
82 # include "mozilla/CacheNtDllThunk.h"
83 #endif
85 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
86 # include "mozilla/SandboxLaunch.h"
87 #endif
89 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
90 # include "GMPProcessParent.h"
91 # include "nsMacUtilsImpl.h"
92 #endif
94 #include "mozilla/ipc/UtilityProcessHost.h"
95 #include "mozilla/ipc/UtilityProcessSandboxing.h"
97 #include "nsClassHashtable.h"
98 #include "nsHashKeys.h"
99 #include "nsNativeCharsetUtils.h"
100 #include "nsTArray.h"
101 #include "nscore.h" // for NS_FREE_PERMANENT_DATA
102 #include "nsIThread.h"
104 using mozilla::MonitorAutoLock;
105 using mozilla::Preferences;
106 using mozilla::StaticMutexAutoLock;
108 #ifdef MOZ_WIDGET_ANDROID
109 # include "AndroidBridge.h"
110 # include "mozilla/java/GeckoProcessManagerWrappers.h"
111 # include "mozilla/java/GeckoProcessTypeWrappers.h"
112 # include "mozilla/java/GeckoResultWrappers.h"
113 # include "mozilla/jni/Refs.h"
114 # include "mozilla/jni/Utils.h"
115 #endif
117 #ifdef MOZ_ENABLE_FORKSERVER
118 # include "mozilla/ipc/ForkServiceChild.h"
119 #endif
121 static bool ShouldHaveDirectoryService() {
122 return GeckoProcessType_Default == XRE_GetProcessType();
125 namespace mozilla {
126 namespace ipc {
128 struct LaunchResults {
129 base::ProcessHandle mHandle = 0;
130 #ifdef XP_DARWIN
131 task_t mChildTask = MACH_PORT_NULL;
132 #endif
133 #ifdef XP_IOS
134 Maybe<ExtensionKitProcess> mExtensionKitProcess;
135 DarwinObjectPtr<xpc_connection_t> mXPCConnection;
136 UniqueBEProcessCapabilityGrant mForegroundCapabilityGrant;
137 #endif
138 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
139 UniquePtr<SandboxBroker> mSandboxBroker;
140 #endif
142 typedef mozilla::MozPromise<LaunchResults, LaunchError, true>
143 ProcessLaunchPromise;
145 // Monotonic counter used to generate a unique ChildID for each process as it is
146 // created. The parent process is given the ChildID of `0`, and each child
147 // process is given a non-zero ID.
148 static Atomic<int32_t> gChildCounter;
150 class BaseProcessLauncher {
151 public:
152 BaseProcessLauncher(GeckoChildProcessHost* aHost,
153 geckoargs::ChildProcessArgs&& aExtraOpts)
154 : mProcessType(aHost->mProcessType),
155 mLaunchOptions(std::move(aHost->mLaunchOptions)),
156 mChildArgs(std::move(aExtraOpts))
157 #ifdef XP_WIN
159 mGroupId(aHost->mGroupId)
160 #endif
161 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
163 mAllowedFilesRead(aHost->mAllowedFilesRead),
164 mSandboxLevel(aHost->mSandboxLevel),
165 mSandbox(aHost->mSandbox),
166 mIsFileContent(aHost->mIsFileContent),
167 mEnableSandboxLogging(aHost->mEnableSandboxLogging)
168 #endif
169 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
171 mDisableOSActivityMode(aHost->mDisableOSActivityMode)
172 #endif
174 aHost->mInitialChannelId.ToProvidedString(mInitialChannelIdString);
175 SprintfLiteral(mChildIDString, "%d", aHost->mChildID);
177 // Compute the serial event target we'll use for launching.
178 nsCOMPtr<nsIEventTarget> threadOrPool = GetIPCLauncher();
179 mLaunchThread =
180 TaskQueue::Create(threadOrPool.forget(), "BaseProcessLauncher");
182 if (ShouldHaveDirectoryService()) {
183 // "Current process directory" means the app dir, not the current
184 // working dir or similar.
185 mozilla::Unused
186 << nsDirectoryService::gService->GetCurrentProcessDirectory(
187 getter_AddRefs(mAppDir));
191 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BaseProcessLauncher);
193 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
194 void SetLaunchArchitecture(uint32_t aLaunchArch) {
195 mLaunchArch = aLaunchArch;
197 #endif
199 RefPtr<ProcessLaunchPromise> Launch(GeckoChildProcessHost*);
201 protected:
202 virtual ~BaseProcessLauncher() = default;
204 RefPtr<ProcessLaunchPromise> PerformAsyncLaunch();
205 RefPtr<ProcessLaunchPromise> FinishLaunch();
207 // Overrideable hooks. If superclass behavior is invoked, it's always at the
208 // top of the override.
209 virtual Result<Ok, LaunchError> DoSetup();
210 virtual RefPtr<ProcessHandlePromise> DoLaunch() = 0;
211 virtual Result<Ok, LaunchError> DoFinishLaunch();
213 void MapChildLogging();
215 static BinPathType GetPathToBinary(FilePath&, GeckoProcessType);
217 void GetChildLogName(const char* origLogName, nsACString& buffer);
219 const char* ChildProcessType() {
220 return XRE_GeckoProcessTypeToString(mProcessType);
223 nsCOMPtr<nsISerialEventTarget> mLaunchThread;
224 GeckoProcessType mProcessType;
225 UniquePtr<base::LaunchOptions> mLaunchOptions;
226 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
227 uint32_t mLaunchArch = base::PROCESS_ARCH_INVALID;
228 #endif
229 geckoargs::ChildProcessArgs mChildArgs;
230 #ifdef XP_WIN
231 nsString mGroupId;
232 #endif
233 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
234 std::vector<std::wstring> mAllowedFilesRead;
235 int32_t mSandboxLevel;
236 SandboxingKind mSandbox;
237 bool mIsFileContent;
238 bool mEnableSandboxLogging;
239 #endif
240 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
241 // Controls whether or not the process will be launched with
242 // environment variable OS_ACTIVITY_MODE set to "disabled".
243 bool mDisableOSActivityMode;
244 #endif
245 LaunchResults mResults = LaunchResults();
246 TimeStamp mStartTimeStamp = TimeStamp::Now();
247 char mInitialChannelIdString[NSID_LENGTH];
248 char mChildIDString[32];
250 // Set during launch.
251 nsCOMPtr<nsIFile> mAppDir;
254 #ifdef XP_WIN
255 class WindowsProcessLauncher : public BaseProcessLauncher {
256 public:
257 WindowsProcessLauncher(GeckoChildProcessHost* aHost,
258 geckoargs::ChildProcessArgs&& aExtraOpts)
259 : BaseProcessLauncher(aHost, std::move(aExtraOpts)),
260 mCachedNtdllThunk(GetCachedNtDllThunk()) {}
262 protected:
263 virtual Result<Ok, LaunchError> DoSetup() override;
264 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
265 virtual Result<Ok, LaunchError> DoFinishLaunch() override;
267 mozilla::Maybe<CommandLine> mCmdLine;
268 # ifdef MOZ_SANDBOX
269 bool mUseSandbox = false;
270 # endif
272 const Buffer<IMAGE_THUNK_DATA>* mCachedNtdllThunk;
274 typedef WindowsProcessLauncher ProcessLauncher;
275 #endif // XP_WIN
277 #ifdef XP_UNIX
278 class PosixProcessLauncher : public BaseProcessLauncher {
279 public:
280 PosixProcessLauncher(GeckoChildProcessHost* aHost,
281 geckoargs::ChildProcessArgs&& aExtraOpts)
282 : BaseProcessLauncher(aHost, std::move(aExtraOpts)),
283 mProfileDir(aHost->mProfileDir) {}
285 protected:
286 virtual Result<Ok, LaunchError> DoSetup() override;
287 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
289 nsCOMPtr<nsIFile> mProfileDir;
292 # if defined(XP_MACOSX)
293 class MacProcessLauncher : public PosixProcessLauncher {
294 public:
295 MacProcessLauncher(GeckoChildProcessHost* aHost,
296 geckoargs::ChildProcessArgs&& aExtraOpts)
297 : PosixProcessLauncher(aHost, std::move(aExtraOpts)),
298 // Put a random number into the channel name, so that
299 // a compromised renderer can't pretend being the child
300 // that's forked off.
301 mMachConnectionName(
302 StringPrintf("org.mozilla.machname.%d",
303 base::RandInt(0, std::numeric_limits<int>::max()))) {
304 MOZ_ASSERT(mMachConnectionName.size() < BOOTSTRAP_MAX_NAME_LEN);
307 protected:
308 virtual Result<Ok, LaunchError> DoFinishLaunch() override;
310 std::string mMachConnectionName;
311 // We add a mach port to the command line so the child can communicate its
312 // 'task_t' back to the parent.
313 mozilla::UniqueMachReceiveRight mParentRecvPort;
315 friend class PosixProcessLauncher;
317 typedef MacProcessLauncher ProcessLauncher;
318 # elif defined(MOZ_WIDGET_ANDROID)
319 class AndroidProcessLauncher : public PosixProcessLauncher {
320 public:
321 AndroidProcessLauncher(GeckoChildProcessHost* aHost,
322 geckoargs::ChildProcessArgs&& aExtraOpts)
323 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
325 protected:
326 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
327 RefPtr<ProcessHandlePromise> LaunchAndroidService(
328 const GeckoProcessType aType, const geckoargs::ChildProcessArgs& args);
330 typedef AndroidProcessLauncher ProcessLauncher;
331 // NB: Technically Android is linux (i.e. XP_LINUX is defined), but we want
332 // orthogonal IPC machinery there. Conversely, there are tier-3 non-Linux
333 // platforms (BSD and Solaris) where we want the "linux" IPC machinery. So
334 // we use MOZ_WIDGET_* to choose the platform backend.
335 # elif defined(MOZ_WIDGET_GTK)
336 class LinuxProcessLauncher : public PosixProcessLauncher {
337 public:
338 LinuxProcessLauncher(GeckoChildProcessHost* aHost,
339 geckoargs::ChildProcessArgs&& aExtraOpts)
340 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
342 protected:
343 virtual Result<Ok, LaunchError> DoSetup() override;
345 typedef LinuxProcessLauncher ProcessLauncher;
346 # elif defined(MOZ_WIDGET_UIKIT)
347 class IosProcessLauncher : public PosixProcessLauncher {
348 public:
349 IosProcessLauncher(GeckoChildProcessHost* aHost,
350 geckoargs::ChildProcessArgs&& aExtraOpts)
351 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
353 protected:
354 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
356 DarwinObjectPtr<xpc_object_t> mBootstrapMessage;
358 typedef IosProcessLauncher ProcessLauncher;
359 # else
360 # error "Unknown platform"
361 # endif
362 #endif // XP_UNIX
364 using base::ProcessHandle;
365 using mozilla::ipc::BaseProcessLauncher;
366 using mozilla::ipc::ProcessLauncher;
368 mozilla::StaticAutoPtr<mozilla::LinkedList<GeckoChildProcessHost>>
369 GeckoChildProcessHost::sGeckoChildProcessHosts;
371 mozilla::StaticMutex GeckoChildProcessHost::sMutex;
373 GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
374 bool aIsFileContent)
375 : mProcessType(aProcessType),
376 mChildID(++gChildCounter),
377 mIsFileContent(aIsFileContent),
378 mMonitor("mozilla.ipc.GeckoChildProcessHost.mMonitor"),
379 mLaunchOptions(MakeUnique<base::LaunchOptions>()),
380 mInitialChannelId(nsID::GenerateUUID()),
381 mProcessState(CREATING_CHANNEL),
382 #ifdef XP_WIN
383 mGroupId(u"-"),
384 #endif
385 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
386 mEnableSandboxLogging(false),
387 mSandboxLevel(0),
388 #endif
389 mHandleLock("mozilla.ipc.GeckoChildProcessHost.mHandleLock"),
390 mChildProcessHandle(0),
391 #if defined(XP_DARWIN)
392 mChildTask(MACH_PORT_NULL),
393 #endif
394 #if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
395 mDisableOSActivityMode(false),
396 #endif
397 mDestroying(false) {
398 MOZ_COUNT_CTOR(GeckoChildProcessHost);
399 MOZ_RELEASE_ASSERT(mChildID > 0, "gChildCounter overflowed");
400 StaticMutexAutoLock lock(sMutex);
401 if (!sGeckoChildProcessHosts) {
402 sGeckoChildProcessHosts = new mozilla::LinkedList<GeckoChildProcessHost>();
404 sGeckoChildProcessHosts->insertBack(this);
405 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
406 if (aProcessType == GeckoProcessType_RDD) {
407 // The RDD process makes limited use of EGL. If Mesa's shader
408 // cache is enabled and the directory isn't explicitly set, then
409 // it will try to getpwuid() the user which can cause problems
410 // with sandboxing. Because we shouldn't need shader caching in
411 // this process, we just disable the cache to prevent that.
412 mLaunchOptions->env_map["MESA_GLSL_CACHE_DISABLE"] = "true";
413 mLaunchOptions->env_map["MESA_SHADER_CACHE_DISABLE"] = "true";
414 // In case the nvidia driver is also loaded:
415 mLaunchOptions->env_map["__GL_SHADER_DISK_CACHE"] = "0";
417 #endif
420 GeckoChildProcessHost::~GeckoChildProcessHost() {
421 AssertIOThread();
422 MOZ_RELEASE_ASSERT(mDestroying);
424 MOZ_COUNT_DTOR(GeckoChildProcessHost);
427 mozilla::AutoWriteLock hLock(mHandleLock);
428 #if defined(XP_DARWIN)
429 if (mChildTask != MACH_PORT_NULL) {
430 mach_port_deallocate(mach_task_self(), mChildTask);
432 #endif
433 #if defined(XP_IOS)
434 if (mForegroundCapabilityGrant) {
435 mForegroundCapabilityGrant.reset();
437 if (mExtensionKitProcess) {
438 mExtensionKitProcess->Invalidate();
440 if (mXPCConnection) {
441 xpc_connection_cancel(mXPCConnection.get());
443 #endif
445 if (mChildProcessHandle != 0) {
446 ProcessWatcher::EnsureProcessTerminated(
447 mChildProcessHandle
448 #ifdef NS_FREE_PERMANENT_DATA
449 // If we're doing leak logging, shutdown can be slow.
451 false // don't "force"
452 #endif
454 mChildProcessHandle = 0;
459 base::ProcessHandle GeckoChildProcessHost::GetChildProcessHandle() {
460 mozilla::AutoReadLock handleLock(mHandleLock);
461 return mChildProcessHandle;
464 base::ProcessId GeckoChildProcessHost::GetChildProcessId() {
465 mozilla::AutoReadLock handleLock(mHandleLock);
466 if (!mChildProcessHandle) {
467 return 0;
469 return base::GetProcId(mChildProcessHandle);
472 #ifdef XP_DARWIN
473 task_t GeckoChildProcessHost::GetChildTask() {
474 mozilla::AutoReadLock handleLock(mHandleLock);
475 return mChildTask;
477 #endif
479 void GeckoChildProcessHost::RemoveFromProcessList() {
480 StaticMutexAutoLock lock(sMutex);
481 if (!sGeckoChildProcessHosts) {
482 return;
484 LinkedListElement<GeckoChildProcessHost>::removeFrom(
485 *sGeckoChildProcessHosts);
488 void GeckoChildProcessHost::Destroy() {
489 MOZ_RELEASE_ASSERT(!mDestroying);
490 // We can remove from the list before it's really destroyed
491 RemoveFromProcessList();
492 RefPtr<ProcessHandlePromise> whenReady = mHandlePromise;
494 if (!whenReady) {
495 // AsyncLaunch not called yet, so dispatch immediately.
496 whenReady = ProcessHandlePromise::CreateAndReject(
497 LaunchError("DestroyEarly"), __func__);
500 using Value = ProcessHandlePromise::ResolveOrRejectValue;
501 mDestroying = true;
502 whenReady->Then(XRE_GetAsyncIOEventTarget(), __func__,
503 [this](const Value&) { delete this; });
506 // static
507 mozilla::BinPathType BaseProcessLauncher::GetPathToBinary(
508 FilePath& exePath, GeckoProcessType processType) {
509 exePath = {};
510 BinPathType pathType = XRE_GetChildProcBinPathType(processType);
512 if (pathType == BinPathType::Self) {
513 #if defined(XP_WIN)
514 wchar_t exePathBuf[MAXPATHLEN];
515 if (!::GetModuleFileNameW(nullptr, exePathBuf, MAXPATHLEN)) {
516 MOZ_CRASH("GetModuleFileNameW failed (FIXME)");
518 exePath = FilePath::FromWStringHack(exePathBuf);
519 #else
520 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
521 #endif
522 return pathType;
525 #ifdef MOZ_WIDGET_COCOA
526 // The GMP child process runs via the Media Plugin Helper executable
527 // which is a clone of plugin-container allowing for GMP-specific
528 // codesigning entitlements.
529 nsCString bundleName;
530 std::string executableLeafName;
531 if (processType == GeckoProcessType_GMPlugin &&
532 mozilla::StaticPrefs::media_plugin_helper_process_enabled()) {
533 bundleName = MOZ_EME_PROCESS_BUNDLENAME;
534 executableLeafName = MOZ_EME_PROCESS_NAME_BRANDED;
535 } else {
536 bundleName = MOZ_CHILD_PROCESS_BUNDLENAME;
537 executableLeafName = MOZ_CHILD_PROCESS_NAME;
539 #endif
541 if (ShouldHaveDirectoryService()) {
542 MOZ_ASSERT(gGREBinPath);
543 #ifdef XP_WIN
544 exePath = FilePath(char16ptr_t(gGREBinPath));
545 #elif MOZ_WIDGET_COCOA
546 nsCOMPtr<nsIFile> childProcPath;
547 if (NS_SUCCEEDED(NS_NewLocalFile(nsDependentString(gGREBinPath),
548 getter_AddRefs(childProcPath)))) {
549 // We need to use an App Bundle on OS X so that we can hide
550 // the dock icon. See Bug 557225.
551 if (NS_SUCCEEDED(childProcPath->AppendNative(bundleName)) &&
552 NS_SUCCEEDED(childProcPath->AppendNative("Contents"_ns)) &&
553 NS_SUCCEEDED(childProcPath->AppendNative("MacOS"_ns))) {
554 nsCString tempCPath;
555 if (NS_SUCCEEDED(childProcPath->GetNativePath(tempCPath))) {
556 exePath = FilePath(tempCPath.get());
560 #else
561 nsCString path;
562 if (NS_SUCCEEDED(
563 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path))) {
564 exePath = FilePath(path.get());
566 #endif
569 if (exePath.empty()) {
570 #ifdef XP_WIN
571 exePath =
572 FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
573 #else
574 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
575 #endif
576 exePath = exePath.DirName();
579 #ifdef MOZ_WIDGET_COCOA
580 exePath = exePath.Append(executableLeafName);
581 #else
582 exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
583 #endif
585 return pathType;
588 #ifdef MOZ_WIDGET_COCOA
589 class AutoCFTypeObject {
590 public:
591 explicit AutoCFTypeObject(CFTypeRef object) { mObject = object; }
592 ~AutoCFTypeObject() { ::CFRelease(mObject); }
594 private:
595 CFTypeRef mObject;
597 #endif
599 // We start the unique IDs at 1 so that 0 can be used to mean that
600 // a component has no unique ID assigned to it.
601 uint32_t GeckoChildProcessHost::sNextUniqueID = 1;
603 /* static */
604 uint32_t GeckoChildProcessHost::GetUniqueID() { return sNextUniqueID++; }
606 /* static */
607 void GeckoChildProcessHost::SetEnv(const char* aKey, const char* aValue) {
608 MOZ_ASSERT(mLaunchOptions);
609 mLaunchOptions->env_map[ENVIRONMENT_STRING(aKey)] =
610 ENVIRONMENT_STRING(aValue);
613 bool GeckoChildProcessHost::PrepareLaunch(
614 geckoargs::ChildProcessArgs& aExtraOpts) {
615 if (CrashReporter::GetEnabled()) {
616 CrashReporter::OOPInit();
619 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
620 if (!SandboxLaunch::Configure(mProcessType, mSandbox, aExtraOpts,
621 mLaunchOptions.get())) {
622 return false;
624 #endif
626 #ifdef XP_WIN
628 # if defined(MOZ_SANDBOX)
629 // We need to get the pref here as the process is launched off main thread.
630 if (mProcessType == GeckoProcessType_Content) {
631 // Win32k Lockdown state must be initialized on the main thread.
632 // This is our last chance to do it before it is read on the IPC Launch
633 // thread
634 GetWin32kLockdownState();
635 mSandboxLevel = GetEffectiveContentSandboxLevel();
636 mEnableSandboxLogging =
637 Preferences::GetBool("security.sandbox.logging.enabled");
639 // We currently have to whitelist certain paths for tests to work in some
640 // development configurations.
641 nsAutoString readPaths;
642 nsresult rv = Preferences::GetString(
643 "security.sandbox.content.read_path_whitelist", readPaths);
644 if (NS_SUCCEEDED(rv)) {
645 for (const nsAString& readPath : readPaths.Split(',')) {
646 nsString trimmedPath(readPath);
647 trimmedPath.Trim(" ", true, true);
648 std::wstring resolvedPath(trimmedPath.Data());
649 // Check if path ends with '\' as this indicates we want to give read
650 // access to a directory and so it needs a wildcard.
651 if (resolvedPath.back() == L'\\') {
652 resolvedPath.append(L"*");
654 mAllowedFilesRead.push_back(resolvedPath);
658 # endif
660 # if defined(MOZ_SANDBOX)
661 // For other process types we can't rely on them being launched on main
662 // thread and they may not have access to prefs in the child process, so allow
663 // them to turn on logging via an environment variable.
664 mEnableSandboxLogging =
665 mEnableSandboxLogging || !!PR_GetEnv("MOZ_SANDBOX_LOGGING");
667 # endif
668 #elif defined(XP_MACOSX)
669 # if defined(MOZ_SANDBOX)
670 if (ShouldHaveDirectoryService() &&
671 mProcessType != GeckoProcessType_GMPlugin) {
672 mozilla::Unused << NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
673 getter_AddRefs(mProfileDir));
675 # endif
676 #endif
678 return true;
681 #ifdef XP_WIN
682 void GeckoChildProcessHost::InitWindowsGroupID() {
683 // On Win7+, pass the application user model to the child, so it can
684 // register with it. This insures windows created by the container
685 // properly group with the parent app on the Win7 taskbar.
686 nsCOMPtr<nsIWinTaskbar> taskbarInfo = do_GetService(NS_TASKBAR_CONTRACTID);
687 if (taskbarInfo) {
688 bool isSupported = false;
689 taskbarInfo->GetAvailable(&isSupported);
690 nsAutoString appId;
691 if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
692 MOZ_ASSERT(mGroupId.EqualsLiteral("-"));
693 mGroupId.Assign(appId);
697 #endif
699 bool GeckoChildProcessHost::SyncLaunch(geckoargs::ChildProcessArgs aExtraOpts,
700 int aTimeoutMs) {
701 if (!AsyncLaunch(std::move(aExtraOpts))) {
702 return false;
704 return WaitUntilConnected(aTimeoutMs);
707 // Note: for most process types, we currently call AsyncLaunch, and therefore
708 // the *ProcessLauncher constructor, on the main thread, while the
709 // ProcessLauncher methods to actually execute the launch are called on the IO
710 // or IPC launcher thread. GMP processes are an exception - the GMP code
711 // invokes GeckoChildProcessHost from non-main-threads, and therefore we cannot
712 // rely on having access to mainthread-only services (like the directory
713 // service) from this code if we're launching that type of process.
714 bool GeckoChildProcessHost::AsyncLaunch(
715 geckoargs::ChildProcessArgs aExtraOpts) {
716 if (!PrepareLaunch(aExtraOpts)) {
717 return false;
720 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
721 if (IsMacSandboxLaunchEnabled() &&
722 !AppendMacSandboxParams(aExtraOpts.mArgs)) {
723 return false;
725 #endif
727 RefPtr<BaseProcessLauncher> launcher =
728 new ProcessLauncher(this, std::move(aExtraOpts));
729 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
730 launcher->SetLaunchArchitecture(mLaunchArch);
731 #endif
733 // Note: Destroy() waits on mHandlePromise to delete |this|. As such, we want
734 // to be sure that all of our post-launch processing on |this| happens before
735 // mHandlePromise notifies.
736 MOZ_ASSERT(mHandlePromise == nullptr);
737 mHandlePromise =
738 mozilla::InvokeAsync<GeckoChildProcessHost*>(
739 XRE_GetAsyncIOEventTarget(), launcher.get(), __func__,
740 &BaseProcessLauncher::Launch, this)
741 ->Then(
742 XRE_GetAsyncIOEventTarget(), __func__,
743 [this](LaunchResults&& aResults) {
746 mozilla::AutoWriteLock handleLock(mHandleLock);
747 if (!OpenPrivilegedHandle(base::GetProcId(aResults.mHandle))
748 #ifdef XP_WIN
749 // If we failed in opening the process handle, try
750 // harder by duplicating one.
751 && !::DuplicateHandle(
752 ::GetCurrentProcess(), aResults.mHandle,
753 ::GetCurrentProcess(), &mChildProcessHandle,
754 PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
755 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ |
756 SYNCHRONIZE,
757 FALSE, 0)
758 #endif // XP_WIN
760 MOZ_CRASH("cannot open handle to child process");
762 // The original handle is no longer needed; it must
763 // be closed to prevent a resource leak.
764 base::CloseProcessHandle(aResults.mHandle);
765 // FIXME (bug 1720523): define a cross-platform
766 // "safe" invalid value to use in places like this.
767 aResults.mHandle = 0;
769 #ifdef XP_DARWIN
770 this->mChildTask = aResults.mChildTask;
771 #endif
772 #ifdef XP_IOS
773 this->mExtensionKitProcess = aResults.mExtensionKitProcess;
774 this->mXPCConnection = aResults.mXPCConnection;
775 this->mForegroundCapabilityGrant =
776 std::move(aResults.mForegroundCapabilityGrant);
777 #endif
779 if (mNodeChannel) {
780 mNodeChannel->SetOtherPid(
781 base::GetProcId(this->mChildProcessHandle));
782 #ifdef XP_DARWIN
783 mNodeChannel->SetMachTaskPort(this->mChildTask);
784 #endif
787 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
788 this->mSandboxBroker = std::move(aResults.mSandboxBroker);
789 #endif
791 MonitorAutoLock lock(mMonitor);
792 // The OnChannel{Connected,Error} may have already advanced
793 // the state.
794 if (mProcessState < PROCESS_CREATED) {
795 mProcessState = PROCESS_CREATED;
797 lock.Notify();
799 return ProcessHandlePromise::CreateAndResolve(
800 GetChildProcessHandle(), __func__);
802 [this](const LaunchError aError) {
803 // WaitUntilConnected might be waiting for us to signal.
804 // If something failed let's set the error state and notify.
805 CHROMIUM_LOG(ERROR)
806 << "Failed to launch "
807 << XRE_GeckoProcessTypeToString(mProcessType)
808 << " subprocess @" << aError.FunctionName()
809 << " (Error:" << aError.ErrorCode() << ")";
810 Telemetry::Accumulate(
811 Telemetry::SUBPROCESS_LAUNCH_FAILURE,
812 nsDependentCString(
813 XRE_GeckoProcessTypeToString(mProcessType)));
814 nsCString telemetryKey = nsPrintfCString(
815 #if defined(XP_WIN)
816 "%s,0x%lx,%s",
817 #else
818 "%s,%ld,%s",
819 #endif
820 aError.FunctionName().get(), aError.ErrorCode(),
821 XRE_GeckoProcessTypeToString(mProcessType));
822 // Max telemetry key is 72 chars
823 // https://searchfox.org/mozilla-central/rev/c244b16815d1fc827d141472b9faac5610f250e7/toolkit/components/telemetry/core/TelemetryScalar.cpp#105
824 if (telemetryKey.Length() > 72) {
825 NS_WARNING(nsPrintfCString("Truncating telemetry key: %s",
826 telemetryKey.get())
827 .get());
828 telemetryKey.Truncate(72);
830 glean::dom_parentprocess::process_launch_errors
831 .Get(telemetryKey)
832 .Add(1);
834 MonitorAutoLock lock(mMonitor);
835 mProcessState = PROCESS_ERROR;
836 lock.Notify();
838 return ProcessHandlePromise::CreateAndReject(aError, __func__);
840 return true;
843 bool GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs) {
844 AUTO_PROFILER_LABEL("GeckoChildProcessHost::WaitUntilConnected", OTHER);
846 // NB: this uses a different mechanism than the chromium parent
847 // class.
848 TimeDuration timeout = (aTimeoutMs > 0)
849 ? TimeDuration::FromMilliseconds(aTimeoutMs)
850 : TimeDuration::Forever();
852 MonitorAutoLock lock(mMonitor);
853 TimeStamp waitStart = TimeStamp::Now();
854 TimeStamp current;
856 // We'll receive several notifications, we need to exit when we
857 // have either successfully launched or have timed out.
858 while (mProcessState != PROCESS_CONNECTED) {
859 // If there was an error then return it, don't wait out the timeout.
860 if (mProcessState == PROCESS_ERROR) {
861 break;
864 CVStatus status = lock.Wait(timeout);
865 if (status == CVStatus::Timeout) {
866 break;
869 if (timeout != TimeDuration::Forever()) {
870 current = TimeStamp::Now();
871 timeout -= current - waitStart;
872 waitStart = current;
876 return mProcessState == PROCESS_CONNECTED;
879 bool GeckoChildProcessHost::WaitForProcessHandle() {
880 MonitorAutoLock lock(mMonitor);
881 while (mProcessState < PROCESS_CREATED) {
882 lock.Wait();
884 MOZ_ASSERT(mProcessState == PROCESS_ERROR || GetChildProcessHandle());
886 return mProcessState < PROCESS_ERROR;
889 bool GeckoChildProcessHost::LaunchAndWaitForProcessHandle(
890 geckoargs::ChildProcessArgs aExtraOpts) {
891 if (!AsyncLaunch(std::move(aExtraOpts))) {
892 return false;
894 return WaitForProcessHandle();
897 void GeckoChildProcessHost::InitializeChannel(
898 IPC::Channel::ChannelHandle&& aServerHandle) {
899 // Create the IPC channel which will be used for communication with this
900 // process.
901 mozilla::UniquePtr<IPC::Channel> channel = MakeUnique<IPC::Channel>(
902 std::move(aServerHandle), IPC::Channel::MODE_SERVER,
903 base::kInvalidProcessId);
904 #if defined(XP_WIN)
905 channel->StartAcceptingHandles(IPC::Channel::MODE_SERVER);
906 #elif defined(XP_DARWIN)
907 channel->StartAcceptingMachPorts(IPC::Channel::MODE_SERVER);
908 #endif
910 mNodeController = NodeController::GetSingleton();
911 std::tie(mInitialPort, mNodeChannel) =
912 mNodeController->InviteChildProcess(std::move(channel), this);
914 MonitorAutoLock lock(mMonitor);
915 mProcessState = CHANNEL_INITIALIZED;
916 lock.Notify();
919 void GeckoChildProcessHost::SetAlreadyDead() {
920 mozilla::AutoWriteLock handleLock(mHandleLock);
921 if (mChildProcessHandle &&
922 mChildProcessHandle != base::kInvalidProcessHandle) {
923 base::CloseProcessHandle(mChildProcessHandle);
926 mChildProcessHandle = 0;
929 void BaseProcessLauncher::GetChildLogName(const char* origLogName,
930 nsACString& buffer) {
931 #ifdef XP_WIN
932 // On Windows we must expand relative paths because sandboxing rules
933 // bound only to full paths. fopen fowards to NtCreateFile which checks
934 // the path against the sanboxing rules as passed to fopen (left relative).
935 char absPath[MAX_PATH + 2];
936 if (_fullpath(absPath, origLogName, sizeof(absPath))) {
937 buffer.Append(absPath);
938 } else
939 #endif
941 buffer.Append(origLogName);
944 // Remove .moz_log extension to avoid its duplication, it will be added
945 // automatically by the logging backend
946 static constexpr auto kMozLogExt = nsLiteralCString{MOZ_LOG_FILE_EXTENSION};
947 if (StringEndsWith(buffer, kMozLogExt)) {
948 buffer.Truncate(buffer.Length() - kMozLogExt.Length());
951 // Append child-specific postfix to name
952 buffer.AppendLiteral(".child-");
953 buffer.AppendASCII(mChildIDString);
956 // Windows needs a single dedicated thread for process launching,
957 // because of thread-safety restrictions/assertions in the sandbox
958 // code.
960 // Android also needs a single dedicated thread to simplify thread
961 // safety in java.
963 // Fork server needs a dedicated thread for accessing
964 // |ForkServiceChild|.
965 #if defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID) || \
966 defined(MOZ_ENABLE_FORKSERVER)
968 static mozilla::StaticMutex gIPCLaunchThreadMutex;
969 static mozilla::StaticRefPtr<nsIThread> gIPCLaunchThread
970 MOZ_GUARDED_BY(gIPCLaunchThreadMutex);
972 class IPCLaunchThreadObserver final : public nsIObserver {
973 public:
974 NS_DECL_ISUPPORTS
975 NS_DECL_NSIOBSERVER
976 protected:
977 virtual ~IPCLaunchThreadObserver() = default;
980 NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver, nsIObserver, nsISupports)
982 NS_IMETHODIMP
983 IPCLaunchThreadObserver::Observe(nsISupports* aSubject, const char* aTopic,
984 const char16_t* aData) {
985 MOZ_RELEASE_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0);
987 nsCOMPtr<nsIThread> thread;
989 StaticMutexAutoLock lock(gIPCLaunchThreadMutex);
990 thread = gIPCLaunchThread.forget();
993 nsresult rv = thread ? thread->Shutdown() : NS_OK;
994 mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
995 return rv;
998 nsCOMPtr<nsIEventTarget> GetIPCLauncher() {
999 StaticMutexAutoLock lock(gIPCLaunchThreadMutex);
1000 if (!gIPCLaunchThread) {
1001 nsCOMPtr<nsIThread> thread;
1002 nsresult rv = NS_NewNamedThread("IPC Launch"_ns, getter_AddRefs(thread));
1003 if (!NS_WARN_IF(NS_FAILED(rv))) {
1004 NS_DispatchToMainThread(
1005 NS_NewRunnableFunction("GeckoChildProcessHost::GetIPCLauncher", [] {
1006 nsCOMPtr<nsIObserverService> obsService =
1007 mozilla::services::GetObserverService();
1008 nsCOMPtr<nsIObserver> obs = new IPCLaunchThreadObserver();
1009 obsService->AddObserver(obs, "xpcom-shutdown-threads", false);
1010 }));
1011 gIPCLaunchThread = thread.forget();
1015 nsCOMPtr<nsIEventTarget> thread = gIPCLaunchThread.get();
1016 MOZ_DIAGNOSTIC_ASSERT(thread);
1017 return thread;
1020 #else // defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID) ||
1021 // defined(MOZ_ENABLE_FORKSERVER)
1023 // Other platforms use an on-demand thread pool.
1025 nsCOMPtr<nsIEventTarget> GetIPCLauncher() {
1026 nsCOMPtr<nsIEventTarget> pool =
1027 mozilla::SharedThreadPool::Get("IPC Launch"_ns);
1028 MOZ_DIAGNOSTIC_ASSERT(pool);
1029 return pool;
1032 #endif // XP_WIN || MOZ_WIDGET_ANDROID || MOZ_ENABLE_FORKSERVER
1034 void
1035 #if defined(XP_WIN)
1036 AddAppDirToCommandLine(CommandLine& aCmdLine, nsIFile* aAppDir)
1037 #else
1038 AddAppDirToCommandLine(geckoargs::ChildProcessArgs& aCmdLine,
1039 nsIFile* aAppDir, nsIFile* aProfileDir)
1040 #endif
1042 // Content processes need access to application resources, so pass
1043 // the full application directory path to the child process.
1044 if (aAppDir) {
1045 #if defined(XP_WIN)
1046 nsString path;
1047 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetPath(path));
1048 aCmdLine.AppendLooseValue(UTF8ToWide(geckoargs::sAppDir.Name()));
1049 std::wstring wpath(path.get());
1050 aCmdLine.AppendLooseValue(wpath);
1051 #else
1052 nsAutoCString path;
1053 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetNativePath(path));
1054 geckoargs::sAppDir.Put(path.get(), aCmdLine);
1055 #endif
1057 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1058 // Full path to the profile dir
1059 if (aProfileDir) {
1060 // If the profile doesn't exist, normalization will
1061 // fail. But we don't return an error here because some
1062 // tests require startup with a missing profile dir.
1063 // For users, almost universally, the profile will be in
1064 // the home directory and normalization isn't required.
1065 mozilla::Unused << aProfileDir->Normalize();
1066 nsAutoCString path;
1067 MOZ_ALWAYS_SUCCEEDS(aProfileDir->GetNativePath(path));
1068 geckoargs::sProfile.Put(path.get(), aCmdLine);
1070 #endif
1074 #if defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
1075 static bool Contains(const geckoargs::ChildProcessArgs& aExtraOpts,
1076 const char* aValue) {
1077 return std::any_of(aExtraOpts.mArgs.begin(), aExtraOpts.mArgs.end(),
1078 [&](const std::string arg) {
1079 return arg.find(aValue) != std::string::npos;
1082 #endif // defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
1084 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::PerformAsyncLaunch() {
1085 Result<Ok, LaunchError> aError = DoSetup();
1086 if (aError.isErr()) {
1087 return ProcessLaunchPromise::CreateAndReject(aError.unwrapErr(), __func__);
1089 RefPtr<BaseProcessLauncher> self = this;
1090 return DoLaunch()->Then(
1091 mLaunchThread, __func__,
1092 [self](base::ProcessHandle aHandle) {
1093 self->mResults.mHandle = aHandle;
1094 return self->FinishLaunch();
1096 [](LaunchError aError) {
1097 return ProcessLaunchPromise::CreateAndReject(aError, __func__);
1101 Result<Ok, LaunchError> BaseProcessLauncher::DoSetup() {
1102 RefPtr<BaseProcessLauncher> self = this;
1103 GetProfilerEnvVarsForChildProcess([self](const char* key, const char* value) {
1104 self->mLaunchOptions->env_map[ENVIRONMENT_STRING(key)] =
1105 ENVIRONMENT_STRING(value);
1107 #ifdef MOZ_MEMORY
1108 if (mProcessType == GeckoProcessType_Content) {
1109 nsAutoCString mallocOpts(PR_GetEnv("MALLOC_OPTIONS"));
1110 // Disable randomization of small arenas in content.
1111 mallocOpts.Append("r");
1112 self->mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MALLOC_OPTIONS")] =
1113 ENVIRONMENT_STRING(mallocOpts.get());
1115 #endif
1117 MapChildLogging();
1119 geckoargs::sInitialChannelID.Put(mInitialChannelIdString, mChildArgs);
1121 geckoargs::sParentPid.Put(static_cast<uint64_t>(base::GetCurrentProcId()),
1122 mChildArgs);
1124 if (!CrashReporter::IsDummy() && CrashReporter::GetEnabled()) {
1125 #if defined(MOZ_WIDGET_COCOA) || defined(XP_WIN)
1126 geckoargs::sCrashReporter.Put(CrashReporter::GetChildNotificationPipe(),
1127 mChildArgs);
1128 #elif defined(XP_UNIX)
1129 UniqueFileHandle childCrashFd = CrashReporter::GetChildNotificationPipe();
1130 if (!childCrashFd) {
1131 return Err(LaunchError("DuplicateFileHandle failed"));
1133 geckoargs::sCrashReporter.Put(std::move(childCrashFd), mChildArgs);
1134 #endif
1137 return Ok();
1140 void BaseProcessLauncher::MapChildLogging() {
1141 const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
1142 const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
1144 if (origNSPRLogName) {
1145 nsAutoCString nsprLogName;
1146 GetChildLogName(origNSPRLogName, nsprLogName);
1147 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("NSPR_LOG_FILE")] =
1148 ENVIRONMENT_STRING(nsprLogName.get());
1150 if (origMozLogName) {
1151 nsAutoCString mozLogName;
1152 GetChildLogName(origMozLogName, mozLogName);
1153 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MOZ_LOG_FILE")] =
1154 ENVIRONMENT_STRING(mozLogName.get());
1157 // `RUST_LOG_CHILD` is meant for logging child processes only.
1158 nsAutoCString childRustLog(PR_GetEnv("RUST_LOG_CHILD"));
1159 if (!childRustLog.IsEmpty()) {
1160 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("RUST_LOG")] =
1161 ENVIRONMENT_STRING(childRustLog.get());
1165 Result<Ok, LaunchError> BaseProcessLauncher::DoFinishLaunch() {
1166 // We're in the parent and the child was launched. Clean up any FDs which were
1167 // transferred to the child in the parent as soon as possible, which will
1168 // allow the parent to detect when the child closes its handle (either due to
1169 // normal exit or due to crash).
1170 mChildArgs.mFiles.clear();
1172 return Ok();
1175 #if defined(MOZ_WIDGET_GTK)
1176 Result<Ok, LaunchError> LinuxProcessLauncher::DoSetup() {
1177 Result<Ok, LaunchError> aError = PosixProcessLauncher::DoSetup();
1178 if (aError.isErr()) {
1179 return aError;
1182 if (mProcessType == GeckoProcessType_Content) {
1183 // disable IM module to avoid sandbox violation
1184 mLaunchOptions->env_map["GTK_IM_MODULE"] = "gtk-im-context-simple";
1186 // Disable ATK accessibility code in content processes because it conflicts
1187 // with the sandbox, and we proxy that information through the main process
1188 // anyway.
1189 mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1";
1192 return Ok();
1194 #endif // MOZ_WIDGET_GTK
1196 #ifdef XP_UNIX
1197 Result<Ok, LaunchError> PosixProcessLauncher::DoSetup() {
1198 Result<Ok, LaunchError> aError = BaseProcessLauncher::DoSetup();
1199 if (aError.isErr()) {
1200 return aError;
1203 // XPCOM may not be initialized in some subprocesses. We don't want
1204 // to initialize XPCOM just for the directory service, especially
1205 // since LD_LIBRARY_PATH is already set correctly in subprocesses
1206 // (meaning that we don't need to set that up in the environment).
1207 if (ShouldHaveDirectoryService()) {
1208 MOZ_ASSERT(gGREBinPath);
1209 nsCString path;
1210 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
1211 # if defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \
1212 defined(XP_NETBSD) || defined(XP_OPENBSD)
1213 const char* ld_library_path = PR_GetEnv("LD_LIBRARY_PATH");
1214 nsCString new_ld_lib_path(path.get());
1216 if (ld_library_path && *ld_library_path) {
1217 new_ld_lib_path.Append(':');
1218 new_ld_lib_path.Append(ld_library_path);
1220 mLaunchOptions->env_map["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
1222 # elif XP_MACOSX
1223 // With signed production Mac builds, the dynamic linker (dyld) will
1224 // ignore dyld environment variables preventing the use of variables
1225 // such as DYLD_LIBRARY_PATH and DYLD_INSERT_LIBRARIES.
1227 // If we're running with gtests, add the gtest XUL ahead of normal XUL on
1228 // the DYLD_LIBRARY_PATH so that plugin-container.app loads it instead.
1229 nsCString new_dyld_lib_path(path.get());
1230 if (PR_GetEnv("MOZ_RUN_GTEST")) {
1231 new_dyld_lib_path = path + "/gtest:"_ns + new_dyld_lib_path;
1232 mLaunchOptions->env_map["DYLD_LIBRARY_PATH"] = new_dyld_lib_path.get();
1235 // DYLD_INSERT_LIBRARIES is currently unused by default but we allow
1236 // it to be set by the external environment.
1237 const char* interpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
1238 if (interpose && strlen(interpose) > 0) {
1239 mLaunchOptions->env_map["DYLD_INSERT_LIBRARIES"] = interpose;
1242 // Prevent connection attempts to diagnosticd(8) to save cycles. Log
1243 // messages can trigger these connection attempts, but access to
1244 // diagnosticd is blocked in sandboxed child processes.
1245 # if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
1246 if (mDisableOSActivityMode) {
1247 mLaunchOptions->env_map["OS_ACTIVITY_MODE"] = "disable";
1249 # endif // defined(MOZ_SANDBOX)
1250 # endif
1253 FilePath exePath;
1254 BinPathType pathType = GetPathToBinary(exePath, mProcessType);
1256 // Make sure the executable path is present at the start of our argument list.
1257 // If we're using BinPathType::Self, also add the `-contentproc` argument.
1258 if (pathType == BinPathType::Self) {
1259 std::string args[]{exePath.value(), "-contentproc"};
1260 mChildArgs.mArgs.insert(mChildArgs.mArgs.begin(), std::begin(args),
1261 std::end(args));
1262 } else {
1263 mChildArgs.mArgs.insert(mChildArgs.mArgs.begin(), exePath.value());
1266 if ((mProcessType == GeckoProcessType_Content ||
1267 mProcessType == GeckoProcessType_ForkServer) &&
1268 Omnijar::IsInitialized()) {
1269 // Make sure that child processes can find the omnijar, if they
1270 // use full XPCOM. See Omnijar::ChildProcessInit and its callers.
1271 nsAutoCString path;
1272 nsCOMPtr<nsIFile> greFile = Omnijar::GetPath(Omnijar::GRE);
1273 if (greFile && NS_SUCCEEDED(greFile->GetNativePath(path))) {
1274 geckoargs::sGREOmni.Put(path.get(), mChildArgs);
1276 nsCOMPtr<nsIFile> appFile = Omnijar::GetPath(Omnijar::APP);
1277 if (appFile && NS_SUCCEEDED(appFile->GetNativePath(path))) {
1278 geckoargs::sAppOmni.Put(path.get(), mChildArgs);
1282 if (mProcessType != GeckoProcessType_GMPlugin) {
1283 // Add the application directory path (-appdir path)
1284 # ifdef XP_MACOSX
1285 AddAppDirToCommandLine(mChildArgs, mAppDir, mProfileDir);
1286 # else
1287 AddAppDirToCommandLine(mChildArgs, mAppDir, nullptr);
1288 # endif
1291 // XXX Command line params past this point are expected to be at
1292 // the end of the command line string, and in a specific order.
1293 // See XRE_InitChildProcess in nsEmbedFunction.
1295 # ifdef MOZ_WIDGET_COCOA
1297 auto* thisMac = static_cast<MacProcessLauncher*>(this);
1298 kern_return_t kr =
1299 bootstrap_check_in(bootstrap_port, thisMac->mMachConnectionName.c_str(),
1300 getter_Transfers(thisMac->mParentRecvPort));
1301 if (kr != KERN_SUCCESS) {
1302 CHROMIUM_LOG(ERROR) << "parent bootstrap_check_in failed: "
1303 << mach_error_string(kr);
1304 return Err(LaunchError("bootstrap_check_in", kr));
1306 mChildArgs.mArgs.push_back(thisMac->mMachConnectionName.c_str());
1308 # endif // MOZ_WIDGET_COCOA
1310 mChildArgs.mArgs.push_back(mChildIDString);
1312 mChildArgs.mArgs.push_back(ChildProcessType());
1314 # if !defined(MOZ_WIDGET_ANDROID)
1315 // Add any files which need to be transferred to fds_to_remap.
1316 // NOTE: This doesn't transfer ownership of the files out of `mChildArgs`.
1317 geckoargs::AddToFdsToRemap(mChildArgs, mLaunchOptions->fds_to_remap);
1318 # endif
1320 return Ok();
1322 #endif // XP_UNIX
1324 #if defined(MOZ_WIDGET_ANDROID)
1325 RefPtr<ProcessHandlePromise> AndroidProcessLauncher::DoLaunch() {
1326 return LaunchAndroidService(mProcessType, mChildArgs);
1328 #endif // MOZ_WIDGET_ANDROID
1330 #ifdef XP_UNIX
1331 RefPtr<ProcessHandlePromise> PosixProcessLauncher::DoLaunch() {
1332 ProcessHandle handle = 0;
1333 Result<Ok, LaunchError> result = Err(LaunchError{"Launch not attempted"});
1334 # ifdef MOZ_ENABLE_FORKSERVER
1335 if (mProcessType != GeckoProcessType_ForkServer && ForkServiceChild::Get()) {
1336 result = ForkServiceChild::Get()->SendForkNewSubprocess(
1337 std::move(mChildArgs), std::move(*mLaunchOptions), &handle);
1338 } else
1339 # endif
1341 result =
1342 base::LaunchApp(mChildArgs.mArgs, std::move(*mLaunchOptions), &handle);
1345 if (result.isErr()) {
1346 return ProcessHandlePromise::CreateAndReject(result.unwrapErr(), __func__);
1348 return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1350 #endif // XP_UNIX
1352 #ifdef XP_IOS
1353 RefPtr<ProcessHandlePromise> IosProcessLauncher::DoLaunch() {
1354 ExtensionKitProcess::Kind kind = ExtensionKitProcess::Kind::WebContent;
1355 if (mProcessType == GeckoProcessType_GPU) {
1356 kind = ExtensionKitProcess::Kind::Rendering;
1357 } else if (mProcessType == GeckoProcessType_Socket) {
1358 kind = ExtensionKitProcess::Kind::Networking;
1361 DarwinObjectPtr<xpc_object_t> bootstrapMessage =
1362 AdoptDarwinObject(xpc_dictionary_create_empty());
1363 xpc_dictionary_set_string(bootstrapMessage.get(), "message-name",
1364 "bootstrap");
1366 DarwinObjectPtr<xpc_object_t> environDict =
1367 AdoptDarwinObject(xpc_dictionary_create_empty());
1368 for (auto& [envKey, envValue] : mLaunchOptions->env_map) {
1369 xpc_dictionary_set_string(environDict.get(), envKey.c_str(),
1370 envValue.c_str());
1372 xpc_dictionary_set_value(bootstrapMessage.get(), "environ",
1373 environDict.get());
1375 // Setup stdout and stderr to inherit.
1376 xpc_dictionary_set_fd(bootstrapMessage.get(), "stdout", STDOUT_FILENO);
1377 xpc_dictionary_set_fd(bootstrapMessage.get(), "stderr", STDERR_FILENO);
1379 DarwinObjectPtr<xpc_object_t> argsArray =
1380 AdoptDarwinObject(xpc_array_create_empty());
1381 for (auto& argv : mChildArgs.mArgs) {
1382 xpc_array_set_string(argsArray.get(), XPC_ARRAY_APPEND, argv.c_str());
1384 MOZ_ASSERT(xpc_array_get_count(argsArray.get()) == mChildArgs.mArgs.size());
1385 xpc_dictionary_set_value(bootstrapMessage.get(), "argv", argsArray.get());
1387 DarwinObjectPtr<xpc_object_t> fdsArray =
1388 AdoptDarwinObject(xpc_array_create_empty());
1389 for (auto& file : mChildArgs.mFiles) {
1390 xpc_array_set_fd(fdsArray.get(), XPC_ARRAY_APPEND, file.get());
1392 MOZ_ASSERT(xpc_array_get_count(fdsArray.get()) == mChildArgs.mFiles.size());
1393 xpc_dictionary_set_value(bootstrapMessage.get(), "fds", fdsArray.get());
1395 DarwinObjectPtr<xpc_object_t> sendRightsArray =
1396 AdoptDarwinObject(xpc_array_create_empty());
1397 for (auto& sendRight : mChildArgs.mSendRights) {
1398 // NOTE: As iOS doesn't expose an xpc_array_set_mach_send function, send
1399 // rights are wrapped with single-key dictionaries.
1400 DarwinObjectPtr<xpc_object_t> sendRightWrapper =
1401 AdoptDarwinObject(xpc_dictionary_create_empty());
1402 xpc_dictionary_set_mach_send(sendRightWrapper.get(), "port",
1403 sendRight.get());
1404 xpc_array_set_value(sendRightsArray.get(), XPC_ARRAY_APPEND,
1405 sendRightWrapper.get());
1407 MOZ_ASSERT(xpc_array_get_count(sendRightsArray.get()) ==
1408 mChildArgs.mSendRights.size());
1409 xpc_dictionary_set_value(bootstrapMessage.get(), "sendRights",
1410 sendRightsArray.get());
1412 auto promise = MakeRefPtr<ProcessHandlePromise::Private>(__func__);
1413 ExtensionKitProcess::StartProcess(kind, [self = RefPtr{this}, promise,
1414 bootstrapMessage =
1415 std::move(bootstrapMessage)](
1416 Result<ExtensionKitProcess,
1417 LaunchError>&& result) {
1418 if (result.isErr()) {
1419 CHROMIUM_LOG(ERROR) << "ExtensionKitProcess::StartProcess failed";
1420 promise->Reject(result.unwrapErr(), __func__);
1421 return;
1424 auto process = result.unwrap();
1425 self->mResults.mForegroundCapabilityGrant =
1426 process.GrantForegroundCapability();
1427 self->mResults.mXPCConnection = process.MakeLibXPCConnection();
1428 self->mResults.mExtensionKitProcess = Some(std::move(process));
1430 // We don't actually use the event handler for anything other than
1431 // watching for errors. Once the promise is resolved, this becomes a
1432 // no-op.
1433 xpc_connection_set_event_handler(self->mResults.mXPCConnection.get(), ^(
1434 xpc_object_t event) {
1435 if (!event || xpc_get_type(event) == XPC_TYPE_ERROR) {
1436 CHROMIUM_LOG(WARNING) << "XPC connection received encountered an error";
1437 promise->Reject(LaunchError("xpc_connection_event_handler"), __func__);
1440 xpc_connection_resume(self->mResults.mXPCConnection.get());
1442 // Send our bootstrap message to the content and wait for it to reply with
1443 // the task port before resolving.
1444 // FIXME: Should we have a time-out for if the child process doesn't respond
1445 // in time? The main thread may be blocked while we're starting this
1446 // process.
1447 xpc_connection_send_message_with_reply(
1448 self->mResults.mXPCConnection.get(), bootstrapMessage.get(), nullptr,
1449 ^(xpc_object_t reply) {
1450 if (xpc_get_type(reply) == XPC_TYPE_ERROR) {
1451 CHROMIUM_LOG(ERROR)
1452 << "Got error sending XPC bootstrap message to child";
1453 promise->Reject(
1454 LaunchError("xpc_connection_send_message_with_reply error"),
1455 __func__);
1456 return;
1459 if (xpc_get_type(reply) != XPC_TYPE_DICTIONARY) {
1460 CHROMIUM_LOG(ERROR)
1461 << "Unexpected reply type for bootstrap message from child";
1462 promise->Reject(
1463 LaunchError(
1464 "xpc_connection_send_message_with_reply non-dictionary"),
1465 __func__);
1466 return;
1469 // FIXME: We have to trust the child to tell us its pid & mach task.
1470 // WebKit uses `xpc_connection_get_pid` to get the pid, however this
1471 // is marked as unavailable on iOS.
1473 // Given how the process is started, however, validating this
1474 // information it sends us this early during startup may be
1475 // unnecessary.
1476 self->mResults.mChildTask =
1477 xpc_dictionary_copy_mach_send(reply, "task");
1478 pid_t pid =
1479 static_cast<pid_t>(xpc_dictionary_get_int64(reply, "pid"));
1480 CHROMIUM_LOG(INFO) << "ExtensionKit process started, task: "
1481 << self->mResults.mChildTask << ", pid: " << pid;
1483 pid_t taskPid;
1484 kern_return_t kr = pid_for_task(self->mResults.mChildTask, &taskPid);
1485 if (kr != KERN_SUCCESS || pid != taskPid) {
1486 CHROMIUM_LOG(ERROR) << "Could not validate child task matches pid";
1487 promise->Reject(LaunchError("pid_for_task mismatch"), __func__);
1488 return;
1491 promise->Resolve(pid, __func__);
1495 return promise;
1497 #endif
1499 #ifdef XP_MACOSX
1500 Result<Ok, LaunchError> MacProcessLauncher::DoFinishLaunch() {
1501 Result<Ok, LaunchError> aError = PosixProcessLauncher::DoFinishLaunch();
1502 if (aError.isErr()) {
1503 return aError;
1506 MOZ_ASSERT(mParentRecvPort, "should have been configured during DoSetup()");
1508 // Wait for the child process to send us its 'task_t' data, then send it the
1509 // mach send/receive rights which are being passed on the commandline.
1510 const int kTimeoutMs = 10000;
1511 MOZ_TRY(MachHandleProcessCheckIn(
1512 mParentRecvPort.get(), base::GetProcId(mResults.mHandle), kTimeoutMs,
1513 mChildArgs.mSendRights, &mResults.mChildTask));
1515 return Ok();
1517 #endif // XP_MACOSX
1519 #ifdef XP_WIN
1520 Result<Ok, LaunchError> WindowsProcessLauncher::DoSetup() {
1521 Result<Ok, LaunchError> aError = BaseProcessLauncher::DoSetup();
1522 if (aError.isErr()) {
1523 return aError;
1526 FilePath exePath;
1527 BinPathType pathType = GetPathToBinary(exePath, mProcessType);
1529 # if defined(MOZ_SANDBOX) || defined(_ARM64_)
1530 const bool isGMP = mProcessType == GeckoProcessType_GMPlugin;
1531 const bool isWidevine = isGMP && Contains(mChildArgs, "gmp-widevinecdm");
1532 # endif // defined(MOZ_SANDBOX) || defined(_ARM64_)
1534 mCmdLine.emplace(exePath.ToWStringHack());
1536 if (pathType == BinPathType::Self) {
1537 mCmdLine->AppendLooseValue(UTF8ToWide("-contentproc"));
1540 # ifdef HAS_DLL_BLOCKLIST
1541 if (IsDynamicBlocklistDisabled(
1542 gSafeMode,
1543 CommandLine::ForCurrentProcess()->HasSwitch(UTF8ToWide(
1544 mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch)))) {
1545 mCmdLine->AppendLooseValue(
1546 UTF8ToWide(mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch));
1548 # endif // HAS_DLL_BLOCKLIST
1550 for (const std::string& arg : mChildArgs.mArgs) {
1551 mCmdLine->AppendLooseValue(UTF8ToWide(arg));
1554 # if defined(MOZ_SANDBOX)
1555 mResults.mSandboxBroker = MakeUnique<SandboxBroker>();
1557 // XXX: Bug 1124167: We should get rid of the process specific logic for
1558 // sandboxing in this class at some point. Unfortunately it will take a bit
1559 // of reorganizing so I don't think this patch is the right time.
1560 switch (mProcessType) {
1561 case GeckoProcessType_Content:
1562 if (mSandboxLevel > 0) {
1563 // For now we treat every failure as fatal in
1564 // SetSecurityLevelForContentProcess and just crash there right away.
1565 // Should this change in the future then we should also handle the error
1566 // here.
1567 mResults.mSandboxBroker->SetSecurityLevelForContentProcess(
1568 mSandboxLevel, mIsFileContent);
1569 mUseSandbox = true;
1571 break;
1572 case GeckoProcessType_IPDLUnitTest:
1573 // XXX: We don't sandbox this process type yet
1574 break;
1575 case GeckoProcessType_GMPlugin:
1576 if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
1577 // The Widevine CDM on Windows can only load at USER_RESTRICTED,
1578 // not at USER_LOCKDOWN. So look in the command line arguments
1579 // to see if we're loading the path to the Widevine CDM, and if
1580 // so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN.
1581 auto level =
1582 isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown;
1583 if (NS_WARN_IF(
1584 !mResults.mSandboxBroker->SetSecurityLevelForGMPlugin(level))) {
1585 return Err(LaunchError("SetSecurityLevelForGMPlugin"));
1587 mUseSandbox = true;
1589 break;
1590 case GeckoProcessType_GPU:
1591 if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) {
1592 // For now we treat every failure as fatal in
1593 // SetSecurityLevelForGPUProcess and just crash there right away. Should
1594 // this change in the future then we should also handle the error here.
1595 mResults.mSandboxBroker->SetSecurityLevelForGPUProcess(mSandboxLevel);
1596 mUseSandbox = true;
1598 break;
1599 case GeckoProcessType_VR:
1600 if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) {
1601 // TODO: Implement sandbox for VR process, Bug 1430043.
1603 break;
1604 case GeckoProcessType_RDD:
1605 if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
1606 if (NS_WARN_IF(
1607 !mResults.mSandboxBroker->SetSecurityLevelForRDDProcess())) {
1608 return Err(LaunchError("SetSecurityLevelForRDDProcess"));
1610 mUseSandbox = true;
1612 break;
1613 case GeckoProcessType_Socket:
1614 if (!PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS_SANDBOX")) {
1615 if (NS_WARN_IF(
1616 !mResults.mSandboxBroker->SetSecurityLevelForSocketProcess())) {
1617 return Err(LaunchError("SetSecurityLevelForSocketProcess"));
1619 mUseSandbox = true;
1621 break;
1622 case GeckoProcessType_Utility:
1623 if (IsUtilitySandboxEnabled(mSandbox)) {
1624 if (!mResults.mSandboxBroker->SetSecurityLevelForUtilityProcess(
1625 mSandbox)) {
1626 return Err(LaunchError("SetSecurityLevelForUtilityProcess"));
1628 mUseSandbox = true;
1630 break;
1631 case GeckoProcessType_Default:
1632 default:
1633 MOZ_CRASH("Bad process type in GeckoChildProcessHost");
1634 break;
1637 if (mUseSandbox) {
1638 for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end();
1639 ++it) {
1640 mResults.mSandboxBroker->AllowReadFile(it->c_str());
1643 if (mResults.mSandboxBroker->IsWin32kLockedDown()) {
1644 mCmdLine->AppendLooseValue(
1645 UTF8ToWide(geckoargs::sWin32kLockedDown.Name()));
1648 # endif // defined(MOZ_SANDBOX)
1650 // Add the application directory path (-appdir path)
1651 AddAppDirToCommandLine(mCmdLine.ref(), mAppDir);
1653 // XXX Command line params past this point are expected to be at
1654 // the end of the command line string, and in a specific order.
1655 // See XRE_InitChildProcess in nsEmbedFunction.
1657 // Win app model id
1658 mCmdLine->AppendLooseValue(mGroupId.get());
1660 // Gecko child id
1661 mCmdLine->AppendLooseValue(UTF8ToWide(mChildIDString));
1663 // Process type
1664 mCmdLine->AppendLooseValue(UTF8ToWide(ChildProcessType()));
1666 // Add any files which need to be transferred to handles_to_inherit.
1667 for (auto& file : mChildArgs.mFiles) {
1668 mLaunchOptions->handles_to_inherit.push_back(file.get());
1671 # ifdef MOZ_SANDBOX
1672 if (mUseSandbox) {
1673 // Mark the handles to inherit as inheritable.
1674 for (HANDLE h : mLaunchOptions->handles_to_inherit) {
1675 mResults.mSandboxBroker->AddHandleToShare(h);
1678 # endif // MOZ_SANDBOX
1680 return Ok();
1683 RefPtr<ProcessHandlePromise> WindowsProcessLauncher::DoLaunch() {
1684 ProcessHandle handle = 0;
1685 # ifdef MOZ_SANDBOX
1686 if (mUseSandbox) {
1687 const IMAGE_THUNK_DATA* cachedNtdllThunk =
1688 mCachedNtdllThunk ? mCachedNtdllThunk->begin() : nullptr;
1689 Result<Ok, LaunchError> err = mResults.mSandboxBroker->LaunchApp(
1690 mCmdLine->program().c_str(), mCmdLine->command_line_string().c_str(),
1691 mLaunchOptions->env_map, mProcessType, mEnableSandboxLogging,
1692 cachedNtdllThunk, &handle);
1693 if (err.isOk()) {
1694 EnvironmentLog("MOZ_PROCESS_LOG")
1695 .print("==> process %d launched child process %d (%S)\n",
1696 base::GetCurrentProcId(), base::GetProcId(handle),
1697 mCmdLine->command_line_string().c_str());
1698 return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1700 return ProcessHandlePromise::CreateAndReject(err.unwrapErr(), __func__);
1702 # endif // defined(MOZ_SANDBOX)
1704 Result<Ok, LaunchError> launchErr =
1705 base::LaunchApp(mCmdLine.ref(), *mLaunchOptions, &handle);
1706 if (launchErr.isErr()) {
1707 return ProcessHandlePromise::CreateAndReject(launchErr.unwrapErr(),
1708 __func__);
1710 return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1713 Result<Ok, LaunchError> WindowsProcessLauncher::DoFinishLaunch() {
1714 Result<Ok, LaunchError> err = BaseProcessLauncher::DoFinishLaunch();
1715 if (err.isErr()) {
1716 return err;
1719 return Ok();
1721 #endif // XP_WIN
1723 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::FinishLaunch() {
1724 Result<Ok, LaunchError> aError = DoFinishLaunch();
1725 if (aError.isErr()) {
1726 return ProcessLaunchPromise::CreateAndReject(aError.unwrapErr(), __func__);
1729 MOZ_DIAGNOSTIC_ASSERT(mResults.mHandle);
1731 Telemetry::AccumulateTimeDelta(Telemetry::CHILD_PROCESS_LAUNCH_MS,
1732 mStartTimeStamp);
1734 return ProcessLaunchPromise::CreateAndResolve(std::move(mResults), __func__);
1737 bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid) {
1738 if (mChildProcessHandle) {
1739 MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
1740 return true;
1743 return base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle);
1746 void GeckoChildProcessHost::OnChannelConnected(base::ProcessId peer_pid) {
1748 mozilla::AutoWriteLock hLock(mHandleLock);
1749 if (!OpenPrivilegedHandle(peer_pid)) {
1750 MOZ_CRASH("can't open handle to child process");
1753 MonitorAutoLock lock(mMonitor);
1754 mProcessState = PROCESS_CONNECTED;
1755 lock.Notify();
1758 RefPtr<ProcessHandlePromise> GeckoChildProcessHost::WhenProcessHandleReady() {
1759 MOZ_ASSERT(mHandlePromise != nullptr);
1760 return mHandlePromise;
1763 #ifdef MOZ_WIDGET_ANDROID
1764 RefPtr<ProcessHandlePromise> AndroidProcessLauncher::LaunchAndroidService(
1765 const GeckoProcessType aType, const geckoargs::ChildProcessArgs& args) {
1766 JNIEnv* const env = mozilla::jni::GetEnvForThread();
1767 MOZ_ASSERT(env);
1769 const size_t argvSize = args.mArgs.size();
1770 jni::ObjectArray::LocalRef jargs =
1771 jni::ObjectArray::New<jni::String>(argvSize);
1772 for (size_t ix = 0; ix < argvSize; ix++) {
1773 jargs->SetElement(ix, jni::StringParam(args.mArgs[ix].c_str(), env));
1776 std::vector<int> fds(args.mFiles.size());
1777 for (size_t ix = 0; ix < fds.size(); ix++) {
1778 fds[ix] = args.mFiles[ix].get();
1780 jni::IntArray::LocalRef jfds = jni::IntArray::New(fds.data(), fds.size());
1782 auto type = java::GeckoProcessType::FromInt(aType);
1783 auto genericResult = java::GeckoProcessManager::Start(type, jargs, jfds);
1784 auto typedResult = java::GeckoResult::LocalRef(std::move(genericResult));
1785 return ProcessHandlePromise::FromGeckoResult(typedResult);
1787 #endif
1789 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1790 bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector& aArgs) {
1791 MacSandboxInfo info;
1792 if (NS_WARN_IF(!FillMacSandboxInfo(info))) {
1793 return false;
1795 info.AppendAsParams(aArgs);
1796 return true;
1799 // Fill |aInfo| with the flags needed to launch the utility sandbox
1800 bool GeckoChildProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
1801 aInfo.type = GetDefaultMacSandboxType();
1802 aInfo.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled") ||
1803 PR_GetEnv("MOZ_SANDBOX_LOGGING");
1805 nsAutoCString appPath;
1806 if (!nsMacUtilsImpl::GetAppPath(appPath)) {
1807 MOZ_CRASH("Failed to get app path");
1809 aInfo.appPath.assign(appPath.get());
1810 return true;
1813 void GeckoChildProcessHost::DisableOSActivityMode() {
1814 mDisableOSActivityMode = true;
1818 // If early sandbox startup is enabled for this process type, map the
1819 // process type to the sandbox type and enable the sandbox. Returns true
1820 // if no errors were encountered or if early sandbox startup is not
1821 // enabled for this process. Returns false if an error was encountered.
1823 /* static */
1824 bool GeckoChildProcessHost::StartMacSandbox(int aArgc, char** aArgv,
1825 std::string& aErrorMessage) {
1826 MacSandboxType sandboxType = MacSandboxType_Invalid;
1827 switch (XRE_GetProcessType()) {
1828 // For now, only support early sandbox startup for content,
1829 // RDD, and GMP processes. Add case statements for the additional
1830 // process types once early sandbox startup is implemented for them.
1831 case GeckoProcessType_Content:
1832 // Content processes don't use GeckoChildProcessHost
1833 // to configure sandboxing so hard code the sandbox type.
1834 sandboxType = MacSandboxType_Content;
1835 break;
1836 case GeckoProcessType_RDD:
1837 sandboxType = RDDProcessHost::GetMacSandboxType();
1838 break;
1839 case GeckoProcessType_Socket:
1840 sandboxType = net::SocketProcessHost::GetMacSandboxType();
1841 break;
1842 case GeckoProcessType_GMPlugin:
1843 sandboxType = gmp::GMPProcessParent::GetMacSandboxType();
1844 break;
1845 case GeckoProcessType_Utility:
1846 sandboxType = ipc::UtilityProcessHost::GetMacSandboxType();
1847 break;
1848 default:
1849 return true;
1852 return mozilla::StartMacSandboxIfEnabled(sandboxType, aArgc, aArgv,
1853 aErrorMessage);
1856 #endif /* XP_MACOSX && MOZ_SANDBOX */
1858 /* static */
1859 void GeckoChildProcessHost::GetAll(const GeckoProcessCallback& aCallback) {
1860 StaticMutexAutoLock lock(sMutex);
1861 if (!sGeckoChildProcessHosts) {
1862 return;
1864 for (GeckoChildProcessHost* gp = sGeckoChildProcessHosts->getFirst(); gp;
1865 gp = static_cast<mozilla::LinkedListElement<GeckoChildProcessHost>*>(gp)
1866 ->getNext()) {
1867 aCallback(gp);
1871 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::Launch(
1872 GeckoChildProcessHost* aHost) {
1873 AssertIOThread();
1875 // The ForkServer doesn't use IPC::Channel for communication, so we can skip
1876 // initializing it.
1877 if (mProcessType != GeckoProcessType_ForkServer) {
1878 IPC::Channel::ChannelHandle serverHandle;
1879 IPC::Channel::ChannelHandle clientHandle;
1880 if (!IPC::Channel::CreateRawPipe(&serverHandle, &clientHandle)) {
1881 return ProcessLaunchPromise::CreateAndReject(LaunchError("CreateRawPipe"),
1882 __func__);
1884 aHost->InitializeChannel(std::move(serverHandle));
1885 geckoargs::sIPCHandle.Put(std::move(clientHandle), mChildArgs);
1888 return InvokeAsync(mLaunchThread, this, __func__,
1889 &BaseProcessLauncher::PerformAsyncLaunch);
1892 } // namespace ipc
1893 } // namespace mozilla