blob: 4657fcac3a27916284c658375f7b574010d4f603 [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_PAGE_NODE_IMPL_H_
#define COMPONENTS_PERFORMANCE_MANAGER_GRAPH_PAGE_NODE_IMPL_H_
#include <memory>
#include <string>
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/types/pass_key.h"
#include "components/performance_manager/graph/node_attached_data.h"
#include "components/performance_manager/graph/node_base.h"
#include "components/performance_manager/public/freezing/freezing.h"
#include "components/performance_manager/public/graph/page_node.h"
#include "components/performance_manager/public/web_contents_proxy.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
namespace performance_manager {
class FrameNodeImpl;
class FrozenFrameAggregatorAccess;
class PageAggregatorAccess;
class PageLoadTrackerAccess;
class SiteDataAccess;
class PageNodeImpl
: public PublicNodeImpl<PageNodeImpl, PageNode>,
public TypedNodeBase<PageNodeImpl, PageNode, PageNodeObserver> {
public:
using PassKey = base::PassKey<PageNodeImpl>;
using FrozenFrameDataStorage =
InternalNodeAttachedDataStorage<sizeof(uintptr_t) + 8>;
using PageAggregatorDataStorage =
InternalNodeAttachedDataStorage<sizeof(uintptr_t) + 16>;
static constexpr NodeTypeEnum Type() { return NodeTypeEnum::kPage; }
PageNodeImpl(const WebContentsProxy& contents_proxy,
const std::string& browser_context_id,
const GURL& visible_url,
bool is_visible,
bool is_audible,
base::TimeTicks visibility_change_time,
PageState page_state);
PageNodeImpl(const PageNodeImpl&) = delete;
PageNodeImpl& operator=(const PageNodeImpl&) = delete;
~PageNodeImpl() override;
// Returns the web contents associated with this page node. It is valid to
// call this function on any thread but the weak pointer must only be
// dereferenced on the UI thread.
const WebContentsProxy& contents_proxy() const;
void SetType(PageType type);
void SetIsVisible(bool is_visible);
void SetIsAudible(bool is_audible);
void SetLoadingState(LoadingState loading_state);
void SetUkmSourceId(ukm::SourceId ukm_source_id);
void OnFaviconUpdated();
void OnTitleUpdated();
void OnAboutToBeDiscarded(base::WeakPtr<PageNode> new_page_node);
void OnMainFrameNavigationCommitted(bool same_document,
base::TimeTicks navigation_committed_time,
int64_t navigation_id,
const GURL& url,
const std::string& contents_mime_type);
// Returns 0 if no navigation has happened, otherwise returns the time since
// the last navigation commit.
base::TimeDelta TimeSinceLastNavigation() const;
// Returns the time since the last visibility change, it should always have a
// value since we set the visibility property when we create a
// page node.
base::TimeDelta TimeSinceLastVisibilityChange() const;
// Returns the current main frame node (if there is one), otherwise returns
// any of the potentially multiple main frames that currently exist. If there
// are no main frames at the moment, returns nullptr.
FrameNodeImpl* GetMainFrameNodeImpl() const;
// Accessors.
const std::string& browser_context_id() const;
FrameNodeImpl* opener_frame_node() const;
FrameNodeImpl* embedder_frame_node() const;
EmbeddingType embedding_type() const;
PageType type() const;
bool is_visible() const;
bool is_audible() const;
LoadingState loading_state() const;
ukm::SourceId ukm_source_id() const;
LifecycleState lifecycle_state() const;
bool is_holding_weblock() const;
bool is_holding_indexeddb_lock() const;
const base::flat_set<FrameNodeImpl*>& main_frame_nodes() const;
base::TimeTicks usage_estimate_time() const;
uint64_t private_footprint_kb_estimate() const;
const GURL& main_frame_url() const;
int64_t navigation_id() const;
const std::string& contents_mime_type() const;
bool had_form_interaction() const;
bool had_user_edits() const;
const absl::optional<freezing::FreezingVote>& freezing_vote() const;
PageState page_state() const;
// Invoked to set/clear the opener of this page.
void SetOpenerFrameNode(FrameNodeImpl* opener);
void ClearOpenerFrameNode();
// Invoked to set/clear the embedder of this page.
void SetEmbedderFrameNodeAndEmbeddingType(FrameNodeImpl* embedder,
EmbeddingType embedder_type);
void ClearEmbedderFrameNodeAndEmbeddingType();
void set_usage_estimate_time(base::TimeTicks usage_estimate_time);
void set_private_footprint_kb_estimate(
uint64_t private_footprint_kb_estimate);
void set_has_nonempty_beforeunload(bool has_nonempty_beforeunload);
void set_freezing_vote(absl::optional<freezing::FreezingVote> freezing_vote);
void set_page_state(PageState page_state);
void SetLifecycleStateForTesting(LifecycleState lifecycle_state) {
SetLifecycleState(lifecycle_state);
}
void SetIsHoldingWebLockForTesting(bool is_holding_weblock) {
SetIsHoldingWebLock(is_holding_weblock);
}
void SetIsHoldingIndexedDBLockForTesting(bool is_holding_weblock) {
SetIsHoldingIndexedDBLock(is_holding_weblock);
}
void SetHadFormInteractionForTesting(bool had_form_interaction) {
SetHadFormInteraction(had_form_interaction);
}
void SetHadUserEditsForTesting(bool had_user_edits) {
SetHadUserEdits(had_user_edits);
}
base::WeakPtr<PageNodeImpl> GetWeakPtrOnUIThread() {
// TODO(siggi): Validate thread context.
return weak_this_;
}
base::WeakPtr<PageNodeImpl> GetWeakPtr() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return weak_factory_.GetWeakPtr();
}
// Accessors to some of the NodeAttachedData:
std::unique_ptr<NodeAttachedData>& GetSiteData(
base::PassKey<SiteDataAccess>) {
return site_data_;
}
std::unique_ptr<NodeAttachedData>& GetPageLoadTrackerData(
base::PassKey<PageLoadTrackerAccess>) {
return page_load_tracker_data_;
}
FrozenFrameDataStorage& GetFrozenFrameData(
base::PassKey<FrozenFrameAggregatorAccess>) {
return frozen_frame_data_;
}
PageAggregatorDataStorage& GetPageAggregatorData(
base::PassKey<PageAggregatorAccess>) {
return page_aggregator_data_;
}
// Functions meant to be called by a FrameNodeImpl:
void AddFrame(base::PassKey<FrameNodeImpl>, FrameNodeImpl* frame_node);
void RemoveFrame(base::PassKey<FrameNodeImpl>, FrameNodeImpl* frame_node);
// Function meant to be called by FrozenFrameAggregatorAccess.
void SetLifecycleState(base::PassKey<FrozenFrameAggregatorAccess>,
LifecycleState lifecycle_state) {
SetLifecycleState(lifecycle_state);
}
// Functions meant to be called by PageAggregatorAccess:
void SetIsHoldingWebLock(base::PassKey<PageAggregatorAccess>,
bool is_holding_weblock) {
SetIsHoldingWebLock(is_holding_weblock);
}
void SetIsHoldingIndexedDBLock(base::PassKey<PageAggregatorAccess>,
bool is_holding_indexeddb_lock) {
SetIsHoldingIndexedDBLock(is_holding_indexeddb_lock);
}
void SetHadFormInteraction(base::PassKey<PageAggregatorAccess>,
bool had_form_interaction) {
SetHadFormInteraction(had_form_interaction);
}
void SetHadUserEdits(base::PassKey<PageAggregatorAccess>,
bool had_user_edits) {
SetHadUserEdits(had_user_edits);
}
private:
friend class PageNodeImplDescriber;
// PageNode implementation.
PageState GetPageState() const override;
const std::string& GetBrowserContextID() const override;
const FrameNode* GetOpenerFrameNode() const override;
const FrameNode* GetEmbedderFrameNode() const override;
EmbeddingType GetEmbeddingType() const override;
PageType GetType() const override;
bool IsVisible() const override;
base::TimeDelta GetTimeSinceLastVisibilityChange() const override;
bool IsAudible() const override;
LoadingState GetLoadingState() const override;
ukm::SourceId GetUkmSourceID() const override;
LifecycleState GetLifecycleState() const override;
bool IsHoldingWebLock() const override;
bool IsHoldingIndexedDBLock() const override;
int64_t GetNavigationID() const override;
const std::string& GetContentsMimeType() const override;
base::TimeDelta GetTimeSinceLastNavigation() const override;
const FrameNode* GetMainFrameNode() const override;
bool VisitMainFrameNodes(const FrameNodeVisitor& visitor) const override;
const base::flat_set<const FrameNode*> GetMainFrameNodes() const override;
const GURL& GetMainFrameUrl() const override;
bool HadFormInteraction() const override;
bool HadUserEdits() const override;
const WebContentsProxy& GetContentsProxy() const override;
const absl::optional<freezing::FreezingVote>& GetFreezingVote()
const override;
uint64_t EstimateResidentSetSize() const override;
uint64_t EstimatePrivateFootprintSize() const override;
// NodeBase:
void OnJoiningGraph() override;
void OnBeforeLeavingGraph() override;
void RemoveNodeAttachedData() override;
void SetLifecycleState(LifecycleState lifecycle_state);
void SetIsHoldingWebLock(bool is_holding_weblock);
void SetIsHoldingIndexedDBLock(bool is_holding_indexeddb_lock);
void SetHadFormInteraction(bool had_form_interaction);
void SetHadUserEdits(bool had_user_edits);
// The WebContentsProxy associated with this page.
const WebContentsProxy contents_proxy_;
// The main frame nodes of this page. There can be more than one main frame
// in a page, among other reasons because during main frame navigation, the
// pending navigation will coexist with the existing main frame until it's
// committed.
base::flat_set<FrameNodeImpl*> main_frame_nodes_
GUARDED_BY_CONTEXT(sequence_checker_);
// The total count of frames that tally up to this page.
size_t frame_node_count_ GUARDED_BY_CONTEXT(sequence_checker_) = 0;
// The last time at which the page visibility changed.
base::TimeTicks visibility_change_time_ GUARDED_BY_CONTEXT(sequence_checker_);
// The last time at which a main frame navigation was committed.
base::TimeTicks navigation_committed_time_
GUARDED_BY_CONTEXT(sequence_checker_);
// The time the most recent resource usage estimate applies to.
base::TimeTicks usage_estimate_time_ GUARDED_BY_CONTEXT(sequence_checker_);
// The most current memory footprint estimate.
uint64_t private_footprint_kb_estimate_
GUARDED_BY_CONTEXT(sequence_checker_) = 0;
// Indicates whether or not this page has a non-empty beforeunload handler.
// This is an aggregation of the same value on each frame in the page's frame
// tree. The aggregation is made at the moment all frames associated with a
// page have transition to frozen.
bool has_nonempty_beforeunload_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
// The URL the main frame last committed, or the initial URL a page was
// initialized with. The latter case is distinguished by a zero navigation ID.
ObservedProperty::
NotifiesOnlyOnChanges<GURL, &PageNodeObserver::OnMainFrameUrlChanged>
main_frame_url_ GUARDED_BY_CONTEXT(sequence_checker_);
// The unique ID of the navigation handle the main frame last committed, or
// zero if the page has never committed a navigation.
int64_t navigation_id_ GUARDED_BY_CONTEXT(sequence_checker_) = 0;
// The MIME type of the content associated with the last committed navigation
// event for the main frame of this page or an empty string if the page has
// never committed a navigation
std::string contents_mime_type_ GUARDED_BY_CONTEXT(sequence_checker_);
// The unique ID of the browser context that this page belongs to.
const std::string browser_context_id_;
// The opener of this page, if there is one.
raw_ptr<FrameNodeImpl> opener_frame_node_
GUARDED_BY_CONTEXT(sequence_checker_) = nullptr;
// The embedder of this page, if there is one.
raw_ptr<FrameNodeImpl> embedder_frame_node_
GUARDED_BY_CONTEXT(sequence_checker_) = nullptr;
// The way in which this page was embedded, if it was embedded.
EmbeddingType embedding_type_ GUARDED_BY_CONTEXT(sequence_checker_) =
EmbeddingType::kInvalid;
// The type of the page.
ObservedProperty::NotifiesOnlyOnChangesWithPreviousValue<
PageType,
PageType,
&PageNodeObserver::OnTypeChanged>
type_ GUARDED_BY_CONTEXT(sequence_checker_){PageType::kUnknown};
// Whether or not the page is visible. Driven by browser instrumentation.
// Initialized on construction.
ObservedProperty::NotifiesOnlyOnChanges<bool,
&PageNodeObserver::OnIsVisibleChanged>
is_visible_ GUARDED_BY_CONTEXT(sequence_checker_){false};
// Whether or not the page is audible. Driven by browser instrumentation.
// Initialized on construction.
ObservedProperty::NotifiesOnlyOnChanges<bool,
&PageNodeObserver::OnIsAudibleChanged>
is_audible_ GUARDED_BY_CONTEXT(sequence_checker_){false};
// The loading state. This is driven by instrumentation in the browser
// process.
ObservedProperty::NotifiesOnlyOnChangesWithPreviousValue<
LoadingState,
LoadingState,
&PageNodeObserver::OnLoadingStateChanged>
loading_state_ GUARDED_BY_CONTEXT(sequence_checker_){
LoadingState::kLoadingNotStarted};
// The UKM source ID associated with the URL of the main frame of this page.
ObservedProperty::NotifiesOnlyOnChanges<
ukm::SourceId,
&PageNodeObserver::OnUkmSourceIdChanged>
ukm_source_id_ GUARDED_BY_CONTEXT(sequence_checker_){
ukm::kInvalidSourceId};
// The lifecycle state of this page. This is aggregated from the lifecycle
// state of each frame in the frame tree.
ObservedProperty::NotifiesOnlyOnChanges<
LifecycleState,
&PageNodeObserver::OnPageLifecycleStateChanged>
lifecycle_state_ GUARDED_BY_CONTEXT(sequence_checker_){
LifecycleState::kRunning};
// Indicates if at least one frame of the page is currently holding a WebLock.
ObservedProperty::NotifiesOnlyOnChanges<
bool,
&PageNodeObserver::OnPageIsHoldingWebLockChanged>
is_holding_weblock_ GUARDED_BY_CONTEXT(sequence_checker_){false};
// Indicates if at least one frame of the page is currently holding an
// IndexedDB lock.
ObservedProperty::NotifiesOnlyOnChanges<
bool,
&PageNodeObserver::OnPageIsHoldingIndexedDBLockChanged>
is_holding_indexeddb_lock_ GUARDED_BY_CONTEXT(sequence_checker_){false};
// Indicates if at least one frame of the page has received some form
// interactions.
ObservedProperty::NotifiesOnlyOnChanges<
bool,
&PageNodeObserver::OnHadFormInteractionChanged>
had_form_interaction_ GUARDED_BY_CONTEXT(sequence_checker_){false};
// Indicates if at least one frame of the page has received some
// user-initiated edits.
ObservedProperty::
NotifiesOnlyOnChanges<bool, &PageNodeObserver::OnHadUserEditsChanged>
had_user_edits_ GUARDED_BY_CONTEXT(sequence_checker_){false};
// The freezing vote associated with this page, see the comment of to
// Page::GetFreezingVote for a description of the different values this can
// take.
ObservedProperty::NotifiesOnlyOnChangesWithPreviousValue<
absl::optional<freezing::FreezingVote>,
absl::optional<freezing::FreezingVote>,
&PageNodeObserver::OnFreezingVoteChanged>
freezing_vote_ GUARDED_BY_CONTEXT(sequence_checker_);
// The state of this page.
ObservedProperty::NotifiesOnlyOnChangesWithPreviousValue<
PageState,
PageState,
&PageNodeObserver::OnPageStateChanged>
page_state_ GUARDED_BY_CONTEXT(sequence_checker_){PageState::kActive};
// Storage for PageLoadTracker user data.
std::unique_ptr<NodeAttachedData> page_load_tracker_data_
GUARDED_BY_CONTEXT(sequence_checker_);
// Storage for SiteDataNodeData user data.
std::unique_ptr<NodeAttachedData> site_data_
GUARDED_BY_CONTEXT(sequence_checker_);
// Inline storage for FrozenFrameAggregator user data.
FrozenFrameDataStorage frozen_frame_data_
GUARDED_BY_CONTEXT(sequence_checker_);
// Inline storage for PageAggregatorAccess user data.
PageAggregatorDataStorage page_aggregator_data_
GUARDED_BY_CONTEXT(sequence_checker_);
base::WeakPtr<PageNodeImpl> weak_this_;
base::WeakPtrFactory<PageNodeImpl> weak_factory_
GUARDED_BY_CONTEXT(sequence_checker_){this};
};
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_GRAPH_PAGE_NODE_IMPL_H_