Backed out 2 changesets (bug 1816628) for causing OS X mochitests-plain failures...
[gecko.git] / ipc / glue / GeckoChildProcessHost.cpp
blob232ee935d66b87ada92fa6d572d76fc5a4b296c5
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 #include "mozilla/ProcessType.h"
17 #ifdef MOZ_WIDGET_COCOA
18 # include <bsm/libbsm.h>
19 # include <mach/mach_traps.h>
20 # include <servers/bootstrap.h>
21 # include "SharedMemoryBasic.h"
22 # include "base/rand_util.h"
23 # include "chrome/common/mach_ipc_mac.h"
24 # include "mozilla/StaticPrefs_media.h"
25 # include "nsILocalFileMac.h"
26 #endif
28 #include "GeckoProfiler.h"
29 #include "MainThreadUtils.h"
30 #include "mozilla/Preferences.h"
31 #include "mozilla/Sprintf.h"
32 #include "nsXPCOMPrivate.h"
33 #include "prenv.h"
34 #include "prerror.h"
36 #if defined(MOZ_SANDBOX)
37 # include "mozilla/SandboxSettings.h"
38 # include "nsAppDirectoryServiceDefs.h"
39 #endif
41 #include <sys/stat.h>
43 #include "ProtocolUtils.h"
44 #include "mozilla/LinkedList.h"
45 #include "mozilla/Logging.h"
46 #include "mozilla/Maybe.h"
47 #include "mozilla/GeckoArgs.h"
48 #include "mozilla/Omnijar.h"
49 #include "mozilla/RDDProcessHost.h"
50 #include "mozilla/Services.h"
51 #include "mozilla/SharedThreadPool.h"
52 #include "mozilla/StaticMutex.h"
53 #include "mozilla/TaskQueue.h"
54 #include "mozilla/Telemetry.h"
55 #include "mozilla/UniquePtrExtensions.h"
56 #include "mozilla/ipc/BrowserProcessSubThread.h"
57 #include "mozilla/ipc/EnvironmentMap.h"
58 #include "mozilla/ipc/NodeController.h"
59 #include "mozilla/net/SocketProcessHost.h"
60 #include "nsDirectoryService.h"
61 #include "nsDirectoryServiceDefs.h"
62 #include "nsExceptionHandler.h"
63 #include "nsIFile.h"
64 #include "nsIObserverService.h"
65 #include "nsPrintfCString.h"
67 #ifdef XP_WIN
68 # include <stdlib.h>
70 # include "mozilla/WindowsVersion.h"
71 # include "nsIWinTaskbar.h"
72 # define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
74 # if defined(MOZ_SANDBOX)
75 # include "WinUtils.h"
76 # include "mozilla/Preferences.h"
77 # include "mozilla/sandboxing/sandboxLogging.h"
78 # if defined(_ARM64_)
79 # include "mozilla/remoteSandboxBroker.h"
80 # endif
81 # endif
83 # include "mozilla/NativeNt.h"
84 # include "mozilla/CacheNtDllThunk.h"
85 #endif
87 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
88 # include "mozilla/SandboxLaunch.h"
89 #endif
91 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
92 # include "GMPProcessParent.h"
93 # include "nsMacUtilsImpl.h"
94 #endif
96 #include "mozilla/ipc/UtilityProcessHost.h"
97 #include "mozilla/ipc/UtilityProcessSandboxing.h"
99 #include "nsClassHashtable.h"
100 #include "nsHashKeys.h"
101 #include "nsNativeCharsetUtils.h"
102 #include "nsTArray.h"
103 #include "nscore.h" // for NS_FREE_PERMANENT_DATA
104 #include "nsIThread.h"
106 using mozilla::MonitorAutoLock;
107 using mozilla::Preferences;
108 using mozilla::StaticMutexAutoLock;
110 #ifdef MOZ_WIDGET_ANDROID
111 # include "AndroidBridge.h"
112 # include "mozilla/java/GeckoProcessManagerWrappers.h"
113 # include "mozilla/java/GeckoProcessTypeWrappers.h"
114 # include "mozilla/java/GeckoResultWrappers.h"
115 # include "mozilla/jni/Refs.h"
116 # include "mozilla/jni/Utils.h"
117 #endif
119 #ifdef MOZ_ENABLE_FORKSERVER
120 # include "mozilla/ipc/ForkServiceChild.h"
121 #endif
123 static bool ShouldHaveDirectoryService() {
124 return GeckoProcessType_Default == XRE_GetProcessType();
127 namespace mozilla {
128 namespace ipc {
130 struct LaunchResults {
131 base::ProcessHandle mHandle = 0;
132 #ifdef XP_MACOSX
133 task_t mChildTask = MACH_PORT_NULL;
134 #endif
135 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
136 RefPtr<AbstractSandboxBroker> mSandboxBroker;
137 #endif
139 typedef mozilla::MozPromise<LaunchResults, LaunchError, true>
140 ProcessLaunchPromise;
142 static Atomic<int32_t> gChildCounter;
144 static inline nsISerialEventTarget* IOThread() {
145 return XRE_GetIOMessageLoop()->SerialEventTarget();
148 class BaseProcessLauncher {
149 public:
150 BaseProcessLauncher(GeckoChildProcessHost* aHost,
151 std::vector<std::string>&& aExtraOpts)
152 : mProcessType(aHost->mProcessType),
153 mLaunchOptions(std::move(aHost->mLaunchOptions)),
154 mExtraOpts(std::move(aExtraOpts)),
155 #ifdef XP_WIN
156 mGroupId(aHost->mGroupId),
157 #endif
158 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
159 mAllowedFilesRead(aHost->mAllowedFilesRead),
160 mSandboxLevel(aHost->mSandboxLevel),
161 mSandbox(aHost->mSandbox),
162 mIsFileContent(aHost->mIsFileContent),
163 mEnableSandboxLogging(aHost->mEnableSandboxLogging),
164 #endif
165 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
166 mDisableOSActivityMode(aHost->mDisableOSActivityMode),
167 #endif
168 mTmpDirName(aHost->mTmpDirName),
169 mChildId(++gChildCounter) {
170 SprintfLiteral(mPidString, "%" PRIPID, base::GetCurrentProcId());
171 aHost->mInitialChannelId.ToProvidedString(mInitialChannelIdString);
173 // Compute the serial event target we'll use for launching.
174 nsCOMPtr<nsIEventTarget> threadOrPool = GetIPCLauncher();
175 mLaunchThread =
176 TaskQueue::Create(threadOrPool.forget(), "BaseProcessLauncher");
178 if (ShouldHaveDirectoryService()) {
179 // "Current process directory" means the app dir, not the current
180 // working dir or similar.
181 mozilla::Unused
182 << nsDirectoryService::gService->GetCurrentProcessDirectory(
183 getter_AddRefs(mAppDir));
187 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BaseProcessLauncher);
189 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
190 void SetLaunchArchitecture(uint32_t aLaunchArch) {
191 mLaunchArch = aLaunchArch;
193 #endif
195 RefPtr<ProcessLaunchPromise> Launch(GeckoChildProcessHost*);
197 protected:
198 virtual ~BaseProcessLauncher() = default;
200 RefPtr<ProcessLaunchPromise> PerformAsyncLaunch();
201 RefPtr<ProcessLaunchPromise> FinishLaunch();
203 // Overrideable hooks. If superclass behavior is invoked, it's always at the
204 // top of the override.
205 virtual Result<Ok, LaunchError> DoSetup();
206 virtual RefPtr<ProcessHandlePromise> DoLaunch() = 0;
207 virtual Result<Ok, LaunchError> DoFinishLaunch();
209 void MapChildLogging();
211 static BinPathType GetPathToBinary(FilePath&, GeckoProcessType);
213 void GetChildLogName(const char* origLogName, nsACString& buffer);
215 const char* ChildProcessType() {
216 return XRE_GeckoProcessTypeToString(mProcessType);
219 nsCOMPtr<nsISerialEventTarget> mLaunchThread;
220 GeckoProcessType mProcessType;
221 UniquePtr<base::LaunchOptions> mLaunchOptions;
222 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
223 uint32_t mLaunchArch = base::PROCESS_ARCH_INVALID;
224 #endif
225 std::vector<std::string> mExtraOpts;
226 #ifdef XP_WIN
227 nsString mGroupId;
228 #endif
229 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
230 std::vector<std::wstring> mAllowedFilesRead;
231 int32_t mSandboxLevel;
232 SandboxingKind mSandbox;
233 bool mIsFileContent;
234 bool mEnableSandboxLogging;
235 #endif
236 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
237 // Controls whether or not the process will be launched with
238 // environment variable OS_ACTIVITY_MODE set to "disabled".
239 bool mDisableOSActivityMode;
240 #endif
241 nsCString mTmpDirName;
242 LaunchResults mResults = LaunchResults();
243 int32_t mChildId;
244 TimeStamp mStartTimeStamp = TimeStamp::Now();
245 char mPidString[32];
246 char mInitialChannelIdString[NSID_LENGTH];
248 // Set during launch.
249 IPC::Channel::ChannelHandle mClientChannelHandle;
250 nsCOMPtr<nsIFile> mAppDir;
253 #ifdef XP_WIN
254 class WindowsProcessLauncher final : public BaseProcessLauncher {
255 public:
256 WindowsProcessLauncher(GeckoChildProcessHost* aHost,
257 std::vector<std::string>&& aExtraOpts)
258 : BaseProcessLauncher(aHost, std::move(aExtraOpts)),
259 mCachedNtdllThunk(GetCachedNtDllThunk()) {}
261 protected:
262 virtual Result<Ok, LaunchError> DoSetup() override;
263 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
264 virtual Result<Ok, LaunchError> DoFinishLaunch() override;
266 private:
267 void AddApplicationPrefetchArgument();
269 mozilla::Maybe<CommandLine> mCmdLine;
270 bool mUseSandbox = false;
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 std::vector<std::string>&& aExtraOpts)
282 : BaseProcessLauncher(aHost, std::move(aExtraOpts)),
283 mProfileDir(aHost->mProfileDir),
284 mChannelDstFd(IPC::Channel::GetClientChannelHandle()) {}
286 protected:
287 virtual Result<Ok, LaunchError> DoSetup() override;
288 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
290 nsCOMPtr<nsIFile> mProfileDir;
292 std::vector<std::string> mChildArgv;
293 int mChannelDstFd;
296 # if defined(XP_MACOSX)
297 class MacProcessLauncher : public PosixProcessLauncher {
298 public:
299 MacProcessLauncher(GeckoChildProcessHost* aHost,
300 std::vector<std::string>&& aExtraOpts)
301 : PosixProcessLauncher(aHost, std::move(aExtraOpts)),
302 // Put a random number into the channel name, so that
303 // a compromised renderer can't pretend being the child
304 // that's forked off.
305 mMachConnectionName(
306 StringPrintf("org.mozilla.machname.%d",
307 base::RandInt(0, std::numeric_limits<int>::max()))) {
308 MOZ_ASSERT(mMachConnectionName.size() < BOOTSTRAP_MAX_NAME_LEN);
311 protected:
312 virtual Result<Ok, LaunchError> DoFinishLaunch() override;
314 std::string mMachConnectionName;
315 // We add a mach port to the command line so the child can communicate its
316 // 'task_t' back to the parent.
317 mozilla::UniqueMachReceiveRight mParentRecvPort;
319 friend class PosixProcessLauncher;
321 typedef MacProcessLauncher ProcessLauncher;
322 # elif defined(MOZ_WIDGET_ANDROID)
323 class AndroidProcessLauncher : public PosixProcessLauncher {
324 public:
325 AndroidProcessLauncher(GeckoChildProcessHost* aHost,
326 std::vector<std::string>&& aExtraOpts)
327 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
329 protected:
330 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
331 RefPtr<ProcessHandlePromise> LaunchAndroidService(
332 const GeckoProcessType aType, const std::vector<std::string>& argv,
333 const base::file_handle_mapping_vector& fds_to_remap);
335 typedef AndroidProcessLauncher ProcessLauncher;
336 // NB: Technically Android is linux (i.e. XP_LINUX is defined), but we want
337 // orthogonal IPC machinery there. Conversely, there are tier-3 non-Linux
338 // platforms (BSD and Solaris) where we want the "linux" IPC machinery. So
339 // we use MOZ_WIDGET_* to choose the platform backend.
340 # elif defined(MOZ_WIDGET_GTK)
341 class LinuxProcessLauncher : public PosixProcessLauncher {
342 public:
343 LinuxProcessLauncher(GeckoChildProcessHost* aHost,
344 std::vector<std::string>&& aExtraOpts)
345 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
347 protected:
348 virtual Result<Ok, LaunchError> DoSetup() override;
350 typedef LinuxProcessLauncher ProcessLauncher;
351 # elif
352 # error "Unknown platform"
353 # endif
354 #endif // XP_UNIX
356 using base::ProcessHandle;
357 using mozilla::ipc::BaseProcessLauncher;
358 using mozilla::ipc::ProcessLauncher;
360 mozilla::StaticAutoPtr<mozilla::LinkedList<GeckoChildProcessHost>>
361 GeckoChildProcessHost::sGeckoChildProcessHosts;
363 mozilla::StaticMutex GeckoChildProcessHost::sMutex;
365 GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
366 bool aIsFileContent)
367 : mProcessType(aProcessType),
368 mIsFileContent(aIsFileContent),
369 mMonitor("mozilla.ipc.GeckoChildProcessHost.mMonitor"),
370 mLaunchOptions(MakeUnique<base::LaunchOptions>()),
371 mInitialChannelId(nsID::GenerateUUID()),
372 mProcessState(CREATING_CHANNEL),
373 #ifdef XP_WIN
374 mGroupId(u"-"),
375 #endif
376 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
377 mEnableSandboxLogging(false),
378 mSandboxLevel(0),
379 #endif
380 mHandleLock("mozilla.ipc.GeckoChildProcessHost.mHandleLock"),
381 mChildProcessHandle(0),
382 #if defined(MOZ_WIDGET_COCOA)
383 mChildTask(MACH_PORT_NULL),
384 #endif
385 #if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
386 mDisableOSActivityMode(false),
387 #endif
388 mDestroying(false) {
389 MOZ_COUNT_CTOR(GeckoChildProcessHost);
390 StaticMutexAutoLock lock(sMutex);
391 if (!sGeckoChildProcessHosts) {
392 sGeckoChildProcessHosts = new mozilla::LinkedList<GeckoChildProcessHost>();
394 sGeckoChildProcessHosts->insertBack(this);
395 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
396 if (aProcessType == GeckoProcessType_Content) {
397 # if defined(MOZ_CONTENT_TEMP_DIR)
398 // The content process needs the content temp dir:
399 nsCOMPtr<nsIFile> contentTempDir;
400 nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
401 getter_AddRefs(contentTempDir));
402 if (NS_SUCCEEDED(rv)) {
403 contentTempDir->GetNativePath(mTmpDirName);
405 # endif
406 } else 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
418 #if defined(MOZ_ENABLE_FORKSERVER)
419 if (aProcessType != GeckoProcessType_ForkServer && ForkServiceChild::Get()) {
420 mLaunchOptions->use_forkserver = true;
422 #endif
425 GeckoChildProcessHost::~GeckoChildProcessHost()
428 AssertIOThread();
429 MOZ_RELEASE_ASSERT(mDestroying);
431 MOZ_COUNT_DTOR(GeckoChildProcessHost);
434 mozilla::AutoWriteLock hLock(mHandleLock);
435 #if defined(MOZ_WIDGET_COCOA)
436 if (mChildTask != MACH_PORT_NULL) {
437 mach_port_deallocate(mach_task_self(), mChildTask);
439 #endif
441 if (mChildProcessHandle != 0) {
442 ProcessWatcher::EnsureProcessTerminated(
443 mChildProcessHandle
444 #ifdef NS_FREE_PERMANENT_DATA
445 // If we're doing leak logging, shutdown can be slow.
447 false // don't "force"
448 #endif
450 mChildProcessHandle = 0;
454 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
455 if (mSandboxBroker) {
456 mSandboxBroker->Shutdown();
457 mSandboxBroker = nullptr;
459 #endif
462 base::ProcessHandle GeckoChildProcessHost::GetChildProcessHandle() {
463 mozilla::AutoReadLock handleLock(mHandleLock);
464 return mChildProcessHandle;
467 base::ProcessId GeckoChildProcessHost::GetChildProcessId() {
468 mozilla::AutoReadLock handleLock(mHandleLock);
469 if (!mChildProcessHandle) {
470 return 0;
472 return base::GetProcId(mChildProcessHandle);
475 #ifdef XP_MACOSX
476 task_t GeckoChildProcessHost::GetChildTask() {
477 mozilla::AutoReadLock handleLock(mHandleLock);
478 return mChildTask;
480 #endif
482 void GeckoChildProcessHost::RemoveFromProcessList() {
483 StaticMutexAutoLock lock(sMutex);
484 if (!sGeckoChildProcessHosts) {
485 return;
487 LinkedListElement<GeckoChildProcessHost>::removeFrom(
488 *sGeckoChildProcessHosts);
491 void GeckoChildProcessHost::Destroy() {
492 MOZ_RELEASE_ASSERT(!mDestroying);
493 // We can remove from the list before it's really destroyed
494 RemoveFromProcessList();
495 RefPtr<ProcessHandlePromise> whenReady = mHandlePromise;
497 if (!whenReady) {
498 // AsyncLaunch not called yet, so dispatch immediately.
499 whenReady = ProcessHandlePromise::CreateAndReject(
500 LaunchError("DestroyEarly"), __func__);
503 using Value = ProcessHandlePromise::ResolveOrRejectValue;
504 mDestroying = true;
505 whenReady->Then(XRE_GetIOMessageLoop()->SerialEventTarget(), __func__,
506 [this](const Value&) { delete this; });
509 // static
510 mozilla::BinPathType BaseProcessLauncher::GetPathToBinary(
511 FilePath& exePath, GeckoProcessType processType) {
512 BinPathType pathType = XRE_GetChildProcBinPathType(processType);
514 if (pathType == BinPathType::Self) {
515 #if defined(XP_WIN)
516 wchar_t exePathBuf[MAXPATHLEN];
517 if (!::GetModuleFileNameW(nullptr, exePathBuf, MAXPATHLEN)) {
518 MOZ_CRASH("GetModuleFileNameW failed (FIXME)");
520 exePath = FilePath::FromWStringHack(exePathBuf);
521 #else
522 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
523 #endif
524 return pathType;
527 #ifdef MOZ_WIDGET_COCOA
528 // The GMP child process runs via the Media Plugin Helper executable
529 // which is a clone of plugin-container allowing for GMP-specific
530 // codesigning entitlements.
531 nsCString bundleName;
532 std::string executableLeafName;
533 if (processType == GeckoProcessType_GMPlugin &&
534 mozilla::StaticPrefs::media_plugin_helper_process_enabled()) {
535 bundleName = MOZ_EME_PROCESS_BUNDLENAME;
536 executableLeafName = MOZ_EME_PROCESS_NAME_BRANDED;
537 } else {
538 bundleName = MOZ_CHILD_PROCESS_BUNDLENAME;
539 executableLeafName = MOZ_CHILD_PROCESS_NAME;
541 #endif
543 if (ShouldHaveDirectoryService()) {
544 MOZ_ASSERT(gGREBinPath);
545 #ifdef XP_WIN
546 exePath = FilePath(char16ptr_t(gGREBinPath));
547 #elif MOZ_WIDGET_COCOA
548 nsCOMPtr<nsIFile> childProcPath;
549 NS_NewLocalFile(nsDependentString(gGREBinPath), false,
550 getter_AddRefs(childProcPath));
552 // We need to use an App Bundle on OS X so that we can hide
553 // the dock icon. See Bug 557225.
554 childProcPath->AppendNative(bundleName);
555 childProcPath->AppendNative("Contents"_ns);
556 childProcPath->AppendNative("MacOS"_ns);
557 nsCString tempCPath;
558 childProcPath->GetNativePath(tempCPath);
559 exePath = FilePath(tempCPath.get());
560 #else
561 nsCString path;
562 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
563 exePath = FilePath(path.get());
564 #endif
567 if (exePath.empty()) {
568 #ifdef XP_WIN
569 exePath =
570 FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
571 #else
572 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
573 #endif
574 exePath = exePath.DirName();
577 #ifdef MOZ_WIDGET_COCOA
578 exePath = exePath.Append(executableLeafName);
579 #else
580 exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
581 #endif
583 return pathType;
586 #ifdef MOZ_WIDGET_COCOA
587 class AutoCFTypeObject {
588 public:
589 explicit AutoCFTypeObject(CFTypeRef object) { mObject = object; }
590 ~AutoCFTypeObject() { ::CFRelease(mObject); }
592 private:
593 CFTypeRef mObject;
595 #endif
597 // We start the unique IDs at 1 so that 0 can be used to mean that
598 // a component has no unique ID assigned to it.
599 uint32_t GeckoChildProcessHost::sNextUniqueID = 1;
601 /* static */
602 uint32_t GeckoChildProcessHost::GetUniqueID() { return sNextUniqueID++; }
604 /* static */
605 void GeckoChildProcessHost::SetEnv(const char* aKey, const char* aValue) {
606 MOZ_ASSERT(mLaunchOptions);
607 mLaunchOptions->env_map[ENVIRONMENT_STRING(aKey)] =
608 ENVIRONMENT_STRING(aValue);
611 void GeckoChildProcessHost::PrepareLaunch() {
612 if (CrashReporter::GetEnabled()) {
613 CrashReporter::OOPInit();
616 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
617 SandboxLaunch::Configure(mProcessType, mSandbox, mLaunchOptions.get());
618 #endif
620 #ifdef XP_WIN
622 # if defined(MOZ_SANDBOX)
623 // We need to get the pref here as the process is launched off main thread.
624 if (mProcessType == GeckoProcessType_Content) {
625 // Win32k Lockdown state must be initialized on the main thread.
626 // This is our last chance to do it before it is read on the IPC Launch
627 // thread
628 GetWin32kLockdownState();
629 mSandboxLevel = GetEffectiveContentSandboxLevel();
630 mEnableSandboxLogging =
631 Preferences::GetBool("security.sandbox.logging.enabled");
633 // We currently have to whitelist certain paths for tests to work in some
634 // development configurations.
635 nsAutoString readPaths;
636 nsresult rv = Preferences::GetString(
637 "security.sandbox.content.read_path_whitelist", readPaths);
638 if (NS_SUCCEEDED(rv)) {
639 for (const nsAString& readPath : readPaths.Split(',')) {
640 nsString trimmedPath(readPath);
641 trimmedPath.Trim(" ", true, true);
642 std::wstring resolvedPath(trimmedPath.Data());
643 // Check if path ends with '\' as this indicates we want to give read
644 // access to a directory and so it needs a wildcard.
645 if (resolvedPath.back() == L'\\') {
646 resolvedPath.append(L"*");
648 mAllowedFilesRead.push_back(resolvedPath);
652 # endif
654 # if defined(MOZ_SANDBOX)
655 // For other process types we can't rely on them being launched on main
656 // thread and they may not have access to prefs in the child process, so allow
657 // them to turn on logging via an environment variable.
658 mEnableSandboxLogging =
659 mEnableSandboxLogging || !!PR_GetEnv("MOZ_SANDBOX_LOGGING");
661 # endif
662 #elif defined(XP_MACOSX)
663 # if defined(MOZ_SANDBOX)
664 if (ShouldHaveDirectoryService() &&
665 mProcessType != GeckoProcessType_GMPlugin) {
666 mozilla::Unused << NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
667 getter_AddRefs(mProfileDir));
669 # endif
670 #endif
673 #ifdef XP_WIN
674 void GeckoChildProcessHost::InitWindowsGroupID() {
675 // On Win7+, pass the application user model to the child, so it can
676 // register with it. This insures windows created by the container
677 // properly group with the parent app on the Win7 taskbar.
678 nsCOMPtr<nsIWinTaskbar> taskbarInfo = do_GetService(NS_TASKBAR_CONTRACTID);
679 if (taskbarInfo) {
680 bool isSupported = false;
681 taskbarInfo->GetAvailable(&isSupported);
682 nsAutoString appId;
683 if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
684 MOZ_ASSERT(mGroupId.EqualsLiteral("-"));
685 mGroupId.Assign(appId);
689 #endif
691 bool GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts,
692 int aTimeoutMs) {
693 if (!AsyncLaunch(std::move(aExtraOpts))) {
694 return false;
696 return WaitUntilConnected(aTimeoutMs);
699 // Note: for most process types, we currently call AsyncLaunch, and therefore
700 // the *ProcessLauncher constructor, on the main thread, while the
701 // ProcessLauncher methods to actually execute the launch are called on the IO
702 // or IPC launcher thread. GMP processes are an exception - the GMP code
703 // invokes GeckoChildProcessHost from non-main-threads, and therefore we cannot
704 // rely on having access to mainthread-only services (like the directory
705 // service) from this code if we're launching that type of process.
706 bool GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts) {
707 PrepareLaunch();
709 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
710 if (IsMacSandboxLaunchEnabled() && !AppendMacSandboxParams(aExtraOpts)) {
711 return false;
713 #endif
715 RefPtr<BaseProcessLauncher> launcher =
716 new ProcessLauncher(this, std::move(aExtraOpts));
717 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
718 launcher->SetLaunchArchitecture(mLaunchArch);
719 #endif
721 // Note: Destroy() waits on mHandlePromise to delete |this|. As such, we want
722 // to be sure that all of our post-launch processing on |this| happens before
723 // mHandlePromise notifies.
724 MOZ_ASSERT(mHandlePromise == nullptr);
725 mHandlePromise =
726 mozilla::InvokeAsync<GeckoChildProcessHost*>(
727 IOThread(), launcher.get(), __func__, &BaseProcessLauncher::Launch,
728 this)
729 ->Then(
730 IOThread(), __func__,
731 [this](LaunchResults&& aResults) {
734 mozilla::AutoWriteLock handleLock(mHandleLock);
735 if (!OpenPrivilegedHandle(base::GetProcId(aResults.mHandle))
736 #ifdef XP_WIN
737 // If we failed in opening the process handle, try
738 // harder by duplicating one.
739 && !::DuplicateHandle(
740 ::GetCurrentProcess(), aResults.mHandle,
741 ::GetCurrentProcess(), &mChildProcessHandle,
742 PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
743 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ |
744 SYNCHRONIZE,
745 FALSE, 0)
746 #endif // XP_WIN
748 MOZ_CRASH("cannot open handle to child process");
750 // The original handle is no longer needed; it must
751 // be closed to prevent a resource leak.
752 base::CloseProcessHandle(aResults.mHandle);
753 // FIXME (bug 1720523): define a cross-platform
754 // "safe" invalid value to use in places like this.
755 aResults.mHandle = 0;
757 #ifdef XP_MACOSX
758 this->mChildTask = aResults.mChildTask;
759 #endif
761 if (mNodeChannel) {
762 mNodeChannel->SetOtherPid(
763 base::GetProcId(this->mChildProcessHandle));
764 #ifdef XP_MACOSX
765 mNodeChannel->SetMachTaskPort(this->mChildTask);
766 #endif
769 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
770 this->mSandboxBroker = std::move(aResults.mSandboxBroker);
771 #endif
773 MonitorAutoLock lock(mMonitor);
774 // The OnChannel{Connected,Error} may have already advanced
775 // the state.
776 if (mProcessState < PROCESS_CREATED) {
777 mProcessState = PROCESS_CREATED;
779 lock.Notify();
781 return ProcessHandlePromise::CreateAndResolve(
782 GetChildProcessHandle(), __func__);
784 [this](const LaunchError aError) {
785 // WaitUntilConnected might be waiting for us to signal.
786 // If something failed let's set the error state and notify.
787 CHROMIUM_LOG(ERROR)
788 << "Failed to launch "
789 << XRE_GeckoProcessTypeToString(mProcessType)
790 << " subprocess";
791 Telemetry::Accumulate(
792 Telemetry::SUBPROCESS_LAUNCH_FAILURE,
793 nsDependentCString(
794 XRE_GeckoProcessTypeToString(mProcessType)));
795 nsCString telemetryKey = nsPrintfCString(
796 #if defined(XP_WIN)
797 "%s,0x%lx,%s",
798 #else
799 "%s,%d,%s",
800 #endif
801 aError.FunctionName(), aError.ErrorCode(),
802 XRE_GeckoProcessTypeToString(mProcessType));
803 // Max telemetry key is 72 chars
804 // https://searchfox.org/mozilla-central/rev/c244b16815d1fc827d141472b9faac5610f250e7/toolkit/components/telemetry/core/TelemetryScalar.cpp#105
805 if (telemetryKey.Length() > 72) {
806 NS_WARNING(nsPrintfCString("Truncating telemetry key: %s",
807 telemetryKey.get())
808 .get());
809 telemetryKey.Truncate(72);
811 Telemetry::ScalarAdd(
812 Telemetry::ScalarID::
813 DOM_PARENTPROCESS_PROCESS_LAUNCH_ERRORS,
814 NS_ConvertUTF8toUTF16(telemetryKey), 1);
816 MonitorAutoLock lock(mMonitor);
817 mProcessState = PROCESS_ERROR;
818 lock.Notify();
820 return ProcessHandlePromise::CreateAndReject(aError, __func__);
822 return true;
825 bool GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs) {
826 AUTO_PROFILER_LABEL("GeckoChildProcessHost::WaitUntilConnected", OTHER);
828 // NB: this uses a different mechanism than the chromium parent
829 // class.
830 TimeDuration timeout = (aTimeoutMs > 0)
831 ? TimeDuration::FromMilliseconds(aTimeoutMs)
832 : TimeDuration::Forever();
834 MonitorAutoLock lock(mMonitor);
835 TimeStamp waitStart = TimeStamp::Now();
836 TimeStamp current;
838 // We'll receive several notifications, we need to exit when we
839 // have either successfully launched or have timed out.
840 while (mProcessState != PROCESS_CONNECTED) {
841 // If there was an error then return it, don't wait out the timeout.
842 if (mProcessState == PROCESS_ERROR) {
843 break;
846 CVStatus status = lock.Wait(timeout);
847 if (status == CVStatus::Timeout) {
848 break;
851 if (timeout != TimeDuration::Forever()) {
852 current = TimeStamp::Now();
853 timeout -= current - waitStart;
854 waitStart = current;
858 return mProcessState == PROCESS_CONNECTED;
861 bool GeckoChildProcessHost::WaitForProcessHandle() {
862 MonitorAutoLock lock(mMonitor);
863 while (mProcessState < PROCESS_CREATED) {
864 lock.Wait();
866 MOZ_ASSERT(mProcessState == PROCESS_ERROR || GetChildProcessHandle());
868 return mProcessState < PROCESS_ERROR;
871 bool GeckoChildProcessHost::LaunchAndWaitForProcessHandle(
872 StringVector aExtraOpts) {
873 if (!AsyncLaunch(std::move(aExtraOpts))) {
874 return false;
876 return WaitForProcessHandle();
879 void GeckoChildProcessHost::InitializeChannel(
880 IPC::Channel::ChannelHandle&& aServerHandle) {
881 // Create the IPC channel which will be used for communication with this
882 // process.
883 mozilla::UniquePtr<IPC::Channel> channel = MakeUnique<IPC::Channel>(
884 std::move(aServerHandle), IPC::Channel::MODE_SERVER,
885 base::kInvalidProcessId);
886 #if defined(XP_WIN)
887 channel->StartAcceptingHandles(IPC::Channel::MODE_SERVER);
888 #elif defined(XP_DARWIN)
889 channel->StartAcceptingMachPorts(IPC::Channel::MODE_SERVER);
890 #endif
892 mNodeController = NodeController::GetSingleton();
893 std::tie(mInitialPort, mNodeChannel) =
894 mNodeController->InviteChildProcess(std::move(channel), this);
896 MonitorAutoLock lock(mMonitor);
897 mProcessState = CHANNEL_INITIALIZED;
898 lock.Notify();
901 void GeckoChildProcessHost::SetAlreadyDead() {
902 mozilla::AutoWriteLock handleLock(mHandleLock);
903 if (mChildProcessHandle &&
904 mChildProcessHandle != base::kInvalidProcessHandle) {
905 base::CloseProcessHandle(mChildProcessHandle);
908 mChildProcessHandle = 0;
911 void BaseProcessLauncher::GetChildLogName(const char* origLogName,
912 nsACString& buffer) {
913 #ifdef XP_WIN
914 // On Windows we must expand relative paths because sandboxing rules
915 // bound only to full paths. fopen fowards to NtCreateFile which checks
916 // the path against the sanboxing rules as passed to fopen (left relative).
917 char absPath[MAX_PATH + 2];
918 if (_fullpath(absPath, origLogName, sizeof(absPath))) {
919 buffer.Append(absPath);
920 } else
921 #endif
923 buffer.Append(origLogName);
926 // Remove .moz_log extension to avoid its duplication, it will be added
927 // automatically by the logging backend
928 static constexpr auto kMozLogExt = nsLiteralCString{MOZ_LOG_FILE_EXTENSION};
929 if (StringEndsWith(buffer, kMozLogExt)) {
930 buffer.Truncate(buffer.Length() - kMozLogExt.Length());
933 // Append child-specific postfix to name
934 buffer.AppendLiteral(".child-");
935 buffer.AppendInt(mChildId);
938 // Windows needs a single dedicated thread for process launching,
939 // because of thread-safety restrictions/assertions in the sandbox
940 // code.
942 // Android also needs a single dedicated thread to simplify thread
943 // safety in java.
945 // Fork server needs a dedicated thread for accessing
946 // |ForkServiceChild|.
947 #if defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID) || \
948 defined(MOZ_ENABLE_FORKSERVER)
950 static mozilla::StaticMutex gIPCLaunchThreadMutex;
951 static mozilla::StaticRefPtr<nsIThread> gIPCLaunchThread
952 MOZ_GUARDED_BY(gIPCLaunchThreadMutex);
954 class IPCLaunchThreadObserver final : public nsIObserver {
955 public:
956 NS_DECL_ISUPPORTS
957 NS_DECL_NSIOBSERVER
958 protected:
959 virtual ~IPCLaunchThreadObserver() = default;
962 NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver, nsIObserver, nsISupports)
964 NS_IMETHODIMP
965 IPCLaunchThreadObserver::Observe(nsISupports* aSubject, const char* aTopic,
966 const char16_t* aData) {
967 MOZ_RELEASE_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0);
968 StaticMutexAutoLock lock(gIPCLaunchThreadMutex);
970 nsresult rv = NS_OK;
971 if (gIPCLaunchThread) {
972 rv = gIPCLaunchThread->Shutdown();
973 gIPCLaunchThread = nullptr;
975 mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
976 return rv;
979 nsCOMPtr<nsIEventTarget> GetIPCLauncher() {
980 StaticMutexAutoLock lock(gIPCLaunchThreadMutex);
981 if (!gIPCLaunchThread) {
982 nsCOMPtr<nsIThread> thread;
983 nsresult rv = NS_NewNamedThread("IPC Launch"_ns, getter_AddRefs(thread));
984 if (!NS_WARN_IF(NS_FAILED(rv))) {
985 NS_DispatchToMainThread(
986 NS_NewRunnableFunction("GeckoChildProcessHost::GetIPCLauncher", [] {
987 nsCOMPtr<nsIObserverService> obsService =
988 mozilla::services::GetObserverService();
989 nsCOMPtr<nsIObserver> obs = new IPCLaunchThreadObserver();
990 obsService->AddObserver(obs, "xpcom-shutdown-threads", false);
991 }));
992 gIPCLaunchThread = thread.forget();
996 nsCOMPtr<nsIEventTarget> thread = gIPCLaunchThread.get();
997 MOZ_DIAGNOSTIC_ASSERT(thread);
998 return thread;
1001 #else // defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID) ||
1002 // defined(MOZ_ENABLE_FORKSERVER)
1004 // Other platforms use an on-demand thread pool.
1006 nsCOMPtr<nsIEventTarget> GetIPCLauncher() {
1007 nsCOMPtr<nsIEventTarget> pool =
1008 mozilla::SharedThreadPool::Get("IPC Launch"_ns);
1009 MOZ_DIAGNOSTIC_ASSERT(pool);
1010 return pool;
1013 #endif // XP_WIN || MOZ_WIDGET_ANDROID || MOZ_ENABLE_FORKSERVER
1015 void
1016 #if defined(XP_WIN)
1017 AddAppDirToCommandLine(CommandLine& aCmdLine, nsIFile* aAppDir)
1018 #else
1019 AddAppDirToCommandLine(std::vector<std::string>& aCmdLine, nsIFile* aAppDir,
1020 nsIFile* aProfileDir)
1021 #endif
1023 // Content processes need access to application resources, so pass
1024 // the full application directory path to the child process.
1025 if (aAppDir) {
1026 #if defined(XP_WIN)
1027 nsString path;
1028 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetPath(path));
1029 aCmdLine.AppendLooseValue(UTF8ToWide(geckoargs::sAppDir.Name()));
1030 std::wstring wpath(path.get());
1031 aCmdLine.AppendLooseValue(wpath);
1032 #else
1033 nsAutoCString path;
1034 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetNativePath(path));
1035 geckoargs::sAppDir.Put(path.get(), aCmdLine);
1036 #endif
1038 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1039 // Full path to the profile dir
1040 if (aProfileDir) {
1041 // If the profile doesn't exist, normalization will
1042 // fail. But we don't return an error here because some
1043 // tests require startup with a missing profile dir.
1044 // For users, almost universally, the profile will be in
1045 // the home directory and normalization isn't required.
1046 mozilla::Unused << aProfileDir->Normalize();
1047 nsAutoCString path;
1048 MOZ_ALWAYS_SUCCEEDS(aProfileDir->GetNativePath(path));
1049 geckoargs::sProfile.Put(path.get(), aCmdLine);
1051 #endif
1055 #if defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
1056 static bool Contains(const std::vector<std::string>& aExtraOpts,
1057 const char* aValue) {
1058 return std::any_of(aExtraOpts.begin(), aExtraOpts.end(),
1059 [&](const std::string arg) {
1060 return arg.find(aValue) != std::string::npos;
1063 #endif // defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
1065 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::PerformAsyncLaunch() {
1066 Result<Ok, LaunchError> aError = DoSetup();
1067 if (aError.isErr()) {
1068 return ProcessLaunchPromise::CreateAndReject(aError.unwrapErr(), __func__);
1070 RefPtr<BaseProcessLauncher> self = this;
1071 return DoLaunch()->Then(
1072 mLaunchThread, __func__,
1073 [self](base::ProcessHandle aHandle) {
1074 self->mResults.mHandle = aHandle;
1075 return self->FinishLaunch();
1077 [](LaunchError aError) {
1078 return ProcessLaunchPromise::CreateAndReject(aError, __func__);
1082 Result<Ok, LaunchError> BaseProcessLauncher::DoSetup() {
1083 RefPtr<BaseProcessLauncher> self = this;
1084 GetProfilerEnvVarsForChildProcess([self](const char* key, const char* value) {
1085 self->mLaunchOptions->env_map[ENVIRONMENT_STRING(key)] =
1086 ENVIRONMENT_STRING(value);
1088 #ifdef MOZ_MEMORY
1089 if (mProcessType == GeckoProcessType_Content) {
1090 nsAutoCString mallocOpts(PR_GetEnv("MALLOC_OPTIONS"));
1091 // Disable randomization of small arenas in content.
1092 mallocOpts.Append("r");
1093 self->mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MALLOC_OPTIONS")] =
1094 ENVIRONMENT_STRING(mallocOpts.get());
1096 #endif
1098 MapChildLogging();
1100 return Ok();
1103 void BaseProcessLauncher::MapChildLogging() {
1104 const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
1105 const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
1107 if (origNSPRLogName) {
1108 nsAutoCString nsprLogName;
1109 GetChildLogName(origNSPRLogName, nsprLogName);
1110 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("NSPR_LOG_FILE")] =
1111 ENVIRONMENT_STRING(nsprLogName.get());
1113 if (origMozLogName) {
1114 nsAutoCString mozLogName;
1115 GetChildLogName(origMozLogName, mozLogName);
1116 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MOZ_LOG_FILE")] =
1117 ENVIRONMENT_STRING(mozLogName.get());
1120 // `RUST_LOG_CHILD` is meant for logging child processes only.
1121 nsAutoCString childRustLog(PR_GetEnv("RUST_LOG_CHILD"));
1122 if (!childRustLog.IsEmpty()) {
1123 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("RUST_LOG")] =
1124 ENVIRONMENT_STRING(childRustLog.get());
1128 Result<Ok, LaunchError> BaseProcessLauncher::DoFinishLaunch() {
1129 // We're in the parent and the child was launched. Close the child channel
1130 // handle in the parent as soon as possible, which will allow the parent to
1131 // detect when the child closes its handle (either due to normal exit or due
1132 // to crash).
1133 mClientChannelHandle = nullptr;
1135 return Ok();
1138 #if defined(MOZ_WIDGET_GTK)
1139 Result<Ok, LaunchError> LinuxProcessLauncher::DoSetup() {
1140 Result<Ok, LaunchError> aError = PosixProcessLauncher::DoSetup();
1141 if (aError.isErr()) {
1142 return aError;
1145 if (mProcessType == GeckoProcessType_Content) {
1146 // disable IM module to avoid sandbox violation
1147 mLaunchOptions->env_map["GTK_IM_MODULE"] = "gtk-im-context-simple";
1149 // Disable ATK accessibility code in content processes because it conflicts
1150 // with the sandbox, and we proxy that information through the main process
1151 // anyway.
1152 mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1";
1155 # ifdef MOZ_SANDBOX
1156 if (!mTmpDirName.IsEmpty()) {
1157 // Point a bunch of things that might want to write from content to our
1158 // shiny new content-process specific tmpdir
1159 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("TMPDIR")] =
1160 ENVIRONMENT_STRING(mTmpDirName.get());
1161 // Partial fix for bug 1380051 (not persistent - should be)
1162 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
1163 ENVIRONMENT_STRING(mTmpDirName.get());
1165 # endif // MOZ_SANDBOX
1167 return Ok();
1169 #endif // MOZ_WIDGET_GTK
1171 #ifdef XP_UNIX
1172 Result<Ok, LaunchError> PosixProcessLauncher::DoSetup() {
1173 Result<Ok, LaunchError> aError = BaseProcessLauncher::DoSetup();
1174 if (aError.isErr()) {
1175 return aError;
1178 // XPCOM may not be initialized in some subprocesses. We don't want
1179 // to initialize XPCOM just for the directory service, especially
1180 // since LD_LIBRARY_PATH is already set correctly in subprocesses
1181 // (meaning that we don't need to set that up in the environment).
1182 if (ShouldHaveDirectoryService()) {
1183 MOZ_ASSERT(gGREBinPath);
1184 nsCString path;
1185 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
1186 # if defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \
1187 defined(XP_NETBSD) || defined(XP_OPENBSD)
1188 const char* ld_library_path = PR_GetEnv("LD_LIBRARY_PATH");
1189 nsCString new_ld_lib_path(path.get());
1191 if (ld_library_path && *ld_library_path) {
1192 new_ld_lib_path.Append(':');
1193 new_ld_lib_path.Append(ld_library_path);
1195 mLaunchOptions->env_map["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
1197 # elif XP_DARWIN
1198 // With signed production Mac builds, the dynamic linker (dyld) will
1199 // ignore dyld environment variables preventing the use of variables
1200 // such as DYLD_LIBRARY_PATH and DYLD_INSERT_LIBRARIES.
1202 // If we're running with gtests, add the gtest XUL ahead of normal XUL on
1203 // the DYLD_LIBRARY_PATH so that plugin-container.app loads it instead.
1204 nsCString new_dyld_lib_path(path.get());
1205 if (PR_GetEnv("MOZ_RUN_GTEST")) {
1206 new_dyld_lib_path = path + "/gtest:"_ns + new_dyld_lib_path;
1207 mLaunchOptions->env_map["DYLD_LIBRARY_PATH"] = new_dyld_lib_path.get();
1210 // DYLD_INSERT_LIBRARIES is currently unused by default but we allow
1211 // it to be set by the external environment.
1212 const char* interpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
1213 if (interpose && strlen(interpose) > 0) {
1214 mLaunchOptions->env_map["DYLD_INSERT_LIBRARIES"] = interpose;
1217 // Prevent connection attempts to diagnosticd(8) to save cycles. Log
1218 // messages can trigger these connection attempts, but access to
1219 // diagnosticd is blocked in sandboxed child processes.
1220 # ifdef MOZ_SANDBOX
1221 if (mDisableOSActivityMode) {
1222 mLaunchOptions->env_map["OS_ACTIVITY_MODE"] = "disable";
1224 # endif // defined(MOZ_SANDBOX)
1225 # endif
1228 FilePath exePath;
1229 BinPathType pathType = GetPathToBinary(exePath, mProcessType);
1231 // remap the IPC socket fd to a well-known int, as the OS does for
1232 // STDOUT_FILENO, for example
1233 // The fork server doesn't use IPC::Channel, so can skip this step.
1234 if (mProcessType != GeckoProcessType_ForkServer) {
1235 # ifdef MOZ_WIDGET_ANDROID
1236 // On Android mChannelDstFd is uninitialised and the launching code uses
1237 // only the first of each pair.
1238 mLaunchOptions->fds_to_remap.push_back(
1239 std::pair<int, int>(mClientChannelHandle.get(), -1));
1240 # else
1241 MOZ_ASSERT(mChannelDstFd >= 0);
1242 mLaunchOptions->fds_to_remap.push_back(
1243 std::pair<int, int>(mClientChannelHandle.get(), mChannelDstFd));
1244 # endif
1247 // no need for kProcessChannelID, the child process inherits the
1248 // other end of the socketpair() from us
1250 mChildArgv.push_back(exePath.value());
1252 if (pathType == BinPathType::Self) {
1253 mChildArgv.push_back("-contentproc");
1256 mChildArgv.insert(mChildArgv.end(), mExtraOpts.begin(), mExtraOpts.end());
1258 if ((mProcessType == GeckoProcessType_Content ||
1259 mProcessType == GeckoProcessType_ForkServer) &&
1260 Omnijar::IsInitialized()) {
1261 // Make sure that child processes can find the omnijar, if they
1262 // use full XPCOM. See Omnijar::ChildProcessInit and its callers.
1263 nsAutoCString path;
1264 nsCOMPtr<nsIFile> greFile = Omnijar::GetPath(Omnijar::GRE);
1265 if (greFile && NS_SUCCEEDED(greFile->GetNativePath(path))) {
1266 geckoargs::sGREOmni.Put(path.get(), mChildArgv);
1268 nsCOMPtr<nsIFile> appFile = Omnijar::GetPath(Omnijar::APP);
1269 if (appFile && NS_SUCCEEDED(appFile->GetNativePath(path))) {
1270 geckoargs::sAppOmni.Put(path.get(), mChildArgv);
1274 if (mProcessType != GeckoProcessType_GMPlugin) {
1275 // Add the application directory path (-appdir path)
1276 # ifdef XP_MACOSX
1277 AddAppDirToCommandLine(mChildArgv, mAppDir, mProfileDir);
1278 # else
1279 AddAppDirToCommandLine(mChildArgv, mAppDir, nullptr);
1280 # endif
1283 mChildArgv.push_back(mInitialChannelIdString);
1285 mChildArgv.push_back(mPidString);
1287 if (!CrashReporter::IsDummy()) {
1288 # if defined(MOZ_WIDGET_COCOA)
1289 mChildArgv.push_back(CrashReporter::GetChildNotificationPipe());
1290 # elif defined(XP_UNIX)
1291 int childCrashFd, childCrashRemapFd;
1292 if (NS_WARN_IF(!CrashReporter::CreateNotificationPipeForChild(
1293 &childCrashFd, &childCrashRemapFd))) {
1294 return Err(LaunchError("CR::CreateNotificationPipeForChild"));
1297 if (0 <= childCrashFd) {
1298 mLaunchOptions->fds_to_remap.push_back(
1299 std::pair<int, int>(childCrashFd, childCrashRemapFd));
1300 // "true" == crash reporting enabled
1301 mChildArgv.push_back("true");
1302 } else {
1303 // "false" == crash reporting disabled
1304 mChildArgv.push_back("false");
1306 # endif
1309 # ifdef MOZ_WIDGET_COCOA
1311 auto* thisMac = static_cast<MacProcessLauncher*>(this);
1312 kern_return_t kr =
1313 bootstrap_check_in(bootstrap_port, thisMac->mMachConnectionName.c_str(),
1314 getter_Transfers(thisMac->mParentRecvPort));
1315 if (kr != KERN_SUCCESS) {
1316 CHROMIUM_LOG(ERROR) << "parent bootstrap_check_in failed: "
1317 << mach_error_string(kr);
1318 return Err(LaunchError("bootstrap_check_in", kr));
1320 mChildArgv.push_back(thisMac->mMachConnectionName.c_str());
1322 # endif // MOZ_WIDGET_COCOA
1324 mChildArgv.push_back(ChildProcessType());
1325 return Ok();
1327 #endif // XP_UNIX
1329 #if defined(MOZ_WIDGET_ANDROID)
1330 RefPtr<ProcessHandlePromise> AndroidProcessLauncher::DoLaunch() {
1331 return LaunchAndroidService(mProcessType, mChildArgv,
1332 mLaunchOptions->fds_to_remap);
1334 #endif // MOZ_WIDGET_ANDROID
1336 #ifdef XP_UNIX
1337 RefPtr<ProcessHandlePromise> PosixProcessLauncher::DoLaunch() {
1338 ProcessHandle handle = 0;
1339 Result<Ok, LaunchError> aError =
1340 base::LaunchApp(mChildArgv, std::move(*mLaunchOptions), &handle);
1341 if (aError.isErr()) {
1342 return ProcessHandlePromise::CreateAndReject(aError.unwrapErr(), __func__);
1344 return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1346 #endif // XP_UNIX
1348 #ifdef XP_MACOSX
1349 Result<Ok, LaunchError> MacProcessLauncher::DoFinishLaunch() {
1350 Result<Ok, LaunchError> aError = PosixProcessLauncher::DoFinishLaunch();
1351 if (aError.isErr()) {
1352 return aError;
1355 MOZ_ASSERT(mParentRecvPort, "should have been configured during DoSetup()");
1357 // Wait for the child process to send us its 'task_t' data.
1358 const int kTimeoutMs = 10000;
1360 mozilla::UniqueMachSendRight child_task;
1361 audit_token_t audit_token{};
1362 kern_return_t kr = MachReceivePortSendRight(
1363 mParentRecvPort, mozilla::Some(kTimeoutMs), &child_task, &audit_token);
1364 if (kr != KERN_SUCCESS) {
1365 std::string errString = StringPrintf("0x%x %s", kr, mach_error_string(kr));
1366 CHROMIUM_LOG(ERROR) << "parent MachReceivePortSendRight failed: "
1367 << errString;
1368 return Err(LaunchError("MachReceivePortSendRight", kr));
1371 // Ensure the message was sent by the newly spawned child process.
1372 if (audit_token_to_pid(audit_token) != base::GetProcId(mResults.mHandle)) {
1373 CHROMIUM_LOG(ERROR) << "task_t was not sent by child process";
1374 return Err(LaunchError("audit_token_to_pid"));
1377 // Ensure the task_t corresponds to the newly spawned child process.
1378 pid_t task_pid = -1;
1379 kr = pid_for_task(child_task.get(), &task_pid);
1380 if (kr != KERN_SUCCESS) {
1381 CHROMIUM_LOG(ERROR) << "pid_for_task failed: " << mach_error_string(kr);
1382 return Err(LaunchError("pid_for_task", kr));
1384 if (task_pid != base::GetProcId(mResults.mHandle)) {
1385 CHROMIUM_LOG(ERROR) << "task_t is not for child process";
1386 return Err(LaunchError("task_pid"));
1389 mResults.mChildTask = child_task.release();
1391 return Ok();
1393 #endif // XP_MACOSX
1395 #ifdef XP_WIN
1396 void WindowsProcessLauncher::AddApplicationPrefetchArgument() {
1397 // The Application Launch Prefetcher (ALPF) is an ill-documented Windows
1398 // subsystem that's intended to speed up process launching, apparently mostly
1399 // by assuming that a binary is going to want to load the same DLLs as it did
1400 // the last time it launched, and getting those prepped for loading as well.
1402 // For most applications, that's a good bet. For Firefox, it's less so, since
1403 // we use the same binary with different arguments to do completely different
1404 // things. Windows does allow applications to take up multiple slots in this
1405 // cache, but the "which bucket does this invocation go in?" mechanism is
1406 // highly unusual: the OS scans the command line and looks for a command-line
1407 // switch of a particular form.
1409 // (There is allegedly a way to do this without involving the command line,
1410 // OVERRIDE_PREFETCH_PARAMETER, but it's even more poorly documented.)
1412 // Applications' different prefetch-cache buckets are named with numbers from
1413 // "1" to some OS-version-determined limit, with an additional implicit "0"
1414 // cache bucket which is used when no valid prefetch cache slot is named.
1416 // (The "0" bucket's existence and behavior is not documented, but has been
1417 // confirmed by observing the creation and enumeration of cache files in the
1418 // C:\Windows\Prefetch folder.)
1419 static size_t const kMaxSlotNo = IsWin1122H2OrLater() ? 16 : 8;
1421 // Determine the prefetch-slot number to be used for the process we're about
1422 // to launch.
1424 // This may be changed freely between Firefox versions, as a Firefox update
1425 // will completely invalidate the prefetch cache anyway.
1426 size_t const prefetchSlot = [&]() -> size_t {
1427 switch (mProcessType) {
1428 // This code path is not used when starting the main process...
1429 case GeckoProcessType_Default:
1430 // ...ForkServer is not used on Windows...
1431 case GeckoProcessType_ForkServer:
1432 // ..."End" isn't a process-type, just a limit...
1433 case GeckoProcessType_End:
1434 // ...and any new process-types should be considered explicitly here.
1435 default:
1436 MOZ_ASSERT_UNREACHABLE("Invalid process type");
1437 return 0;
1439 // These are started so rarely that we're not concerned about their
1440 // interaction with the prefetch cache.
1441 case GeckoProcessType_IPDLUnitTest:
1442 case GeckoProcessType_VR:
1443 return 0;
1445 // We reserve 1 for the main process as started by the launcher process.
1446 // (See LauncherProcessWin.cpp.) Otherwise, we mostly match the process-
1447 // type enumeration.
1448 case GeckoProcessType_Content:
1449 return 2;
1450 case GeckoProcessType_Socket:
1451 return 3; // usurps IPDLUnitTest
1452 case GeckoProcessType_GMPlugin:
1453 return 4;
1454 case GeckoProcessType_GPU:
1455 return 5;
1456 case GeckoProcessType_RemoteSandboxBroker:
1457 return 6; // usurps VR
1458 case GeckoProcessType_RDD:
1459 return 7;
1461 case GeckoProcessType_Utility:
1462 // Continue the enumeration, using the SandboxingKind as a
1463 // probably-passably-precise proxy for the process's purpose.
1465 // (On Win10 and earlier this will lump all utility processes
1466 // into slot 8.)
1467 return std::min(kMaxSlotNo, 8 + static_cast<size_t>(mSandbox));
1469 }();
1470 MOZ_ASSERT(prefetchSlot <= kMaxSlotNo);
1472 if (prefetchSlot == 0) {
1473 // default; no explicit argument needed
1474 return;
1477 std::wstring arg(L"/prefetch:");
1479 wchar_t buf[3];
1480 if (0 != _ultow_s(prefetchSlot, buf, 10)) {
1481 MOZ_ASSERT(false);
1482 return;
1484 arg.append(buf);
1486 mCmdLine->AppendLooseValue(arg);
1489 Result<Ok, LaunchError> WindowsProcessLauncher::DoSetup() {
1490 Result<Ok, LaunchError> aError = BaseProcessLauncher::DoSetup();
1491 if (aError.isErr()) {
1492 return aError;
1495 FilePath exePath;
1496 BinPathType pathType = GetPathToBinary(exePath, mProcessType);
1498 # if defined(MOZ_SANDBOX) || defined(_ARM64_)
1499 const bool isGMP = mProcessType == GeckoProcessType_GMPlugin;
1500 const bool isWidevine = isGMP && Contains(mExtraOpts, "gmp-widevinecdm");
1501 # if defined(_ARM64_)
1502 bool useRemoteSandboxBroker = false;
1503 if (mLaunchArch & (base::PROCESS_ARCH_I386 | base::PROCESS_ARCH_X86_64)) {
1504 // On Windows on ARM64 for ClearKey and Widevine, and for the sandbox
1505 // launcher process, we want to run the x86 plugin-container.exe in
1506 // the "i686" subdirectory, instead of the aarch64 plugin-container.exe.
1507 // So insert "i686" into the exePath.
1508 exePath = exePath.DirName().AppendASCII("i686").Append(exePath.BaseName());
1509 useRemoteSandboxBroker =
1510 mProcessType != GeckoProcessType_RemoteSandboxBroker;
1512 # endif // if defined(_ARM64_)
1513 # endif // defined(MOZ_SANDBOX) || defined(_ARM64_)
1515 mCmdLine.emplace(exePath.ToWStringHack());
1517 if (pathType == BinPathType::Self) {
1518 mCmdLine->AppendLooseValue(UTF8ToWide("-contentproc"));
1521 # ifdef HAS_DLL_BLOCKLIST
1522 if (IsDynamicBlocklistDisabled(
1523 gSafeMode,
1524 CommandLine::ForCurrentProcess()->HasSwitch(UTF8ToWide(
1525 mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch)))) {
1526 mCmdLine->AppendLooseValue(
1527 UTF8ToWide(mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch));
1529 # endif // HAS_DLL_BLOCKLIST
1531 // Inherit the initial client channel handle into the child process.
1532 std::wstring processChannelID =
1533 std::to_wstring(uint32_t(uintptr_t(mClientChannelHandle.get())));
1534 mLaunchOptions->handles_to_inherit.push_back(mClientChannelHandle.get());
1535 mCmdLine->AppendSwitchWithValue(switches::kProcessChannelID,
1536 processChannelID);
1538 for (std::vector<std::string>::iterator it = mExtraOpts.begin();
1539 it != mExtraOpts.end(); ++it) {
1540 mCmdLine->AppendLooseValue(UTF8ToWide(*it));
1543 # if defined(MOZ_SANDBOX)
1544 # if defined(_ARM64_)
1545 if (useRemoteSandboxBroker)
1546 mResults.mSandboxBroker = new RemoteSandboxBroker(mLaunchArch);
1547 else
1548 # endif // if defined(_ARM64_)
1549 mResults.mSandboxBroker = new SandboxBroker();
1551 // XXX: Bug 1124167: We should get rid of the process specific logic for
1552 // sandboxing in this class at some point. Unfortunately it will take a bit
1553 // of reorganizing so I don't think this patch is the right time.
1554 switch (mProcessType) {
1555 case GeckoProcessType_Content:
1556 if (mSandboxLevel > 0) {
1557 // For now we treat every failure as fatal in
1558 // SetSecurityLevelForContentProcess and just crash there right away.
1559 // Should this change in the future then we should also handle the error
1560 // here.
1561 mResults.mSandboxBroker->SetSecurityLevelForContentProcess(
1562 mSandboxLevel, mIsFileContent);
1563 mUseSandbox = true;
1565 break;
1566 case GeckoProcessType_IPDLUnitTest:
1567 // XXX: We don't sandbox this process type yet
1568 break;
1569 case GeckoProcessType_GMPlugin:
1570 if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
1571 // The Widevine CDM on Windows can only load at USER_RESTRICTED,
1572 // not at USER_LOCKDOWN. So look in the command line arguments
1573 // to see if we're loading the path to the Widevine CDM, and if
1574 // so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN.
1575 auto level =
1576 isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown;
1577 if (NS_WARN_IF(
1578 !mResults.mSandboxBroker->SetSecurityLevelForGMPlugin(level))) {
1579 return Err(LaunchError("SetSecurityLevelForGMPlugin"));
1581 mUseSandbox = true;
1583 break;
1584 case GeckoProcessType_GPU:
1585 if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) {
1586 // For now we treat every failure as fatal in
1587 // SetSecurityLevelForGPUProcess and just crash there right away. Should
1588 // this change in the future then we should also handle the error here.
1589 mResults.mSandboxBroker->SetSecurityLevelForGPUProcess(mSandboxLevel);
1590 mUseSandbox = true;
1592 break;
1593 case GeckoProcessType_VR:
1594 if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) {
1595 // TODO: Implement sandbox for VR process, Bug 1430043.
1597 break;
1598 case GeckoProcessType_RDD:
1599 if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
1600 if (NS_WARN_IF(
1601 !mResults.mSandboxBroker->SetSecurityLevelForRDDProcess())) {
1602 return Err(LaunchError("SetSecurityLevelForRDDProcess"));
1604 mUseSandbox = true;
1606 break;
1607 case GeckoProcessType_Socket:
1608 if (!PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS_SANDBOX")) {
1609 if (NS_WARN_IF(
1610 !mResults.mSandboxBroker->SetSecurityLevelForSocketProcess())) {
1611 return Err(LaunchError("SetSecurityLevelForSocketProcess"));
1613 mUseSandbox = true;
1615 break;
1616 case GeckoProcessType_Utility:
1617 if (IsUtilitySandboxEnabled(mSandbox)) {
1618 if (!mResults.mSandboxBroker->SetSecurityLevelForUtilityProcess(
1619 mSandbox)) {
1620 return Err(LaunchError("SetSecurityLevelForUtilityProcess"));
1622 mUseSandbox = true;
1624 break;
1625 case GeckoProcessType_RemoteSandboxBroker:
1626 // We don't sandbox the sandbox launcher...
1627 break;
1628 case GeckoProcessType_Default:
1629 default:
1630 MOZ_CRASH("Bad process type in GeckoChildProcessHost");
1631 break;
1634 if (mUseSandbox) {
1635 for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end();
1636 ++it) {
1637 mResults.mSandboxBroker->AllowReadFile(it->c_str());
1640 if (mResults.mSandboxBroker->IsWin32kLockedDown()) {
1641 mCmdLine->AppendLooseValue(
1642 UTF8ToWide(geckoargs::sWin32kLockedDown.Name()));
1645 # endif // defined(MOZ_SANDBOX)
1647 // Add the application directory path (-appdir path)
1648 AddAppDirToCommandLine(mCmdLine.ref(), mAppDir);
1650 // XXX Command line params past this point are expected to be at
1651 // the end of the command line string, and in a specific order.
1652 // See XRE_InitChildProcess in nsEmbedFunction.
1654 // Win app model id
1655 mCmdLine->AppendLooseValue(mGroupId.get());
1657 // Initial MessageChannel id
1658 mCmdLine->AppendLooseValue(UTF8ToWide(mInitialChannelIdString));
1660 // Process id
1661 mCmdLine->AppendLooseValue(UTF8ToWide(mPidString));
1663 mCmdLine->AppendLooseValue(
1664 UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
1666 // Process type
1667 mCmdLine->AppendLooseValue(UTF8ToWide(ChildProcessType()));
1669 // Prefetch cache hint
1670 AddApplicationPrefetchArgument();
1672 # ifdef MOZ_SANDBOX
1673 if (mUseSandbox) {
1674 // Mark the handles to inherit as inheritable.
1675 for (HANDLE h : mLaunchOptions->handles_to_inherit) {
1676 mResults.mSandboxBroker->AddHandleToShare(h);
1679 # endif // MOZ_SANDBOX
1681 return Ok();
1684 RefPtr<ProcessHandlePromise> WindowsProcessLauncher::DoLaunch() {
1685 ProcessHandle handle = 0;
1686 # ifdef MOZ_SANDBOX
1687 if (mUseSandbox) {
1688 const IMAGE_THUNK_DATA* cachedNtdllThunk =
1689 mCachedNtdllThunk ? mCachedNtdllThunk->begin() : nullptr;
1690 Result<Ok, LaunchError> err = mResults.mSandboxBroker->LaunchApp(
1691 mCmdLine->program().c_str(), mCmdLine->command_line_string().c_str(),
1692 mLaunchOptions->env_map, mProcessType, mEnableSandboxLogging,
1693 cachedNtdllThunk, &handle);
1694 if (err.isOk()) {
1695 EnvironmentLog("MOZ_PROCESS_LOG")
1696 .print("==> process %d launched child process %d (%S)\n",
1697 base::GetCurrentProcId(), base::GetProcId(handle),
1698 mCmdLine->command_line_string().c_str());
1699 return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1701 return ProcessHandlePromise::CreateAndReject(err.unwrapErr(), __func__);
1703 # endif // defined(MOZ_SANDBOX)
1705 Result<Ok, LaunchError> launchErr =
1706 base::LaunchApp(mCmdLine.ref(), *mLaunchOptions, &handle);
1707 if (launchErr.isErr()) {
1708 return ProcessHandlePromise::CreateAndReject(launchErr.unwrapErr(),
1709 __func__);
1711 return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1714 Result<Ok, LaunchError> WindowsProcessLauncher::DoFinishLaunch() {
1715 Result<Ok, LaunchError> err = BaseProcessLauncher::DoFinishLaunch();
1716 if (err.isErr()) {
1717 return err;
1720 return Ok();
1722 #endif // XP_WIN
1724 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::FinishLaunch() {
1725 Result<Ok, LaunchError> aError = DoFinishLaunch();
1726 if (aError.isErr()) {
1727 return ProcessLaunchPromise::CreateAndReject(aError.unwrapErr(), __func__);
1730 MOZ_DIAGNOSTIC_ASSERT(mResults.mHandle);
1732 Telemetry::AccumulateTimeDelta(Telemetry::CHILD_PROCESS_LAUNCH_MS,
1733 mStartTimeStamp);
1735 return ProcessLaunchPromise::CreateAndResolve(mResults, __func__);
1738 bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid) {
1739 if (mChildProcessHandle) {
1740 MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
1741 return true;
1744 return base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle);
1747 void GeckoChildProcessHost::OnChannelConnected(base::ProcessId peer_pid) {
1749 mozilla::AutoWriteLock hLock(mHandleLock);
1750 if (!OpenPrivilegedHandle(peer_pid)) {
1751 MOZ_CRASH("can't open handle to child process");
1754 MonitorAutoLock lock(mMonitor);
1755 mProcessState = PROCESS_CONNECTED;
1756 lock.Notify();
1759 RefPtr<ProcessHandlePromise> GeckoChildProcessHost::WhenProcessHandleReady() {
1760 MOZ_ASSERT(mHandlePromise != nullptr);
1761 return mHandlePromise;
1764 #ifdef MOZ_WIDGET_ANDROID
1765 RefPtr<ProcessHandlePromise> AndroidProcessLauncher::LaunchAndroidService(
1766 const GeckoProcessType aType, const std::vector<std::string>& argv,
1767 const base::file_handle_mapping_vector& fds_to_remap) {
1768 MOZ_RELEASE_ASSERT((2 <= fds_to_remap.size()) && (fds_to_remap.size() <= 5));
1769 JNIEnv* const env = mozilla::jni::GetEnvForThread();
1770 MOZ_ASSERT(env);
1772 const int argvSize = argv.size();
1773 jni::ObjectArray::LocalRef jargs =
1774 jni::ObjectArray::New<jni::String>(argvSize);
1775 for (int ix = 0; ix < argvSize; ix++) {
1776 jargs->SetElement(ix, jni::StringParam(argv[ix].c_str(), env));
1779 // XXX: this processing depends entirely on the internals of
1780 // ContentParent::LaunchSubprocess()
1781 // GeckoChildProcessHost::PerformAsyncLaunch(), and the order in
1782 // which they append to fds_to_remap. There must be a better way to do it.
1783 // See bug 1440207.
1784 int32_t prefsFd = fds_to_remap[0].first;
1785 int32_t prefMapFd = fds_to_remap[1].first;
1786 int32_t ipcFd = fds_to_remap[2].first;
1787 int32_t crashFd = -1;
1788 if (fds_to_remap.size() == 4) {
1789 crashFd = fds_to_remap[3].first;
1792 auto type = java::GeckoProcessType::FromInt(aType);
1793 auto genericResult = java::GeckoProcessManager::Start(
1794 type, jargs, prefsFd, prefMapFd, ipcFd, crashFd);
1795 auto typedResult = java::GeckoResult::LocalRef(std::move(genericResult));
1796 return ProcessHandlePromise::FromGeckoResult(typedResult);
1798 #endif
1800 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1801 bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector& aArgs) {
1802 MacSandboxInfo info;
1803 if (NS_WARN_IF(!FillMacSandboxInfo(info))) {
1804 return false;
1806 info.AppendAsParams(aArgs);
1807 return true;
1810 // Fill |aInfo| with the flags needed to launch the utility sandbox
1811 bool GeckoChildProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
1812 aInfo.type = GetDefaultMacSandboxType();
1813 aInfo.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled") ||
1814 PR_GetEnv("MOZ_SANDBOX_LOGGING");
1816 nsAutoCString appPath;
1817 if (!nsMacUtilsImpl::GetAppPath(appPath)) {
1818 MOZ_CRASH("Failed to get app path");
1820 aInfo.appPath.assign(appPath.get());
1821 return true;
1824 void GeckoChildProcessHost::DisableOSActivityMode() {
1825 mDisableOSActivityMode = true;
1829 // If early sandbox startup is enabled for this process type, map the
1830 // process type to the sandbox type and enable the sandbox. Returns true
1831 // if no errors were encountered or if early sandbox startup is not
1832 // enabled for this process. Returns false if an error was encountered.
1834 /* static */
1835 bool GeckoChildProcessHost::StartMacSandbox(int aArgc, char** aArgv,
1836 std::string& aErrorMessage) {
1837 MacSandboxType sandboxType = MacSandboxType_Invalid;
1838 switch (XRE_GetProcessType()) {
1839 // For now, only support early sandbox startup for content,
1840 // RDD, and GMP processes. Add case statements for the additional
1841 // process types once early sandbox startup is implemented for them.
1842 case GeckoProcessType_Content:
1843 // Content processes don't use GeckoChildProcessHost
1844 // to configure sandboxing so hard code the sandbox type.
1845 sandboxType = MacSandboxType_Content;
1846 break;
1847 case GeckoProcessType_RDD:
1848 sandboxType = RDDProcessHost::GetMacSandboxType();
1849 break;
1850 case GeckoProcessType_Socket:
1851 sandboxType = net::SocketProcessHost::GetMacSandboxType();
1852 break;
1853 case GeckoProcessType_GMPlugin:
1854 sandboxType = gmp::GMPProcessParent::GetMacSandboxType();
1855 break;
1856 case GeckoProcessType_Utility:
1857 sandboxType = ipc::UtilityProcessHost::GetMacSandboxType();
1858 break;
1859 default:
1860 return true;
1863 return mozilla::StartMacSandboxIfEnabled(sandboxType, aArgc, aArgv,
1864 aErrorMessage);
1867 #endif /* XP_MACOSX && MOZ_SANDBOX */
1869 /* static */
1870 void GeckoChildProcessHost::GetAll(const GeckoProcessCallback& aCallback) {
1871 StaticMutexAutoLock lock(sMutex);
1872 if (!sGeckoChildProcessHosts) {
1873 return;
1875 for (GeckoChildProcessHost* gp = sGeckoChildProcessHosts->getFirst(); gp;
1876 gp = static_cast<mozilla::LinkedListElement<GeckoChildProcessHost>*>(gp)
1877 ->getNext()) {
1878 aCallback(gp);
1882 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::Launch(
1883 GeckoChildProcessHost* aHost) {
1884 AssertIOThread();
1886 // The ForkServer doesn't use IPC::Channel for communication, so we can skip
1887 // initializing it.
1888 if (mProcessType != GeckoProcessType_ForkServer) {
1889 IPC::Channel::ChannelHandle serverHandle;
1890 if (!IPC::Channel::CreateRawPipe(&serverHandle, &mClientChannelHandle)) {
1891 return ProcessLaunchPromise::CreateAndReject(LaunchError("CreateRawPipe"),
1892 __func__);
1894 aHost->InitializeChannel(std::move(serverHandle));
1897 return InvokeAsync(mLaunchThread, this, __func__,
1898 &BaseProcessLauncher::PerformAsyncLaunch);
1901 } // namespace ipc
1902 } // namespace mozilla