[MBI] Create legacy IPC channel per AgentSchedulingGroup.
This CL introduces separate legacy IPC channels per AgentSchedulingGroup
in "MBI mode". This channel is then used to associate channel-associated
interfaces with, and to send legacy IPC messages.
In addition it does the following:
1. Remove MaybeAssociatedRemote/Receiver, as the ASG's mojo interfaces
are now always channel-associated.
2. ASG and ASGH implement IPC::Listener to handle legacy IPC message on
the new channel.
3. Rename SetUpMojo/ResetMojo to SetUpIPC/ResetIPC.
4. `should_associate_` flag is replaced with an enum to make its meaning
clearer.
Bug: 1111231
Change-Id: I1d850aae48b4a900ab0aef24ac8a58b00cbcb218
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2535954
Commit-Queue: Tal Pressman <talp@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Reviewed-by: Kouhei Ueno <kouhei@chromium.org>
Cr-Commit-Position: refs/heads/master@{#828175}
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index ce284fb..436e17a 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -261,6 +261,8 @@
RWH_CLOSE_PORTAL = 233,
MSDH_INVALID_STREAM_TYPE = 234,
RFH_CREATE_CHILD_FRAME_TOKENS_NOT_FOUND = 235,
+ ASGH_ASSOCIATED_INTERFACE_REQUEST = 236,
+ ASGH_RECEIVED_CONTROL_MESSAGE = 237,
// Please add new elements here. The naming convention is abbreviated class
// name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/renderer_host/agent_scheduling_group_host.cc b/content/browser/renderer_host/agent_scheduling_group_host.cc
index 8fe6b45..492dfe5c 100644
--- a/content/browser/renderer_host/agent_scheduling_group_host.cc
+++ b/content/browser/renderer_host/agent_scheduling_group_host.cc
@@ -9,18 +9,21 @@
#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "base/supports_user_data.h"
+#include "content/browser/bad_message.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/common/agent_scheduling_group.mojom.h"
#include "content/common/renderer.mojom.h"
#include "content/common/state_transitions.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_features.h"
+#include "ipc/ipc_channel_mojo.h"
#include "ipc/ipc_message.h"
namespace content {
namespace {
+using ::IPC::ChannelMojo;
using ::IPC::ChannelProxy;
using ::IPC::Listener;
using ::mojo::AssociatedReceiver;
@@ -52,47 +55,6 @@
} // namespace
-// MaybeAssociatedRemote:
-AgentSchedulingGroupHost::MaybeAssociatedRemote::MaybeAssociatedRemote(
- bool should_associate) {
- if (should_associate) {
- remote_ = AssociatedRemote<mojom::AgentSchedulingGroup>();
- } else {
- remote_ = Remote<mojom::AgentSchedulingGroup>();
- }
-}
-
-AgentSchedulingGroupHost::MaybeAssociatedRemote::~MaybeAssociatedRemote() =
- default;
-
-PendingReceiver<mojom::AgentSchedulingGroup>
-AgentSchedulingGroupHost::MaybeAssociatedRemote::BindNewPipeAndPassReceiver() {
- return absl::get<Remote<mojom::AgentSchedulingGroup>>(remote_)
- .BindNewPipeAndPassReceiver();
-}
-
-PendingAssociatedReceiver<mojom::AgentSchedulingGroup>
-AgentSchedulingGroupHost::MaybeAssociatedRemote::
- BindNewEndpointAndPassReceiver() {
- return absl::get<AssociatedRemote<mojom::AgentSchedulingGroup>>(remote_)
- .BindNewEndpointAndPassReceiver();
-}
-
-void AgentSchedulingGroupHost::MaybeAssociatedRemote::reset() {
- absl::visit([](auto& remote) { remote.reset(); }, remote_);
-}
-
-bool AgentSchedulingGroupHost::MaybeAssociatedRemote::is_bound() {
- return absl::visit([](auto& remote) { return remote.is_bound(); }, remote_);
-}
-
-mojom::AgentSchedulingGroup*
-AgentSchedulingGroupHost::MaybeAssociatedRemote::get() {
- return absl::visit([](auto& r) { return r.get(); }, remote_);
-}
-
-// AgentSchedulingGroupHost:
-
// static
AgentSchedulingGroupHost* AgentSchedulingGroupHost::Get(
const SiteInstance& instance,
@@ -111,26 +73,21 @@
}
AgentSchedulingGroupHost::AgentSchedulingGroupHost(RenderProcessHost& process)
- : AgentSchedulingGroupHost(
- process,
- !base::FeatureList::IsEnabled(
- features::kMbiDetachAgentSchedulingGroupFromChannel)) {}
-
-AgentSchedulingGroupHost::AgentSchedulingGroupHost(RenderProcessHost& process,
- bool should_associate)
: process_(process),
- should_associate_(should_associate),
- receiver_(this),
- mojo_remote_(should_associate) {
+ association_mode_(base::FeatureList::IsEnabled(
+ features::kMbiDetachAgentSchedulingGroupFromChannel)
+ ? IPCAssociationMode::kUnassociated
+ : IPCAssociationMode::kAssociatedWithProcess),
+ receiver_(this) {
process_.AddObserver(this);
// The RenderProcessHost's channel and other mojo interfaces are bound by the
- // time this class is constructed, so we eagerly initialize this class's mojos
+ // time this class is constructed, so we eagerly initialize this class's IPC
// so they have the same bind lifetime as those of the RenderProcessHost.
// Furthermore, when the RenderProcessHost's channel and mojo interfaces get
// reset and reinitialized, we'll be notified so that we can reset and
// reinitialize ours as well.
- SetUpMojo();
+ SetUpIPC();
}
// DO NOT USE |process_| HERE! At this point it (or at least parts of it) is no
@@ -148,17 +105,17 @@
// We mirror the RenderProcessHost flow here by resetting our mojos, and
// reinitializing them once the process's IPC::ChannelProxy and renderer
// interface are reinitialized.
- ResetMojo();
+ ResetIPC();
// RenderProcessHostImpl will attempt to call this method later if it has not
- // already been called. We call it now since `SetUpMojo()` relies on it being
- // called, thus setting up the IPC ChannelProxy and mojom::Renderer interface.
+ // already been called. We call it now since `SetUpIPC()` relies on it being
+ // called, thus setting up the IPC channel and mojom::Renderer interface.
process_.EnableSendQueue();
// We call this so that we can immediately queue IPC and mojo messages on the
// new channel/interfaces that are bound for the next renderer process, should
// one eventually be spun up.
- SetUpMojo();
+ SetUpIPC();
}
void AgentSchedulingGroupHost::RenderProcessHostDestroyed(
@@ -176,6 +133,37 @@
SetState(LifecycleState::kRenderProcessHostDestroyed);
}
+bool AgentSchedulingGroupHost::OnMessageReceived(const IPC::Message& message) {
+ if (message.routing_id() == MSG_ROUTING_CONTROL) {
+ bad_message::ReceivedBadMessage(&process_,
+ bad_message::ASGH_RECEIVED_CONTROL_MESSAGE);
+ return false;
+ }
+
+ auto* listener = GetListener(message.routing_id());
+ if (!listener)
+ return false;
+
+ return listener->OnMessageReceived(message);
+}
+
+void AgentSchedulingGroupHost::OnBadMessageReceived(
+ const IPC::Message& message) {
+ // If a bad message is received, it should be treated the same as a bad
+ // message on the renderer-wide channel (i.e., kill the renderer).
+ return process_.OnBadMessageReceived(message);
+}
+
+void AgentSchedulingGroupHost::OnAssociatedInterfaceRequest(
+ const std::string& interface_name,
+ mojo::ScopedInterfaceEndpointHandle handle) {
+ // There shouldn't be any interfaces requested this way - process-wide
+ // interfaces should be requested via the process-wide channel, and
+ // ASG-related interfaces should go through `RouteProvider`.
+ bad_message::ReceivedBadMessage(
+ &process_, bad_message::ASGH_ASSOCIATED_INTERFACE_REQUEST);
+}
+
RenderProcessHost* AgentSchedulingGroupHost::GetProcess() {
// TODO(crbug.com/1111231): Make the condition below hold.
// Currently the DCHECK doesn't hold, since RenderViewHostImpl outlives
@@ -202,12 +190,30 @@
ChannelProxy* AgentSchedulingGroupHost::GetChannel() {
DCHECK_EQ(state_, LifecycleState::kBound);
- return process_.GetChannel();
+
+ if (association_mode_ == IPCAssociationMode::kAssociatedWithProcess)
+ return process_.GetChannel();
+
+ DCHECK(channel_);
+ return channel_.get();
}
bool AgentSchedulingGroupHost::Send(IPC::Message* message) {
DCHECK_EQ(state_, LifecycleState::kBound);
- return process_.Send(message);
+
+ std::unique_ptr<IPC::Message> msg(message);
+
+ if (association_mode_ == IPCAssociationMode::kAssociatedWithProcess)
+ return process_.Send(msg.release());
+
+ // This DCHECK is too idealistic for now - messages that are handled by
+ // filters are sent as control messages since they are intercepted before
+ // routing. It is put here as documentation for now, since this code would not
+ // be reached until we activate `kUnassociated`.
+ DCHECK_NE(message->routing_id(), MSG_ROUTING_CONTROL);
+
+ DCHECK(channel_);
+ return channel_->Send(msg.release());
}
void AgentSchedulingGroupHost::AddRoute(int32_t routing_id,
@@ -246,10 +252,11 @@
int32_t routing_id,
mojom::AgentSchedulingGroup::DestroyViewCallback callback) {
DCHECK_EQ(state_, LifecycleState::kBound);
- if (mojo_remote_.is_bound())
+ if (mojo_remote_.is_bound()) {
mojo_remote_.get()->DestroyView(routing_id, std::move(callback));
- else
+ } else {
std::move(callback).Run();
+ }
}
void AgentSchedulingGroupHost::CreateFrameProxy(
@@ -288,36 +295,85 @@
listener->OnAssociatedInterfaceRequest(name, receiver.PassHandle());
}
-void AgentSchedulingGroupHost::ResetMojo() {
+void AgentSchedulingGroupHost::ResetIPC() {
DCHECK_EQ(state_, LifecycleState::kRenderProcessExited);
receiver_.reset();
mojo_remote_.reset();
remote_route_provider_.reset();
route_provider_receiver_.reset();
associated_interface_provider_receivers_.Clear();
+ channel_ = nullptr;
}
-void AgentSchedulingGroupHost::SetUpMojo() {
+void AgentSchedulingGroupHost::SetUpIPC() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // The RenderProcessHostImpl's renderer interface must be initialized at this
- // at this point. We don't DCHECK |process_.IsInitializedAndNotDead()| here
- // because we may end up here after the render process has died but before
- // RenderProcessHostImpl::Init() is called. Therefore, the process can
- // accept IPCs that will be queued for the next render process if one is spun
- // up.
- DCHECK(process_.GetRendererInterface());
-
DCHECK(state_ == LifecycleState::kNewborn ||
state_ == LifecycleState::kRenderProcessExited);
- if (should_associate_) {
+ // The RenderProcessHostImpl's renderer interface must be initialized at this
+ // point. We don't DCHECK |process_.IsInitializedAndNotDead()| here because
+ // we may end up here after the renderer process has died but before
+ // RenderProcessHostImpl::Init() is called. Therefore, the process can accept
+ // IPCs that will be queued for the next renderer process if one is spun up.
+ DCHECK(process_.GetRendererInterface());
+
+ DCHECK(!channel_);
+ DCHECK(!mojo_remote_.is_bound());
+ DCHECK(!receiver_.is_bound());
+ DCHECK(!remote_route_provider_.is_bound());
+ DCHECK(!route_provider_receiver_.is_bound());
+
+ // After this function returns, all of `this`'s associated mojo interfaces
+ // need to be bound, and associated "properly" - in `kUnassociated` mode that
+ // means they are associated with the ASG's channel, and in
+ // `kAssociatedWithProcess` mode with the process-global channel. This
+ // initialization is done in a number of steps:
+ // 1. If we're in `kUnassociated` mode, create an IPC Channel (i.e.,
+ // initialize `channel_`). After this, regardless of which mode we're in,
+ // the ASGH would have a channel.
+ // 2. Initialize `mojo_remote_`. In `kAssociatedWithProcess` mode, this can be
+ // done via the `mojom::Renderer` interface, but in `kUnassociated` mode
+ // this *has* to be done via the just-created channel (so the interface is
+ // associated with the correct pipe).
+ // 3. All the ASGH's other associated interfaces can now be initialized via
+ // `mojo_remote_`, and will be transitively associated with the appropriate
+ // IPC channel/pipe.
+ if (association_mode_ == IPCAssociationMode::kAssociatedWithProcess) {
process_.GetRendererInterface()->CreateAssociatedAgentSchedulingGroup(
mojo_remote_.BindNewEndpointAndPassReceiver());
} else {
+ auto io_task_runner = GetIOThreadTaskRunner({});
+
+ // Empty interface endpoint to pass pipes more easily.
+ PendingRemote<IPC::mojom::ChannelBootstrap> bootstrap;
+
process_.GetRendererInterface()->CreateAgentSchedulingGroup(
- mojo_remote_.BindNewPipeAndPassReceiver());
+ bootstrap.InitWithNewPipeAndPassReceiver());
+
+ auto channel_factory = ChannelMojo::CreateServerFactory(
+ bootstrap.PassPipe(), /*ipc_task_runner=*/io_task_runner,
+ /*proxy_task_runner=*/base::ThreadTaskRunnerHandle::Get());
+
+ // TODO(crbug.com/1111231): Android WebViews (that support synchronous
+ // compositing) send sync messages from the browser to the renderer, and
+ // therefore need a `SyncChannel`. However, we don't plan to support
+ // WebViews at this stage, so a plain `ChannelProxy` is fine for now.
+ channel_ = ChannelProxy::Create(
+ std::move(channel_factory), /*listener=*/this,
+ /*ipc_task_runner=*/io_task_runner,
+ /*listener_task_runner=*/base::ThreadTaskRunnerHandle::Get());
+
+ // TODO(crbug.com/1111231): Add necessary filters.
+ // Most of the filters currently installed on the process-wide channel are:
+ // 1. "Process-bound", that is, they do not handle messages sent using ASG,
+ // 2. Pepper/NaCl-related, that are going away, and are not supported, or
+ // 3. Related to Android WebViews, which are not currently supported.
+
+ channel_->GetRemoteAssociatedInterface(&mojo_remote_);
}
+ DCHECK(mojo_remote_.is_bound());
+
mojo_remote_.get()->BindAssociatedInterfaces(
receiver_.BindNewEndpointAndPassRemote(),
route_provider_receiver_.BindNewEndpointAndPassRemote(),
diff --git a/content/browser/renderer_host/agent_scheduling_group_host.h b/content/browser/renderer_host/agent_scheduling_group_host.h
index 8efdc7a..db4e4d71 100644
--- a/content/browser/renderer_host/agent_scheduling_group_host.h
+++ b/content/browser/renderer_host/agent_scheduling_group_host.h
@@ -14,17 +14,16 @@
#include "content/common/renderer.mojom-forward.h"
#include "content/common/state_transitions.h"
#include "content/public/browser/render_process_host_observer.h"
+#include "ipc/ipc_listener.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
-#include "third_party/abseil-cpp/absl/types/variant.h"
#include "third_party/blink/public/mojom/associated_interfaces/associated_interfaces.mojom.h"
namespace IPC {
class ChannelProxy;
-class Listener;
class Message;
} // namespace IPC
@@ -43,6 +42,7 @@
// RenderProcessHost.
class CONTENT_EXPORT AgentSchedulingGroupHost
: public RenderProcessHostObserver,
+ public IPC::Listener,
public mojom::AgentSchedulingGroupHost,
public mojom::RouteProvider,
public blink::mojom::AssociatedInterfaceProvider {
@@ -54,7 +54,6 @@
static AgentSchedulingGroupHost* Get(const SiteInstance& instance,
RenderProcessHost& process);
- // Utility ctor, forwarding to the main ctor below.
// Should not be called explicitly. Use `Get()` instead.
explicit AgentSchedulingGroupHost(RenderProcessHost& process);
~AgentSchedulingGroupHost() override;
@@ -106,41 +105,12 @@
friend StateTransitions<LifecycleState>;
friend std::ostream& operator<<(std::ostream& os, LifecycleState state);
- // `MaybeAssociatedRemote` is a temporary helper class that allows us to
- // switch between using an associated and non-associated remote. This behavior
- // is controlled by the `kMbiDetachAgentSchedulingGroupFromChannel` feature
- // flag. Associated remotes are associated with the IPC channel (transitively,
- // via the `Renderer` interface), thus preserving cross-agent scheduling group
- // message order. Non-associated interfaces are independent from each other
- // and do not preserve message order between agent scheduling groups.
- // TODO(crbug.com/1111231): Remove this once we can remove the flag.
- class MaybeAssociatedRemote {
- public:
- explicit MaybeAssociatedRemote(bool should_associate);
- ~MaybeAssociatedRemote();
-
- mojo::PendingReceiver<mojom::AgentSchedulingGroup>
- BindNewPipeAndPassReceiver() WARN_UNUSED_RESULT;
- mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup>
- BindNewEndpointAndPassReceiver() WARN_UNUSED_RESULT;
-
- void reset();
- bool is_bound();
- mojom::AgentSchedulingGroup* get();
-
- private:
- absl::variant<mojo::Remote<mojom::AgentSchedulingGroup>,
- mojo::AssociatedRemote<mojom::AgentSchedulingGroup>>
- remote_;
- };
-
- // Main constructor.
- // |should_associate| determines whether the `AgentSchedulingGroupHost` and
- // `AgentSchedulingGroup` mojos should be associated with the `Renderer` or
- // not. If they are, message order will be preserved across the entire
- // process. If not, ordering will only be preserved inside an
- // `AgentSchedulingGroup`.
- AgentSchedulingGroupHost(RenderProcessHost& process, bool should_associate);
+ // IPC::Listener
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnBadMessageReceived(const IPC::Message& message) override;
+ void OnAssociatedInterfaceRequest(
+ const std::string& interface_name,
+ mojo::ScopedInterfaceEndpointHandle handle) override;
// mojom::RouteProvider
void GetRoute(
@@ -159,8 +129,8 @@
const ChildProcessTerminationInfo& info) override;
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
- void ResetMojo();
- void SetUpMojo();
+ void ResetIPC();
+ void SetUpIPC();
void SetState(LifecycleState state);
@@ -169,19 +139,34 @@
// The RenderProcessHost this AgentSchedulingGroup is assigned to.
RenderProcessHost& process_;
- const bool should_associate_;
+ enum class IPCAssociationMode {
+ // In this mode, the AgentSchedulingGroup will use the process-wide legacy
+ // IPC channel for communication with the renderer process and to associate
+ // its interfaces with.
+ kAssociatedWithProcess = 0,
+
+ // In this mode, each AgentSchedulingGroup will have its own legacy IPC
+ // channel for communication with the renderer process and to associate its
+ // interfaces with.
+ kUnassociated = 1,
+ };
+ const IPCAssociationMode association_mode_;
+
+ // This AgentSchedulingGroup's legacy IPC channel. Will only be used in
+ // `kUnassociated` mode.
+ std::unique_ptr<IPC::ChannelProxy> channel_;
// Map of registered IPC listeners.
base::IDMap<IPC::Listener*> listener_map_;
+ // Remote stub of `mojom::AgentSchedulingGroup`, used for sending calls to the
+ // (renderer-side) `AgentSchedulingGroup`.
+ mojo::AssociatedRemote<mojom::AgentSchedulingGroup> mojo_remote_;
+
// Implementation of `mojom::AgentSchedulingGroupHost`, used for responding to
// calls from the (renderer-side) `AgentSchedulingGroup`.
mojo::AssociatedReceiver<mojom::AgentSchedulingGroupHost> receiver_;
- // Remote stub of `mojom::AgentSchedulingGroup`, used for sending calls to the
- // (renderer-side) `AgentSchedulingGroup`.
- MaybeAssociatedRemote mojo_remote_;
-
// The `mojom::RouteProvider` mojo pair to setup
// `blink::AssociatedInterfaceProvider` routes between this and the
// renderer-side `AgentSchedulingGroup`.
diff --git a/content/common/renderer.mojom b/content/common/renderer.mojom
index ecb1d23..70ab352 100644
--- a/content/common/renderer.mojom
+++ b/content/common/renderer.mojom
@@ -6,6 +6,7 @@
import "content/common/agent_scheduling_group.mojom";
import "content/common/native_types.mojom";
+import "ipc/ipc.mojom";
import "mojo/public/mojom/base/generic_pending_receiver.mojom";
import "mojo/public/mojom/base/time.mojom";
import "services/network/public/mojom/network_types.mojom";
@@ -58,22 +59,24 @@
// This should be used for implementing browser-to-renderer control messages
// which need to retain FIFO with respect to legacy IPC messages.
interface Renderer {
- // Tells the renderer to create a new AgentSchedulingGroup, that will
- // listen to messages sent by the host via the pending
- // |agent_scheduling_group|. This will create "independent" agent scheduling
- // groups that are not associated with the IPC channel, which will not
- // guarantee any order across agent scheduling groups.
+ // Tells the renderer to create a new AgentSchedulingGroup, and initialize its
+ // legacy IPC Channel using the pipe provided by `bootstrap`. The channel will
+ // later be used to bind the mojom::AgentSchedulingGroup receiver, that
+ // listens to messages sent by the host.
+ // This will create an "independent" agent scheduling group that is not
+ // associated with the process-wide or other groups' IPC channels, meaning
+ // there is no guaranteed ordering between them.
CreateAgentSchedulingGroup(
- pending_receiver<AgentSchedulingGroup> agent_scheduling_group
- );
+ pending_receiver<IPC.mojom.ChannelBootstrap> bootstrap);
// Tells the renderer to create a new AgentSchedulingGroup, that will
// listen to messages sent by the host via the pending
- // |agent_scheduling_group|. This will create a channel-associated interface
- // that will preserve message ordering across agent scheduling groups.
+ // |agent_scheduling_group|.
+ // This will create an agent scheduling group that is associated with the
+ // process-wide IPC channel, preserving message ordering across different
+ // agent scheduling groups.
CreateAssociatedAgentSchedulingGroup(
- pending_associated_receiver<AgentSchedulingGroup> agent_scheduling_group
- );
+ pending_associated_receiver<AgentSchedulingGroup> agent_scheduling_group);
// Tells the renderer that the network type has changed so that
// navigator.onLine and navigator.connection can be updated.
diff --git a/content/renderer/agent_scheduling_group.cc b/content/renderer/agent_scheduling_group.cc
index a253662..73f3252 100644
--- a/content/renderer/agent_scheduling_group.cc
+++ b/content/renderer/agent_scheduling_group.cc
@@ -6,16 +6,22 @@
#include "base/feature_list.h"
#include "base/util/type_safety/pass_key.h"
+#include "content/common/agent_scheduling_group.mojom.h"
#include "content/public/common/content_features.h"
#include "content/renderer/compositor/compositor_dependencies.h"
#include "content/renderer/render_frame_proxy.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/render_view_impl.h"
+#include "ipc/ipc_channel_mojo.h"
+#include "ipc/ipc_listener.h"
+#include "ipc/ipc_sync_channel.h"
#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
namespace content {
+using ::IPC::ChannelMojo;
using ::IPC::Listener;
+using ::IPC::SyncChannel;
using ::mojo::AssociatedReceiver;
using ::mojo::AssociatedRemote;
using ::mojo::PendingAssociatedReceiver;
@@ -35,53 +41,49 @@
} // namespace
-// MaybeAssociatedReceiver:
-AgentSchedulingGroup::MaybeAssociatedReceiver::MaybeAssociatedReceiver(
- AgentSchedulingGroup& impl,
- PendingReceiver<mojom::AgentSchedulingGroup> receiver,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : receiver_(absl::in_place_type<Receiver<mojom::AgentSchedulingGroup>>,
- &impl,
- std::move(receiver),
- task_runner) {}
-
-AgentSchedulingGroup::MaybeAssociatedReceiver::MaybeAssociatedReceiver(
- AgentSchedulingGroup& impl,
- PendingAssociatedReceiver<mojom::AgentSchedulingGroup> receiver,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : receiver_(
- absl::in_place_type<AssociatedReceiver<mojom::AgentSchedulingGroup>>,
- &impl,
- std::move(receiver),
- task_runner) {}
-
-AgentSchedulingGroup::MaybeAssociatedReceiver::~MaybeAssociatedReceiver() =
- default;
-
// AgentSchedulingGroup:
AgentSchedulingGroup::AgentSchedulingGroup(
RenderThread& render_thread,
- PendingReceiver<mojom::AgentSchedulingGroup> receiver)
- : agent_group_scheduler_(
+ mojo::PendingReceiver<IPC::mojom::ChannelBootstrap> bootstrap)
+ : association_mode_(IPCAssociationMode::kUnassociated),
+ agent_group_scheduler_(
blink::scheduler::WebThreadScheduler::MainThreadScheduler()
->CreateAgentGroupScheduler()),
render_thread_(render_thread),
- receiver_(*this,
- std::move(receiver),
- agent_group_scheduler_->DefaultTaskRunner()) {
+ // `receiver_` will be bound by `OnAssociatedInterfaceRequest()`.
+ receiver_(this) {
DCHECK(agent_group_scheduler_);
DCHECK(base::FeatureList::IsEnabled(
features::kMbiDetachAgentSchedulingGroupFromChannel));
+
+ channel_ = SyncChannel::Create(
+ /*listener=*/this, /*ipc_task_runner=*/render_thread_.GetIOTaskRunner(),
+ /*listener_task_runner=*/agent_group_scheduler_->DefaultTaskRunner(),
+ render_thread_.GetShutdownEvent());
+
+ // TODO(crbug.com/1111231): Add necessary filters.
+ // Currently, the renderer process has these filters:
+ // 1. `UnfreezableMessageFilter` - in the process of being removed,
+ // 2. `PnaclTranslationResourceHost` - NaCl is going away, and
+ // 3. `AutomationMessageFilter` - needs to be handled somehow.
+
+ channel_->Init(
+ ChannelMojo::CreateClientFactory(
+ bootstrap.PassPipe(),
+ /*ipc_task_runner=*/render_thread_.GetIOTaskRunner(),
+ /*proxy_task_runner=*/agent_group_scheduler_->DefaultTaskRunner()),
+ /*create_pipe_now=*/true);
}
AgentSchedulingGroup::AgentSchedulingGroup(
RenderThread& render_thread,
PendingAssociatedReceiver<mojom::AgentSchedulingGroup> receiver)
- : agent_group_scheduler_(
+ : association_mode_(IPCAssociationMode::kAssociatedWithProcess),
+ agent_group_scheduler_(
blink::scheduler::WebThreadScheduler::MainThreadScheduler()
->CreateAgentGroupScheduler()),
render_thread_(render_thread),
- receiver_(*this,
+ receiver_(this,
std::move(receiver),
agent_group_scheduler_->DefaultTaskRunner()) {
DCHECK(agent_group_scheduler_);
@@ -91,12 +93,49 @@
AgentSchedulingGroup::~AgentSchedulingGroup() = default;
-// IPC messages to be forwarded to the `RenderThread`, for now. In the future
-// they will be handled directly by the `AgentSchedulingGroup`.
+bool AgentSchedulingGroup::OnMessageReceived(const IPC::Message& message) {
+ DCHECK_NE(message.routing_id(), MSG_ROUTING_CONTROL);
+
+ auto* listener = GetListener(message.routing_id());
+ if (!listener)
+ return false;
+
+ return listener->OnMessageReceived(message);
+}
+
+void AgentSchedulingGroup::OnBadMessageReceived(const IPC::Message& message) {
+ // Not strictly required, since we don't currently do anything with bad
+ // messages in the renderer, but if we ever do then this will "just work".
+ return ToImpl(render_thread_).OnBadMessageReceived(message);
+}
+
+void AgentSchedulingGroup::OnAssociatedInterfaceRequest(
+ const std::string& interface_name,
+ mojo::ScopedInterfaceEndpointHandle handle) {
+ // The ASG's channel should only be used to bootstrap the ASG mojo interface.
+ DCHECK_EQ(interface_name, mojom::AgentSchedulingGroup::Name_);
+ DCHECK(!receiver_.is_bound());
+
+ PendingAssociatedReceiver<mojom::AgentSchedulingGroup> pending_receiver(
+ std::move(handle));
+ receiver_.Bind(std::move(pending_receiver),
+ agent_group_scheduler_->DefaultTaskRunner());
+}
+
bool AgentSchedulingGroup::Send(IPC::Message* message) {
- // TODO(crbug.com/1111231): For some reason, changing this to use
- // render_thread_ causes trybots to time out (not specific tests).
- return RenderThread::Get()->Send(message);
+ std::unique_ptr<IPC::Message> msg(message);
+
+ if (association_mode_ == IPCAssociationMode::kAssociatedWithProcess)
+ return render_thread_.Send(msg.release());
+
+ // This DCHECK is too idealistic for now - messages that are handled by
+ // filters are sent control messages since they are intercepted before
+ // routing. It is put here as documentation for now, since this code would not
+ // be reached until we activate `kUnassociated`.
+ DCHECK_NE(message->routing_id(), MSG_ROUTING_CONTROL);
+
+ DCHECK(channel_);
+ return channel_->Send(msg.release());
}
void AgentSchedulingGroup::AddRoute(int32_t routing_id, Listener* listener) {
diff --git a/content/renderer/agent_scheduling_group.h b/content/renderer/agent_scheduling_group.h
index 90ed0f5..0ac011db 100644
--- a/content/renderer/agent_scheduling_group.h
+++ b/content/renderer/agent_scheduling_group.h
@@ -9,18 +9,19 @@
#include "content/common/agent_scheduling_group.mojom.h"
#include "content/common/associated_interfaces.mojom.h"
#include "content/common/content_export.h"
+#include "ipc/ipc.mojom.h"
+#include "ipc/ipc_listener.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
-#include "third_party/abseil-cpp/absl/types/variant.h"
#include "third_party/blink/public/mojom/associated_interfaces/associated_interfaces.mojom.h"
#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
namespace IPC {
-class Listener;
class Message;
+class SyncChannel;
} // namespace IPC
namespace content {
@@ -33,22 +34,21 @@
// to obtain ordering guarantees between different Mojo (associated) interfaces
// and legacy IPC messages.
class CONTENT_EXPORT AgentSchedulingGroup
- : public mojom::AgentSchedulingGroup,
+ : public IPC::Listener,
+ public mojom::AgentSchedulingGroup,
public mojom::RouteProvider,
public blink::mojom::AssociatedInterfaceProvider {
public:
AgentSchedulingGroup(
RenderThread& render_thread,
- mojo::PendingReceiver<mojom::AgentSchedulingGroup> receiver);
+ mojo::PendingReceiver<IPC::mojom::ChannelBootstrap> bootstrap);
AgentSchedulingGroup(
RenderThread& render_thread,
mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup> receiver);
~AgentSchedulingGroup() override;
AgentSchedulingGroup(const AgentSchedulingGroup&) = delete;
- AgentSchedulingGroup(const AgentSchedulingGroup&&) = delete;
AgentSchedulingGroup& operator=(const AgentSchedulingGroup&) = delete;
- AgentSchedulingGroup& operator=(const AgentSchedulingGroup&&) = delete;
bool Send(IPC::Message* message);
void AddRoute(int32_t routing_id, IPC::Listener* listener);
@@ -62,32 +62,12 @@
}
private:
- // `MaybeAssociatedReceiver` is a temporary helper class that allows us to
- // switch between using an associated and non-associated receiver. This
- // behavior is controlled by the `kMbiDetachAgentSchedulingGroupFromChannel`
- // feature flag. Associated receivers are associated with the IPC channel
- // (transitively, via the `Renderer` interface), thus preserving cross-agent
- // scheduling group message order. Non-associated receivers are independent
- // from each other and do not preserve message order between agent scheduling
- // groups.
- // TODO(crbug.com/1111231): Remove these once we can remove the flag.
- class MaybeAssociatedReceiver {
- public:
- MaybeAssociatedReceiver(
- AgentSchedulingGroup& impl,
- mojo::PendingReceiver<mojom::AgentSchedulingGroup> receiver,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
- MaybeAssociatedReceiver(
- AgentSchedulingGroup& impl,
- mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup> receiver,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
- ~MaybeAssociatedReceiver();
-
- private:
- absl::variant<mojo::Receiver<mojom::AgentSchedulingGroup>,
- mojo::AssociatedReceiver<mojom::AgentSchedulingGroup>>
- receiver_;
- };
+ // IPC::Listener:
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnBadMessageReceived(const IPC::Message& message) override;
+ void OnAssociatedInterfaceRequest(
+ const std::string& interface_name,
+ mojo::ScopedInterfaceEndpointHandle handle) override;
// mojom::AgentSchedulingGroup:
void CreateView(mojom::CreateViewParamsPtr params) override;
@@ -122,6 +102,23 @@
IPC::Listener* GetListener(int32_t routing_id);
+ enum class IPCAssociationMode {
+ // In this mode, the AgentSchedulingGroup will use the process-wide legacy
+ // IPC channel for communication with the renderer process and to associate
+ // its interfaces with.
+ kAssociatedWithProcess = 0,
+
+ // In this mode, each AgentSchedulingGroup will have its own legacy IPC
+ // channel for communication with the renderer process and to associate its
+ // interfaces with.
+ kUnassociated = 1,
+ };
+ const IPCAssociationMode association_mode_;
+
+ // This AgentSchedulingGroup's legacy IPC channel. Will only be used in
+ // `kUnassociated` mode.
+ std::unique_ptr<IPC::SyncChannel> channel_;
+
// Map of registered IPC listeners.
base::IDMap<IPC::Listener*> listener_map_;
@@ -133,7 +130,7 @@
// Implementation of `mojom::AgentSchedulingGroup`, used for responding to
// calls from the (browser-side) `AgentSchedulingGroupHost`.
- MaybeAssociatedReceiver receiver_;
+ mojo::AssociatedReceiver<mojom::AgentSchedulingGroup> receiver_;
// Remote stub of mojom::AgentSchedulingGroupHost, used for sending calls to
// the (browser-side) AgentSchedulingGroupHost.
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 5a43139..b0dc8414 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1642,9 +1642,9 @@
}
void RenderThreadImpl::CreateAgentSchedulingGroup(
- mojo::PendingReceiver<mojom::AgentSchedulingGroup> agent_scheduling_group) {
- agent_scheduling_groups_.emplace(std::make_unique<AgentSchedulingGroup>(
- *this, std::move(agent_scheduling_group)));
+ mojo::PendingReceiver<IPC::mojom::ChannelBootstrap> bootstrap) {
+ agent_scheduling_groups_.emplace(
+ std::make_unique<AgentSchedulingGroup>(*this, std::move(bootstrap)));
}
void RenderThreadImpl::CreateAssociatedAgentSchedulingGroup(
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 989f770..a195f88f 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -439,8 +439,7 @@
// mojom::Renderer:
void CreateAgentSchedulingGroup(
- mojo::PendingReceiver<mojom::AgentSchedulingGroup> agent_scheduling_group)
- override;
+ mojo::PendingReceiver<IPC::mojom::ChannelBootstrap> bootstrap) override;
void CreateAssociatedAgentSchedulingGroup(
mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup>
agent_scheduling_group) override;
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 8d12bb7..7bd5fb0 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -6625,6 +6625,8 @@
<int value="233" label="RWH_CLOSE_PORTAL"/>
<int value="234" label="MSDH_INVALID_STREAM_TYPE"/>
<int value="235" label="RFH_CREATE_CHILD_FRAME_TOKENS_NOT_FOUND"/>
+ <int value="236" label="ASGH_ASSOCIATED_INTERFACE_REQUEST"/>
+ <int value="237" label="ASGH_RECEIVED_CONTROL_MESSAGE"/>
</enum>
<enum name="BadMessageReasonExtensions">