Simplify ChildProcess init by removing ChildProcessHostBootstrap interface
Before this CL, the child process start-up flow went like this: 1.) Browser would create a Mojo invitation, with a mojom::ChildProcess receiver, that ChildThreadImpl would recover and bind. 2.) ChildThreadImpl immediately creates a remote for its ChildProcessHost so it can start queueing messages for the browser process, even though it is not bound to the browser. 3.) ChildThreadImpl asynchronously waits for ChildProcess::Initialize to be invoked by the browser process; this supplies a remote for mojom::ChildProcessHostBootstrap, which the child process uses to send the receiver for the remote created in (1). 4.) Browser receives this, binding it to either RenderProcessHostImpl::io_thread_host_impl_ or ChildProcessHostImpl In short, there's an awkward dance that has to be done between the browser <-> renderer ((3) above), so that they can both immediately initialize remotes for each other. This CL removes the extra IPC round trip by removing ChildProcessHostBootstrap, and steps (3) & (4) above. This is done by attaching a second message pipe to the mojo invitation corresponding to the ChildProcessHost receiver, so the child process has it immediately on init. At this point, the child process can create a remote for the ChildProcessHost, and immediately bind it to the pipe which is bound to the browser process's ChildProcessHost receiver. Bug: N/A R=haraken@chromium.org,rockot@google.com Change-Id: I8f7b4b698b82e25d1c5c991c9639e57de05a6360 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2393158 Reviewed-by: Ken Rockot <rockot@google.com> Reviewed-by: Matt Falkenhagen <falken@chromium.org> Reviewed-by: Martin Barbella <mbarbella@chromium.org> Reviewed-by: Tal Pressman <talp@chromium.org> Reviewed-by: Kentaro Hara <haraken@chromium.org> Commit-Queue: Dominic Farolino <dom@chromium.org> Cr-Commit-Position: refs/heads/master@{#805037}
This commit is contained in:

committed by
Commit Bot

parent
363d1da56b
commit
1f77378d5e
content
tools/ipc_fuzzer/message_replay
@ -28,8 +28,6 @@ using testing::WithArgs;
|
||||
|
||||
class MockChildProcess : public mojom::ChildProcess {
|
||||
public:
|
||||
MOCK_METHOD1(Initialize,
|
||||
void(mojo::PendingRemote<mojom::ChildProcessHostBootstrap>));
|
||||
MOCK_METHOD0(ProcessShutdown, void());
|
||||
MOCK_METHOD1(GetTaskPort, void(GetTaskPortCallback));
|
||||
#if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
|
||||
|
@ -143,6 +143,7 @@
|
||||
#include "content/browser/webui/web_ui_controller_factory_registry.h"
|
||||
#include "content/common/child_process.mojom.h"
|
||||
#include "content/common/child_process_host_impl.h"
|
||||
#include "content/common/content_constants_internal.h"
|
||||
#include "content/common/content_switches_internal.h"
|
||||
#include "content/common/frame_messages.h"
|
||||
#include "content/common/in_process_child_thread_params.h"
|
||||
@ -1304,28 +1305,19 @@ void InvokeBadMojoMessageCallbackForTesting(int render_process_id,
|
||||
// |mojom::ChildProcessHost| interface. This exists to allow the process host
|
||||
// to bind incoming receivers on the IO-thread without a main-thread hop if
|
||||
// necessary. Also owns the RPHI's |mojom::ChildProcess| remote.
|
||||
class RenderProcessHostImpl::IOThreadHostImpl
|
||||
: public mojom::ChildProcessHostBootstrap,
|
||||
public mojom::ChildProcessHost {
|
||||
class RenderProcessHostImpl::IOThreadHostImpl : public mojom::ChildProcessHost {
|
||||
public:
|
||||
IOThreadHostImpl(int render_process_id,
|
||||
base::WeakPtr<RenderProcessHostImpl> weak_host,
|
||||
std::unique_ptr<service_manager::BinderRegistry> binders,
|
||||
mojo::PendingReceiver<mojom::ChildProcessHostBootstrap>
|
||||
bootstrap_receiver)
|
||||
mojo::PendingReceiver<mojom::ChildProcessHost> host_receiver)
|
||||
: render_process_id_(render_process_id),
|
||||
weak_host_(std::move(weak_host)),
|
||||
binders_(std::move(binders)),
|
||||
bootstrap_receiver_(this, std::move(bootstrap_receiver)) {}
|
||||
receiver_(this, std::move(host_receiver)) {}
|
||||
~IOThreadHostImpl() override = default;
|
||||
|
||||
private:
|
||||
// mojom::ChildProcessHostBootstrap implementation:
|
||||
void BindProcessHost(
|
||||
mojo::PendingReceiver<mojom::ChildProcessHost> receiver) override {
|
||||
receiver_.Bind(std::move(receiver));
|
||||
}
|
||||
|
||||
// mojom::ChildProcessHost implementation:
|
||||
void BindHostReceiver(mojo::GenericPendingReceiver receiver) override {
|
||||
const auto& interceptor = GetBindHostReceiverInterceptor();
|
||||
@ -1394,7 +1386,6 @@ class RenderProcessHostImpl::IOThreadHostImpl
|
||||
const int render_process_id_;
|
||||
const base::WeakPtr<RenderProcessHostImpl> weak_host_;
|
||||
std::unique_ptr<service_manager::BinderRegistry> binders_;
|
||||
mojo::Receiver<mojom::ChildProcessHostBootstrap> bootstrap_receiver_;
|
||||
mojo::Receiver<mojom::ChildProcessHost> receiver_{this};
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(IOThreadHostImpl);
|
||||
@ -1907,8 +1898,15 @@ void RenderProcessHostImpl::InitializeChannelProxy() {
|
||||
// process.
|
||||
mojo_invitation_ = {};
|
||||
child_process_.reset();
|
||||
child_process_.Bind(mojo::PendingRemote<mojom::ChildProcess>(
|
||||
mojo_invitation_.AttachMessagePipe(0), /*version=*/0));
|
||||
mojo::PendingRemote<mojom::ChildProcess> child_pending_remote(
|
||||
mojo_invitation_.AttachMessagePipe(kChildProcessReceiverAttachmentName),
|
||||
/*version=*/0);
|
||||
child_process_.Bind(std::move(child_pending_remote));
|
||||
|
||||
// We'll bind this receiver to |io_thread_host_impl_| when it is created.
|
||||
child_host_pending_receiver_ = mojo::PendingReceiver<mojom::ChildProcessHost>(
|
||||
mojo_invitation_.AttachMessagePipe(
|
||||
kChildProcessHostRemoteAttachmentName));
|
||||
|
||||
// Bootstrap the IPC Channel.
|
||||
mojo::PendingRemote<IPC::mojom::ChannelBootstrap> bootstrap;
|
||||
@ -2553,11 +2551,10 @@ void RenderProcessHostImpl::RegisterMojoInterfaces() {
|
||||
GetContentClient()->browser()->ExposeInterfacesToRenderer(
|
||||
registry.get(), associated_interfaces_.get(), this);
|
||||
|
||||
mojo::PendingRemote<mojom::ChildProcessHostBootstrap> bootstrap_remote;
|
||||
DCHECK(child_host_pending_receiver_);
|
||||
io_thread_host_impl_.emplace(
|
||||
GetIOThreadTaskRunner({}), GetID(), instance_weak_factory_->GetWeakPtr(),
|
||||
std::move(registry), bootstrap_remote.InitWithNewPipeAndPassReceiver());
|
||||
child_process_->Initialize(std::move(bootstrap_remote));
|
||||
std::move(registry), std::move(child_host_pending_receiver_));
|
||||
}
|
||||
|
||||
void RenderProcessHostImpl::BindRouteProvider(
|
||||
|
@ -1171,6 +1171,8 @@ class CONTENT_EXPORT RenderProcessHostImpl
|
||||
std::unique_ptr<PluginRegistryImpl> plugin_registry_;
|
||||
|
||||
mojo::Remote<mojom::ChildProcess> child_process_;
|
||||
// This will be bound to |io_thread_host_impl_|.
|
||||
mojo::PendingReceiver<mojom::ChildProcessHost> child_host_pending_receiver_;
|
||||
mojo::AssociatedRemote<mojom::RouteProvider> remote_route_provider_;
|
||||
mojo::AssociatedRemote<mojom::Renderer> renderer_interface_;
|
||||
mojo::AssociatedReceiver<mojom::RendererHost> renderer_host_receiver_{this};
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "content/child/browser_exposed_child_interfaces.h"
|
||||
#include "content/child/child_process.h"
|
||||
#include "content/common/child_process.mojom.h"
|
||||
#include "content/common/content_constants_internal.h"
|
||||
#include "content/common/field_trial_recorder.mojom.h"
|
||||
#include "content/common/in_process_child_thread_params.h"
|
||||
#include "content/common/mojo_core_library_support.h"
|
||||
@ -244,13 +245,11 @@ class ChildThreadImpl::IOThreadState
|
||||
scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner,
|
||||
base::WeakPtr<ChildThreadImpl> weak_main_thread,
|
||||
base::RepeatingClosure quit_closure,
|
||||
ChildThreadImpl::Options::ServiceBinder service_binder,
|
||||
mojo::PendingReceiver<mojom::ChildProcessHost> host_receiver)
|
||||
ChildThreadImpl::Options::ServiceBinder service_binder)
|
||||
: main_thread_task_runner_(std::move(main_thread_task_runner)),
|
||||
weak_main_thread_(std::move(weak_main_thread)),
|
||||
quit_closure_(std::move(quit_closure)),
|
||||
service_binder_(std::move(service_binder)),
|
||||
host_receiver_(std::move(host_receiver)) {}
|
||||
service_binder_(std::move(service_binder)) {}
|
||||
|
||||
// Used only in the deprecated Service Manager IPC mode.
|
||||
void BindChildProcessReceiver(
|
||||
@ -282,14 +281,6 @@ class ChildThreadImpl::IOThreadState
|
||||
~IOThreadState() override = default;
|
||||
|
||||
// mojom::ChildProcess:
|
||||
void Initialize(mojo::PendingRemote<mojom::ChildProcessHostBootstrap>
|
||||
bootstrap) override {
|
||||
// The browser only calls this method once.
|
||||
DCHECK(host_receiver_);
|
||||
mojo::Remote<mojom::ChildProcessHostBootstrap>(std::move(bootstrap))
|
||||
->BindProcessHost(std::move(host_receiver_));
|
||||
}
|
||||
|
||||
void ProcessShutdown() override {
|
||||
main_thread_task_runner_->PostTask(FROM_HERE,
|
||||
base::BindOnce(quit_closure_));
|
||||
@ -399,7 +390,6 @@ class ChildThreadImpl::IOThreadState
|
||||
mojo::BinderMap interface_binders_;
|
||||
bool wait_for_interface_binders_ = true;
|
||||
mojo::Receiver<mojom::ChildProcess> receiver_{this};
|
||||
mojo::PendingReceiver<mojom::ChildProcessHost> host_receiver_;
|
||||
|
||||
// The pending legacy IPC channel endpoint to fuse with one we will eventually
|
||||
// receiver on the ChildProcess interface. Only used when not in the
|
||||
@ -505,14 +495,9 @@ ChildThreadImpl::ChildThreadImpl(base::RepeatingClosure quit_closure,
|
||||
channel_connected_factory_(
|
||||
new base::WeakPtrFactory<ChildThreadImpl>(this)),
|
||||
ipc_task_runner_(options.ipc_task_runner) {
|
||||
mojo::PendingRemote<mojom::ChildProcessHost> remote_host;
|
||||
auto host_receiver = remote_host.InitWithNewPipeAndPassReceiver();
|
||||
child_process_host_ = mojo::SharedRemote<mojom::ChildProcessHost>(
|
||||
std::move(remote_host), GetIOTaskRunner());
|
||||
io_thread_state_ = base::MakeRefCounted<IOThreadState>(
|
||||
base::ThreadTaskRunnerHandle::Get(), weak_factory_.GetWeakPtr(),
|
||||
quit_closure_, std::move(options.service_binder),
|
||||
std::move(host_receiver));
|
||||
quit_closure_, std::move(options.service_binder));
|
||||
|
||||
// |ExposeInterfacesToBrowser()| must be called exactly once. Subclasses which
|
||||
// set |exposes_interfaces_to_browser| in Options signify that they take
|
||||
@ -567,10 +552,8 @@ void ChildThreadImpl::Init(const Options& options) {
|
||||
IPC::Logging::GetInstance()->SetIPCSender(this);
|
||||
#endif
|
||||
|
||||
// Only one of these will be made valid by the block below. This determines
|
||||
// whether we were launched in normal IPC mode or deprecated Service Manager
|
||||
// IPC mode.
|
||||
mojo::ScopedMessagePipeHandle child_process_pipe;
|
||||
mojo::ScopedMessagePipeHandle child_process_pipe_for_receiver;
|
||||
mojo::ScopedMessagePipeHandle child_process_host_pipe_for_remote;
|
||||
if (!IsInBrowserProcess()) {
|
||||
// If using a shared Mojo Core library, IPC support is already initialized.
|
||||
if (!IsMojoCoreSharedLibraryEnabled()) {
|
||||
@ -586,11 +569,26 @@ void ChildThreadImpl::Init(const Options& options) {
|
||||
mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST);
|
||||
}
|
||||
mojo::IncomingInvitation invitation = InitializeMojoIPCChannel();
|
||||
child_process_pipe = invitation.ExtractMessagePipe(0);
|
||||
child_process_pipe_for_receiver =
|
||||
invitation.ExtractMessagePipe(kChildProcessReceiverAttachmentName);
|
||||
child_process_host_pipe_for_remote =
|
||||
invitation.ExtractMessagePipe(kChildProcessHostRemoteAttachmentName);
|
||||
} else {
|
||||
child_process_pipe = options.mojo_invitation->ExtractMessagePipe(0);
|
||||
child_process_pipe_for_receiver =
|
||||
options.mojo_invitation->ExtractMessagePipe(
|
||||
kChildProcessReceiverAttachmentName);
|
||||
child_process_host_pipe_for_remote =
|
||||
options.mojo_invitation->ExtractMessagePipe(
|
||||
kChildProcessHostRemoteAttachmentName);
|
||||
}
|
||||
|
||||
// Now that we've recovered the message pipe for the ChildProcessHost, build
|
||||
// our |child_process_host_| with it.
|
||||
mojo::PendingRemote<mojom::ChildProcessHost> remote_host(
|
||||
std::move(child_process_host_pipe_for_remote), /*version=*/0u);
|
||||
child_process_host_ = mojo::SharedRemote<mojom::ChildProcessHost>(
|
||||
std::move(remote_host), GetIOTaskRunner());
|
||||
|
||||
sync_message_filter_ = channel_->CreateSyncMessageFilter();
|
||||
|
||||
// In single process mode, browser-side tracing and memory will cover the
|
||||
@ -635,7 +633,7 @@ void ChildThreadImpl::Init(const Options& options) {
|
||||
channel_->AddFilter(startup_filter);
|
||||
}
|
||||
|
||||
DCHECK(child_process_pipe.is_valid());
|
||||
DCHECK(child_process_pipe_for_receiver.is_valid());
|
||||
mojo::PendingRemote<IPC::mojom::ChannelBootstrap> legacy_ipc_bootstrap;
|
||||
mojo::ScopedMessagePipeHandle legacy_ipc_channel_handle =
|
||||
legacy_ipc_bootstrap.InitWithNewPipeAndPassReceiver().PassPipe();
|
||||
@ -651,7 +649,7 @@ void ChildThreadImpl::Init(const Options& options) {
|
||||
base::BindOnce(&IOThreadState::BindChildProcessReceiverAndLegacyIpc,
|
||||
io_thread_state_,
|
||||
mojo::PendingReceiver<mojom::ChildProcess>(
|
||||
std::move(child_process_pipe)),
|
||||
std::move(child_process_pipe_for_receiver)),
|
||||
std::move(legacy_ipc_bootstrap)));
|
||||
|
||||
int connection_timeout = kConnectionTimeoutS;
|
||||
|
@ -19,30 +19,9 @@ interface ChildProcessHost {
|
||||
BindHostReceiver(mojo_base.mojom.GenericPendingReceiver receiver);
|
||||
};
|
||||
|
||||
// An interface bound on the browser's IO thread to accept a ChildProcessHost
|
||||
// receiver from the child process. A remote to this interface is sent to child
|
||||
// processes via |ChildProcess.Initialize()| so that the child process may in
|
||||
// turn send back a ChildProcessHost receiver for the browser to bind. This
|
||||
// allows the child process to begin queuing messages on its ChildProcessHost
|
||||
// immediately upon startup without first waiting for
|
||||
// |ChildProcess.Initialize()|.
|
||||
//
|
||||
// NOTE: This is a separate interface and message rather than a simple reply to
|
||||
// |ChildProcess.Initialize()| because RenderProcessHostImpl binds its
|
||||
// ChildProcess remote on the main thread, and the ChildProcessHost receiver
|
||||
// needs to be accepted and bound on the IO thread without a main-thread hop.
|
||||
interface ChildProcessHostBootstrap {
|
||||
BindProcessHost(pending_receiver<ChildProcessHost> receiver);
|
||||
};
|
||||
|
||||
// A control interface the browser uses to drive the behavior of all types of
|
||||
// Content child processes.
|
||||
interface ChildProcess {
|
||||
// The first message sent by the process host to the child process. This is
|
||||
// sent to allow the child process to bootstrap its own ChildProcessHost
|
||||
// interface, to which it may have already queued messages.
|
||||
Initialize(pending_remote<ChildProcessHostBootstrap> boostrap);
|
||||
|
||||
// Tells the child process that it's safe to shutdown.
|
||||
ProcessShutdown();
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "build/build_config.h"
|
||||
#include "content/common/content_constants_internal.h"
|
||||
#include "content/public/common/child_process_host_delegate.h"
|
||||
#include "content/public/common/content_paths.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
@ -122,14 +123,19 @@ ChildProcessHostImpl::ChildProcessHostImpl(ChildProcessHostDelegate* delegate,
|
||||
// disconnected pipe so it quietly discards messages.
|
||||
ignore_result(child_process_.BindNewPipeAndPassReceiver());
|
||||
channel_ = IPC::ChannelMojo::Create(
|
||||
mojo_invitation_->AttachMessagePipe(0), IPC::Channel::MODE_SERVER, this,
|
||||
base::ThreadTaskRunnerHandle::Get(),
|
||||
mojo_invitation_->AttachMessagePipe(
|
||||
kChildProcessReceiverAttachmentName),
|
||||
IPC::Channel::MODE_SERVER, this, base::ThreadTaskRunnerHandle::Get(),
|
||||
base::ThreadTaskRunnerHandle::Get(),
|
||||
mojo::internal::MessageQuotaChecker::MaybeCreate());
|
||||
} else if (ipc_mode_ == IpcMode::kNormal) {
|
||||
child_process_.Bind(mojo::PendingRemote<mojom::ChildProcess>(
|
||||
mojo_invitation_->AttachMessagePipe(0), /*version=*/0));
|
||||
child_process_->Initialize(bootstrap_receiver_.BindNewPipeAndPassRemote());
|
||||
mojo_invitation_->AttachMessagePipe(
|
||||
kChildProcessReceiverAttachmentName),
|
||||
/*version=*/0));
|
||||
receiver_.Bind(mojo::PendingReceiver<mojom::ChildProcessHost>(
|
||||
mojo_invitation_->AttachMessagePipe(
|
||||
kChildProcessHostRemoteAttachmentName)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,11 +269,6 @@ uint64_t ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
|
||||
1;
|
||||
}
|
||||
|
||||
void ChildProcessHostImpl::BindProcessHost(
|
||||
mojo::PendingReceiver<mojom::ChildProcessHost> receiver) {
|
||||
receiver_.Bind(std::move(receiver));
|
||||
}
|
||||
|
||||
void ChildProcessHostImpl::BindHostReceiver(
|
||||
mojo::GenericPendingReceiver receiver) {
|
||||
delegate_->BindHostReceiver(std::move(receiver));
|
||||
|
@ -38,7 +38,6 @@ class ChildProcessHostDelegate;
|
||||
class CONTENT_EXPORT ChildProcessHostImpl
|
||||
: public ChildProcessHost,
|
||||
public IPC::Listener,
|
||||
public mojom::ChildProcessHostBootstrap,
|
||||
public mojom::ChildProcessHost {
|
||||
public:
|
||||
~ChildProcessHostImpl() override;
|
||||
@ -88,10 +87,6 @@ class CONTENT_EXPORT ChildProcessHostImpl
|
||||
|
||||
ChildProcessHostImpl(ChildProcessHostDelegate* delegate, IpcMode ipc_mode);
|
||||
|
||||
// mojom::ChildProcessHostBootstrap implementation:
|
||||
void BindProcessHost(
|
||||
mojo::PendingReceiver<mojom::ChildProcessHost> receiver) override;
|
||||
|
||||
// mojom::ChildProcessHost implementation:
|
||||
void BindHostReceiver(mojo::GenericPendingReceiver receiver) override;
|
||||
|
||||
@ -115,7 +110,6 @@ class CONTENT_EXPORT ChildProcessHostImpl
|
||||
bool opening_channel_; // True while we're waiting the channel to be opened.
|
||||
std::unique_ptr<IPC::Channel> channel_;
|
||||
mojo::Remote<mojom::ChildProcess> child_process_;
|
||||
mojo::Receiver<mojom::ChildProcessHostBootstrap> bootstrap_receiver_{this};
|
||||
mojo::Receiver<mojom::ChildProcessHost> receiver_{this};
|
||||
|
||||
// Holds all the IPC message filters. Since this object lives on the IO
|
||||
|
@ -19,4 +19,7 @@ const int kTraceEventRendererMainThreadSortIndex = -1;
|
||||
|
||||
const char kDoNotTrackHeader[] = "DNT";
|
||||
|
||||
const int kChildProcessReceiverAttachmentName = 0;
|
||||
const int kChildProcessHostRemoteAttachmentName = 1;
|
||||
|
||||
} // namespace content
|
||||
|
@ -38,6 +38,11 @@ CONTENT_EXPORT extern const int kTraceEventRendererMainThreadSortIndex;
|
||||
// HTTP header set in requests to indicate they should be marked DoNotTrack.
|
||||
extern const char kDoNotTrackHeader[];
|
||||
|
||||
// Constants for attaching message pipes to the mojo invitation used to
|
||||
// initialize child processes.
|
||||
extern const int kChildProcessReceiverAttachmentName;
|
||||
extern const int kChildProcessHostRemoteAttachmentName;
|
||||
|
||||
} // namespace content
|
||||
|
||||
#endif // CONTENT_COMMON_CONTENT_CONSTANTS_INTERNAL_H_
|
||||
|
@ -58,11 +58,6 @@ class FakeChildProcessImpl
|
||||
return disconnected_process_.get();
|
||||
}
|
||||
|
||||
void Initialize(mojo::PendingRemote<content::mojom::ChildProcessHostBootstrap>
|
||||
bootstrap) override {
|
||||
bootstrap_.Bind(std::move(bootstrap));
|
||||
}
|
||||
|
||||
void BootstrapLegacyIpc(
|
||||
mojo::PendingReceiver<IPC::mojom::ChannelBootstrap> receiver) override {
|
||||
mojo::FusePipes(std::move(receiver), std::move(legacy_ipc_bootstrap_));
|
||||
@ -70,7 +65,6 @@ class FakeChildProcessImpl
|
||||
|
||||
private:
|
||||
mojo::PendingRemote<IPC::mojom::ChannelBootstrap> legacy_ipc_bootstrap_;
|
||||
mojo::Remote<content::mojom::ChildProcessHostBootstrap> bootstrap_;
|
||||
mojo::Remote<content::mojom::ChildProcess> disconnected_process_;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user