blob: 90d4f4d45a2c7ae9157e728911a2c66b5649ca1f [file] [log] [blame]
// Copyright (c) 2021 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.
#ifndef CONTENT_BROWSER_SITE_INSTANCE_GROUP_H_
#define CONTENT_BROWSER_SITE_INSTANCE_GROUP_H_
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/safe_ref.h"
#include "base/observer_list.h"
#include "base/types/id_type.h"
#include "content/browser/renderer_host/agent_scheduling_group_host.h"
#include "content/common/content_export.h"
#include "content/public/browser/browsing_instance_id.h"
#include "content/public/browser/render_process_host_observer.h"
#include "third_party/perfetto/include/perfetto/tracing/traced_proto.h"
namespace perfetto::protos::pbzero {
class SiteInstanceGroup;
} // namespace perfetto::protos::pbzero
namespace content {
class SiteInstance;
struct ChildProcessTerminationInfo;
using SiteInstanceGroupId = base::IdType32<class SiteInstanceGroupIdTag>;
// A SiteInstanceGroup represents one view of a browsing context group's frame
// trees within a renderer process. It provides a tuning knob, allowing the
// number of groups to vary (for process allocation and
// painting/input/scheduling decisions) without affecting the number of security
// principals that are tracked with SiteInstances.
//
// Similar to layers composing an image from many colors, a set of
// SiteInstanceGroups compose a web page from many renderer processes. Each
// group represents one renderer process' view of a browsing context group,
// containing both local frames (organized into widgets of contiguous frames)
// and proxies for frames in other groups or processes.
//
// The documents in the local frames of a group are organized into
// SiteInstances, representing an atomic group of similar origin documents that
// can access each other directly. A group contains all the documents of one or
// more SiteInstances, all belonging to the same browsing context group (aka
// BrowsingInstance). Each browsing context group has its own set of
// SiteInstanceGroups.
//
// A SiteInstanceGroup is used for generating painted surfaces, directing input
// events, and facilitating communication between frames in different groups.
// The browser process coordinates activities across groups to produce a full
// web page.
//
// SiteInstanceGroups are refcounted by the SiteInstances using them, allowing
// for flexible policies. Currently, each SiteInstanceGroup has exactly one
// SiteInstance. See crbug.com/1195535.
class CONTENT_EXPORT SiteInstanceGroup
: public base::RefCounted<SiteInstanceGroup>,
public RenderProcessHostObserver {
public:
class CONTENT_EXPORT Observer {
public:
// Called when this SiteInstanceGroup transitions to having no active
// frames, as measured by active_frame_count().
virtual void ActiveFrameCountIsZero(SiteInstanceGroup* site_instance) {}
// Called when the renderer process of this SiteInstanceGroup has exited.
// Note that GetProcess() still returns the same RenderProcessHost instance.
// You can reinitialize it by a call to SiteInstance::GetProcess()->Init().
virtual void RenderProcessGone(SiteInstanceGroup* site_instance,
const ChildProcessTerminationInfo& info) {}
};
SiteInstanceGroup(BrowsingInstanceId browsing_instance_id,
RenderProcessHost* process);
SiteInstanceGroup(const SiteInstanceGroup&) = delete;
SiteInstanceGroup& operator=(const SiteInstanceGroup&) = delete;
SiteInstanceGroupId GetId() const;
base::SafeRef<SiteInstanceGroup> GetSafeRef();
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Increase the number of active frames in this SiteInstanceGroup. This is
// increased when a frame is created.
void IncrementActiveFrameCount();
// Decrease the number of active frames in this SiteInstanceGroup. This is
// decreased when a frame is destroyed. Decrementing this to zero will notify
// observers, and may trigger deletion of proxies.
void DecrementActiveFrameCount();
// Get the number of active frames which belong to this SiteInstanceGroup. If
// there are no active frames left, all frames in this SiteInstanceGroup can
// be safely discarded.
size_t active_frame_count() const { return active_frame_count_; }
// `process_` and `agent_scheduling_group_` have to be set together. See
// `process_` for more details.
// TODO(crbug.com/1294045): Remove once `this` has the same lifetime as
// `process`.
void SetProcessAndAgentSchedulingGroup(RenderProcessHost* process);
RenderProcessHost* process() const { return process_; }
bool has_process() const { return process_ != nullptr; }
BrowsingInstanceId browsing_instance_id() const {
return browsing_instance_id_;
}
AgentSchedulingGroupHost& agent_scheduling_group() {
DCHECK(agent_scheduling_group_);
DCHECK_EQ(agent_scheduling_group_->GetProcess(), process_);
return *agent_scheduling_group_;
}
bool has_agent_scheduling_group() {
return agent_scheduling_group_ != nullptr;
}
using TraceProto = perfetto::protos::pbzero::SiteInstanceGroup;
// Write a representation of this object into a trace.
void WriteIntoTrace(perfetto::TracedProto<TraceProto> proto) const;
private:
friend class RefCounted<SiteInstanceGroup>;
~SiteInstanceGroup() override;
// RenderProcessHostObserver implementation.
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
void RenderProcessExited(RenderProcessHost* host,
const ChildProcessTerminationInfo& info) override;
// A unique ID for this SiteInstanceGroup.
SiteInstanceGroupId id_;
// ID of the BrowsingInstance this SiteInstanceGroup belongs to.
const BrowsingInstanceId browsing_instance_id_;
// The number of active frames in this SiteInstanceGroup.
size_t active_frame_count_ = 0;
// Current RenderProcessHost that is rendering pages for this
// SiteInstanceGroup, and AgentSchedulingGroupHost (within the process) this
// SiteInstanceGroup belongs to. Since AgentSchedulingGroupHost is associated
// with a specific RenderProcessHost, these *must be* changed together to
// avoid UAF!
// The |process_| pointer (and hence the |agent_scheduling_group_| pointer as
// well) will only change once the RenderProcessHost is destructed. They will
// still remain the same even if the process crashes, since in that scenario
// the RenderProcessHost remains the same.
raw_ptr<RenderProcessHost> process_ = nullptr;
raw_ptr<AgentSchedulingGroupHost> agent_scheduling_group_ = nullptr;
base::ObserverList<Observer, true>::Unchecked observers_;
base::WeakPtrFactory<SiteInstanceGroup> weak_ptr_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_SITE_INSTANCE_GROUP_H_