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"
17 # include <mach/mach_traps.h>
18 # include "SharedMemoryBasic.h"
19 # include "base/rand_util.h"
20 # include "chrome/common/mach_ipc_mac.h"
21 # include "mozilla/StaticPrefs_media.h"
23 #ifdef MOZ_WIDGET_COCOA
24 # include <bsm/libbsm.h>
25 # include <servers/bootstrap.h>
26 # include "nsILocalFileMac.h"
29 #include "GeckoProfiler.h"
30 #include "MainThreadUtils.h"
31 #include "mozilla/Preferences.h"
32 #include "mozilla/Sprintf.h"
33 #include "nsXPCOMPrivate.h"
37 #if defined(MOZ_SANDBOX)
38 # include "mozilla/SandboxSettings.h"
39 # include "nsAppDirectoryServiceDefs.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/Telemetry.h"
56 #include "mozilla/UniquePtrExtensions.h"
57 #include "mozilla/ipc/BrowserProcessSubThread.h"
58 #include "mozilla/ipc/EnvironmentMap.h"
59 #include "mozilla/ipc/NodeController.h"
60 #include "mozilla/net/SocketProcessHost.h"
61 #include "nsDirectoryService.h"
62 #include "nsDirectoryServiceDefs.h"
63 #include "nsExceptionHandler.h"
65 #include "nsIObserverService.h"
66 #include "nsPrintfCString.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"
79 # include "mozilla/remoteSandboxBroker.h"
83 # include "mozilla/NativeNt.h"
84 # include "mozilla/CacheNtDllThunk.h"
87 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
88 # include "mozilla/SandboxLaunch.h"
91 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
92 # include "GMPProcessParent.h"
93 # include "nsMacUtilsImpl.h"
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"
119 #ifdef MOZ_ENABLE_FORKSERVER
120 # include "mozilla/ipc/ForkServiceChild.h"
123 static bool ShouldHaveDirectoryService() {
124 return GeckoProcessType_Default
== XRE_GetProcessType();
130 struct LaunchResults
{
131 base::ProcessHandle mHandle
= 0;
133 task_t mChildTask
= MACH_PORT_NULL
;
136 Maybe
<ExtensionKitProcess
> mExtensionKitProcess
;
137 DarwinObjectPtr
<xpc_connection_t
> mXPCConnection
;
138 UniqueBEProcessCapabilityGrant mForegroundCapabilityGrant
;
140 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
141 RefPtr
<AbstractSandboxBroker
> mSandboxBroker
;
144 typedef mozilla::MozPromise
<LaunchResults
, LaunchError
, true>
145 ProcessLaunchPromise
;
147 static Atomic
<int32_t> gChildCounter
;
149 static inline nsISerialEventTarget
* IOThread() {
150 return XRE_GetIOMessageLoop()->SerialEventTarget();
153 class BaseProcessLauncher
{
155 BaseProcessLauncher(GeckoChildProcessHost
* aHost
,
156 std::vector
<std::string
>&& aExtraOpts
)
157 : mProcessType(aHost
->mProcessType
),
158 mLaunchOptions(std::move(aHost
->mLaunchOptions
)),
159 mExtraOpts(std::move(aExtraOpts
)),
161 mGroupId(aHost
->mGroupId
),
163 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
164 mAllowedFilesRead(aHost
->mAllowedFilesRead
),
165 mSandboxLevel(aHost
->mSandboxLevel
),
166 mSandbox(aHost
->mSandbox
),
167 mIsFileContent(aHost
->mIsFileContent
),
168 mEnableSandboxLogging(aHost
->mEnableSandboxLogging
),
170 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
171 mDisableOSActivityMode(aHost
->mDisableOSActivityMode
),
173 mTmpDirName(aHost
->mTmpDirName
),
174 mChildId(++gChildCounter
) {
175 SprintfLiteral(mPidString
, "%" PRIPID
, base::GetCurrentProcId());
176 aHost
->mInitialChannelId
.ToProvidedString(mInitialChannelIdString
);
178 // Compute the serial event target we'll use for launching.
179 nsCOMPtr
<nsIEventTarget
> threadOrPool
= GetIPCLauncher();
181 TaskQueue::Create(threadOrPool
.forget(), "BaseProcessLauncher");
183 if (ShouldHaveDirectoryService()) {
184 // "Current process directory" means the app dir, not the current
185 // working dir or similar.
187 << nsDirectoryService::gService
->GetCurrentProcessDirectory(
188 getter_AddRefs(mAppDir
));
192 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BaseProcessLauncher
);
194 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
195 void SetLaunchArchitecture(uint32_t aLaunchArch
) {
196 mLaunchArch
= aLaunchArch
;
200 RefPtr
<ProcessLaunchPromise
> Launch(GeckoChildProcessHost
*);
203 virtual ~BaseProcessLauncher() = default;
205 RefPtr
<ProcessLaunchPromise
> PerformAsyncLaunch();
206 RefPtr
<ProcessLaunchPromise
> FinishLaunch();
208 // Overrideable hooks. If superclass behavior is invoked, it's always at the
209 // top of the override.
210 virtual Result
<Ok
, LaunchError
> DoSetup();
211 virtual RefPtr
<ProcessHandlePromise
> DoLaunch() = 0;
212 virtual Result
<Ok
, LaunchError
> DoFinishLaunch();
214 void MapChildLogging();
216 static BinPathType
GetPathToBinary(FilePath
&, GeckoProcessType
);
218 void GetChildLogName(const char* origLogName
, nsACString
& buffer
);
220 const char* ChildProcessType() {
221 return XRE_GeckoProcessTypeToString(mProcessType
);
224 nsCOMPtr
<nsISerialEventTarget
> mLaunchThread
;
225 GeckoProcessType mProcessType
;
226 UniquePtr
<base::LaunchOptions
> mLaunchOptions
;
227 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
228 uint32_t mLaunchArch
= base::PROCESS_ARCH_INVALID
;
230 std::vector
<std::string
> mExtraOpts
;
234 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
235 std::vector
<std::wstring
> mAllowedFilesRead
;
236 int32_t mSandboxLevel
;
237 SandboxingKind mSandbox
;
239 bool mEnableSandboxLogging
;
241 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
242 // Controls whether or not the process will be launched with
243 // environment variable OS_ACTIVITY_MODE set to "disabled".
244 bool mDisableOSActivityMode
;
246 nsCString mTmpDirName
;
247 LaunchResults mResults
= LaunchResults();
249 TimeStamp mStartTimeStamp
= TimeStamp::Now();
251 char mInitialChannelIdString
[NSID_LENGTH
];
253 // Set during launch.
254 IPC::Channel::ChannelHandle mClientChannelHandle
;
255 nsCOMPtr
<nsIFile
> mAppDir
;
259 class WindowsProcessLauncher
: public BaseProcessLauncher
{
261 WindowsProcessLauncher(GeckoChildProcessHost
* aHost
,
262 std::vector
<std::string
>&& aExtraOpts
)
263 : BaseProcessLauncher(aHost
, std::move(aExtraOpts
)),
264 mCachedNtdllThunk(GetCachedNtDllThunk()) {}
267 virtual Result
<Ok
, LaunchError
> DoSetup() override
;
268 virtual RefPtr
<ProcessHandlePromise
> DoLaunch() override
;
269 virtual Result
<Ok
, LaunchError
> DoFinishLaunch() override
;
271 mozilla::Maybe
<CommandLine
> mCmdLine
;
273 bool mUseSandbox
= false;
276 const Buffer
<IMAGE_THUNK_DATA
>* mCachedNtdllThunk
;
278 typedef WindowsProcessLauncher ProcessLauncher
;
282 class PosixProcessLauncher
: public BaseProcessLauncher
{
284 PosixProcessLauncher(GeckoChildProcessHost
* aHost
,
285 std::vector
<std::string
>&& aExtraOpts
)
286 : BaseProcessLauncher(aHost
, std::move(aExtraOpts
)),
287 mProfileDir(aHost
->mProfileDir
),
288 mChannelDstFd(IPC::Channel::GetClientChannelHandle()) {}
291 virtual Result
<Ok
, LaunchError
> DoSetup() override
;
292 virtual RefPtr
<ProcessHandlePromise
> DoLaunch() override
;
294 nsCOMPtr
<nsIFile
> mProfileDir
;
296 std::vector
<std::string
> mChildArgv
;
300 # if defined(XP_MACOSX)
301 class MacProcessLauncher
: public PosixProcessLauncher
{
303 MacProcessLauncher(GeckoChildProcessHost
* aHost
,
304 std::vector
<std::string
>&& aExtraOpts
)
305 : PosixProcessLauncher(aHost
, std::move(aExtraOpts
)),
306 // Put a random number into the channel name, so that
307 // a compromised renderer can't pretend being the child
308 // that's forked off.
310 StringPrintf("org.mozilla.machname.%d",
311 base::RandInt(0, std::numeric_limits
<int>::max()))) {
312 MOZ_ASSERT(mMachConnectionName
.size() < BOOTSTRAP_MAX_NAME_LEN
);
316 virtual Result
<Ok
, LaunchError
> DoFinishLaunch() override
;
318 std::string mMachConnectionName
;
319 // We add a mach port to the command line so the child can communicate its
320 // 'task_t' back to the parent.
321 mozilla::UniqueMachReceiveRight mParentRecvPort
;
323 friend class PosixProcessLauncher
;
325 typedef MacProcessLauncher ProcessLauncher
;
326 # elif defined(MOZ_WIDGET_ANDROID)
327 class AndroidProcessLauncher
: public PosixProcessLauncher
{
329 AndroidProcessLauncher(GeckoChildProcessHost
* aHost
,
330 std::vector
<std::string
>&& aExtraOpts
)
331 : PosixProcessLauncher(aHost
, std::move(aExtraOpts
)) {}
334 virtual RefPtr
<ProcessHandlePromise
> DoLaunch() override
;
335 RefPtr
<ProcessHandlePromise
> LaunchAndroidService(
336 const GeckoProcessType aType
, const std::vector
<std::string
>& argv
,
337 const base::file_handle_mapping_vector
& fds_to_remap
);
339 typedef AndroidProcessLauncher ProcessLauncher
;
340 // NB: Technically Android is linux (i.e. XP_LINUX is defined), but we want
341 // orthogonal IPC machinery there. Conversely, there are tier-3 non-Linux
342 // platforms (BSD and Solaris) where we want the "linux" IPC machinery. So
343 // we use MOZ_WIDGET_* to choose the platform backend.
344 # elif defined(MOZ_WIDGET_GTK)
345 class LinuxProcessLauncher
: public PosixProcessLauncher
{
347 LinuxProcessLauncher(GeckoChildProcessHost
* aHost
,
348 std::vector
<std::string
>&& aExtraOpts
)
349 : PosixProcessLauncher(aHost
, std::move(aExtraOpts
)) {}
352 virtual Result
<Ok
, LaunchError
> DoSetup() override
;
354 typedef LinuxProcessLauncher ProcessLauncher
;
355 # elif defined(MOZ_WIDGET_UIKIT)
356 class IosProcessLauncher
: public PosixProcessLauncher
{
358 IosProcessLauncher(GeckoChildProcessHost
* aHost
,
359 std::vector
<std::string
>&& aExtraOpts
)
360 : PosixProcessLauncher(aHost
, std::move(aExtraOpts
)) {}
363 virtual RefPtr
<ProcessHandlePromise
> DoLaunch() override
;
365 DarwinObjectPtr
<xpc_object_t
> mBootstrapMessage
;
367 typedef IosProcessLauncher ProcessLauncher
;
369 # error "Unknown platform"
373 using base::ProcessHandle
;
374 using mozilla::ipc::BaseProcessLauncher
;
375 using mozilla::ipc::ProcessLauncher
;
377 mozilla::StaticAutoPtr
<mozilla::LinkedList
<GeckoChildProcessHost
>>
378 GeckoChildProcessHost::sGeckoChildProcessHosts
;
380 mozilla::StaticMutex
GeckoChildProcessHost::sMutex
;
382 GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType
,
384 : mProcessType(aProcessType
),
385 mIsFileContent(aIsFileContent
),
386 mMonitor("mozilla.ipc.GeckoChildProcessHost.mMonitor"),
387 mLaunchOptions(MakeUnique
<base::LaunchOptions
>()),
388 mInitialChannelId(nsID::GenerateUUID()),
389 mProcessState(CREATING_CHANNEL
),
393 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
394 mEnableSandboxLogging(false),
397 mHandleLock("mozilla.ipc.GeckoChildProcessHost.mHandleLock"),
398 mChildProcessHandle(0),
399 #if defined(XP_DARWIN)
400 mChildTask(MACH_PORT_NULL
),
402 #if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
403 mDisableOSActivityMode(false),
406 MOZ_COUNT_CTOR(GeckoChildProcessHost
);
407 StaticMutexAutoLock
lock(sMutex
);
408 if (!sGeckoChildProcessHosts
) {
409 sGeckoChildProcessHosts
= new mozilla::LinkedList
<GeckoChildProcessHost
>();
411 sGeckoChildProcessHosts
->insertBack(this);
412 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
413 if (aProcessType
== GeckoProcessType_Content
) {
414 # if defined(MOZ_CONTENT_TEMP_DIR)
415 // The content process needs the content temp dir:
416 nsCOMPtr
<nsIFile
> contentTempDir
;
417 nsresult rv
= NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR
,
418 getter_AddRefs(contentTempDir
));
419 if (NS_SUCCEEDED(rv
)) {
420 contentTempDir
->GetNativePath(mTmpDirName
);
423 } else if (aProcessType
== GeckoProcessType_RDD
) {
424 // The RDD process makes limited use of EGL. If Mesa's shader
425 // cache is enabled and the directory isn't explicitly set, then
426 // it will try to getpwuid() the user which can cause problems
427 // with sandboxing. Because we shouldn't need shader caching in
428 // this process, we just disable the cache to prevent that.
429 mLaunchOptions
->env_map
["MESA_GLSL_CACHE_DISABLE"] = "true";
430 mLaunchOptions
->env_map
["MESA_SHADER_CACHE_DISABLE"] = "true";
431 // In case the nvidia driver is also loaded:
432 mLaunchOptions
->env_map
["__GL_SHADER_DISK_CACHE"] = "0";
435 #if defined(MOZ_ENABLE_FORKSERVER)
436 if (aProcessType
!= GeckoProcessType_ForkServer
&& ForkServiceChild::Get()) {
437 mLaunchOptions
->use_forkserver
= true;
442 GeckoChildProcessHost::~GeckoChildProcessHost()
446 MOZ_RELEASE_ASSERT(mDestroying
);
448 MOZ_COUNT_DTOR(GeckoChildProcessHost
);
451 mozilla::AutoWriteLock
hLock(mHandleLock
);
452 #if defined(XP_DARWIN)
453 if (mChildTask
!= MACH_PORT_NULL
) {
454 mach_port_deallocate(mach_task_self(), mChildTask
);
458 if (mForegroundCapabilityGrant
) {
459 mForegroundCapabilityGrant
.reset();
461 if (mExtensionKitProcess
) {
462 mExtensionKitProcess
->Invalidate();
464 if (mXPCConnection
) {
465 xpc_connection_cancel(mXPCConnection
.get());
469 if (mChildProcessHandle
!= 0) {
470 ProcessWatcher::EnsureProcessTerminated(
472 #ifdef NS_FREE_PERMANENT_DATA
473 // If we're doing leak logging, shutdown can be slow.
475 false // don't "force"
478 mChildProcessHandle
= 0;
482 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
483 if (mSandboxBroker
) {
484 mSandboxBroker
->Shutdown();
485 mSandboxBroker
= nullptr;
490 base::ProcessHandle
GeckoChildProcessHost::GetChildProcessHandle() {
491 mozilla::AutoReadLock
handleLock(mHandleLock
);
492 return mChildProcessHandle
;
495 base::ProcessId
GeckoChildProcessHost::GetChildProcessId() {
496 mozilla::AutoReadLock
handleLock(mHandleLock
);
497 if (!mChildProcessHandle
) {
500 return base::GetProcId(mChildProcessHandle
);
504 task_t
GeckoChildProcessHost::GetChildTask() {
505 mozilla::AutoReadLock
handleLock(mHandleLock
);
510 void GeckoChildProcessHost::RemoveFromProcessList() {
511 StaticMutexAutoLock
lock(sMutex
);
512 if (!sGeckoChildProcessHosts
) {
515 LinkedListElement
<GeckoChildProcessHost
>::removeFrom(
516 *sGeckoChildProcessHosts
);
519 void GeckoChildProcessHost::Destroy() {
520 MOZ_RELEASE_ASSERT(!mDestroying
);
521 // We can remove from the list before it's really destroyed
522 RemoveFromProcessList();
523 RefPtr
<ProcessHandlePromise
> whenReady
= mHandlePromise
;
526 // AsyncLaunch not called yet, so dispatch immediately.
527 whenReady
= ProcessHandlePromise::CreateAndReject(
528 LaunchError("DestroyEarly"), __func__
);
531 using Value
= ProcessHandlePromise::ResolveOrRejectValue
;
533 whenReady
->Then(XRE_GetIOMessageLoop()->SerialEventTarget(), __func__
,
534 [this](const Value
&) { delete this; });
538 mozilla::BinPathType
BaseProcessLauncher::GetPathToBinary(
539 FilePath
& exePath
, GeckoProcessType processType
) {
540 BinPathType pathType
= XRE_GetChildProcBinPathType(processType
);
542 if (pathType
== BinPathType::Self
) {
544 wchar_t exePathBuf
[MAXPATHLEN
];
545 if (!::GetModuleFileNameW(nullptr, exePathBuf
, MAXPATHLEN
)) {
546 MOZ_CRASH("GetModuleFileNameW failed (FIXME)");
548 exePath
= FilePath::FromWStringHack(exePathBuf
);
550 exePath
= FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
555 #ifdef MOZ_WIDGET_COCOA
556 // The GMP child process runs via the Media Plugin Helper executable
557 // which is a clone of plugin-container allowing for GMP-specific
558 // codesigning entitlements.
559 nsCString bundleName
;
560 std::string executableLeafName
;
561 if (processType
== GeckoProcessType_GMPlugin
&&
562 mozilla::StaticPrefs::media_plugin_helper_process_enabled()) {
563 bundleName
= MOZ_EME_PROCESS_BUNDLENAME
;
564 executableLeafName
= MOZ_EME_PROCESS_NAME_BRANDED
;
566 bundleName
= MOZ_CHILD_PROCESS_BUNDLENAME
;
567 executableLeafName
= MOZ_CHILD_PROCESS_NAME
;
571 if (ShouldHaveDirectoryService()) {
572 MOZ_ASSERT(gGREBinPath
);
574 exePath
= FilePath(char16ptr_t(gGREBinPath
));
575 #elif MOZ_WIDGET_COCOA
576 nsCOMPtr
<nsIFile
> childProcPath
;
577 NS_NewLocalFile(nsDependentString(gGREBinPath
), false,
578 getter_AddRefs(childProcPath
));
580 // We need to use an App Bundle on OS X so that we can hide
581 // the dock icon. See Bug 557225.
582 childProcPath
->AppendNative(bundleName
);
583 childProcPath
->AppendNative("Contents"_ns
);
584 childProcPath
->AppendNative("MacOS"_ns
);
586 childProcPath
->GetNativePath(tempCPath
);
587 exePath
= FilePath(tempCPath
.get());
590 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath
), path
);
591 exePath
= FilePath(path
.get());
595 if (exePath
.empty()) {
598 FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
600 exePath
= FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
602 exePath
= exePath
.DirName();
605 #ifdef MOZ_WIDGET_COCOA
606 exePath
= exePath
.Append(executableLeafName
);
608 exePath
= exePath
.AppendASCII(MOZ_CHILD_PROCESS_NAME
);
614 #ifdef MOZ_WIDGET_COCOA
615 class AutoCFTypeObject
{
617 explicit AutoCFTypeObject(CFTypeRef object
) { mObject
= object
; }
618 ~AutoCFTypeObject() { ::CFRelease(mObject
); }
625 // We start the unique IDs at 1 so that 0 can be used to mean that
626 // a component has no unique ID assigned to it.
627 uint32_t GeckoChildProcessHost::sNextUniqueID
= 1;
630 uint32_t GeckoChildProcessHost::GetUniqueID() { return sNextUniqueID
++; }
633 void GeckoChildProcessHost::SetEnv(const char* aKey
, const char* aValue
) {
634 MOZ_ASSERT(mLaunchOptions
);
635 mLaunchOptions
->env_map
[ENVIRONMENT_STRING(aKey
)] =
636 ENVIRONMENT_STRING(aValue
);
639 void GeckoChildProcessHost::PrepareLaunch() {
640 if (CrashReporter::GetEnabled()) {
641 CrashReporter::OOPInit();
644 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
645 SandboxLaunch::Configure(mProcessType
, mSandbox
, mLaunchOptions
.get());
650 # if defined(MOZ_SANDBOX)
651 // We need to get the pref here as the process is launched off main thread.
652 if (mProcessType
== GeckoProcessType_Content
) {
653 // Win32k Lockdown state must be initialized on the main thread.
654 // This is our last chance to do it before it is read on the IPC Launch
656 GetWin32kLockdownState();
657 mSandboxLevel
= GetEffectiveContentSandboxLevel();
658 mEnableSandboxLogging
=
659 Preferences::GetBool("security.sandbox.logging.enabled");
661 // We currently have to whitelist certain paths for tests to work in some
662 // development configurations.
663 nsAutoString readPaths
;
664 nsresult rv
= Preferences::GetString(
665 "security.sandbox.content.read_path_whitelist", readPaths
);
666 if (NS_SUCCEEDED(rv
)) {
667 for (const nsAString
& readPath
: readPaths
.Split(',')) {
668 nsString
trimmedPath(readPath
);
669 trimmedPath
.Trim(" ", true, true);
670 std::wstring
resolvedPath(trimmedPath
.Data());
671 // Check if path ends with '\' as this indicates we want to give read
672 // access to a directory and so it needs a wildcard.
673 if (resolvedPath
.back() == L
'\\') {
674 resolvedPath
.append(L
"*");
676 mAllowedFilesRead
.push_back(resolvedPath
);
682 # if defined(MOZ_SANDBOX)
683 // For other process types we can't rely on them being launched on main
684 // thread and they may not have access to prefs in the child process, so allow
685 // them to turn on logging via an environment variable.
686 mEnableSandboxLogging
=
687 mEnableSandboxLogging
|| !!PR_GetEnv("MOZ_SANDBOX_LOGGING");
690 #elif defined(XP_MACOSX)
691 # if defined(MOZ_SANDBOX)
692 if (ShouldHaveDirectoryService() &&
693 mProcessType
!= GeckoProcessType_GMPlugin
) {
694 mozilla::Unused
<< NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
,
695 getter_AddRefs(mProfileDir
));
702 void GeckoChildProcessHost::InitWindowsGroupID() {
703 // On Win7+, pass the application user model to the child, so it can
704 // register with it. This insures windows created by the container
705 // properly group with the parent app on the Win7 taskbar.
706 nsCOMPtr
<nsIWinTaskbar
> taskbarInfo
= do_GetService(NS_TASKBAR_CONTRACTID
);
708 bool isSupported
= false;
709 taskbarInfo
->GetAvailable(&isSupported
);
711 if (isSupported
&& NS_SUCCEEDED(taskbarInfo
->GetDefaultGroupId(appId
))) {
712 MOZ_ASSERT(mGroupId
.EqualsLiteral("-"));
713 mGroupId
.Assign(appId
);
719 bool GeckoChildProcessHost::SyncLaunch(std::vector
<std::string
> aExtraOpts
,
721 if (!AsyncLaunch(std::move(aExtraOpts
))) {
724 return WaitUntilConnected(aTimeoutMs
);
727 // Note: for most process types, we currently call AsyncLaunch, and therefore
728 // the *ProcessLauncher constructor, on the main thread, while the
729 // ProcessLauncher methods to actually execute the launch are called on the IO
730 // or IPC launcher thread. GMP processes are an exception - the GMP code
731 // invokes GeckoChildProcessHost from non-main-threads, and therefore we cannot
732 // rely on having access to mainthread-only services (like the directory
733 // service) from this code if we're launching that type of process.
734 bool GeckoChildProcessHost::AsyncLaunch(std::vector
<std::string
> aExtraOpts
) {
737 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
738 if (IsMacSandboxLaunchEnabled() && !AppendMacSandboxParams(aExtraOpts
)) {
743 RefPtr
<BaseProcessLauncher
> launcher
=
744 new ProcessLauncher(this, std::move(aExtraOpts
));
745 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
746 launcher
->SetLaunchArchitecture(mLaunchArch
);
749 // Note: Destroy() waits on mHandlePromise to delete |this|. As such, we want
750 // to be sure that all of our post-launch processing on |this| happens before
751 // mHandlePromise notifies.
752 MOZ_ASSERT(mHandlePromise
== nullptr);
754 mozilla::InvokeAsync
<GeckoChildProcessHost
*>(
755 IOThread(), launcher
.get(), __func__
, &BaseProcessLauncher::Launch
,
758 IOThread(), __func__
,
759 [this](LaunchResults
&& aResults
) {
762 mozilla::AutoWriteLock
handleLock(mHandleLock
);
763 if (!OpenPrivilegedHandle(base::GetProcId(aResults
.mHandle
))
765 // If we failed in opening the process handle, try
766 // harder by duplicating one.
767 && !::DuplicateHandle(
768 ::GetCurrentProcess(), aResults
.mHandle
,
769 ::GetCurrentProcess(), &mChildProcessHandle
,
770 PROCESS_DUP_HANDLE
| PROCESS_TERMINATE
|
771 PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
|
776 MOZ_CRASH("cannot open handle to child process");
778 // The original handle is no longer needed; it must
779 // be closed to prevent a resource leak.
780 base::CloseProcessHandle(aResults
.mHandle
);
781 // FIXME (bug 1720523): define a cross-platform
782 // "safe" invalid value to use in places like this.
783 aResults
.mHandle
= 0;
786 this->mChildTask
= aResults
.mChildTask
;
789 this->mExtensionKitProcess
= aResults
.mExtensionKitProcess
;
790 this->mXPCConnection
= aResults
.mXPCConnection
;
791 this->mForegroundCapabilityGrant
=
792 std::move(aResults
.mForegroundCapabilityGrant
);
796 mNodeChannel
->SetOtherPid(
797 base::GetProcId(this->mChildProcessHandle
));
799 mNodeChannel
->SetMachTaskPort(this->mChildTask
);
803 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
804 this->mSandboxBroker
= std::move(aResults
.mSandboxBroker
);
807 MonitorAutoLock
lock(mMonitor
);
808 // The OnChannel{Connected,Error} may have already advanced
810 if (mProcessState
< PROCESS_CREATED
) {
811 mProcessState
= PROCESS_CREATED
;
815 return ProcessHandlePromise::CreateAndResolve(
816 GetChildProcessHandle(), __func__
);
818 [this](const LaunchError aError
) {
819 // WaitUntilConnected might be waiting for us to signal.
820 // If something failed let's set the error state and notify.
822 << "Failed to launch "
823 << XRE_GeckoProcessTypeToString(mProcessType
)
824 << " subprocess @" << aError
.FunctionName()
825 << " (Error:" << aError
.ErrorCode() << ")";
826 Telemetry::Accumulate(
827 Telemetry::SUBPROCESS_LAUNCH_FAILURE
,
829 XRE_GeckoProcessTypeToString(mProcessType
)));
830 nsCString telemetryKey
= nsPrintfCString(
836 aError
.FunctionName().get(), aError
.ErrorCode(),
837 XRE_GeckoProcessTypeToString(mProcessType
));
838 // Max telemetry key is 72 chars
839 // https://searchfox.org/mozilla-central/rev/c244b16815d1fc827d141472b9faac5610f250e7/toolkit/components/telemetry/core/TelemetryScalar.cpp#105
840 if (telemetryKey
.Length() > 72) {
841 NS_WARNING(nsPrintfCString("Truncating telemetry key: %s",
844 telemetryKey
.Truncate(72);
846 Telemetry::ScalarAdd(
847 Telemetry::ScalarID::
848 DOM_PARENTPROCESS_PROCESS_LAUNCH_ERRORS
,
849 NS_ConvertUTF8toUTF16(telemetryKey
), 1);
851 MonitorAutoLock
lock(mMonitor
);
852 mProcessState
= PROCESS_ERROR
;
855 return ProcessHandlePromise::CreateAndReject(aError
, __func__
);
860 bool GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs
) {
861 AUTO_PROFILER_LABEL("GeckoChildProcessHost::WaitUntilConnected", OTHER
);
863 // NB: this uses a different mechanism than the chromium parent
865 TimeDuration timeout
= (aTimeoutMs
> 0)
866 ? TimeDuration::FromMilliseconds(aTimeoutMs
)
867 : TimeDuration::Forever();
869 MonitorAutoLock
lock(mMonitor
);
870 TimeStamp waitStart
= TimeStamp::Now();
873 // We'll receive several notifications, we need to exit when we
874 // have either successfully launched or have timed out.
875 while (mProcessState
!= PROCESS_CONNECTED
) {
876 // If there was an error then return it, don't wait out the timeout.
877 if (mProcessState
== PROCESS_ERROR
) {
881 CVStatus status
= lock
.Wait(timeout
);
882 if (status
== CVStatus::Timeout
) {
886 if (timeout
!= TimeDuration::Forever()) {
887 current
= TimeStamp::Now();
888 timeout
-= current
- waitStart
;
893 return mProcessState
== PROCESS_CONNECTED
;
896 bool GeckoChildProcessHost::WaitForProcessHandle() {
897 MonitorAutoLock
lock(mMonitor
);
898 while (mProcessState
< PROCESS_CREATED
) {
901 MOZ_ASSERT(mProcessState
== PROCESS_ERROR
|| GetChildProcessHandle());
903 return mProcessState
< PROCESS_ERROR
;
906 bool GeckoChildProcessHost::LaunchAndWaitForProcessHandle(
907 StringVector aExtraOpts
) {
908 if (!AsyncLaunch(std::move(aExtraOpts
))) {
911 return WaitForProcessHandle();
914 void GeckoChildProcessHost::InitializeChannel(
915 IPC::Channel::ChannelHandle
&& aServerHandle
) {
916 // Create the IPC channel which will be used for communication with this
918 mozilla::UniquePtr
<IPC::Channel
> channel
= MakeUnique
<IPC::Channel
>(
919 std::move(aServerHandle
), IPC::Channel::MODE_SERVER
,
920 base::kInvalidProcessId
);
922 channel
->StartAcceptingHandles(IPC::Channel::MODE_SERVER
);
923 #elif defined(XP_DARWIN)
924 channel
->StartAcceptingMachPorts(IPC::Channel::MODE_SERVER
);
927 mNodeController
= NodeController::GetSingleton();
928 std::tie(mInitialPort
, mNodeChannel
) =
929 mNodeController
->InviteChildProcess(std::move(channel
), this);
931 MonitorAutoLock
lock(mMonitor
);
932 mProcessState
= CHANNEL_INITIALIZED
;
936 void GeckoChildProcessHost::SetAlreadyDead() {
937 mozilla::AutoWriteLock
handleLock(mHandleLock
);
938 if (mChildProcessHandle
&&
939 mChildProcessHandle
!= base::kInvalidProcessHandle
) {
940 base::CloseProcessHandle(mChildProcessHandle
);
943 mChildProcessHandle
= 0;
946 void BaseProcessLauncher::GetChildLogName(const char* origLogName
,
947 nsACString
& buffer
) {
949 // On Windows we must expand relative paths because sandboxing rules
950 // bound only to full paths. fopen fowards to NtCreateFile which checks
951 // the path against the sanboxing rules as passed to fopen (left relative).
952 char absPath
[MAX_PATH
+ 2];
953 if (_fullpath(absPath
, origLogName
, sizeof(absPath
))) {
954 buffer
.Append(absPath
);
958 buffer
.Append(origLogName
);
961 // Remove .moz_log extension to avoid its duplication, it will be added
962 // automatically by the logging backend
963 static constexpr auto kMozLogExt
= nsLiteralCString
{MOZ_LOG_FILE_EXTENSION
};
964 if (StringEndsWith(buffer
, kMozLogExt
)) {
965 buffer
.Truncate(buffer
.Length() - kMozLogExt
.Length());
968 // Append child-specific postfix to name
969 buffer
.AppendLiteral(".child-");
970 buffer
.AppendInt(mChildId
);
973 // Windows needs a single dedicated thread for process launching,
974 // because of thread-safety restrictions/assertions in the sandbox
977 // Android also needs a single dedicated thread to simplify thread
980 // Fork server needs a dedicated thread for accessing
981 // |ForkServiceChild|.
982 #if defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID) || \
983 defined(MOZ_ENABLE_FORKSERVER)
985 static mozilla::StaticMutex gIPCLaunchThreadMutex
;
986 static mozilla::StaticRefPtr
<nsIThread
> gIPCLaunchThread
987 MOZ_GUARDED_BY(gIPCLaunchThreadMutex
);
989 class IPCLaunchThreadObserver final
: public nsIObserver
{
994 virtual ~IPCLaunchThreadObserver() = default;
997 NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver
, nsIObserver
, nsISupports
)
1000 IPCLaunchThreadObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
1001 const char16_t
* aData
) {
1002 MOZ_RELEASE_ASSERT(strcmp(aTopic
, "xpcom-shutdown-threads") == 0);
1003 StaticMutexAutoLock
lock(gIPCLaunchThreadMutex
);
1005 nsresult rv
= NS_OK
;
1006 if (gIPCLaunchThread
) {
1007 rv
= gIPCLaunchThread
->Shutdown();
1008 gIPCLaunchThread
= nullptr;
1010 mozilla::Unused
<< NS_WARN_IF(NS_FAILED(rv
));
1014 nsCOMPtr
<nsIEventTarget
> GetIPCLauncher() {
1015 StaticMutexAutoLock
lock(gIPCLaunchThreadMutex
);
1016 if (!gIPCLaunchThread
) {
1017 nsCOMPtr
<nsIThread
> thread
;
1018 nsresult rv
= NS_NewNamedThread("IPC Launch"_ns
, getter_AddRefs(thread
));
1019 if (!NS_WARN_IF(NS_FAILED(rv
))) {
1020 NS_DispatchToMainThread(
1021 NS_NewRunnableFunction("GeckoChildProcessHost::GetIPCLauncher", [] {
1022 nsCOMPtr
<nsIObserverService
> obsService
=
1023 mozilla::services::GetObserverService();
1024 nsCOMPtr
<nsIObserver
> obs
= new IPCLaunchThreadObserver();
1025 obsService
->AddObserver(obs
, "xpcom-shutdown-threads", false);
1027 gIPCLaunchThread
= thread
.forget();
1031 nsCOMPtr
<nsIEventTarget
> thread
= gIPCLaunchThread
.get();
1032 MOZ_DIAGNOSTIC_ASSERT(thread
);
1036 #else // defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID) ||
1037 // defined(MOZ_ENABLE_FORKSERVER)
1039 // Other platforms use an on-demand thread pool.
1041 nsCOMPtr
<nsIEventTarget
> GetIPCLauncher() {
1042 nsCOMPtr
<nsIEventTarget
> pool
=
1043 mozilla::SharedThreadPool::Get("IPC Launch"_ns
);
1044 MOZ_DIAGNOSTIC_ASSERT(pool
);
1048 #endif // XP_WIN || MOZ_WIDGET_ANDROID || MOZ_ENABLE_FORKSERVER
1052 AddAppDirToCommandLine(CommandLine
& aCmdLine
, nsIFile
* aAppDir
)
1054 AddAppDirToCommandLine(std::vector
<std::string
>& aCmdLine
, nsIFile
* aAppDir
,
1055 nsIFile
* aProfileDir
)
1058 // Content processes need access to application resources, so pass
1059 // the full application directory path to the child process.
1063 MOZ_ALWAYS_SUCCEEDS(aAppDir
->GetPath(path
));
1064 aCmdLine
.AppendLooseValue(UTF8ToWide(geckoargs::sAppDir
.Name()));
1065 std::wstring
wpath(path
.get());
1066 aCmdLine
.AppendLooseValue(wpath
);
1069 MOZ_ALWAYS_SUCCEEDS(aAppDir
->GetNativePath(path
));
1070 geckoargs::sAppDir
.Put(path
.get(), aCmdLine
);
1073 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1074 // Full path to the profile dir
1076 // If the profile doesn't exist, normalization will
1077 // fail. But we don't return an error here because some
1078 // tests require startup with a missing profile dir.
1079 // For users, almost universally, the profile will be in
1080 // the home directory and normalization isn't required.
1081 mozilla::Unused
<< aProfileDir
->Normalize();
1083 MOZ_ALWAYS_SUCCEEDS(aProfileDir
->GetNativePath(path
));
1084 geckoargs::sProfile
.Put(path
.get(), aCmdLine
);
1090 #if defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
1091 static bool Contains(const std::vector
<std::string
>& aExtraOpts
,
1092 const char* aValue
) {
1093 return std::any_of(aExtraOpts
.begin(), aExtraOpts
.end(),
1094 [&](const std::string arg
) {
1095 return arg
.find(aValue
) != std::string::npos
;
1098 #endif // defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
1100 RefPtr
<ProcessLaunchPromise
> BaseProcessLauncher::PerformAsyncLaunch() {
1101 Result
<Ok
, LaunchError
> aError
= DoSetup();
1102 if (aError
.isErr()) {
1103 return ProcessLaunchPromise::CreateAndReject(aError
.unwrapErr(), __func__
);
1105 RefPtr
<BaseProcessLauncher
> self
= this;
1106 return DoLaunch()->Then(
1107 mLaunchThread
, __func__
,
1108 [self
](base::ProcessHandle aHandle
) {
1109 self
->mResults
.mHandle
= aHandle
;
1110 return self
->FinishLaunch();
1112 [](LaunchError aError
) {
1113 return ProcessLaunchPromise::CreateAndReject(aError
, __func__
);
1117 Result
<Ok
, LaunchError
> BaseProcessLauncher::DoSetup() {
1118 RefPtr
<BaseProcessLauncher
> self
= this;
1119 GetProfilerEnvVarsForChildProcess([self
](const char* key
, const char* value
) {
1120 self
->mLaunchOptions
->env_map
[ENVIRONMENT_STRING(key
)] =
1121 ENVIRONMENT_STRING(value
);
1124 if (mProcessType
== GeckoProcessType_Content
) {
1125 nsAutoCString
mallocOpts(PR_GetEnv("MALLOC_OPTIONS"));
1126 // Disable randomization of small arenas in content.
1127 mallocOpts
.Append("r");
1128 self
->mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("MALLOC_OPTIONS")] =
1129 ENVIRONMENT_STRING(mallocOpts
.get());
1138 void BaseProcessLauncher::MapChildLogging() {
1139 const char* origNSPRLogName
= PR_GetEnv("NSPR_LOG_FILE");
1140 const char* origMozLogName
= PR_GetEnv("MOZ_LOG_FILE");
1142 if (origNSPRLogName
) {
1143 nsAutoCString nsprLogName
;
1144 GetChildLogName(origNSPRLogName
, nsprLogName
);
1145 mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("NSPR_LOG_FILE")] =
1146 ENVIRONMENT_STRING(nsprLogName
.get());
1148 if (origMozLogName
) {
1149 nsAutoCString mozLogName
;
1150 GetChildLogName(origMozLogName
, mozLogName
);
1151 mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("MOZ_LOG_FILE")] =
1152 ENVIRONMENT_STRING(mozLogName
.get());
1155 // `RUST_LOG_CHILD` is meant for logging child processes only.
1156 nsAutoCString
childRustLog(PR_GetEnv("RUST_LOG_CHILD"));
1157 if (!childRustLog
.IsEmpty()) {
1158 mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("RUST_LOG")] =
1159 ENVIRONMENT_STRING(childRustLog
.get());
1163 Result
<Ok
, LaunchError
> BaseProcessLauncher::DoFinishLaunch() {
1164 // We're in the parent and the child was launched. Close the child channel
1165 // handle in the parent as soon as possible, which will allow the parent to
1166 // detect when the child closes its handle (either due to normal exit or due
1168 mClientChannelHandle
= nullptr;
1173 #if defined(MOZ_WIDGET_GTK)
1174 Result
<Ok
, LaunchError
> LinuxProcessLauncher::DoSetup() {
1175 Result
<Ok
, LaunchError
> aError
= PosixProcessLauncher::DoSetup();
1176 if (aError
.isErr()) {
1180 if (mProcessType
== GeckoProcessType_Content
) {
1181 // disable IM module to avoid sandbox violation
1182 mLaunchOptions
->env_map
["GTK_IM_MODULE"] = "gtk-im-context-simple";
1184 // Disable ATK accessibility code in content processes because it conflicts
1185 // with the sandbox, and we proxy that information through the main process
1187 mLaunchOptions
->env_map
["NO_AT_BRIDGE"] = "1";
1191 if (!mTmpDirName
.IsEmpty()) {
1192 // Point a bunch of things that might want to write from content to our
1193 // shiny new content-process specific tmpdir
1194 mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("TMPDIR")] =
1195 ENVIRONMENT_STRING(mTmpDirName
.get());
1196 // Partial fix for bug 1380051 (not persistent - should be)
1197 mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
1198 ENVIRONMENT_STRING(mTmpDirName
.get());
1200 # endif // MOZ_SANDBOX
1204 #endif // MOZ_WIDGET_GTK
1207 Result
<Ok
, LaunchError
> PosixProcessLauncher::DoSetup() {
1208 Result
<Ok
, LaunchError
> aError
= BaseProcessLauncher::DoSetup();
1209 if (aError
.isErr()) {
1213 // XPCOM may not be initialized in some subprocesses. We don't want
1214 // to initialize XPCOM just for the directory service, especially
1215 // since LD_LIBRARY_PATH is already set correctly in subprocesses
1216 // (meaning that we don't need to set that up in the environment).
1217 if (ShouldHaveDirectoryService()) {
1218 MOZ_ASSERT(gGREBinPath
);
1220 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath
), path
);
1221 # if defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \
1222 defined(XP_NETBSD) || defined(XP_OPENBSD)
1223 const char* ld_library_path
= PR_GetEnv("LD_LIBRARY_PATH");
1224 nsCString
new_ld_lib_path(path
.get());
1226 if (ld_library_path
&& *ld_library_path
) {
1227 new_ld_lib_path
.Append(':');
1228 new_ld_lib_path
.Append(ld_library_path
);
1230 mLaunchOptions
->env_map
["LD_LIBRARY_PATH"] = new_ld_lib_path
.get();
1233 // With signed production Mac builds, the dynamic linker (dyld) will
1234 // ignore dyld environment variables preventing the use of variables
1235 // such as DYLD_LIBRARY_PATH and DYLD_INSERT_LIBRARIES.
1237 // If we're running with gtests, add the gtest XUL ahead of normal XUL on
1238 // the DYLD_LIBRARY_PATH so that plugin-container.app loads it instead.
1239 nsCString
new_dyld_lib_path(path
.get());
1240 if (PR_GetEnv("MOZ_RUN_GTEST")) {
1241 new_dyld_lib_path
= path
+ "/gtest:"_ns
+ new_dyld_lib_path
;
1242 mLaunchOptions
->env_map
["DYLD_LIBRARY_PATH"] = new_dyld_lib_path
.get();
1245 // DYLD_INSERT_LIBRARIES is currently unused by default but we allow
1246 // it to be set by the external environment.
1247 const char* interpose
= PR_GetEnv("DYLD_INSERT_LIBRARIES");
1248 if (interpose
&& strlen(interpose
) > 0) {
1249 mLaunchOptions
->env_map
["DYLD_INSERT_LIBRARIES"] = interpose
;
1252 // Prevent connection attempts to diagnosticd(8) to save cycles. Log
1253 // messages can trigger these connection attempts, but access to
1254 // diagnosticd is blocked in sandboxed child processes.
1255 # if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
1256 if (mDisableOSActivityMode
) {
1257 mLaunchOptions
->env_map
["OS_ACTIVITY_MODE"] = "disable";
1259 # endif // defined(MOZ_SANDBOX)
1264 BinPathType pathType
= GetPathToBinary(exePath
, mProcessType
);
1266 // remap the IPC socket fd to a well-known int, as the OS does for
1267 // STDOUT_FILENO, for example
1268 // The fork server doesn't use IPC::Channel, so can skip this step.
1269 if (mProcessType
!= GeckoProcessType_ForkServer
) {
1270 # if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT)
1271 // On Android/iOS, mChannelDstFd is initialised to -1 and the launching
1272 // code uses only the first of each pair.
1273 MOZ_ASSERT(mChannelDstFd
>= 0);
1275 mLaunchOptions
->fds_to_remap
.push_back(
1276 std::pair
<int, int>(mClientChannelHandle
.get(), mChannelDstFd
));
1279 // no need for kProcessChannelID, the child process inherits the
1280 // other end of the socketpair() from us
1282 mChildArgv
.push_back(exePath
.value());
1284 if (pathType
== BinPathType::Self
) {
1285 mChildArgv
.push_back("-contentproc");
1288 mChildArgv
.insert(mChildArgv
.end(), mExtraOpts
.begin(), mExtraOpts
.end());
1290 if ((mProcessType
== GeckoProcessType_Content
||
1291 mProcessType
== GeckoProcessType_ForkServer
) &&
1292 Omnijar::IsInitialized()) {
1293 // Make sure that child processes can find the omnijar, if they
1294 // use full XPCOM. See Omnijar::ChildProcessInit and its callers.
1296 nsCOMPtr
<nsIFile
> greFile
= Omnijar::GetPath(Omnijar::GRE
);
1297 if (greFile
&& NS_SUCCEEDED(greFile
->GetNativePath(path
))) {
1298 geckoargs::sGREOmni
.Put(path
.get(), mChildArgv
);
1300 nsCOMPtr
<nsIFile
> appFile
= Omnijar::GetPath(Omnijar::APP
);
1301 if (appFile
&& NS_SUCCEEDED(appFile
->GetNativePath(path
))) {
1302 geckoargs::sAppOmni
.Put(path
.get(), mChildArgv
);
1306 if (mProcessType
!= GeckoProcessType_GMPlugin
) {
1307 // Add the application directory path (-appdir path)
1309 AddAppDirToCommandLine(mChildArgv
, mAppDir
, mProfileDir
);
1311 AddAppDirToCommandLine(mChildArgv
, mAppDir
, nullptr);
1315 mChildArgv
.push_back(mInitialChannelIdString
);
1317 mChildArgv
.push_back(mPidString
);
1319 if (!CrashReporter::IsDummy()) {
1320 # if defined(MOZ_WIDGET_COCOA)
1321 mChildArgv
.push_back(CrashReporter::GetChildNotificationPipe());
1322 # elif defined(XP_UNIX)
1323 int childCrashFd
, childCrashRemapFd
;
1324 if (NS_WARN_IF(!CrashReporter::CreateNotificationPipeForChild(
1325 &childCrashFd
, &childCrashRemapFd
))) {
1326 return Err(LaunchError("CR::CreateNotificationPipeForChild"));
1329 if (0 <= childCrashFd
) {
1330 mLaunchOptions
->fds_to_remap
.push_back(
1331 std::pair
<int, int>(childCrashFd
, childCrashRemapFd
));
1332 // "true" == crash reporting enabled
1333 mChildArgv
.push_back("true");
1335 // "false" == crash reporting disabled
1336 mChildArgv
.push_back("false");
1341 # ifdef MOZ_WIDGET_COCOA
1343 auto* thisMac
= static_cast<MacProcessLauncher
*>(this);
1345 bootstrap_check_in(bootstrap_port
, thisMac
->mMachConnectionName
.c_str(),
1346 getter_Transfers(thisMac
->mParentRecvPort
));
1347 if (kr
!= KERN_SUCCESS
) {
1348 CHROMIUM_LOG(ERROR
) << "parent bootstrap_check_in failed: "
1349 << mach_error_string(kr
);
1350 return Err(LaunchError("bootstrap_check_in", kr
));
1352 mChildArgv
.push_back(thisMac
->mMachConnectionName
.c_str());
1354 # endif // MOZ_WIDGET_COCOA
1356 mChildArgv
.push_back(ChildProcessType());
1361 #if defined(MOZ_WIDGET_ANDROID)
1362 RefPtr
<ProcessHandlePromise
> AndroidProcessLauncher::DoLaunch() {
1363 return LaunchAndroidService(mProcessType
, mChildArgv
,
1364 mLaunchOptions
->fds_to_remap
);
1366 #endif // MOZ_WIDGET_ANDROID
1369 RefPtr
<ProcessHandlePromise
> PosixProcessLauncher::DoLaunch() {
1370 ProcessHandle handle
= 0;
1371 Result
<Ok
, LaunchError
> aError
=
1372 base::LaunchApp(mChildArgv
, std::move(*mLaunchOptions
), &handle
);
1373 if (aError
.isErr()) {
1374 return ProcessHandlePromise::CreateAndReject(aError
.unwrapErr(), __func__
);
1376 return ProcessHandlePromise::CreateAndResolve(handle
, __func__
);
1381 RefPtr
<ProcessHandlePromise
> IosProcessLauncher::DoLaunch() {
1382 MOZ_RELEASE_ASSERT(mLaunchOptions
->fds_to_remap
.size() == 3,
1383 "Unexpected fds_to_remap on iOS");
1385 ExtensionKitProcess::Kind kind
= ExtensionKitProcess::Kind::WebContent
;
1386 if (mProcessType
== GeckoProcessType_GPU
) {
1387 kind
= ExtensionKitProcess::Kind::Rendering
;
1388 } else if (mProcessType
== GeckoProcessType_Socket
) {
1389 kind
= ExtensionKitProcess::Kind::Networking
;
1392 DarwinObjectPtr
<xpc_object_t
> bootstrapMessage
=
1393 AdoptDarwinObject(xpc_dictionary_create_empty());
1394 xpc_dictionary_set_string(bootstrapMessage
.get(), "message-name",
1397 DarwinObjectPtr
<xpc_object_t
> environDict
=
1398 AdoptDarwinObject(xpc_dictionary_create_empty());
1399 for (auto& [envKey
, envValue
] : mLaunchOptions
->env_map
) {
1400 xpc_dictionary_set_string(environDict
.get(), envKey
.c_str(),
1403 xpc_dictionary_set_value(bootstrapMessage
.get(), "environ",
1406 // XXX: this processing depends entirely on the internals of
1407 // ContentParent::LaunchSubprocess()
1408 // GeckoChildProcessHost::PerformAsyncLaunch(), and the order in
1409 // which they append to fds_to_remap. There must be a better way to do it.
1411 int prefsFd
= mLaunchOptions
->fds_to_remap
[0].first
;
1412 int prefMapFd
= mLaunchOptions
->fds_to_remap
[1].first
;
1413 int ipcFd
= mLaunchOptions
->fds_to_remap
[2].first
;
1414 xpc_dictionary_set_fd(bootstrapMessage
.get(), "prefs", prefsFd
);
1415 xpc_dictionary_set_fd(bootstrapMessage
.get(), "prefmap", prefMapFd
);
1416 xpc_dictionary_set_fd(bootstrapMessage
.get(), "channel", ipcFd
);
1418 // Setup stdout and stderr to inherit.
1419 xpc_dictionary_set_fd(bootstrapMessage
.get(), "stdout", STDOUT_FILENO
);
1420 xpc_dictionary_set_fd(bootstrapMessage
.get(), "stderr", STDERR_FILENO
);
1422 DarwinObjectPtr
<xpc_object_t
> argsArray
=
1423 AdoptDarwinObject(xpc_array_create_empty());
1424 for (auto& argv
: mChildArgv
) {
1425 xpc_array_set_string(argsArray
.get(), XPC_ARRAY_APPEND
, argv
.c_str());
1427 MOZ_ASSERT(xpc_array_get_count(argsArray
.get()) == mChildArgv
.size());
1428 xpc_dictionary_set_value(bootstrapMessage
.get(), "argv", argsArray
.get());
1430 auto promise
= MakeRefPtr
<ProcessHandlePromise::Private
>(__func__
);
1431 ExtensionKitProcess::StartProcess(kind
, [self
= RefPtr
{this}, promise
,
1433 std::move(bootstrapMessage
)](
1434 Result
<ExtensionKitProcess
,
1435 LaunchError
>&& result
) {
1436 if (result
.isErr()) {
1437 CHROMIUM_LOG(ERROR
) << "ExtensionKitProcess::StartProcess failed";
1438 promise
->Reject(result
.unwrapErr(), __func__
);
1442 auto process
= result
.unwrap();
1443 self
->mResults
.mForegroundCapabilityGrant
=
1444 process
.GrantForegroundCapability();
1445 self
->mResults
.mXPCConnection
= process
.MakeLibXPCConnection();
1446 self
->mResults
.mExtensionKitProcess
= Some(std::move(process
));
1448 // We don't actually use the event handler for anything other than
1449 // watching for errors. Once the promise is resolved, this becomes a
1451 xpc_connection_set_event_handler(self
->mResults
.mXPCConnection
.get(), ^(
1452 xpc_object_t event
) {
1453 if (!event
|| xpc_get_type(event
) == XPC_TYPE_ERROR
) {
1454 CHROMIUM_LOG(WARNING
) << "XPC connection received encountered an error";
1455 promise
->Reject(LaunchError("xpc_connection_event_handler"), __func__
);
1458 xpc_connection_resume(self
->mResults
.mXPCConnection
.get());
1460 // Send our bootstrap message to the content and wait for it to reply with
1461 // the task port before resolving.
1462 // FIXME: Should we have a time-out for if the child process doesn't respond
1463 // in time? The main thread may be blocked while we're starting this
1465 xpc_connection_send_message_with_reply(
1466 self
->mResults
.mXPCConnection
.get(), bootstrapMessage
.get(), nullptr,
1467 ^(xpc_object_t reply
) {
1468 if (xpc_get_type(reply
) == XPC_TYPE_ERROR
) {
1470 << "Got error sending XPC bootstrap message to child";
1472 LaunchError("xpc_connection_send_message_with_reply error"),
1477 if (xpc_get_type(reply
) != XPC_TYPE_DICTIONARY
) {
1479 << "Unexpected reply type for bootstrap message from child";
1482 "xpc_connection_send_message_with_reply non-dictionary"),
1487 // FIXME: We have to trust the child to tell us its pid & mach task.
1488 // WebKit uses `xpc_connection_get_pid` to get the pid, however this
1489 // is marked as unavailable on iOS.
1491 // Given how the process is started, however, validating this
1492 // information it sends us this early during startup may be
1494 self
->mResults
.mChildTask
=
1495 xpc_dictionary_copy_mach_send(reply
, "task");
1497 static_cast<pid_t
>(xpc_dictionary_get_int64(reply
, "pid"));
1498 CHROMIUM_LOG(INFO
) << "ExtensionKit process started, task: "
1499 << self
->mResults
.mChildTask
<< ", pid: " << pid
;
1502 kern_return_t kr
= pid_for_task(self
->mResults
.mChildTask
, &taskPid
);
1503 if (kr
!= KERN_SUCCESS
|| pid
!= taskPid
) {
1504 CHROMIUM_LOG(ERROR
) << "Could not validate child task matches pid";
1505 promise
->Reject(LaunchError("pid_for_task mismatch"), __func__
);
1509 promise
->Resolve(pid
, __func__
);
1518 Result
<Ok
, LaunchError
> MacProcessLauncher::DoFinishLaunch() {
1519 Result
<Ok
, LaunchError
> aError
= PosixProcessLauncher::DoFinishLaunch();
1520 if (aError
.isErr()) {
1524 MOZ_ASSERT(mParentRecvPort
, "should have been configured during DoSetup()");
1526 // Wait for the child process to send us its 'task_t' data.
1527 const int kTimeoutMs
= 10000;
1529 mozilla::UniqueMachSendRight child_task
;
1530 audit_token_t audit_token
{};
1531 kern_return_t kr
= MachReceivePortSendRight(
1532 mParentRecvPort
, mozilla::Some(kTimeoutMs
), &child_task
, &audit_token
);
1533 if (kr
!= KERN_SUCCESS
) {
1534 std::string errString
= StringPrintf("0x%x %s", kr
, mach_error_string(kr
));
1535 CHROMIUM_LOG(ERROR
) << "parent MachReceivePortSendRight failed: "
1537 return Err(LaunchError("MachReceivePortSendRight", kr
));
1540 // Ensure the message was sent by the newly spawned child process.
1541 if (audit_token_to_pid(audit_token
) != base::GetProcId(mResults
.mHandle
)) {
1542 CHROMIUM_LOG(ERROR
) << "task_t was not sent by child process";
1543 return Err(LaunchError("audit_token_to_pid"));
1546 // Ensure the task_t corresponds to the newly spawned child process.
1547 pid_t task_pid
= -1;
1548 kr
= pid_for_task(child_task
.get(), &task_pid
);
1549 if (kr
!= KERN_SUCCESS
) {
1550 CHROMIUM_LOG(ERROR
) << "pid_for_task failed: " << mach_error_string(kr
);
1551 return Err(LaunchError("pid_for_task", kr
));
1553 if (task_pid
!= base::GetProcId(mResults
.mHandle
)) {
1554 CHROMIUM_LOG(ERROR
) << "task_t is not for child process";
1555 return Err(LaunchError("task_pid"));
1558 mResults
.mChildTask
= child_task
.release();
1565 Result
<Ok
, LaunchError
> WindowsProcessLauncher::DoSetup() {
1566 Result
<Ok
, LaunchError
> aError
= BaseProcessLauncher::DoSetup();
1567 if (aError
.isErr()) {
1572 BinPathType pathType
= GetPathToBinary(exePath
, mProcessType
);
1574 # if defined(MOZ_SANDBOX) || defined(_ARM64_)
1575 const bool isGMP
= mProcessType
== GeckoProcessType_GMPlugin
;
1576 const bool isWidevine
= isGMP
&& Contains(mExtraOpts
, "gmp-widevinecdm");
1577 # if defined(_ARM64_)
1578 bool useRemoteSandboxBroker
= false;
1579 if (mLaunchArch
& (base::PROCESS_ARCH_I386
| base::PROCESS_ARCH_X86_64
)) {
1580 // On Windows on ARM64 for ClearKey and Widevine, and for the sandbox
1581 // launcher process, we want to run the x86 plugin-container.exe in
1582 // the "i686" subdirectory, instead of the aarch64 plugin-container.exe.
1583 // So insert "i686" into the exePath.
1584 exePath
= exePath
.DirName().AppendASCII("i686").Append(exePath
.BaseName());
1585 useRemoteSandboxBroker
=
1586 mProcessType
!= GeckoProcessType_RemoteSandboxBroker
;
1588 # endif // if defined(_ARM64_)
1589 # endif // defined(MOZ_SANDBOX) || defined(_ARM64_)
1591 mCmdLine
.emplace(exePath
.ToWStringHack());
1593 if (pathType
== BinPathType::Self
) {
1594 mCmdLine
->AppendLooseValue(UTF8ToWide("-contentproc"));
1597 # ifdef HAS_DLL_BLOCKLIST
1598 if (IsDynamicBlocklistDisabled(
1600 CommandLine::ForCurrentProcess()->HasSwitch(UTF8ToWide(
1601 mozilla::geckoargs::sDisableDynamicDllBlocklist
.sMatch
)))) {
1602 mCmdLine
->AppendLooseValue(
1603 UTF8ToWide(mozilla::geckoargs::sDisableDynamicDllBlocklist
.sMatch
));
1605 # endif // HAS_DLL_BLOCKLIST
1607 // Inherit the initial client channel handle into the child process.
1608 std::wstring processChannelID
=
1609 std::to_wstring(uint32_t(uintptr_t(mClientChannelHandle
.get())));
1610 mLaunchOptions
->handles_to_inherit
.push_back(mClientChannelHandle
.get());
1611 mCmdLine
->AppendSwitchWithValue(switches::kProcessChannelID
,
1614 for (std::vector
<std::string
>::iterator it
= mExtraOpts
.begin();
1615 it
!= mExtraOpts
.end(); ++it
) {
1616 mCmdLine
->AppendLooseValue(UTF8ToWide(*it
));
1619 # if defined(MOZ_SANDBOX)
1620 # if defined(_ARM64_)
1621 if (useRemoteSandboxBroker
)
1622 mResults
.mSandboxBroker
= new RemoteSandboxBroker(mLaunchArch
);
1624 # endif // if defined(_ARM64_)
1625 mResults
.mSandboxBroker
= new SandboxBroker();
1627 // XXX: Bug 1124167: We should get rid of the process specific logic for
1628 // sandboxing in this class at some point. Unfortunately it will take a bit
1629 // of reorganizing so I don't think this patch is the right time.
1630 switch (mProcessType
) {
1631 case GeckoProcessType_Content
:
1632 if (mSandboxLevel
> 0) {
1633 // For now we treat every failure as fatal in
1634 // SetSecurityLevelForContentProcess and just crash there right away.
1635 // Should this change in the future then we should also handle the error
1637 mResults
.mSandboxBroker
->SetSecurityLevelForContentProcess(
1638 mSandboxLevel
, mIsFileContent
);
1642 case GeckoProcessType_IPDLUnitTest
:
1643 // XXX: We don't sandbox this process type yet
1645 case GeckoProcessType_GMPlugin
:
1646 if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
1647 // The Widevine CDM on Windows can only load at USER_RESTRICTED,
1648 // not at USER_LOCKDOWN. So look in the command line arguments
1649 // to see if we're loading the path to the Widevine CDM, and if
1650 // so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN.
1652 isWidevine
? SandboxBroker::Restricted
: SandboxBroker::LockDown
;
1654 !mResults
.mSandboxBroker
->SetSecurityLevelForGMPlugin(level
))) {
1655 return Err(LaunchError("SetSecurityLevelForGMPlugin"));
1660 case GeckoProcessType_GPU
:
1661 if (mSandboxLevel
> 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) {
1662 // For now we treat every failure as fatal in
1663 // SetSecurityLevelForGPUProcess and just crash there right away. Should
1664 // this change in the future then we should also handle the error here.
1665 mResults
.mSandboxBroker
->SetSecurityLevelForGPUProcess(mSandboxLevel
);
1669 case GeckoProcessType_VR
:
1670 if (mSandboxLevel
> 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) {
1671 // TODO: Implement sandbox for VR process, Bug 1430043.
1674 case GeckoProcessType_RDD
:
1675 if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
1677 !mResults
.mSandboxBroker
->SetSecurityLevelForRDDProcess())) {
1678 return Err(LaunchError("SetSecurityLevelForRDDProcess"));
1683 case GeckoProcessType_Socket
:
1684 if (!PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS_SANDBOX")) {
1686 !mResults
.mSandboxBroker
->SetSecurityLevelForSocketProcess())) {
1687 return Err(LaunchError("SetSecurityLevelForSocketProcess"));
1692 case GeckoProcessType_Utility
:
1693 if (IsUtilitySandboxEnabled(mSandbox
)) {
1694 if (!mResults
.mSandboxBroker
->SetSecurityLevelForUtilityProcess(
1696 return Err(LaunchError("SetSecurityLevelForUtilityProcess"));
1701 case GeckoProcessType_RemoteSandboxBroker
:
1702 // We don't sandbox the sandbox launcher...
1704 case GeckoProcessType_Default
:
1706 MOZ_CRASH("Bad process type in GeckoChildProcessHost");
1711 for (auto it
= mAllowedFilesRead
.begin(); it
!= mAllowedFilesRead
.end();
1713 mResults
.mSandboxBroker
->AllowReadFile(it
->c_str());
1716 if (mResults
.mSandboxBroker
->IsWin32kLockedDown()) {
1717 mCmdLine
->AppendLooseValue(
1718 UTF8ToWide(geckoargs::sWin32kLockedDown
.Name()));
1721 # endif // defined(MOZ_SANDBOX)
1723 // Add the application directory path (-appdir path)
1724 AddAppDirToCommandLine(mCmdLine
.ref(), mAppDir
);
1726 // XXX Command line params past this point are expected to be at
1727 // the end of the command line string, and in a specific order.
1728 // See XRE_InitChildProcess in nsEmbedFunction.
1731 mCmdLine
->AppendLooseValue(mGroupId
.get());
1733 // Initial MessageChannel id
1734 mCmdLine
->AppendLooseValue(UTF8ToWide(mInitialChannelIdString
));
1737 mCmdLine
->AppendLooseValue(UTF8ToWide(mPidString
));
1739 mCmdLine
->AppendLooseValue(
1740 UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
1743 mCmdLine
->AppendLooseValue(UTF8ToWide(ChildProcessType()));
1747 // Mark the handles to inherit as inheritable.
1748 for (HANDLE h
: mLaunchOptions
->handles_to_inherit
) {
1749 mResults
.mSandboxBroker
->AddHandleToShare(h
);
1752 # endif // MOZ_SANDBOX
1757 RefPtr
<ProcessHandlePromise
> WindowsProcessLauncher::DoLaunch() {
1758 ProcessHandle handle
= 0;
1761 const IMAGE_THUNK_DATA
* cachedNtdllThunk
=
1762 mCachedNtdllThunk
? mCachedNtdllThunk
->begin() : nullptr;
1763 Result
<Ok
, LaunchError
> err
= mResults
.mSandboxBroker
->LaunchApp(
1764 mCmdLine
->program().c_str(), mCmdLine
->command_line_string().c_str(),
1765 mLaunchOptions
->env_map
, mProcessType
, mEnableSandboxLogging
,
1766 cachedNtdllThunk
, &handle
);
1768 EnvironmentLog("MOZ_PROCESS_LOG")
1769 .print("==> process %d launched child process %d (%S)\n",
1770 base::GetCurrentProcId(), base::GetProcId(handle
),
1771 mCmdLine
->command_line_string().c_str());
1772 return ProcessHandlePromise::CreateAndResolve(handle
, __func__
);
1774 return ProcessHandlePromise::CreateAndReject(err
.unwrapErr(), __func__
);
1776 # endif // defined(MOZ_SANDBOX)
1778 Result
<Ok
, LaunchError
> launchErr
=
1779 base::LaunchApp(mCmdLine
.ref(), *mLaunchOptions
, &handle
);
1780 if (launchErr
.isErr()) {
1781 return ProcessHandlePromise::CreateAndReject(launchErr
.unwrapErr(),
1784 return ProcessHandlePromise::CreateAndResolve(handle
, __func__
);
1787 Result
<Ok
, LaunchError
> WindowsProcessLauncher::DoFinishLaunch() {
1788 Result
<Ok
, LaunchError
> err
= BaseProcessLauncher::DoFinishLaunch();
1797 RefPtr
<ProcessLaunchPromise
> BaseProcessLauncher::FinishLaunch() {
1798 Result
<Ok
, LaunchError
> aError
= DoFinishLaunch();
1799 if (aError
.isErr()) {
1800 return ProcessLaunchPromise::CreateAndReject(aError
.unwrapErr(), __func__
);
1803 MOZ_DIAGNOSTIC_ASSERT(mResults
.mHandle
);
1805 Telemetry::AccumulateTimeDelta(Telemetry::CHILD_PROCESS_LAUNCH_MS
,
1808 return ProcessLaunchPromise::CreateAndResolve(std::move(mResults
), __func__
);
1811 bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid
) {
1812 if (mChildProcessHandle
) {
1813 MOZ_ASSERT(aPid
== base::GetProcId(mChildProcessHandle
));
1817 return base::OpenPrivilegedProcessHandle(aPid
, &mChildProcessHandle
);
1820 void GeckoChildProcessHost::OnChannelConnected(base::ProcessId peer_pid
) {
1822 mozilla::AutoWriteLock
hLock(mHandleLock
);
1823 if (!OpenPrivilegedHandle(peer_pid
)) {
1824 MOZ_CRASH("can't open handle to child process");
1827 MonitorAutoLock
lock(mMonitor
);
1828 mProcessState
= PROCESS_CONNECTED
;
1832 RefPtr
<ProcessHandlePromise
> GeckoChildProcessHost::WhenProcessHandleReady() {
1833 MOZ_ASSERT(mHandlePromise
!= nullptr);
1834 return mHandlePromise
;
1837 #ifdef MOZ_WIDGET_ANDROID
1838 RefPtr
<ProcessHandlePromise
> AndroidProcessLauncher::LaunchAndroidService(
1839 const GeckoProcessType aType
, const std::vector
<std::string
>& argv
,
1840 const base::file_handle_mapping_vector
& fds_to_remap
) {
1841 MOZ_RELEASE_ASSERT((2 <= fds_to_remap
.size()) && (fds_to_remap
.size() <= 5));
1842 JNIEnv
* const env
= mozilla::jni::GetEnvForThread();
1845 const int argvSize
= argv
.size();
1846 jni::ObjectArray::LocalRef jargs
=
1847 jni::ObjectArray::New
<jni::String
>(argvSize
);
1848 for (int ix
= 0; ix
< argvSize
; ix
++) {
1849 jargs
->SetElement(ix
, jni::StringParam(argv
[ix
].c_str(), env
));
1852 // XXX: this processing depends entirely on the internals of
1853 // ContentParent::LaunchSubprocess()
1854 // GeckoChildProcessHost::PerformAsyncLaunch(), and the order in
1855 // which they append to fds_to_remap. There must be a better way to do it.
1857 int32_t prefsFd
= fds_to_remap
[0].first
;
1858 int32_t prefMapFd
= fds_to_remap
[1].first
;
1859 int32_t ipcFd
= fds_to_remap
[2].first
;
1860 int32_t crashFd
= -1;
1861 if (fds_to_remap
.size() == 4) {
1862 crashFd
= fds_to_remap
[3].first
;
1865 auto type
= java::GeckoProcessType::FromInt(aType
);
1866 auto genericResult
= java::GeckoProcessManager::Start(
1867 type
, jargs
, prefsFd
, prefMapFd
, ipcFd
, crashFd
);
1868 auto typedResult
= java::GeckoResult::LocalRef(std::move(genericResult
));
1869 return ProcessHandlePromise::FromGeckoResult(typedResult
);
1873 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1874 bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector
& aArgs
) {
1875 MacSandboxInfo info
;
1876 if (NS_WARN_IF(!FillMacSandboxInfo(info
))) {
1879 info
.AppendAsParams(aArgs
);
1883 // Fill |aInfo| with the flags needed to launch the utility sandbox
1884 bool GeckoChildProcessHost::FillMacSandboxInfo(MacSandboxInfo
& aInfo
) {
1885 aInfo
.type
= GetDefaultMacSandboxType();
1886 aInfo
.shouldLog
= Preferences::GetBool("security.sandbox.logging.enabled") ||
1887 PR_GetEnv("MOZ_SANDBOX_LOGGING");
1889 nsAutoCString appPath
;
1890 if (!nsMacUtilsImpl::GetAppPath(appPath
)) {
1891 MOZ_CRASH("Failed to get app path");
1893 aInfo
.appPath
.assign(appPath
.get());
1897 void GeckoChildProcessHost::DisableOSActivityMode() {
1898 mDisableOSActivityMode
= true;
1902 // If early sandbox startup is enabled for this process type, map the
1903 // process type to the sandbox type and enable the sandbox. Returns true
1904 // if no errors were encountered or if early sandbox startup is not
1905 // enabled for this process. Returns false if an error was encountered.
1908 bool GeckoChildProcessHost::StartMacSandbox(int aArgc
, char** aArgv
,
1909 std::string
& aErrorMessage
) {
1910 MacSandboxType sandboxType
= MacSandboxType_Invalid
;
1911 switch (XRE_GetProcessType()) {
1912 // For now, only support early sandbox startup for content,
1913 // RDD, and GMP processes. Add case statements for the additional
1914 // process types once early sandbox startup is implemented for them.
1915 case GeckoProcessType_Content
:
1916 // Content processes don't use GeckoChildProcessHost
1917 // to configure sandboxing so hard code the sandbox type.
1918 sandboxType
= MacSandboxType_Content
;
1920 case GeckoProcessType_RDD
:
1921 sandboxType
= RDDProcessHost::GetMacSandboxType();
1923 case GeckoProcessType_Socket
:
1924 sandboxType
= net::SocketProcessHost::GetMacSandboxType();
1926 case GeckoProcessType_GMPlugin
:
1927 sandboxType
= gmp::GMPProcessParent::GetMacSandboxType();
1929 case GeckoProcessType_Utility
:
1930 sandboxType
= ipc::UtilityProcessHost::GetMacSandboxType();
1936 return mozilla::StartMacSandboxIfEnabled(sandboxType
, aArgc
, aArgv
,
1940 #endif /* XP_MACOSX && MOZ_SANDBOX */
1943 void GeckoChildProcessHost::GetAll(const GeckoProcessCallback
& aCallback
) {
1944 StaticMutexAutoLock
lock(sMutex
);
1945 if (!sGeckoChildProcessHosts
) {
1948 for (GeckoChildProcessHost
* gp
= sGeckoChildProcessHosts
->getFirst(); gp
;
1949 gp
= static_cast<mozilla::LinkedListElement
<GeckoChildProcessHost
>*>(gp
)
1955 RefPtr
<ProcessLaunchPromise
> BaseProcessLauncher::Launch(
1956 GeckoChildProcessHost
* aHost
) {
1959 // The ForkServer doesn't use IPC::Channel for communication, so we can skip
1961 if (mProcessType
!= GeckoProcessType_ForkServer
) {
1962 IPC::Channel::ChannelHandle serverHandle
;
1963 if (!IPC::Channel::CreateRawPipe(&serverHandle
, &mClientChannelHandle
)) {
1964 return ProcessLaunchPromise::CreateAndReject(LaunchError("CreateRawPipe"),
1967 aHost
->InitializeChannel(std::move(serverHandle
));
1970 return InvokeAsync(mLaunchThread
, this, __func__
,
1971 &BaseProcessLauncher::PerformAsyncLaunch
);
1975 } // namespace mozilla