--- a/ipc/chromium/src/base/process_util.h
+++ b/ipc/chromium/src/base/process_util.h
@@ -90,56 +90,68 @@ ProcessId GetProcId(ProcessHandle proces
// TODO(agl): remove this function
// WARNING: do not use. It's inherently race-prone in the face of
// multi-threading.
void SetAllFDsToCloseOnExec();
// Close all file descriptors, expect those which are a destination in the
// given multimap. Only call this function in a child process where you know
// that there aren't any other threads.
void CloseSuperfluousFds(const base::InjectiveMultimap& saved_map);
+
+typedef std::vector<std::pair<int, int> > file_handle_mapping_vector;
+typedef std::map<std::string, std::string> environment_map;
#endif
+struct LaunchOptions {
+ // If true, wait for the process to terminate. Otherwise, return
+ // immediately.
+ bool wait = false;
+
+#if defined(OS_WIN)
+ bool start_hidden = false;
+#endif
+
+#if defined(OS_POSIX)
+ // Environment variables to be applied in addition to the current
+ // process's environment, replacing them where necessary.
+ environment_map environ;
+
+ // A mapping of (src fd -> dest fd) to propagate into the child
+ // process. All other fds will be closed, except std{in,out,err}.
+ file_handle_mapping_vector fds_to_remap;
+#endif
+};
+
#if defined(OS_WIN)
// Runs the given application name with the given command line. Normally, the
// first command line argument should be the path to the process, and don't
// forget to quote it.
//
-// If wait is true, it will block and wait for the other process to finish,
-// otherwise, it will just continue asynchronously.
-//
// Example (including literal quotes)
// cmdline = "c:\windows\explorer.exe" -foo "c:\bar\"
//
// If process_handle is non-NULL, the process handle of the launched app will be
// stored there on a successful launch.
// NOTE: In this case, the caller is responsible for closing the handle so
// that it doesn't leak!
bool LaunchApp(const std::wstring& cmdline,
- bool wait, bool start_hidden, ProcessHandle* process_handle);
+ const LaunchOptions& options,
+ ProcessHandle* process_handle);
+
#elif defined(OS_POSIX)
// Runs the application specified in argv[0] with the command line argv.
-// Before launching all FDs open in the parent process will be marked as
-// close-on-exec. |fds_to_remap| defines a mapping of src fd->dest fd to
-// propagate FDs into the child process.
//
-// As above, if wait is true, execute synchronously. The pid will be stored
-// in process_handle if that pointer is non-null.
+// The pid will be stored in process_handle if that pointer is
+// non-null.
//
// Note that the first argument in argv must point to the filename,
-// and must be fully specified.
-typedef std::vector<std::pair<int, int> > file_handle_mapping_vector;
+// and must be fully specified (i.e., this will not search $PATH).
bool LaunchApp(const std::vector<std::string>& argv,
- const file_handle_mapping_vector& fds_to_remap,
- bool wait, ProcessHandle* process_handle);
-
-typedef std::map<std::string, std::string> environment_map;
-bool LaunchApp(const std::vector<std::string>& argv,
- const file_handle_mapping_vector& fds_to_remap,
- const environment_map& env_vars_to_set,
- bool wait, ProcessHandle* process_handle);
+ const LaunchOptions& options,
+ ProcessHandle* process_handle);
// Deleter for the array of strings allocated within BuildEnvironmentArray.
struct FreeEnvVarsArray
{
void operator()(char** array);
};
typedef mozilla::UniquePtr<char*[], FreeEnvVarsArray> EnvironmentArray;
@@ -147,17 +159,18 @@ typedef mozilla::UniquePtr<char*[], Free
// Merge an environment map with the current environment.
// Existing variables are overwritten by env_vars_to_set.
EnvironmentArray BuildEnvironmentArray(const environment_map& env_vars_to_set);
#endif
// Executes the application specified by cl. This function delegates to one
// of the above two platform-specific functions.
bool LaunchApp(const CommandLine& cl,
- bool wait, bool start_hidden, ProcessHandle* process_handle);
+ const LaunchOptions&,
+ ProcessHandle* process_handle);
// Used to filter processes by process ID.
class ProcessFilter {
public:
// Returns true to indicate set-inclusion and false otherwise. This method
// should not have side-effects and should be idempotent.
virtual bool Includes(ProcessId pid, ProcessId parent_pid) const = 0;
virtual ~ProcessFilter() { }
--- a/ipc/chromium/src/base/process_util_bsd.cc
+++ b/ipc/chromium/src/base/process_util_bsd.cc
@@ -19,52 +19,44 @@
namespace {
static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
} // namespace
namespace base {
-bool LaunchApp(const std::vector<std::string>& argv,
- const file_handle_mapping_vector& fds_to_remap,
- bool wait, ProcessHandle* process_handle) {
- return LaunchApp(argv, fds_to_remap, environment_map(),
- wait, process_handle);
-}
bool LaunchApp(const std::vector<std::string>& argv,
- const file_handle_mapping_vector& fds_to_remap,
- const environment_map& env_vars_to_set,
- bool wait, ProcessHandle* process_handle) {
+ const LaunchOptions& options,
+ ProcessHandle* process_handle)
+{
bool retval = true;
char* argv_copy[argv.size() + 1];
for (size_t i = 0; i < argv.size(); i++) {
argv_copy[i] = const_cast<char*>(argv[i].c_str());
}
argv_copy[argv.size()] = NULL;
// Make sure we don't leak any FDs to the child process by marking all FDs
// as close-on-exec.
SetAllFDsToCloseOnExec();
- EnvironmentArray vars = BuildEnvironmentArray(env_vars_to_set);
+ EnvironmentArray vars = BuildEnvironmentArray(options.environ);
posix_spawn_file_actions_t file_actions;
if (posix_spawn_file_actions_init(&file_actions) != 0) {
return false;
}
// Turn fds_to_remap array into a set of dup2 calls.
- for (file_handle_mapping_vector::const_iterator it = fds_to_remap.begin();
- it != fds_to_remap.end();
- ++it) {
- int src_fd = it->first;
- int dest_fd = it->second;
+ for (const auto& fd_map : options.fds_to_remap) {
+ int src_fd = fd_map.first;
+ int dest_fd = fd_map.second;
if (src_fd == dest_fd) {
int flags = fcntl(src_fd, F_GETFD);
if (flags != -1) {
fcntl(src_fd, F_SETFD, flags & ~FD_CLOEXEC);
}
} else {
if (posix_spawn_file_actions_adddup2(&file_actions, src_fd, dest_fd) != 0) {
@@ -85,26 +77,25 @@ bool LaunchApp(const std::vector<std::st
posix_spawn_file_actions_destroy(&file_actions);
bool process_handle_valid = pid > 0;
if (!spawn_succeeded || !process_handle_valid) {
retval = false;
} else {
gProcessLog.print("==> process %d launched child process %d\n",
GetCurrentProcId(), pid);
- if (wait)
+ if (options.wait)
HANDLE_EINTR(waitpid(pid, 0, 0));
if (process_handle)
*process_handle = pid;
}
return retval;
}
bool LaunchApp(const CommandLine& cl,
- bool wait, bool start_hidden, ProcessHandle* process_handle) {
- // TODO(playmobil): Do we need to respect the start_hidden flag?
- file_handle_mapping_vector no_files;
- return LaunchApp(cl.argv(), no_files, wait, process_handle);
+ const LaunchOptions& options,
+ ProcessHandle* process_handle) {
+ return LaunchApp(cl.argv(), options, process_handle);
}
} // namespace base
--- a/ipc/chromium/src/base/process_util_linux.cc
+++ b/ipc/chromium/src/base/process_util_linux.cc
@@ -20,43 +20,36 @@ namespace {
static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
} // namespace
namespace base {
bool LaunchApp(const std::vector<std::string>& argv,
- const file_handle_mapping_vector& fds_to_remap,
- bool wait, ProcessHandle* process_handle) {
- return LaunchApp(argv, fds_to_remap, environment_map(),
- wait, process_handle);
-}
-
-bool LaunchApp(const std::vector<std::string>& argv,
- const file_handle_mapping_vector& fds_to_remap,
- const environment_map& env_vars_to_set,
- bool wait, ProcessHandle* process_handle) {
+ const LaunchOptions& options,
+ ProcessHandle* process_handle)
+{
mozilla::UniquePtr<char*[]> argv_cstr(new char*[argv.size() + 1]);
// Illegal to allocate memory after fork and before execvp
InjectiveMultimap fd_shuffle1, fd_shuffle2;
- fd_shuffle1.reserve(fds_to_remap.size());
- fd_shuffle2.reserve(fds_to_remap.size());
+ fd_shuffle1.reserve(options.fds_to_remap.size());
+ fd_shuffle2.reserve(options.fds_to_remap.size());
- EnvironmentArray envp = BuildEnvironmentArray(env_vars_to_set);
+ EnvironmentArray envp = BuildEnvironmentArray(options.environ);
pid_t pid = fork();
if (pid < 0)
return false;
if (pid == 0) {
- for (file_handle_mapping_vector::const_iterator
- it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
- fd_shuffle1.push_back(InjectionArc(it->first, it->second, false));
- fd_shuffle2.push_back(InjectionArc(it->first, it->second, false));
+ // In the child:
+ for (const auto& fd_map : options.fds_to_remap) {
+ fd_shuffle1.push_back(InjectionArc(fd_map.first, fd_map.second, false));
+ fd_shuffle2.push_back(InjectionArc(fd_map.first, fd_map.second, false));
}
if (!ShuffleFileDescriptors(&fd_shuffle1))
_exit(127);
CloseSuperfluousFds(fd_shuffle2);
for (size_t i = 0; i < argv.size(); i++)
@@ -64,29 +57,29 @@ bool LaunchApp(const std::vector<std::st
argv_cstr[argv.size()] = NULL;
execve(argv_cstr[0], argv_cstr.get(), envp.get());
// if we get here, we're in serious trouble and should complain loudly
// NOTE: This is async signal unsafe; it could deadlock instead. (But
// only on debug builds; otherwise it's a signal-safe no-op.)
DLOG(ERROR) << "FAILED TO exec() CHILD PROCESS, path: " << argv_cstr[0];
_exit(127);
- } else {
- gProcessLog.print("==> process %d launched child process %d\n",
- GetCurrentProcId(), pid);
- if (wait)
- HANDLE_EINTR(waitpid(pid, 0, 0));
+ }
- if (process_handle)
- *process_handle = pid;
- }
+ // In the parent:
+ gProcessLog.print("==> process %d launched child process %d\n",
+ GetCurrentProcId(), pid);
+ if (options.wait)
+ HANDLE_EINTR(waitpid(pid, 0, 0));
+
+ if (process_handle)
+ *process_handle = pid;
return true;
}
bool LaunchApp(const CommandLine& cl,
- bool wait, bool start_hidden,
+ const LaunchOptions& options,
ProcessHandle* process_handle) {
- file_handle_mapping_vector no_files;
- return LaunchApp(cl.argv(), no_files, wait, process_handle);
+ return LaunchApp(cl.argv(), options, process_handle);
}
} // namespace base
--- a/ipc/chromium/src/base/process_util_mac.mm
+++ b/ipc/chromium/src/base/process_util_mac.mm
@@ -1,13 +1,14 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-
#include "base/process_util.h"
#include <fcntl.h>
#include <spawn.h>
#include <sys/wait.h>
#include <string>
@@ -19,63 +20,55 @@ namespace {
static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
} // namespace
namespace base {
bool LaunchApp(const std::vector<std::string>& argv,
- const file_handle_mapping_vector& fds_to_remap,
- bool wait, ProcessHandle* process_handle) {
- return LaunchApp(argv, fds_to_remap, environment_map(),
- wait, process_handle);
-}
-
-bool LaunchApp(const std::vector<std::string>& argv,
- const file_handle_mapping_vector& fds_to_remap,
- const environment_map& env_vars_to_set,
- bool wait, ProcessHandle* process_handle) {
+ const LaunchOptions& options,
+ ProcessHandle* process_handle)
+{
bool retval = true;
char* argv_copy[argv.size() + 1];
for (size_t i = 0; i < argv.size(); i++) {
argv_copy[i] = const_cast<char*>(argv[i].c_str());
}
argv_copy[argv.size()] = NULL;
- EnvironmentArray vars = BuildEnvironmentArray(env_vars_to_set);
+ EnvironmentArray vars = BuildEnvironmentArray(options.environ);
posix_spawn_file_actions_t file_actions;
if (posix_spawn_file_actions_init(&file_actions) != 0) {
return false;
}
auto file_actions_guard = mozilla::MakeScopeExit([&file_actions] {
posix_spawn_file_actions_destroy(&file_actions);
});
// Turn fds_to_remap array into a set of dup2 calls.
- for (file_handle_mapping_vector::const_iterator it = fds_to_remap.begin();
- it != fds_to_remap.end();
- ++it) {
- int src_fd = it->first;
- int dest_fd = it->second;
+ for (const auto& fd_map : options.fds_to_remap) {
+ int src_fd = fd_map.first;
+ int dest_fd = fd_map.second;
if (src_fd == dest_fd) {
int flags = fcntl(src_fd, F_GETFD);
if (flags != -1) {
fcntl(src_fd, F_SETFD, flags & ~FD_CLOEXEC);
}
} else {
if (posix_spawn_file_actions_adddup2(&file_actions, src_fd, dest_fd) != 0) {
return false;
}
}
}
+ // Initialize spawn attributes.
posix_spawnattr_t spawnattr;
if (posix_spawnattr_init(&spawnattr) != 0) {
return false;
}
auto spawnattr_guard = mozilla::MakeScopeExit([&spawnattr] {
posix_spawnattr_destroy(&spawnattr);
});
@@ -102,26 +95,25 @@ bool LaunchApp(const std::vector<std::st
vars.get()) == 0);
bool process_handle_valid = pid > 0;
if (!spawn_succeeded || !process_handle_valid) {
retval = false;
} else {
gProcessLog.print("==> process %d launched child process %d\n",
GetCurrentProcId(), pid);
- if (wait)
+ if (options.wait)
HANDLE_EINTR(waitpid(pid, 0, 0));
if (process_handle)
*process_handle = pid;
}
return retval;
}
bool LaunchApp(const CommandLine& cl,
- bool wait, bool start_hidden, ProcessHandle* process_handle) {
- // TODO(playmobil): Do we need to respect the start_hidden flag?
- file_handle_mapping_vector no_files;
- return LaunchApp(cl.argv(), no_files, wait, process_handle);
+ const LaunchOptions& options,
+ ProcessHandle* process_handle) {
+ return LaunchApp(cl.argv(), options, process_handle);
}
} // namespace base
--- a/ipc/chromium/src/base/process_util_win.cc
+++ b/ipc/chromium/src/base/process_util_win.cc
@@ -267,34 +267,35 @@ fail:
void FreeThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList) {
// must be impossible to get a NULL DeleteProcThreadAttributeListPtr, as
// we already checked it existed when creating the data we are now freeing.
(*DeleteProcThreadAttributeListPtr)(lpAttributeList);
free(lpAttributeList);
}
bool LaunchApp(const std::wstring& cmdline,
- bool wait, bool start_hidden, ProcessHandle* process_handle) {
+ const LaunchOptions& options,
+ ProcessHandle* process_handle) {
// We want to inherit the std handles so dump() statements and assertion
// messages in the child process can be seen - but we *do not* want to
// blindly have all handles inherited. Vista and later has a technique
// where only specified handles are inherited - so we use this technique.
// If that fails we just don't inherit anything.
DWORD dwCreationFlags = 0;
BOOL bInheritHandles = FALSE;
// We use a STARTUPINFOEX, but if we can't do the thread attribute thing, we
// just pass the size of a STARTUPINFO.
STARTUPINFOEX startup_info_ex;
ZeroMemory(&startup_info_ex, sizeof(startup_info_ex));
STARTUPINFO &startup_info = startup_info_ex.StartupInfo;
startup_info.cb = sizeof(startup_info);
startup_info.dwFlags = STARTF_USESHOWWINDOW;
- startup_info.wShowWindow = start_hidden ? SW_HIDE : SW_SHOW;
+ startup_info.wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW;
// Per the comment in CreateThreadAttributeList, lpAttributeList will contain
// a pointer to handlesToInherit, so make sure they have the same lifetime.
LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL;
HANDLE handlesToInherit[2];
int handleCount = 0;
// setup our handle array first - if we end up with no handles that can
@@ -335,32 +336,32 @@ bool LaunchApp(const std::wstring& cmdli
gProcessLog.print("==> process %d launched child process %d (%S)\n",
GetCurrentProcId(),
process_info.dwProcessId,
cmdline.c_str());
// Handles must be closed or they will leak
CloseHandle(process_info.hThread);
- if (wait)
+ if (options.wait)
WaitForSingleObject(process_info.hProcess, INFINITE);
// If the caller wants the process handle, we won't close it.
if (process_handle) {
*process_handle = process_info.hProcess;
} else {
CloseHandle(process_info.hProcess);
}
return true;
}
bool LaunchApp(const CommandLine& cl,
- bool wait, bool start_hidden, ProcessHandle* process_handle) {
- return LaunchApp(cl.command_line_string(), wait,
- start_hidden, process_handle);
+ const LaunchOptions& options,
+ ProcessHandle* process_handle) {
+ return LaunchApp(cl.command_line_string(), options, process_handle);
}
bool KillProcess(ProcessHandle process, int exit_code, bool wait) {
bool result = (TerminateProcess(process, exit_code) != FALSE);
if (result && wait) {
// The process may not end immediately due to pending I/O
if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000))
DLOG(ERROR) << "Error waiting for process exit: " << GetLastError();
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -81,16 +81,17 @@ ShouldHaveDirectoryService()
return GeckoProcessType_Default == XRE_GetProcessType();
}
GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
bool aIsFileContent)
: mProcessType(aProcessType),
mIsFileContent(aIsFileContent),
mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
+ mLaunchOptions(MakeUnique<base::LaunchOptions>()),
mProcessState(CREATING_CHANNEL),
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
mEnableSandboxLogging(false),
mSandboxLevel(0),
#endif
mChildProcessHandle(0)
#if defined(MOZ_WIDGET_COCOA)
, mChildTask(MACH_PORT_NULL)
@@ -637,27 +638,26 @@ GeckoChildProcessHost::PerformAsyncLaunc
#if defined(OS_POSIX)
// For POSIX, we have to be extremely anal about *not* using
// std::wstring in code compiled with Mozilla's -fshort-wchar
// configuration, because chromium is compiled with -fno-short-wchar
// and passing wstrings from one config to the other is unsafe. So
// we split the logic here.
# if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD) || defined(OS_SOLARIS)
- base::environment_map newEnvVars;
# if defined(MOZ_WIDGET_GTK)
if (mProcessType == GeckoProcessType_Content) {
// disable IM module to avoid sandbox violation
- newEnvVars["GTK_IM_MODULE"] = "gtk-im-context-simple";
+ mLaunchOptions->environ["GTK_IM_MODULE"] = "gtk-im-context-simple";
// Disable ATK accessibility code in content processes because it conflicts
// with the sandbox, and we proxy that information through the main process
// anyway.
- newEnvVars["NO_AT_BRIDGE"] = "1";
+ mLaunchOptions->environ["NO_AT_BRIDGE"] = "1";
}
# endif // defined(MOZ_WIDGET_GTK)
// XPCOM may not be initialized in some subprocesses. We don't want
// to initialize XPCOM just for the directory service, especially
// since LD_LIBRARY_PATH is already set correctly in subprocesses
// (meaning that we don't need to set that up in the environment).
if (ShouldHaveDirectoryService()) {
@@ -673,20 +673,20 @@ GeckoChildProcessHost::PerformAsyncLaunc
new_ld_lib_path.AppendLiteral("/gtk2:");
new_ld_lib_path.Append(path.get());
}
# endif // (MOZ_WIDGET_GTK == 3)
if (ld_library_path && *ld_library_path) {
new_ld_lib_path.Append(':');
new_ld_lib_path.Append(ld_library_path);
}
- newEnvVars["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
+ mLaunchOptions->environ["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
# elif OS_MACOSX // defined(OS_LINUX) || defined(OS_BSD)
- newEnvVars["DYLD_LIBRARY_PATH"] = path.get();
+ mLaunchOptions->environ["DYLD_LIBRARY_PATH"] = path.get();
// XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin
// process, and has no effect on other subprocesses (the hooks in
// libplugin_child_interpose.dylib become noops). But currently it
// gets set when launching any kind of subprocess.
//
// Trigger "dyld interposing" for the dylib that contains
// plugin_child_interpose.mm. This allows us to hook OS calls in the
// plugin process (ones that don't work correctly in a background
@@ -695,17 +695,17 @@ GeckoChildProcessHost::PerformAsyncLaunc
const char* prevInterpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
nsCString interpose;
if (prevInterpose && strlen(prevInterpose) > 0) {
interpose.Assign(prevInterpose);
interpose.Append(':');
}
interpose.Append(path.get());
interpose.AppendLiteral("/libplugin_child_interpose.dylib");
- newEnvVars["DYLD_INSERT_LIBRARIES"] = interpose.get();
+ mLaunchOptions->environ["DYLD_INSERT_LIBRARIES"] = interpose.get();
# endif // defined(OS_LINUX) || defined(OS_BSD)
}
# endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD) || defined(OS_SOLARIS)
FilePath exePath;
BinaryPathType pathType = GetPathToBinary(exePath, mProcessType);
# if defined(XP_LINUX) && defined(MOZ_SANDBOX)
@@ -720,25 +720,26 @@ GeckoChildProcessHost::PerformAsyncLaunc
preload.AssignLiteral("libmozsandbox.so");
if (const char* oldPreload = PR_GetEnv("LD_PRELOAD")) {
// Doesn't matter if oldPreload is ""; extra separators are ignored.
preload.Append(' ');
preload.Append(oldPreload);
}
// Explicitly construct the std::string to make it clear that this
// isn't retaining a pointer to the nsCString's buffer.
- newEnvVars["LD_PRELOAD"] = std::string(preload.get());
+ mLaunchOptions->environ["LD_PRELOAD"] = std::string(preload.get());
}
# endif // defined(XP_LINUX) && defined(MOZ_SANDBOX)
// remap the IPC socket fd to a well-known int, as the OS does for
// STDOUT_FILENO, for example
int srcChannelFd, dstChannelFd;
channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd);
- mFileMap.push_back(std::pair<int,int>(srcChannelFd, dstChannelFd));
+ mLaunchOptions->fds_to_remap
+ .push_back(std::pair<int,int>(srcChannelFd, dstChannelFd));
// no need for kProcessChannelID, the child process inherits the
// other end of the socketpair() from us
std::vector<std::string> childArgv;
childArgv.push_back(exePath.value());
@@ -785,17 +786,18 @@ GeckoChildProcessHost::PerformAsyncLaunc
# if defined(MOZ_CRASHREPORTER)
# if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
int childCrashFd, childCrashRemapFd;
if (!CrashReporter::CreateNotificationPipeForChild(
&childCrashFd, &childCrashRemapFd))
return false;
if (0 <= childCrashFd) {
- mFileMap.push_back(std::pair<int,int>(childCrashFd, childCrashRemapFd));
+ mLaunchOptions->fds_to_remap
+ .push_back(std::pair<int,int>(childCrashFd, childCrashRemapFd));
// "true" == crash reporting enabled
childArgv.push_back("true");
}
else {
// "false" == crash reporting disabled
childArgv.push_back("false");
}
# elif defined(MOZ_WIDGET_COCOA) // defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
@@ -803,17 +805,17 @@ GeckoChildProcessHost::PerformAsyncLaunc
# endif // defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
# endif // defined(MOZ_CRASHREPORTER)
# if defined(XP_LINUX) && defined(MOZ_SANDBOX)
{
int srcFd, dstFd;
SandboxReporter::Singleton()
->GetClientFileDescriptorMapping(&srcFd, &dstFd);
- mFileMap.push_back(std::make_pair(srcFd, dstFd));
+ mLaunchOptions->fds_to_remap.push_back(std::make_pair(srcFd, dstFd));
}
# endif // defined(XP_LINUX) && defined(MOZ_SANDBOX)
# ifdef MOZ_WIDGET_COCOA
// Add a mach port to the command line so the child can communicate its
// 'task_t' back to the parent.
//
// Put a random number into the channel name, so that a compromised renderer
@@ -821,23 +823,20 @@ GeckoChildProcessHost::PerformAsyncLaunc
std::string mach_connection_name = StringPrintf("org.mozilla.machname.%d",
base::RandInt(0, std::numeric_limits<int>::max()));
childArgv.push_back(mach_connection_name.c_str());
# endif // MOZ_WIDGET_COCOA
childArgv.push_back(childProcessType);
# if defined(MOZ_WIDGET_ANDROID)
- LaunchAndroidService(childProcessType, childArgv, mFileMap, &process);
+ LaunchAndroidService(childProcessType, childArgv,
+ mLaunchOptions->fds_to_remap, &process);
# else // goes with defined(MOZ_WIDGET_ANDROID)
- base::LaunchApp(childArgv, mFileMap,
-# if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD) || defined(OS_SOLARIS)
- newEnvVars,
-# endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD) || defined(OS_SOLARIS)
- false, &process);
+ base::LaunchApp(childArgv, *mLaunchOptions, &process);
# endif // defined(MOZ_WIDGET_ANDROID)
// We're in the parent and the child was launched. Close the child FD in the
// parent as soon as possible, which will allow the parent to detect when the
// child closes its FD (either due to normal exit or due to crash).
GetChannel()->CloseClientFileDescriptor();
# ifdef MOZ_WIDGET_COCOA
@@ -1060,17 +1059,17 @@ GeckoChildProcessHost::PerformAsyncLaunc
EnvironmentLog("MOZ_PROCESS_LOG").print(
"==> process %d launched child process %d (%S)\n",
base::GetCurrentProcId(), base::GetProcId(process),
cmdLine.command_line_string().c_str());
}
} else
# endif // defined(XP_WIN) && defined(MOZ_SANDBOX)
{
- base::LaunchApp(cmdLine, false, false, &process);
+ base::LaunchApp(cmdLine, *mLaunchOptions, &process);
# ifdef MOZ_SANDBOX
// We need to be able to duplicate handles to some types of non-sandboxed
// child processes.
if (mProcessType == GeckoProcessType_Content ||
mProcessType == GeckoProcessType_GPU ||
mProcessType == GeckoProcessType_GMPlugin) {
if (!mSandboxBroker.AddTargetPeer(process)) {
@@ -1107,16 +1106,17 @@ GeckoChildProcessHost::PerformAsyncLaunc
#endif // XP_WIN
) {
MOZ_CRASH("cannot open handle to child process");
}
MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_CREATED;
lock.Notify();
+ mLaunchOptions = nullptr;
return true;
}
bool
GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid)
{
if (mChildProcessHandle) {
MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
--- a/ipc/glue/GeckoChildProcessHost.h
+++ b/ipc/glue/GeckoChildProcessHost.h
@@ -11,16 +11,17 @@
#include "base/process_util.h"
#include "base/waitable_event.h"
#include "chrome/common/child_process_host.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/ipc/FileDescriptor.h"
#include "mozilla/Monitor.h"
#include "mozilla/StaticPtr.h"
+#include "mozilla/UniquePtr.h"
#include "nsCOMPtr.h"
#include "nsXULAppAPI.h" // for GeckoProcessType
#include "nsString.h"
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
#include "sandboxBroker.h"
#endif
@@ -113,16 +114,21 @@ public:
static void EnableSameExecutableForContentProc() { sRunSelfAsContentProc = true; }
protected:
GeckoProcessType mProcessType;
bool mIsFileContent;
Monitor mMonitor;
FilePath mProcessPath;
+ // GeckoChildProcessHost holds the launch options so they can be set
+ // up on the main thread using main-thread-only APIs like prefs, and
+ // then used for the actual launch on another thread. This pointer
+ // is set to null to free the options after the child is launched.
+ UniquePtr<base::LaunchOptions> mLaunchOptions;
// This value must be accessed while holding mMonitor.
enum {
// This object has been constructed, but the OS process has not
// yet.
CREATING_CHANNEL = 0,
// The IPC channel for our subprocess has been created, but the OS
// process has still not been created.
@@ -147,20 +153,16 @@ protected:
#ifdef MOZ_SANDBOX
SandboxBroker mSandboxBroker;
std::vector<std::wstring> mAllowedFilesRead;
bool mEnableSandboxLogging;
int32_t mSandboxLevel;
#endif
#endif // XP_WIN
-#if defined(OS_POSIX)
- base::file_handle_mapping_vector mFileMap;
-#endif
-
ProcessHandle mChildProcessHandle;
#if defined(OS_MACOSX)
task_t mChildTask;
#endif
bool OpenPrivilegedHandle(base::ProcessId aPid);
private:
--- a/widget/LSBUtils.cpp
+++ b/widget/LSBUtils.cpp
@@ -29,24 +29,24 @@ GetLSBRelease(nsACString& aDistributor,
NS_WARNING("pipe() failed!");
return false;
}
std::vector<std::string> argv = {
gLsbReleasePath, "-idrc"
};
- std::vector<std::pair<int, int>> fdMap = {
- { pipefd[1], STDOUT_FILENO }
- };
+ base::LaunchOptions options;
+ options.fds_to_remap.push_back({ pipefd[1], STDOUT_FILENO });
+ options.wait = true;
base::ProcessHandle process;
- base::LaunchApp(argv, fdMap, true, &process);
+ bool ok = base::LaunchApp(argv, options, &process);
close(pipefd[1]);
- if (!process) {
+ if (!ok) {
NS_WARNING("Failed to spawn lsb_release!");
close(pipefd[0]);
return false;
}
FILE* stream = fdopen(pipefd[0], "r");
if (!stream) {
NS_WARNING("Could not wrap fd!");
--- a/xpcom/threads/nsProcessCommon.cpp
+++ b/xpcom/threads/nsProcessCommon.cpp
@@ -571,23 +571,23 @@ nsProcess::RunProcess(bool aBlocking, ch
mPid = static_cast<int32_t>(newPid);
posix_spawnattr_destroy(&spawnattr);
if (result != 0) {
return NS_ERROR_FAILURE;
}
#elif defined(XP_UNIX)
- base::file_handle_mapping_vector fdMap;
+ base::LaunchOptions options;
std::vector<std::string> argvVec;
for (char** arg = aMyArgv; *arg != nullptr; ++arg) {
argvVec.push_back(*arg);
}
pid_t newPid;
- if (base::LaunchApp(argvVec, fdMap, false, &newPid)) {
+ if (base::LaunchApp(argvVec, options, &newPid)) {
static_assert(sizeof(pid_t) <= sizeof(int32_t),
"mPid is large enough to hold a pid");
mPid = static_cast<int32_t>(newPid);
} else {
return NS_ERROR_FAILURE;
}
#else
mProcess = PR_CreateProcess(aMyArgv[0], aMyArgv, nullptr, nullptr);