Bug 1908670 - Home and newtab topic personalization needs region controls r=home...
[gecko.git] / ipc / glue / GeckoChildProcessHost.cpp
blob920045f8bfa20302cdda110ce069db5d910fd818
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "GeckoChildProcessHost.h"
9 #include "base/command_line.h"
10 #include "base/process.h"
11 #include "base/process_util.h"
12 #include "base/string_util.h"
13 #include "base/task.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/process_watcher.h"
16 #ifdef XP_DARWIN
17 # include <mach/mach_traps.h>
18 # include "SharedMemoryBasic.h"
19 # include "base/rand_util.h"
20 # include "chrome/common/mach_ipc_mac.h"
21 # include "mozilla/StaticPrefs_media.h"
22 #endif
23 #ifdef MOZ_WIDGET_COCOA
24 # include <bsm/libbsm.h>
25 # include <servers/bootstrap.h>
26 # include "nsILocalFileMac.h"
27 #endif
29 #include "GeckoProfiler.h"
30 #include "MainThreadUtils.h"
31 #include "mozilla/Preferences.h"
32 #include "mozilla/Sprintf.h"
33 #include "nsXPCOMPrivate.h"
34 #include "prenv.h"
35 #include "prerror.h"
37 #if defined(MOZ_SANDBOX)
38 # include "mozilla/SandboxSettings.h"
39 # include "nsAppDirectoryServiceDefs.h"
40 #endif
42 #include <sys/stat.h>
44 #include "ProtocolUtils.h"
45 #include "mozilla/LinkedList.h"
46 #include "mozilla/Logging.h"
47 #include "mozilla/Maybe.h"
48 #include "mozilla/GeckoArgs.h"
49 #include "mozilla/Omnijar.h"
50 #include "mozilla/RDDProcessHost.h"
51 #include "mozilla/Services.h"
52 #include "mozilla/SharedThreadPool.h"
53 #include "mozilla/StaticMutex.h"
54 #include "mozilla/TaskQueue.h"
55 #include "mozilla/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"
64 #include "nsIFile.h"
65 #include "nsIObserverService.h"
66 #include "nsPrintfCString.h"
68 #ifdef XP_WIN
69 # include <stdlib.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_DARWIN
133 task_t mChildTask = MACH_PORT_NULL;
134 #endif
135 #ifdef XP_IOS
136 Maybe<ExtensionKitProcess> mExtensionKitProcess;
137 DarwinObjectPtr<xpc_connection_t> mXPCConnection;
138 UniqueBEProcessCapabilityGrant mForegroundCapabilityGrant;
139 #endif
140 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
141 RefPtr<AbstractSandboxBroker> mSandboxBroker;
142 #endif
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 {
154 public:
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)),
160 #ifdef XP_WIN
161 mGroupId(aHost->mGroupId),
162 #endif
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),
169 #endif
170 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
171 mDisableOSActivityMode(aHost->mDisableOSActivityMode),
172 #endif
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();
180 mLaunchThread =
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.
186 mozilla::Unused
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;
198 #endif
200 RefPtr<ProcessLaunchPromise> Launch(GeckoChildProcessHost*);
202 protected:
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;
229 #endif
230 std::vector<std::string> mExtraOpts;
231 #ifdef XP_WIN
232 nsString mGroupId;
233 #endif
234 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
235 std::vector<std::wstring> mAllowedFilesRead;
236 int32_t mSandboxLevel;
237 SandboxingKind mSandbox;
238 bool mIsFileContent;
239 bool mEnableSandboxLogging;
240 #endif
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;
245 #endif
246 nsCString mTmpDirName;
247 LaunchResults mResults = LaunchResults();
248 int32_t mChildId;
249 TimeStamp mStartTimeStamp = TimeStamp::Now();
250 char mPidString[32];
251 char mInitialChannelIdString[NSID_LENGTH];
253 // Set during launch.
254 IPC::Channel::ChannelHandle mClientChannelHandle;
255 nsCOMPtr<nsIFile> mAppDir;
258 #ifdef XP_WIN
259 class WindowsProcessLauncher : public BaseProcessLauncher {
260 public:
261 WindowsProcessLauncher(GeckoChildProcessHost* aHost,
262 std::vector<std::string>&& aExtraOpts)
263 : BaseProcessLauncher(aHost, std::move(aExtraOpts)),
264 mCachedNtdllThunk(GetCachedNtDllThunk()) {}
266 protected:
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;
272 # ifdef MOZ_SANDBOX
273 bool mUseSandbox = false;
274 # endif
276 const Buffer<IMAGE_THUNK_DATA>* mCachedNtdllThunk;
278 typedef WindowsProcessLauncher ProcessLauncher;
279 #endif // XP_WIN
281 #ifdef XP_UNIX
282 class PosixProcessLauncher : public BaseProcessLauncher {
283 public:
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()) {}
290 protected:
291 virtual Result<Ok, LaunchError> DoSetup() override;
292 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
294 nsCOMPtr<nsIFile> mProfileDir;
296 std::vector<std::string> mChildArgv;
297 int mChannelDstFd;
300 # if defined(XP_MACOSX)
301 class MacProcessLauncher : public PosixProcessLauncher {
302 public:
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.
309 mMachConnectionName(
310 StringPrintf("org.mozilla.machname.%d",
311 base::RandInt(0, std::numeric_limits<int>::max()))) {
312 MOZ_ASSERT(mMachConnectionName.size() < BOOTSTRAP_MAX_NAME_LEN);
315 protected:
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 {
328 public:
329 AndroidProcessLauncher(GeckoChildProcessHost* aHost,
330 std::vector<std::string>&& aExtraOpts)
331 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
333 protected:
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 {
346 public:
347 LinuxProcessLauncher(GeckoChildProcessHost* aHost,
348 std::vector<std::string>&& aExtraOpts)
349 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
351 protected:
352 virtual Result<Ok, LaunchError> DoSetup() override;
354 typedef LinuxProcessLauncher ProcessLauncher;
355 # elif defined(MOZ_WIDGET_UIKIT)
356 class IosProcessLauncher : public PosixProcessLauncher {
357 public:
358 IosProcessLauncher(GeckoChildProcessHost* aHost,
359 std::vector<std::string>&& aExtraOpts)
360 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
362 protected:
363 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
365 DarwinObjectPtr<xpc_object_t> mBootstrapMessage;
367 typedef IosProcessLauncher ProcessLauncher;
368 # else
369 # error "Unknown platform"
370 # endif
371 #endif // XP_UNIX
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,
383 bool aIsFileContent)
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),
390 #ifdef XP_WIN
391 mGroupId(u"-"),
392 #endif
393 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
394 mEnableSandboxLogging(false),
395 mSandboxLevel(0),
396 #endif
397 mHandleLock("mozilla.ipc.GeckoChildProcessHost.mHandleLock"),
398 mChildProcessHandle(0),
399 #if defined(XP_DARWIN)
400 mChildTask(MACH_PORT_NULL),
401 #endif
402 #if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
403 mDisableOSActivityMode(false),
404 #endif
405 mDestroying(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);
422 # endif
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";
434 #endif
435 #if defined(MOZ_ENABLE_FORKSERVER)
436 if (aProcessType != GeckoProcessType_ForkServer && ForkServiceChild::Get()) {
437 mLaunchOptions->use_forkserver = true;
439 #endif
442 GeckoChildProcessHost::~GeckoChildProcessHost()
445 AssertIOThread();
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);
456 #endif
457 #if defined(XP_IOS)
458 if (mForegroundCapabilityGrant) {
459 mForegroundCapabilityGrant.reset();
461 if (mExtensionKitProcess) {
462 mExtensionKitProcess->Invalidate();
464 if (mXPCConnection) {
465 xpc_connection_cancel(mXPCConnection.get());
467 #endif
469 if (mChildProcessHandle != 0) {
470 ProcessWatcher::EnsureProcessTerminated(
471 mChildProcessHandle
472 #ifdef NS_FREE_PERMANENT_DATA
473 // If we're doing leak logging, shutdown can be slow.
475 false // don't "force"
476 #endif
478 mChildProcessHandle = 0;
482 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
483 if (mSandboxBroker) {
484 mSandboxBroker->Shutdown();
485 mSandboxBroker = nullptr;
487 #endif
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) {
498 return 0;
500 return base::GetProcId(mChildProcessHandle);
503 #ifdef XP_DARWIN
504 task_t GeckoChildProcessHost::GetChildTask() {
505 mozilla::AutoReadLock handleLock(mHandleLock);
506 return mChildTask;
508 #endif
510 void GeckoChildProcessHost::RemoveFromProcessList() {
511 StaticMutexAutoLock lock(sMutex);
512 if (!sGeckoChildProcessHosts) {
513 return;
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;
525 if (!whenReady) {
526 // AsyncLaunch not called yet, so dispatch immediately.
527 whenReady = ProcessHandlePromise::CreateAndReject(
528 LaunchError("DestroyEarly"), __func__);
531 using Value = ProcessHandlePromise::ResolveOrRejectValue;
532 mDestroying = true;
533 whenReady->Then(XRE_GetIOMessageLoop()->SerialEventTarget(), __func__,
534 [this](const Value&) { delete this; });
537 // static
538 mozilla::BinPathType BaseProcessLauncher::GetPathToBinary(
539 FilePath& exePath, GeckoProcessType processType) {
540 BinPathType pathType = XRE_GetChildProcBinPathType(processType);
542 if (pathType == BinPathType::Self) {
543 #if defined(XP_WIN)
544 wchar_t exePathBuf[MAXPATHLEN];
545 if (!::GetModuleFileNameW(nullptr, exePathBuf, MAXPATHLEN)) {
546 MOZ_CRASH("GetModuleFileNameW failed (FIXME)");
548 exePath = FilePath::FromWStringHack(exePathBuf);
549 #else
550 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
551 #endif
552 return pathType;
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;
565 } else {
566 bundleName = MOZ_CHILD_PROCESS_BUNDLENAME;
567 executableLeafName = MOZ_CHILD_PROCESS_NAME;
569 #endif
571 if (ShouldHaveDirectoryService()) {
572 MOZ_ASSERT(gGREBinPath);
573 #ifdef XP_WIN
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);
585 nsCString tempCPath;
586 childProcPath->GetNativePath(tempCPath);
587 exePath = FilePath(tempCPath.get());
588 #else
589 nsCString path;
590 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
591 exePath = FilePath(path.get());
592 #endif
595 if (exePath.empty()) {
596 #ifdef XP_WIN
597 exePath =
598 FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
599 #else
600 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
601 #endif
602 exePath = exePath.DirName();
605 #ifdef MOZ_WIDGET_COCOA
606 exePath = exePath.Append(executableLeafName);
607 #else
608 exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
609 #endif
611 return pathType;
614 #ifdef MOZ_WIDGET_COCOA
615 class AutoCFTypeObject {
616 public:
617 explicit AutoCFTypeObject(CFTypeRef object) { mObject = object; }
618 ~AutoCFTypeObject() { ::CFRelease(mObject); }
620 private:
621 CFTypeRef mObject;
623 #endif
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;
629 /* static */
630 uint32_t GeckoChildProcessHost::GetUniqueID() { return sNextUniqueID++; }
632 /* static */
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());
646 #endif
648 #ifdef XP_WIN
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
655 // thread
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);
680 # endif
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");
689 # endif
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));
697 # endif
698 #endif
701 #ifdef XP_WIN
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);
707 if (taskbarInfo) {
708 bool isSupported = false;
709 taskbarInfo->GetAvailable(&isSupported);
710 nsAutoString appId;
711 if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
712 MOZ_ASSERT(mGroupId.EqualsLiteral("-"));
713 mGroupId.Assign(appId);
717 #endif
719 bool GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts,
720 int aTimeoutMs) {
721 if (!AsyncLaunch(std::move(aExtraOpts))) {
722 return false;
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) {
735 PrepareLaunch();
737 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
738 if (IsMacSandboxLaunchEnabled() && !AppendMacSandboxParams(aExtraOpts)) {
739 return false;
741 #endif
743 RefPtr<BaseProcessLauncher> launcher =
744 new ProcessLauncher(this, std::move(aExtraOpts));
745 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
746 launcher->SetLaunchArchitecture(mLaunchArch);
747 #endif
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);
753 mHandlePromise =
754 mozilla::InvokeAsync<GeckoChildProcessHost*>(
755 IOThread(), launcher.get(), __func__, &BaseProcessLauncher::Launch,
756 this)
757 ->Then(
758 IOThread(), __func__,
759 [this](LaunchResults&& aResults) {
762 mozilla::AutoWriteLock handleLock(mHandleLock);
763 if (!OpenPrivilegedHandle(base::GetProcId(aResults.mHandle))
764 #ifdef XP_WIN
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 |
772 SYNCHRONIZE,
773 FALSE, 0)
774 #endif // XP_WIN
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;
785 #ifdef XP_DARWIN
786 this->mChildTask = aResults.mChildTask;
787 #endif
788 #ifdef XP_IOS
789 this->mExtensionKitProcess = aResults.mExtensionKitProcess;
790 this->mXPCConnection = aResults.mXPCConnection;
791 this->mForegroundCapabilityGrant =
792 std::move(aResults.mForegroundCapabilityGrant);
793 #endif
795 if (mNodeChannel) {
796 mNodeChannel->SetOtherPid(
797 base::GetProcId(this->mChildProcessHandle));
798 #ifdef XP_DARWIN
799 mNodeChannel->SetMachTaskPort(this->mChildTask);
800 #endif
803 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
804 this->mSandboxBroker = std::move(aResults.mSandboxBroker);
805 #endif
807 MonitorAutoLock lock(mMonitor);
808 // The OnChannel{Connected,Error} may have already advanced
809 // the state.
810 if (mProcessState < PROCESS_CREATED) {
811 mProcessState = PROCESS_CREATED;
813 lock.Notify();
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.
821 CHROMIUM_LOG(ERROR)
822 << "Failed to launch "
823 << XRE_GeckoProcessTypeToString(mProcessType)
824 << " subprocess @" << aError.FunctionName()
825 << " (Error:" << aError.ErrorCode() << ")";
826 Telemetry::Accumulate(
827 Telemetry::SUBPROCESS_LAUNCH_FAILURE,
828 nsDependentCString(
829 XRE_GeckoProcessTypeToString(mProcessType)));
830 nsCString telemetryKey = nsPrintfCString(
831 #if defined(XP_WIN)
832 "%s,0x%lx,%s",
833 #else
834 "%s,%ld,%s",
835 #endif
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",
842 telemetryKey.get())
843 .get());
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;
853 lock.Notify();
855 return ProcessHandlePromise::CreateAndReject(aError, __func__);
857 return true;
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
864 // class.
865 TimeDuration timeout = (aTimeoutMs > 0)
866 ? TimeDuration::FromMilliseconds(aTimeoutMs)
867 : TimeDuration::Forever();
869 MonitorAutoLock lock(mMonitor);
870 TimeStamp waitStart = TimeStamp::Now();
871 TimeStamp current;
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) {
878 break;
881 CVStatus status = lock.Wait(timeout);
882 if (status == CVStatus::Timeout) {
883 break;
886 if (timeout != TimeDuration::Forever()) {
887 current = TimeStamp::Now();
888 timeout -= current - waitStart;
889 waitStart = current;
893 return mProcessState == PROCESS_CONNECTED;
896 bool GeckoChildProcessHost::WaitForProcessHandle() {
897 MonitorAutoLock lock(mMonitor);
898 while (mProcessState < PROCESS_CREATED) {
899 lock.Wait();
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))) {
909 return false;
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
917 // process.
918 mozilla::UniquePtr<IPC::Channel> channel = MakeUnique<IPC::Channel>(
919 std::move(aServerHandle), IPC::Channel::MODE_SERVER,
920 base::kInvalidProcessId);
921 #if defined(XP_WIN)
922 channel->StartAcceptingHandles(IPC::Channel::MODE_SERVER);
923 #elif defined(XP_DARWIN)
924 channel->StartAcceptingMachPorts(IPC::Channel::MODE_SERVER);
925 #endif
927 mNodeController = NodeController::GetSingleton();
928 std::tie(mInitialPort, mNodeChannel) =
929 mNodeController->InviteChildProcess(std::move(channel), this);
931 MonitorAutoLock lock(mMonitor);
932 mProcessState = CHANNEL_INITIALIZED;
933 lock.Notify();
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) {
948 #ifdef XP_WIN
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);
955 } else
956 #endif
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
975 // code.
977 // Android also needs a single dedicated thread to simplify thread
978 // safety in java.
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 {
990 public:
991 NS_DECL_ISUPPORTS
992 NS_DECL_NSIOBSERVER
993 protected:
994 virtual ~IPCLaunchThreadObserver() = default;
997 NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver, nsIObserver, nsISupports)
999 NS_IMETHODIMP
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));
1011 return 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);
1026 }));
1027 gIPCLaunchThread = thread.forget();
1031 nsCOMPtr<nsIEventTarget> thread = gIPCLaunchThread.get();
1032 MOZ_DIAGNOSTIC_ASSERT(thread);
1033 return 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);
1045 return pool;
1048 #endif // XP_WIN || MOZ_WIDGET_ANDROID || MOZ_ENABLE_FORKSERVER
1050 void
1051 #if defined(XP_WIN)
1052 AddAppDirToCommandLine(CommandLine& aCmdLine, nsIFile* aAppDir)
1053 #else
1054 AddAppDirToCommandLine(std::vector<std::string>& aCmdLine, nsIFile* aAppDir,
1055 nsIFile* aProfileDir)
1056 #endif
1058 // Content processes need access to application resources, so pass
1059 // the full application directory path to the child process.
1060 if (aAppDir) {
1061 #if defined(XP_WIN)
1062 nsString path;
1063 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetPath(path));
1064 aCmdLine.AppendLooseValue(UTF8ToWide(geckoargs::sAppDir.Name()));
1065 std::wstring wpath(path.get());
1066 aCmdLine.AppendLooseValue(wpath);
1067 #else
1068 nsAutoCString path;
1069 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetNativePath(path));
1070 geckoargs::sAppDir.Put(path.get(), aCmdLine);
1071 #endif
1073 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1074 // Full path to the profile dir
1075 if (aProfileDir) {
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();
1082 nsAutoCString path;
1083 MOZ_ALWAYS_SUCCEEDS(aProfileDir->GetNativePath(path));
1084 geckoargs::sProfile.Put(path.get(), aCmdLine);
1086 #endif
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);
1123 #ifdef MOZ_MEMORY
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());
1131 #endif
1133 MapChildLogging();
1135 return Ok();
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
1167 // to crash).
1168 mClientChannelHandle = nullptr;
1170 return Ok();
1173 #if defined(MOZ_WIDGET_GTK)
1174 Result<Ok, LaunchError> LinuxProcessLauncher::DoSetup() {
1175 Result<Ok, LaunchError> aError = PosixProcessLauncher::DoSetup();
1176 if (aError.isErr()) {
1177 return aError;
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
1186 // anyway.
1187 mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1";
1190 # ifdef MOZ_SANDBOX
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
1202 return Ok();
1204 #endif // MOZ_WIDGET_GTK
1206 #ifdef XP_UNIX
1207 Result<Ok, LaunchError> PosixProcessLauncher::DoSetup() {
1208 Result<Ok, LaunchError> aError = BaseProcessLauncher::DoSetup();
1209 if (aError.isErr()) {
1210 return aError;
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);
1219 nsCString path;
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();
1232 # elif XP_MACOSX
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)
1260 # endif
1263 FilePath exePath;
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);
1274 # endif
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.
1295 nsAutoCString path;
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)
1308 # ifdef XP_MACOSX
1309 AddAppDirToCommandLine(mChildArgv, mAppDir, mProfileDir);
1310 # else
1311 AddAppDirToCommandLine(mChildArgv, mAppDir, nullptr);
1312 # endif
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");
1334 } else {
1335 // "false" == crash reporting disabled
1336 mChildArgv.push_back("false");
1338 # endif
1341 # ifdef MOZ_WIDGET_COCOA
1343 auto* thisMac = static_cast<MacProcessLauncher*>(this);
1344 kern_return_t kr =
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());
1357 return Ok();
1359 #endif // XP_UNIX
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
1368 #ifdef XP_UNIX
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__);
1378 #endif // XP_UNIX
1380 #ifdef XP_IOS
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",
1395 "bootstrap");
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(),
1401 envValue.c_str());
1403 xpc_dictionary_set_value(bootstrapMessage.get(), "environ",
1404 environDict.get());
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.
1410 // See bug 1440207.
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,
1432 bootstrapMessage =
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__);
1439 return;
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
1450 // no-op.
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
1464 // process.
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) {
1469 CHROMIUM_LOG(ERROR)
1470 << "Got error sending XPC bootstrap message to child";
1471 promise->Reject(
1472 LaunchError("xpc_connection_send_message_with_reply error"),
1473 __func__);
1474 return;
1477 if (xpc_get_type(reply) != XPC_TYPE_DICTIONARY) {
1478 CHROMIUM_LOG(ERROR)
1479 << "Unexpected reply type for bootstrap message from child";
1480 promise->Reject(
1481 LaunchError(
1482 "xpc_connection_send_message_with_reply non-dictionary"),
1483 __func__);
1484 return;
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
1493 // unnecessary.
1494 self->mResults.mChildTask =
1495 xpc_dictionary_copy_mach_send(reply, "task");
1496 pid_t pid =
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;
1501 pid_t taskPid;
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__);
1506 return;
1509 promise->Resolve(pid, __func__);
1513 return promise;
1515 #endif
1517 #ifdef XP_MACOSX
1518 Result<Ok, LaunchError> MacProcessLauncher::DoFinishLaunch() {
1519 Result<Ok, LaunchError> aError = PosixProcessLauncher::DoFinishLaunch();
1520 if (aError.isErr()) {
1521 return aError;
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: "
1536 << errString;
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();
1560 return Ok();
1562 #endif // XP_MACOSX
1564 #ifdef XP_WIN
1565 Result<Ok, LaunchError> WindowsProcessLauncher::DoSetup() {
1566 Result<Ok, LaunchError> aError = BaseProcessLauncher::DoSetup();
1567 if (aError.isErr()) {
1568 return aError;
1571 FilePath exePath;
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(
1599 gSafeMode,
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,
1612 processChannelID);
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);
1623 else
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
1636 // here.
1637 mResults.mSandboxBroker->SetSecurityLevelForContentProcess(
1638 mSandboxLevel, mIsFileContent);
1639 mUseSandbox = true;
1641 break;
1642 case GeckoProcessType_IPDLUnitTest:
1643 // XXX: We don't sandbox this process type yet
1644 break;
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.
1651 auto level =
1652 isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown;
1653 if (NS_WARN_IF(
1654 !mResults.mSandboxBroker->SetSecurityLevelForGMPlugin(level))) {
1655 return Err(LaunchError("SetSecurityLevelForGMPlugin"));
1657 mUseSandbox = true;
1659 break;
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);
1666 mUseSandbox = true;
1668 break;
1669 case GeckoProcessType_VR:
1670 if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) {
1671 // TODO: Implement sandbox for VR process, Bug 1430043.
1673 break;
1674 case GeckoProcessType_RDD:
1675 if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
1676 if (NS_WARN_IF(
1677 !mResults.mSandboxBroker->SetSecurityLevelForRDDProcess())) {
1678 return Err(LaunchError("SetSecurityLevelForRDDProcess"));
1680 mUseSandbox = true;
1682 break;
1683 case GeckoProcessType_Socket:
1684 if (!PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS_SANDBOX")) {
1685 if (NS_WARN_IF(
1686 !mResults.mSandboxBroker->SetSecurityLevelForSocketProcess())) {
1687 return Err(LaunchError("SetSecurityLevelForSocketProcess"));
1689 mUseSandbox = true;
1691 break;
1692 case GeckoProcessType_Utility:
1693 if (IsUtilitySandboxEnabled(mSandbox)) {
1694 if (!mResults.mSandboxBroker->SetSecurityLevelForUtilityProcess(
1695 mSandbox)) {
1696 return Err(LaunchError("SetSecurityLevelForUtilityProcess"));
1698 mUseSandbox = true;
1700 break;
1701 case GeckoProcessType_RemoteSandboxBroker:
1702 // We don't sandbox the sandbox launcher...
1703 break;
1704 case GeckoProcessType_Default:
1705 default:
1706 MOZ_CRASH("Bad process type in GeckoChildProcessHost");
1707 break;
1710 if (mUseSandbox) {
1711 for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end();
1712 ++it) {
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.
1730 // Win app model id
1731 mCmdLine->AppendLooseValue(mGroupId.get());
1733 // Initial MessageChannel id
1734 mCmdLine->AppendLooseValue(UTF8ToWide(mInitialChannelIdString));
1736 // Process id
1737 mCmdLine->AppendLooseValue(UTF8ToWide(mPidString));
1739 mCmdLine->AppendLooseValue(
1740 UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
1742 // Process type
1743 mCmdLine->AppendLooseValue(UTF8ToWide(ChildProcessType()));
1745 # ifdef MOZ_SANDBOX
1746 if (mUseSandbox) {
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
1754 return Ok();
1757 RefPtr<ProcessHandlePromise> WindowsProcessLauncher::DoLaunch() {
1758 ProcessHandle handle = 0;
1759 # ifdef MOZ_SANDBOX
1760 if (mUseSandbox) {
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);
1767 if (err.isOk()) {
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(),
1782 __func__);
1784 return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1787 Result<Ok, LaunchError> WindowsProcessLauncher::DoFinishLaunch() {
1788 Result<Ok, LaunchError> err = BaseProcessLauncher::DoFinishLaunch();
1789 if (err.isErr()) {
1790 return err;
1793 return Ok();
1795 #endif // XP_WIN
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,
1806 mStartTimeStamp);
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));
1814 return true;
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;
1829 lock.Notify();
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();
1843 MOZ_ASSERT(env);
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.
1856 // See bug 1440207.
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);
1871 #endif
1873 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1874 bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector& aArgs) {
1875 MacSandboxInfo info;
1876 if (NS_WARN_IF(!FillMacSandboxInfo(info))) {
1877 return false;
1879 info.AppendAsParams(aArgs);
1880 return true;
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());
1894 return true;
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.
1907 /* static */
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;
1919 break;
1920 case GeckoProcessType_RDD:
1921 sandboxType = RDDProcessHost::GetMacSandboxType();
1922 break;
1923 case GeckoProcessType_Socket:
1924 sandboxType = net::SocketProcessHost::GetMacSandboxType();
1925 break;
1926 case GeckoProcessType_GMPlugin:
1927 sandboxType = gmp::GMPProcessParent::GetMacSandboxType();
1928 break;
1929 case GeckoProcessType_Utility:
1930 sandboxType = ipc::UtilityProcessHost::GetMacSandboxType();
1931 break;
1932 default:
1933 return true;
1936 return mozilla::StartMacSandboxIfEnabled(sandboxType, aArgc, aArgv,
1937 aErrorMessage);
1940 #endif /* XP_MACOSX && MOZ_SANDBOX */
1942 /* static */
1943 void GeckoChildProcessHost::GetAll(const GeckoProcessCallback& aCallback) {
1944 StaticMutexAutoLock lock(sMutex);
1945 if (!sGeckoChildProcessHosts) {
1946 return;
1948 for (GeckoChildProcessHost* gp = sGeckoChildProcessHosts->getFirst(); gp;
1949 gp = static_cast<mozilla::LinkedListElement<GeckoChildProcessHost>*>(gp)
1950 ->getNext()) {
1951 aCallback(gp);
1955 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::Launch(
1956 GeckoChildProcessHost* aHost) {
1957 AssertIOThread();
1959 // The ForkServer doesn't use IPC::Channel for communication, so we can skip
1960 // initializing it.
1961 if (mProcessType != GeckoProcessType_ForkServer) {
1962 IPC::Channel::ChannelHandle serverHandle;
1963 if (!IPC::Channel::CreateRawPipe(&serverHandle, &mClientChannelHandle)) {
1964 return ProcessLaunchPromise::CreateAndReject(LaunchError("CreateRawPipe"),
1965 __func__);
1967 aHost->InitializeChannel(std::move(serverHandle));
1970 return InvokeAsync(mLaunchThread, this, __func__,
1971 &BaseProcessLauncher::PerformAsyncLaunch);
1974 } // namespace ipc
1975 } // namespace mozilla