Bug 1440207 - Part 3d: Pass the initial IPC pipe using geckoargs, r=ipc-reviewers,mccr8

The initial IPC pipe was previously the only argument passed as a chromium
command line flag. This changes it to instead be passed using geckoargs,
unifying the platforms, and removing the need for specific handling on every
platform.

Differential Revision: https://phabricator.services.mozilla.com/D221374
This commit is contained in:
Nika Layzell 2024-10-01 22:21:49 +00:00
parent 3c8b71811d
commit fd1d20ea4b
14 changed files with 60 additions and 129 deletions

View File

@ -58,9 +58,10 @@ static nsresult GetGREDir(nsIFile** aResult) {
return NS_OK;
}
ContentProcess::ContentProcess(ProcessId aParentPid,
ContentProcess::ContentProcess(IPC::Channel::ChannelHandle aClientChannel,
ProcessId aParentPid,
const nsID& aMessageChannelId)
: ProcessChild(aParentPid, aMessageChannelId) {
: ProcessChild(std::move(aClientChannel), aParentPid, aMessageChannelId) {
NS_LogInit();
}

View File

@ -25,7 +25,8 @@ class ContentProcess : public mozilla::ipc::ProcessChild {
using ProcessChild = mozilla::ipc::ProcessChild;
public:
ContentProcess(ProcessId aParentPid, const nsID& aMessageChannelId);
ContentProcess(IPC::Channel::ChannelHandle aClientChannel,
ProcessId aParentPid, const nsID& aMessageChannelId);
~ContentProcess();
virtual bool Init(int aArgc, char* aArgv[]) override;

View File

@ -9,10 +9,13 @@
#include "chrome/common/child_process.h"
#include "mozilla/ipc/NodeController.h"
ChildThread::ChildThread(Thread::Options options, base::ProcessId parent_pid)
ChildThread::ChildThread(Thread::Options options,
IPC::Channel::ChannelHandle client_handle,
base::ProcessId parent_pid)
: Thread("IPC I/O Child"),
owner_loop_(MessageLoop::current()),
options_(options),
client_handle_(std::move(client_handle)),
parent_pid_(parent_pid) {
DCHECK(owner_loop_);
}
@ -31,10 +34,8 @@ ChildThread* ChildThread::current() {
void ChildThread::Init() {
// Take ownership of the client channel handle which we inherited, and use it
// to start the initial IPC connection to the parent process.
IPC::Channel::ChannelHandle client_handle(
IPC::Channel::GetClientChannelHandle());
auto channel = mozilla::MakeUnique<IPC::Channel>(
std::move(client_handle), IPC::Channel::MODE_CLIENT, parent_pid_);
std::move(client_handle_), IPC::Channel::MODE_CLIENT, parent_pid_);
#if defined(XP_WIN)
channel->StartAcceptingHandles(IPC::Channel::MODE_CLIENT);
#elif defined(XP_DARWIN)

View File

@ -19,7 +19,9 @@ class ResourceDispatcher;
class ChildThread : public base::Thread {
public:
// Creates the thread.
ChildThread(Thread::Options options, base::ProcessId parent_pid);
ChildThread(Thread::Options options,
IPC::Channel::ChannelHandle client_handle,
base::ProcessId parent_pid);
virtual ~ChildThread();
mozilla::ipc::ScopedPort TakeInitialPort() {
@ -48,6 +50,8 @@ class ChildThread : public base::Thread {
Thread::Options options_;
IPC::Channel::ChannelHandle client_handle_;
base::ProcessId parent_pid_;
DISALLOW_EVIL_CONSTRUCTORS(ChildThread);

View File

@ -142,18 +142,6 @@ class Channel {
void StartAcceptingHandles(Mode mode);
#endif
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
// Used to set the first IPC file descriptor in the child process on
// Android and iOS. See ipc_channel_posix.cc for further details on how this
// is used.
static void SetClientChannelFd(int fd);
#endif // defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
// Get the first IPC channel handle in the child process. This will have been
// set by SetClientChannelFd on Android, will be a constant on other unix
// platforms, or will have been passed on the command line on Windows.
static ChannelHandle::ElementType GetClientChannelHandle();
// Create a new pair of pipe endpoints which can be used to establish a
// native IPC::Channel connection.
static bool CreateRawPipe(ChannelHandle* server, ChannelHandle* client);

View File

@ -59,41 +59,9 @@ using namespace mozilla::ipc;
namespace IPC {
// IPC channels on Windows use named pipes (CreateNamedPipe()) with
// channel ids as the pipe names. Channels on POSIX use anonymous
// Unix domain sockets created via socketpair() as pipes. These don't
// quite line up.
//
// When creating a child subprocess, the parent side of the fork
// arranges it such that the initial control channel ends up on the
// magic file descriptor gClientChannelFd in the child. Future
// connections (file descriptors) can then be passed via that
// connection via sendmsg().
//
// On Android, child processes are created as a service instead of
// forking the parent process. The Android Binder service is used to
// transport the IPC channel file descriptor to the child process.
// So rather than re-mapping the file descriptor to a known value,
// the received channel file descriptor is set by calling
// SetClientChannelFd before gecko has been initialized and started
// in the child process.
//------------------------------------------------------------------------------
namespace {
// This is the file descriptor number that a client process expects to find its
// IPC socket.
static int gClientChannelFd =
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
// On android/ios the fd is set at the time of child creation.
-1
#else
3
#endif // defined(MOZ_WIDGET_ANDROID)
;
//------------------------------------------------------------------------------
bool ErrorIsBrokenPipe(int err) { return err == EPIPE || err == ECONNRESET; }
// Some Android ARM64 devices appear to have a bug where sendmsg
@ -135,12 +103,6 @@ static inline ssize_t corrected_sendmsg(int socket,
} // namespace
//------------------------------------------------------------------------------
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
void Channel::SetClientChannelFd(int fd) { gClientChannelFd = fd; }
#endif // defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
int Channel::GetClientChannelHandle() { return gClientChannelFd; }
Channel::ChannelImpl::ChannelImpl(ChannelHandle pipe, Mode mode,
base::ProcessId other_pid)
: chan_cap_("ChannelImpl::SendMutex",

View File

@ -755,16 +755,6 @@ void Channel::SetOtherPid(base::ProcessId other_pid) {
bool Channel::IsClosed() const { return channel_impl_->IsClosed(); }
HANDLE Channel::GetClientChannelHandle() {
// Read the switch from the command line which passed the initial handle for
// this process, and convert it back into a HANDLE.
std::wstring switchValue = CommandLine::ForCurrentProcess()->GetSwitchValue(
switches::kProcessChannelID);
uint32_t handleInt = std::stoul(switchValue);
return Uint32ToHandle(handleInt);
}
// static
bool Channel::CreateRawPipe(ChannelHandle* server, ChannelHandle* client) {
std::wstring pipe_name =

View File

@ -254,7 +254,6 @@ class BaseProcessLauncher {
char mChildIDString[32];
// Set during launch.
IPC::Channel::ChannelHandle mClientChannelHandle;
nsCOMPtr<nsIFile> mAppDir;
};
@ -287,16 +286,13 @@ class PosixProcessLauncher : public BaseProcessLauncher {
PosixProcessLauncher(GeckoChildProcessHost* aHost,
geckoargs::ChildProcessArgs&& aExtraOpts)
: BaseProcessLauncher(aHost, std::move(aExtraOpts)),
mProfileDir(aHost->mProfileDir),
mChannelDstFd(IPC::Channel::GetClientChannelHandle()) {}
mProfileDir(aHost->mProfileDir) {}
protected:
virtual Result<Ok, LaunchError> DoSetup() override;
virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
nsCOMPtr<nsIFile> mProfileDir;
int mChannelDstFd;
};
# if defined(XP_MACOSX)
@ -1173,11 +1169,11 @@ void BaseProcessLauncher::MapChildLogging() {
}
Result<Ok, LaunchError> BaseProcessLauncher::DoFinishLaunch() {
// We're in the parent and the child was launched. Close the child channel
// handle in the parent as soon as possible, which will allow the parent to
// detect when the child closes its handle (either due to normal exit or due
// to crash).
mClientChannelHandle = nullptr;
// We're in the parent and the child was launched. Clean up any FDs which were
// transferred to the child in the parent as soon as possible, which will
// allow the parent to detect when the child closes its handle (either due to
// normal exit or due to crash).
mChildArgs.mFiles.clear();
return Ok();
}
@ -1263,22 +1259,6 @@ Result<Ok, LaunchError> PosixProcessLauncher::DoSetup() {
FilePath exePath;
BinPathType pathType = GetPathToBinary(exePath, mProcessType);
// remap the IPC socket fd to a well-known int, as the OS does for
// STDOUT_FILENO, for example
// The fork server doesn't use IPC::Channel, so can skip this step.
if (mProcessType != GeckoProcessType_ForkServer) {
# if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT)
// On Android/iOS, mChannelDstFd is initialised to -1 and the launching
// code uses only the first of each pair.
MOZ_ASSERT(mChannelDstFd >= 0);
# endif
mLaunchOptions->fds_to_remap.push_back(
std::pair<int, int>(mClientChannelHandle.get(), mChannelDstFd));
}
// no need for kProcessChannelID, the child process inherits the
// other end of the socketpair() from us
// Make sure the executable path is present at the start of our argument list.
// If we're using BinPathType::Self, also add the `-contentproc` argument.
if (pathType == BinPathType::Self) {
@ -1587,16 +1567,8 @@ Result<Ok, LaunchError> WindowsProcessLauncher::DoSetup() {
}
# endif // HAS_DLL_BLOCKLIST
// Inherit the initial client channel handle into the child process.
std::wstring processChannelID =
std::to_wstring(uint32_t(uintptr_t(mClientChannelHandle.get())));
mLaunchOptions->handles_to_inherit.push_back(mClientChannelHandle.get());
mCmdLine->AppendSwitchWithValue(switches::kProcessChannelID,
processChannelID);
for (std::vector<std::string>::iterator it = mExtraOpts.begin();
it != mExtraOpts.end(); ++it) {
mCmdLine->AppendLooseValue(UTF8ToWide(*it));
for (const std::string& arg : mChildArgs.mArgs) {
mCmdLine->AppendLooseValue(UTF8ToWide(arg));
}
# if defined(MOZ_SANDBOX)
@ -1937,11 +1909,13 @@ RefPtr<ProcessLaunchPromise> BaseProcessLauncher::Launch(
// initializing it.
if (mProcessType != GeckoProcessType_ForkServer) {
IPC::Channel::ChannelHandle serverHandle;
if (!IPC::Channel::CreateRawPipe(&serverHandle, &mClientChannelHandle)) {
IPC::Channel::ChannelHandle clientHandle;
if (!IPC::Channel::CreateRawPipe(&serverHandle, &clientHandle)) {
return ProcessLaunchPromise::CreateAndReject(LaunchError("CreateRawPipe"),
__func__);
}
aHost->InitializeChannel(std::move(serverHandle));
geckoargs::sIPCHandle.Put(std::move(clientHandle), mChildArgs);
}
return InvokeAsync(mLaunchThread, this, __func__,

View File

@ -20,10 +20,11 @@ namespace ipc {
// IPC IO MessageLoop lives.
class IOThreadChild : public ChildThread {
public:
explicit IOThreadChild(base::ProcessId aParentPid)
explicit IOThreadChild(IPC::Channel::ChannelHandle aClientChannel,
base::ProcessId aParentPid)
: ChildThread(base::Thread::Options(MessageLoop::TYPE_IO,
/* stack size */ 0),
aParentPid) {}
std::move(aClientChannel), aParentPid) {}
~IOThreadChild() = default;

View File

@ -33,8 +33,9 @@ nsCString ProcessChild::gIPCShutdownStateAnnotation;
static Atomic<bool> sExpectingShutdown(false);
ProcessChild::ProcessChild(ProcessId aParentPid, const nsID& aMessageChannelId)
: ChildProcess(new IOThreadChild(aParentPid)),
ProcessChild::ProcessChild(IPC::Channel::ChannelHandle aClientChannel,
ProcessId aParentPid, const nsID& aMessageChannelId)
: ChildProcess(new IOThreadChild(std::move(aClientChannel), aParentPid)),
mUILoop(MessageLoop::current()),
mParentPid(aParentPid),
mMessageChannelId(aMessageChannelId) {

View File

@ -27,7 +27,8 @@ class ProcessChild : public ChildProcess {
typedef base::ProcessId ProcessId;
public:
explicit ProcessChild(ProcessId aParentPid, const nsID& aMessageChannelId);
explicit ProcessChild(IPC::Channel::ChannelHandle aClientChannel,
ProcessId aParentPid, const nsID& aMessageChannelId);
ProcessChild(const ProcessChild&) = delete;
ProcessChild& operator=(const ProcessChild&) = delete;

View File

@ -295,14 +295,15 @@ class IPDLUnitTestProcessChild : public ipc::ProcessChild {
// Defined in nsEmbedFunctions.cpp
extern UniquePtr<ipc::ProcessChild> (*gMakeIPDLUnitTestProcessChild)(
base::ProcessId, const nsID&);
IPC::Channel::ChannelHandle, base::ProcessId, const nsID&);
// Initialize gMakeIPDLUnitTestProcessChild in a static constructor.
int _childProcessEntryPointStaticConstructor = ([] {
gMakeIPDLUnitTestProcessChild =
[](base::ProcessId aParentPid,
[](IPC::Channel::ChannelHandle aClientChannel, base::ProcessId aParentPid,
const nsID& aMessageChannelId) -> UniquePtr<ipc::ProcessChild> {
return MakeUnique<IPDLUnitTestProcessChild>(aParentPid, aMessageChannelId);
return MakeUnique<IPDLUnitTestProcessChild>(std::move(aClientChannel),
aParentPid, aMessageChannelId);
};
return 0;
})();

View File

@ -148,6 +148,8 @@ static CommandLineArg<const char*> sGREOmni{"-greomni", "greomni"};
static CommandLineArg<const char*> sAppOmni{"-appomni", "appomni"};
static CommandLineArg<const char*> sProfile{"-profile", "profile"};
static CommandLineArg<UniqueFileHandle> sIPCHandle{"-ipcHandle", "ipchandle"};
static CommandLineArg<UniqueFileHandle> sJsInitHandle{"-jsInitHandle",
"jsinithandle"};
static CommandLineArg<uint64_t> sJsInitLen{"-jsInitLen", "jsinitlen"};

View File

@ -147,7 +147,7 @@ using mozilla::ipc::TestShellParent;
namespace mozilla::_ipdltest {
// Set in IPDLUnitTest.cpp when running gtests.
UniquePtr<mozilla::ipc::ProcessChild> (*gMakeIPDLUnitTestProcessChild)(
base::ProcessId, const nsID&) = nullptr;
IPC::Channel::ChannelHandle, base::ProcessId, const nsID&) = nullptr;
} // namespace mozilla::_ipdltest
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
@ -445,7 +445,9 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
Maybe<base::ProcessId> parentPID = geckoargs::sParentPid.Get(aArgc, aArgv);
Maybe<const char*> initialChannelIdString =
geckoargs::sInitialChannelID.Get(aArgc, aArgv);
if (NS_WARN_IF(!parentPID || !initialChannelIdString)) {
Maybe<IPC::Channel::ChannelHandle> clientChannel =
geckoargs::sIPCHandle.Get(aArgc, aArgv);
if (NS_WARN_IF(!parentPID || !initialChannelIdString || !clientChannel)) {
return NS_ERROR_FAILURE;
}
@ -520,50 +522,52 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
case GeckoProcessType_Content:
ioInterposerGuard.Init();
process = MakeUnique<ContentProcess>(*parentPID, messageChannelId);
process = MakeUnique<ContentProcess>(std::move(*clientChannel),
*parentPID, messageChannelId);
break;
case GeckoProcessType_IPDLUnitTest:
MOZ_RELEASE_ASSERT(mozilla::_ipdltest::gMakeIPDLUnitTestProcessChild,
"xul-gtest not loaded!");
process = mozilla::_ipdltest::gMakeIPDLUnitTestProcessChild(
*parentPID, messageChannelId);
std::move(*clientChannel), *parentPID, messageChannelId);
break;
case GeckoProcessType_GMPlugin:
process =
MakeUnique<gmp::GMPProcessChild>(*parentPID, messageChannelId);
process = MakeUnique<gmp::GMPProcessChild>(
std::move(*clientChannel), *parentPID, messageChannelId);
break;
case GeckoProcessType_GPU:
process =
MakeUnique<gfx::GPUProcessImpl>(*parentPID, messageChannelId);
process = MakeUnique<gfx::GPUProcessImpl>(
std::move(*clientChannel), *parentPID, messageChannelId);
break;
case GeckoProcessType_VR:
process =
MakeUnique<gfx::VRProcessChild>(*parentPID, messageChannelId);
process = MakeUnique<gfx::VRProcessChild>(
std::move(*clientChannel), *parentPID, messageChannelId);
break;
case GeckoProcessType_RDD:
process = MakeUnique<RDDProcessImpl>(*parentPID, messageChannelId);
process = MakeUnique<RDDProcessImpl>(std::move(*clientChannel),
*parentPID, messageChannelId);
break;
case GeckoProcessType_Socket:
ioInterposerGuard.Init();
process =
MakeUnique<net::SocketProcessImpl>(*parentPID, messageChannelId);
process = MakeUnique<net::SocketProcessImpl>(
std::move(*clientChannel), *parentPID, messageChannelId);
break;
case GeckoProcessType_Utility:
process =
MakeUnique<ipc::UtilityProcessImpl>(*parentPID, messageChannelId);
process = MakeUnique<ipc::UtilityProcessImpl>(
std::move(*clientChannel), *parentPID, messageChannelId);
break;
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
case GeckoProcessType_RemoteSandboxBroker:
process = MakeUnique<RemoteSandboxBrokerProcessChild>(
*parentPID, messageChannelId);
std::move(*clientChannel), *parentPID, messageChannelId);
break;
#endif