Commit f38b35b8 authored by kouhei's avatar kouhei Committed by Commit Bot

AgentSchedulingGroupHost: Introduce lifecycle statemachine

This CL introduces a lifecycle statemachine to AgentSchedulingGroupHost.
The `AgentSchedulingGroupHost::state_` makes it explicit which lifestage
the AgentSchedulingGroupHost is currently at, and checks if each method
is called on one of the assumed states.

This is a preparatory work to introducing AgentSchedulingGroupHost
shutdown, which will add more states to the state machine.

Bug: 1141459
Change-Id: Ic8c4f4f85322b52612510b3354d5ae6828311263
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2492281
Commit-Queue: Kouhei Ueno <kouhei@chromium.org>
Auto-Submit: Kouhei Ueno <kouhei@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarDominic Farolino <dom@chromium.org>
Reviewed-by: default avatarTal Pressman <talp@chromium.org>
Cr-Commit-Position: refs/heads/master@{#826664}
parent 186ae3d5
...@@ -6,10 +6,13 @@ ...@@ -6,10 +6,13 @@
#include <memory> #include <memory>
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "base/supports_user_data.h" #include "base/supports_user_data.h"
#include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/common/agent_scheduling_group.mojom.h" #include "content/common/agent_scheduling_group.mojom.h"
#include "content/common/renderer.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/browser/render_process_host.h"
#include "content/public/common/content_features.h" #include "content/public/common/content_features.h"
#include "ipc/ipc_message.h" #include "ipc/ipc_message.h"
...@@ -174,11 +177,14 @@ AgentSchedulingGroupHost::AgentSchedulingGroupHost(RenderProcessHost& process, ...@@ -174,11 +177,14 @@ AgentSchedulingGroupHost::AgentSchedulingGroupHost(RenderProcessHost& process,
// DO NOT USE |process_| HERE! At this point it (or at least parts of it) is no // DO NOT USE |process_| HERE! At this point it (or at least parts of it) is no
// longer valid. // longer valid.
AgentSchedulingGroupHost::~AgentSchedulingGroupHost() = default; AgentSchedulingGroupHost::~AgentSchedulingGroupHost() {
DCHECK_EQ(state_, LifecycleState::kRenderProcessHostDestroyed);
}
void AgentSchedulingGroupHost::RenderProcessExited( void AgentSchedulingGroupHost::RenderProcessExited(
RenderProcessHost* host, RenderProcessHost* host,
const ChildProcessTerminationInfo& info) { const ChildProcessTerminationInfo& info) {
SetState(LifecycleState::kRenderProcessExited);
DCHECK_EQ(host, &process_); DCHECK_EQ(host, &process_);
// We mirror the RenderProcessHost flow here by resetting our mojos, and // We mirror the RenderProcessHost flow here by resetting our mojos, and
...@@ -200,11 +206,26 @@ void AgentSchedulingGroupHost::RenderProcessExited( ...@@ -200,11 +206,26 @@ void AgentSchedulingGroupHost::RenderProcessExited(
void AgentSchedulingGroupHost::RenderProcessHostDestroyed( void AgentSchedulingGroupHost::RenderProcessHostDestroyed(
RenderProcessHost* host) { RenderProcessHost* host) {
if (RenderProcessHost::run_renderer_in_process()) {
// In single process mode, RenderProcessExited call is sometimes omitted.
if (state_ != LifecycleState::kBound) {
RenderProcessExited(host, ChildProcessTerminationInfo());
}
}
DCHECK_EQ(state_, LifecycleState::kBound);
DCHECK_EQ(host, &process_); DCHECK_EQ(host, &process_);
process_.RemoveObserver(this); process_.RemoveObserver(this);
SetState(LifecycleState::kRenderProcessHostDestroyed);
} }
RenderProcessHost* AgentSchedulingGroupHost::GetProcess() { RenderProcessHost* AgentSchedulingGroupHost::GetProcess() {
// TODO(crbug.com/1111231): Make the condition below hold.
// Currently the DCHECK doesn't hold, since RenderViewHostImpl outlives
// its associated AgentSchedulingGroupHost, and the dtor queries the
// associated RenderProcessHost to remove itself from the
// PerProcessRenderViewHostSet and RemoveObserver() itself.
// DCHECK_NE(state_, LifecycleState::kRenderProcessHostDestroyed);
return &process_; return &process_;
} }
...@@ -217,41 +238,48 @@ bool AgentSchedulingGroupHost::Init() { ...@@ -217,41 +238,48 @@ bool AgentSchedulingGroupHost::Init() {
// interfaces. // interfaces.
DCHECK(process_.GetRendererInterface()); DCHECK(process_.GetRendererInterface());
DCHECK(mojo_remote_.is_bound()); DCHECK(mojo_remote_.is_bound());
DCHECK_EQ(state_, LifecycleState::kBound);
return process_.Init(); return process_.Init();
} }
ChannelProxy* AgentSchedulingGroupHost::GetChannel() { ChannelProxy* AgentSchedulingGroupHost::GetChannel() {
DCHECK_EQ(state_, LifecycleState::kBound);
return process_.GetChannel(); return process_.GetChannel();
} }
bool AgentSchedulingGroupHost::Send(IPC::Message* message) { bool AgentSchedulingGroupHost::Send(IPC::Message* message) {
DCHECK_EQ(state_, LifecycleState::kBound);
return process_.Send(message); return process_.Send(message);
} }
void AgentSchedulingGroupHost::AddRoute(int32_t routing_id, void AgentSchedulingGroupHost::AddRoute(int32_t routing_id,
Listener* listener) { Listener* listener) {
DCHECK_EQ(state_, LifecycleState::kBound);
DCHECK(!listener_map_.Lookup(routing_id)); DCHECK(!listener_map_.Lookup(routing_id));
listener_map_.AddWithID(listener, routing_id); listener_map_.AddWithID(listener, routing_id);
process_.AddRoute(routing_id, listener); process_.AddRoute(routing_id, listener);
} }
void AgentSchedulingGroupHost::RemoveRoute(int32_t routing_id) { void AgentSchedulingGroupHost::RemoveRoute(int32_t routing_id) {
DCHECK(listener_map_.Lookup(routing_id)); DCHECK_EQ(state_, LifecycleState::kBound);
listener_map_.Remove(routing_id); listener_map_.Remove(routing_id);
process_.RemoveRoute(routing_id); process_.RemoveRoute(routing_id);
} }
mojom::RouteProvider* AgentSchedulingGroupHost::GetRemoteRouteProvider() { mojom::RouteProvider* AgentSchedulingGroupHost::GetRemoteRouteProvider() {
DCHECK_EQ(state_, LifecycleState::kBound);
return remote_route_provider_.get(); return remote_route_provider_.get();
} }
void AgentSchedulingGroupHost::CreateFrame(mojom::CreateFrameParamsPtr params) { void AgentSchedulingGroupHost::CreateFrame(mojom::CreateFrameParamsPtr params) {
DCHECK_EQ(state_, LifecycleState::kBound);
DCHECK(process_.IsInitializedAndNotDead()); DCHECK(process_.IsInitializedAndNotDead());
DCHECK(mojo_remote_.is_bound()); DCHECK(mojo_remote_.is_bound());
mojo_remote_.get()->CreateFrame(std::move(params)); mojo_remote_.get()->CreateFrame(std::move(params));
} }
void AgentSchedulingGroupHost::CreateView(mojom::CreateViewParamsPtr params) { void AgentSchedulingGroupHost::CreateView(mojom::CreateViewParamsPtr params) {
DCHECK_EQ(state_, LifecycleState::kBound);
DCHECK(process_.IsInitializedAndNotDead()); DCHECK(process_.IsInitializedAndNotDead());
DCHECK(mojo_remote_.is_bound()); DCHECK(mojo_remote_.is_bound());
mojo_remote_.get()->CreateView(std::move(params)); mojo_remote_.get()->CreateView(std::move(params));
...@@ -260,6 +288,7 @@ void AgentSchedulingGroupHost::CreateView(mojom::CreateViewParamsPtr params) { ...@@ -260,6 +288,7 @@ void AgentSchedulingGroupHost::CreateView(mojom::CreateViewParamsPtr params) {
void AgentSchedulingGroupHost::DestroyView( void AgentSchedulingGroupHost::DestroyView(
int32_t routing_id, int32_t routing_id,
mojom::AgentSchedulingGroup::DestroyViewCallback callback) { 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)); mojo_remote_.get()->DestroyView(routing_id, std::move(callback));
else else
...@@ -274,6 +303,7 @@ void AgentSchedulingGroupHost::CreateFrameProxy( ...@@ -274,6 +303,7 @@ void AgentSchedulingGroupHost::CreateFrameProxy(
const FrameReplicationState& replicated_state, const FrameReplicationState& replicated_state,
const base::UnguessableToken& frame_token, const base::UnguessableToken& frame_token,
const base::UnguessableToken& devtools_frame_token) { const base::UnguessableToken& devtools_frame_token) {
DCHECK_EQ(state_, LifecycleState::kBound);
mojo_remote_.get()->CreateFrameProxy( mojo_remote_.get()->CreateFrameProxy(
routing_id, render_view_routing_id, opener_frame_token, parent_routing_id, routing_id, render_view_routing_id, opener_frame_token, parent_routing_id,
replicated_state, frame_token, devtools_frame_token); replicated_state, frame_token, devtools_frame_token);
...@@ -283,6 +313,7 @@ void AgentSchedulingGroupHost::GetRoute( ...@@ -283,6 +313,7 @@ void AgentSchedulingGroupHost::GetRoute(
int32_t routing_id, int32_t routing_id,
mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterfaceProvider> mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterfaceProvider>
receiver) { receiver) {
DCHECK_EQ(state_, LifecycleState::kBound);
DCHECK(receiver.is_valid()); DCHECK(receiver.is_valid());
associated_interface_provider_receivers_.Add(this, std::move(receiver), associated_interface_provider_receivers_.Add(this, std::move(receiver),
routing_id); routing_id);
...@@ -292,6 +323,7 @@ void AgentSchedulingGroupHost::GetAssociatedInterface( ...@@ -292,6 +323,7 @@ void AgentSchedulingGroupHost::GetAssociatedInterface(
const std::string& name, const std::string& name,
mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface> mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface>
receiver) { receiver) {
DCHECK_EQ(state_, LifecycleState::kBound);
int32_t routing_id = int32_t routing_id =
associated_interface_provider_receivers_.current_context(); associated_interface_provider_receivers_.current_context();
...@@ -300,6 +332,7 @@ void AgentSchedulingGroupHost::GetAssociatedInterface( ...@@ -300,6 +332,7 @@ void AgentSchedulingGroupHost::GetAssociatedInterface(
} }
void AgentSchedulingGroupHost::ResetMojo() { void AgentSchedulingGroupHost::ResetMojo() {
DCHECK_EQ(state_, LifecycleState::kRenderProcessExited);
receiver_.reset(); receiver_.reset();
mojo_remote_.reset(); mojo_remote_.reset();
remote_route_provider_.reset(); remote_route_provider_.reset();
...@@ -319,13 +352,21 @@ void AgentSchedulingGroupHost::SetUpMojoIfNeeded() { ...@@ -319,13 +352,21 @@ void AgentSchedulingGroupHost::SetUpMojoIfNeeded() {
DCHECK(process_.GetRendererInterface()); DCHECK(process_.GetRendererInterface());
// Make sure that the bind state of all of this class's mojos are equivalent. // Make sure that the bind state of all of this class's mojos are equivalent.
DCHECK_EQ(mojo_remote_.is_bound(), receiver_.is_bound()); if (state_ == LifecycleState::kBound) {
DCHECK_EQ(receiver_.is_bound(), remote_route_provider_.is_bound()); DCHECK(mojo_remote_.is_bound());
DCHECK_EQ(remote_route_provider_.is_bound(), DCHECK(receiver_.is_bound());
route_provider_receiver_.is_bound()); DCHECK(remote_route_provider_.is_bound());
DCHECK(route_provider_receiver_.is_bound());
if (receiver_.is_bound())
return; return;
}
DCHECK(!mojo_remote_.is_bound());
DCHECK(!receiver_.is_bound());
DCHECK(!remote_route_provider_.is_bound());
DCHECK(!route_provider_receiver_.is_bound());
DCHECK(state_ == LifecycleState::kNewborn ||
state_ == LifecycleState::kRenderProcessExited);
if (should_associate_) { if (should_associate_) {
process_.GetRendererInterface()->CreateAssociatedAgentSchedulingGroup( process_.GetRendererInterface()->CreateAssociatedAgentSchedulingGroup(
...@@ -340,6 +381,47 @@ void AgentSchedulingGroupHost::SetUpMojoIfNeeded() { ...@@ -340,6 +381,47 @@ void AgentSchedulingGroupHost::SetUpMojoIfNeeded() {
mojo_remote_.get()->BindAssociatedRouteProvider( mojo_remote_.get()->BindAssociatedRouteProvider(
route_provider_receiver_.BindNewEndpointAndPassRemote(), route_provider_receiver_.BindNewEndpointAndPassRemote(),
remote_route_provider_.BindNewEndpointAndPassReceiver()); remote_route_provider_.BindNewEndpointAndPassReceiver());
SetState(LifecycleState::kBound);
}
void AgentSchedulingGroupHost::SetState(
AgentSchedulingGroupHost::LifecycleState state) {
static const base::NoDestructor<StateTransitions<LifecycleState>> transitions(
StateTransitions<LifecycleState>({
{LifecycleState::kNewborn, {LifecycleState::kBound}},
{LifecycleState::kBound,
{LifecycleState::kRenderProcessExited,
// Note: kRenderProcessHostDestroyed is only reached through kBound
// state. Upon kRenderProcessExited, we immediately setup a
// unclaimed mojo endpoint to be consumed by the next
// renderer process.
LifecycleState::kRenderProcessHostDestroyed}},
{LifecycleState::kRenderProcessExited, {LifecycleState::kBound}},
}));
DCHECK_STATE_TRANSITION(transitions, state_, state);
state_ = state;
}
std::ostream& operator<<(std::ostream& os,
AgentSchedulingGroupHost::LifecycleState state) {
switch (state) {
case AgentSchedulingGroupHost::LifecycleState::kNewborn:
os << "Newborn";
break;
case AgentSchedulingGroupHost::LifecycleState::kBound:
os << "Bound";
break;
case AgentSchedulingGroupHost::LifecycleState::kRenderProcessExited:
os << "RenderProcessExited";
break;
case AgentSchedulingGroupHost::LifecycleState::kRenderProcessHostDestroyed:
os << "RenderProcessHostDestroyed";
break;
default:
os << "<invalid value: " << static_cast<int>(state) << ">";
}
return os;
} }
Listener* AgentSchedulingGroupHost::GetListener(int32_t routing_id) { Listener* AgentSchedulingGroupHost::GetListener(int32_t routing_id) {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "content/common/associated_interfaces.mojom.h" #include "content/common/associated_interfaces.mojom.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/common/renderer.mojom-forward.h" #include "content/common/renderer.mojom-forward.h"
#include "content/common/state_transitions.h"
#include "content/public/browser/render_process_host_observer.h" #include "content/public/browser/render_process_host_observer.h"
#include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h" #include "mojo/public/cpp/bindings/associated_receiver_set.h"
...@@ -58,11 +59,6 @@ class CONTENT_EXPORT AgentSchedulingGroupHost ...@@ -58,11 +59,6 @@ class CONTENT_EXPORT AgentSchedulingGroupHost
explicit AgentSchedulingGroupHost(RenderProcessHost& process); explicit AgentSchedulingGroupHost(RenderProcessHost& process);
~AgentSchedulingGroupHost() override; ~AgentSchedulingGroupHost() override;
// RenderProcessHostObserver:
void RenderProcessExited(RenderProcessHost* host,
const ChildProcessTerminationInfo& info) override;
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
RenderProcessHost* GetProcess(); RenderProcessHost* GetProcess();
// Ensure that the process this AgentSchedulingGroupHost belongs to is alive. // Ensure that the process this AgentSchedulingGroupHost belongs to is alive.
// Returns |false| if any part of the initialization failed. // Returns |false| if any part of the initialization failed.
...@@ -92,6 +88,24 @@ class CONTENT_EXPORT AgentSchedulingGroupHost ...@@ -92,6 +88,24 @@ class CONTENT_EXPORT AgentSchedulingGroupHost
const base::UnguessableToken& devtools_frame_token); const base::UnguessableToken& devtools_frame_token);
private: private:
enum class LifecycleState {
// Just instantiated, no route assigned yet.
kNewborn,
// Bound mojo connection to the renderer.
kBound,
// Intermediate state between renderer process exit and rebinding mojo
// connections.
kRenderProcessExited,
// RenderProcessHost is destroyed, and `this` is pending for deletion.
// kRenderProcessHostDestroyed is the terminal state of the state machine.
kRenderProcessHostDestroyed,
};
friend StateTransitions<LifecycleState>;
friend std::ostream& operator<<(std::ostream& os, LifecycleState state);
// `MaybeAssociatedReceiver` and `MaybeAssociatedRemote` are temporary helper // `MaybeAssociatedReceiver` and `MaybeAssociatedRemote` are temporary helper
// classes that allow us to switch between using associated and non-associated // classes that allow us to switch between using associated and non-associated
// mojo interfaces. This behavior is controlled by the // mojo interfaces. This behavior is controlled by the
...@@ -173,9 +187,16 @@ class CONTENT_EXPORT AgentSchedulingGroupHost ...@@ -173,9 +187,16 @@ class CONTENT_EXPORT AgentSchedulingGroupHost
mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface> mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface>
receiver) override; receiver) override;
// RenderProcessHostObserver:
void RenderProcessExited(RenderProcessHost* host,
const ChildProcessTerminationInfo& info) override;
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
void ResetMojo(); void ResetMojo();
void SetUpMojoIfNeeded(); void SetUpMojoIfNeeded();
void SetState(LifecycleState state);
IPC::Listener* GetListener(int32_t routing_id); IPC::Listener* GetListener(int32_t routing_id);
// The RenderProcessHost this AgentSchedulingGroup is assigned to. // The RenderProcessHost this AgentSchedulingGroup is assigned to.
...@@ -207,8 +228,12 @@ class CONTENT_EXPORT AgentSchedulingGroupHost ...@@ -207,8 +228,12 @@ class CONTENT_EXPORT AgentSchedulingGroupHost
mojo::AssociatedReceiverSet<blink::mojom::AssociatedInterfaceProvider, mojo::AssociatedReceiverSet<blink::mojom::AssociatedInterfaceProvider,
int32_t> int32_t>
associated_interface_provider_receivers_; associated_interface_provider_receivers_;
LifecycleState state_{LifecycleState::kNewborn};
}; };
std::ostream& operator<<(std::ostream& os,
AgentSchedulingGroupHost::LifecycleState state);
} // namespace content } // namespace content
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment