blob: 918ae3afe00bd79688ff45a9338db87a69066af3 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PERFORMANCE_MANAGER_GRAPH_GRAPH_IMPL_H_
#define COMPONENTS_PERFORMANCE_MANAGER_GRAPH_GRAPH_IMPL_H_
#include <stdint.h>
#include <array>
#include <map>
#include <memory>
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/process/process_handle.h"
#include "base/sequence_checker.h"
#include "components/performance_manager/execution_context/execution_context_registry_impl.h"
#include "components/performance_manager/owned_objects.h"
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/public/graph/graph_registered.h"
#include "components/performance_manager/public/graph/node_attached_data.h"
#include "components/performance_manager/public/graph/node_state.h"
#include "components/performance_manager/public/graph/node_type.h"
#include "components/performance_manager/public/render_process_host_id.h"
#include "components/performance_manager/registered_objects.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
namespace performance_manager {
class FrameNodeImpl;
class Node;
class NodeBase;
class PageNodeImpl;
class ProcessNodeImpl;
class SystemNodeImpl;
class WorkerNodeImpl;
// Represents a graph of the nodes representing a single browser. Maintains a
// set of nodes that can be retrieved in different ways, some indexed. Keeps
// a list of observers that are notified of node addition and removal.
class GraphImpl : public Graph {
public:
// An ObserverList that DCHECK's if any observers are still in it when the
// graph is deleted. `allow_reentrancy` is true because some observers update
// node properties that also trigger observers. (For example
// FrameVisibilityVoter::OnFrameVisibilityChanged() can call
// FrameNodeImpl::SetPriorityAndReason().)
template <typename Observer>
using ObserverList = base::ObserverList<Observer,
/*check_empty=*/true,
/*allow_reentrancy=*/true>;
GraphImpl();
~GraphImpl() override;
// Disallow copy and assign.
GraphImpl(const GraphImpl&) = delete;
GraphImpl& operator=(const GraphImpl&) = delete;
// Set up the graph.
void SetUp();
// Tear down the graph to prepare for deletion.
void TearDown();
// Graph implementation:
void AddFrameNodeObserver(FrameNodeObserver* observer) override;
void AddPageNodeObserver(PageNodeObserver* observer) override;
void AddProcessNodeObserver(ProcessNodeObserver* observer) override;
void AddSystemNodeObserver(SystemNodeObserver* observer) override;
void AddWorkerNodeObserver(WorkerNodeObserver* observer) override;
void RemoveFrameNodeObserver(FrameNodeObserver* observer) override;
void RemovePageNodeObserver(PageNodeObserver* observer) override;
void RemoveProcessNodeObserver(ProcessNodeObserver* observer) override;
void RemoveSystemNodeObserver(SystemNodeObserver* observer) override;
void RemoveWorkerNodeObserver(WorkerNodeObserver* observer) override;
void PassToGraphImpl(std::unique_ptr<GraphOwned> graph_owned) override;
std::unique_ptr<GraphOwned> TakeFromGraph(GraphOwned* graph_owned) override;
void RegisterObject(GraphRegistered* object) override;
void UnregisterObject(GraphRegistered* object) override;
const SystemNode* GetSystemNode() const override;
NodeSetView<const ProcessNode*> GetAllProcessNodes() const override;
NodeSetView<const FrameNode*> GetAllFrameNodes() const override;
NodeSetView<const PageNode*> GetAllPageNodes() const override;
NodeSetView<const WorkerNode*> GetAllWorkerNodes() const override;
bool HasOnlySystemNode() const override;
ukm::UkmRecorder* GetUkmRecorder() const override;
NodeDataDescriberRegistry* GetNodeDataDescriberRegistry() const override;
uintptr_t GetImplType() const override;
const void* GetImpl() const override;
#if DCHECK_IS_ON()
bool IsOnGraphSequence() const override;
#endif
GraphRegistered* GetRegisteredObject(uintptr_t type_id) override;
// Helper function for safely downcasting to the implementation. This also
// casts away constness. This will CHECK on an invalid cast.
static GraphImpl* FromGraph(const Graph* graph);
void set_ukm_recorder(ukm::UkmRecorder* ukm_recorder) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
ukm_recorder_ = ukm_recorder;
}
ukm::UkmRecorder* ukm_recorder() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return ukm_recorder_;
}
SystemNodeImpl* GetSystemNodeImpl() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return system_node_.get();
}
NodeSetView<ProcessNodeImpl*> GetAllProcessNodeImpls() const;
NodeSetView<FrameNodeImpl*> GetAllFrameNodeImpls() const;
NodeSetView<PageNodeImpl*> GetAllPageNodeImpls() const;
NodeSetView<WorkerNodeImpl*> GetAllWorkerNodeImpls() const;
// Retrieves the process node with PID |pid|, if any.
ProcessNodeImpl* GetProcessNodeByPid(base::ProcessId pid);
// Retrieves the frame node with the routing ids of the process and the frame.
FrameNodeImpl* GetFrameNodeById(RenderProcessHostId render_process_id,
int render_frame_id);
// Returns true if |node| is in this graph.
bool NodeInGraph(const NodeBase* node) const;
// Returns true iff `node` is in a state where its edges are publicly visible.
bool NodeEdgesArePublic(const NodeBase* node) const;
// Management functions for node owners, any node added to the graph must be
// removed from the graph before it's deleted.
void AddNewNode(NodeBase* new_node);
void RemoveNode(NodeBase* node);
// Allows explicitly invoking SystemNode destruction for testing.
void ReleaseSystemNodeForTesting() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
ReleaseSystemNode();
}
size_t GraphOwnedCountForTesting() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return graph_owned_.size();
}
size_t GraphRegisteredCountForTesting() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return registered_objects_.size();
}
// Returns the number of registered NodeDataDescribers, for testing.
size_t NodeDataDescriberCountForTesting() const;
protected:
friend class NodeBase;
// Returns the underlying set holding all nodes of type `node_type`.
NodeSet& GetNodesOfType(NodeTypeEnum node_type);
const NodeSet& GetNodesOfType(NodeTypeEnum node_type) const;
// Used to implement `NodeBase::GetNodeState()` and `Node::GetNodeState()`.
NodeState GetNodeState(const NodeBase* node) const;
// Provides access to per-node-class typed observers. Exposed to nodes via
// TypedNodeBase.
template <typename Observer>
const ObserverList<Observer>& GetObservers() const;
private:
struct ProcessAndFrameId {
ProcessAndFrameId(RenderProcessHostId render_process_id,
int render_frame_id);
~ProcessAndFrameId();
ProcessAndFrameId(const ProcessAndFrameId& other);
ProcessAndFrameId& operator=(const ProcessAndFrameId& other);
bool operator<(const ProcessAndFrameId& other) const;
RenderProcessHostId render_process_id;
int render_frame_id;
};
using ProcessByPidMap = std::map<base::ProcessId, ProcessNodeImpl*>;
using FrameById =
std::map<ProcessAndFrameId, raw_ptr<FrameNodeImpl, CtnExperimental>>;
void DispatchBeforeNodeAddedNotifications(NodeBase* node);
void DispatchNodeAddedNotifications(NodeBase* node);
void DispatchBeforeNodeRemovedNotifications(NodeBase* node);
void DispatchNodeRemovedNotifications(NodeBase* node);
// Returns a new serialization ID.
friend class NodeBase;
int64_t GetNextNodeSerializationId();
// Process PID map for use by ProcessNodeImpl.
friend class ProcessNodeImpl;
void BeforeProcessPidChange(ProcessNodeImpl* process,
base::ProcessId new_pid);
// Frame id map for use by FrameNodeImpl.
friend class FrameNodeImpl;
void RegisterFrameNodeForId(RenderProcessHostId render_process_id,
int render_frame_id,
FrameNodeImpl* frame_node);
void UnregisterFrameNodeForId(RenderProcessHostId render_process_id,
int render_frame_id,
FrameNodeImpl* frame_node);
void CreateSystemNode() VALID_CONTEXT_REQUIRED(sequence_checker_);
void ReleaseSystemNode() VALID_CONTEXT_REQUIRED(sequence_checker_);
enum class LifecycleState {
kBeforeSetUp,
kSetUpCalled,
kTearDownCalled,
};
// Tracks the lifecycle state of this instance to enforce calls to `SetUp()`
// and `TearDown()`.
LifecycleState lifecycle_state_ = LifecycleState::kBeforeSetUp;
std::unique_ptr<SystemNodeImpl> system_node_
GUARDED_BY_CONTEXT(sequence_checker_);
std::array<NodeSet, kValidNodeTypeCount> nodes_
GUARDED_BY_CONTEXT(sequence_checker_);
ProcessByPidMap processes_by_pid_ GUARDED_BY_CONTEXT(sequence_checker_);
FrameById frames_by_id_ GUARDED_BY_CONTEXT(sequence_checker_);
raw_ptr<ukm::UkmRecorder> ukm_recorder_
GUARDED_BY_CONTEXT(sequence_checker_) = nullptr;
// Typed observers.
ObserverList<FrameNodeObserver> frame_node_observers_
GUARDED_BY_CONTEXT(sequence_checker_);
ObserverList<PageNodeObserver> page_node_observers_
GUARDED_BY_CONTEXT(sequence_checker_);
ObserverList<ProcessNodeObserver> process_node_observers_
GUARDED_BY_CONTEXT(sequence_checker_);
ObserverList<SystemNodeObserver> system_node_observers_
GUARDED_BY_CONTEXT(sequence_checker_);
ObserverList<WorkerNodeObserver> worker_node_observers_
GUARDED_BY_CONTEXT(sequence_checker_);
// Graph-owned objects. For now we only expect O(10) clients, hence the
// flat_map.
OwnedObjects<GraphOwned,
/* CallbackArgType = */ Graph*,
&GraphOwned::PassToGraphImpl,
&GraphOwned::TakeFromGraphImpl>
graph_owned_ GUARDED_BY_CONTEXT(sequence_checker_);
// Allocated on first use.
mutable std::unique_ptr<NodeDataDescriberRegistry> describer_registry_
GUARDED_BY_CONTEXT(sequence_checker_);
// Storage for GraphRegistered objects.
RegisteredObjects<GraphRegistered> registered_objects_
GUARDED_BY_CONTEXT(sequence_checker_);
execution_context::ExecutionContextRegistryImpl
execution_context_registry_impl_;
// The most recently assigned serialization ID.
int64_t current_node_serialization_id_ GUARDED_BY_CONTEXT(sequence_checker_) =
0u;
// The identity of the node currently being added to or removed from the
// graph, if any. This is used to prevent re-entrant notifications.
raw_ptr<const NodeBase> node_in_transition_ = nullptr;
// The state of the node being added or removed. Any node in the graph not
// explicitly in transition is automatically in the kActiveInGraph state.
NodeState node_in_transition_state_ = NodeState::kNotInGraph;
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_GRAPH_GRAPH_IMPL_H_