blob: 67222ceb5473ee69a2e339f4b7a5aca232c6b1b5 [file]
// Copyright 2017 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 CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_FRAME_NODE_IMPL_H_
#define CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_FRAME_NODE_IMPL_H_
#include <memory>
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/unguessable_token.h"
#include "chrome/browser/performance_manager/graph/node_base.h"
#include "chrome/browser/performance_manager/observers/graph_observer.h"
#include "chrome/browser/performance_manager/public/graph/frame_node.h"
#include "url/gurl.h"
namespace performance_manager {
class PageNodeImpl;
class ProcessNodeImpl;
// Frame nodes form a tree structure, each FrameNode at most has one parent that
// is a FrameNode. Conceptually, a frame corresponds to a
// content::RenderFrameHost in the browser, and a content::RenderFrameImpl /
// blink::LocalFrame in a renderer.
//
// Note that a frame in a frame tree can be replaced with another, with the
// continuity of that position represented via the |frame_tree_node_id|. It is
// possible to have multiple "sibling" nodes that share the same
// |frame_tree_node_id|. Only one of these may contribute to the content being
// rendered, and this node is designated the "current" node in content
// terminology. A swap is effectively atomic but will take place in two steps
// in the graph: the outgoing frame will first be marked as not current, and the
// incoming frame will be marked as current. As such, the graph invariant is
// that there will be 0 or 1 |is_current| frames with a given
// |frame_tree_node_id|.
//
// This occurs when a frame is navigated and the existing frame can't be reused.
// In that case a "provisional" frame is created to start the navigation. Once
// the navigation completes (which may actually involve a redirect to another
// origin meaning the frame has to be destroyed and another one created in
// another process!) and commits, the frame will be swapped with the previously
// active frame.
class FrameNodeImpl
: public PublicNodeImpl<FrameNodeImpl, FrameNode>,
public TypedNodeBase<FrameNodeImpl>,
public resource_coordinator::mojom::DocumentCoordinationUnit {
public:
static constexpr NodeTypeEnum Type() { return NodeTypeEnum::kFrame; }
// Construct a frame node associated with a |process_node|, a |page_node| and
// optionally with a |parent_frame_node|. For the main frame of |page_node|
// the |parent_frame_node| parameter should be nullptr.
FrameNodeImpl(GraphImpl* graph,
ProcessNodeImpl* process_node,
PageNodeImpl* page_node,
FrameNodeImpl* parent_frame_node,
int frame_tree_node_id,
const base::UnguessableToken& dev_tools_token);
~FrameNodeImpl() override;
void Bind(
resource_coordinator::mojom::DocumentCoordinationUnitRequest request);
// resource_coordinator::mojom::DocumentCoordinationUnit implementation.
void SetNetworkAlmostIdle(bool idle) override;
void SetLifecycleState(
resource_coordinator::mojom::LifecycleState state) override;
void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload) override;
void SetInterventionPolicy(
resource_coordinator::mojom::PolicyControlledIntervention intervention,
resource_coordinator::mojom::InterventionPolicy policy) override;
void SetIsAdFrame() override;
void OnNonPersistentNotificationCreated() override;
// Getters for const properties. These can be called from any thread.
FrameNodeImpl* parent_frame_node() const;
PageNodeImpl* page_node() const;
ProcessNodeImpl* process_node() const;
int frame_tree_node_id() const;
const base::UnguessableToken& dev_tools_token() const;
// Getters for non-const properties. These are not thread safe.
const base::flat_set<FrameNodeImpl*>& child_frame_nodes() const;
resource_coordinator::mojom::LifecycleState lifecycle_state() const;
bool has_nonempty_beforeunload() const;
const GURL& url() const;
bool is_current() const;
bool network_almost_idle() const;
bool is_ad_frame() const;
// Setters are not thread safe.
void SetIsCurrent(bool is_current);
// A frame is a main frame if it has no |parent_frame_node|. This can be
// called from any thread.
bool IsMainFrame() const;
// Invoked when a navigation is committed in the frame.
void OnNavigationCommitted(const GURL& url, bool same_document);
// Returns true if all intervention policies have been set for this frame.
bool AreAllInterventionPoliciesSet() const;
// Sets the same policy for all intervention types in this frame. Causes
// Page::OnFrameInterventionPolicyChanged to be invoked.
void SetAllInterventionPoliciesForTesting(
resource_coordinator::mojom::InterventionPolicy policy);
private:
friend class PageNodeImpl;
friend class ProcessNodeImpl;
// Invoked by subframes on joining/leaving the graph.
void AddChildFrame(FrameNodeImpl* frame_node);
void RemoveChildFrame(FrameNodeImpl* frame_node);
void JoinGraph() override;
void LeaveGraph() override;
bool HasFrameNodeInAncestors(FrameNodeImpl* frame_node) const;
bool HasFrameNodeInDescendants(FrameNodeImpl* frame_node) const;
mojo::Binding<resource_coordinator::mojom::DocumentCoordinationUnit> binding_;
FrameNodeImpl* const parent_frame_node_;
PageNodeImpl* const page_node_;
ProcessNodeImpl* const process_node_;
// Can be used to tie together "sibling" frames, where a navigation is ongoing
// in a new frame that will soon replace the existing one.
const int frame_tree_node_id_;
// A unique identifier shared with all representations of this node across
// content and blink. The token is only defined by the browser process and
// is never sent back from the renderer in control calls. It should never be
// used to look up the FrameTreeNode instance.
const base::UnguessableToken dev_tools_token_;
base::flat_set<FrameNodeImpl*> child_frame_nodes_;
ObservedProperty::NotifiesOnlyOnChanges<
resource_coordinator::mojom::LifecycleState,
&GraphObserver::OnLifecycleStateChanged>
lifecycle_state_{resource_coordinator::mojom::LifecycleState::kRunning};
bool has_nonempty_beforeunload_ = false;
GURL url_;
// This is a one way switch. Once marked an ad-frame, always an ad-frame.
bool is_ad_frame_ = false;
ObservedProperty::NotifiesOnlyOnChanges<bool,
&GraphObserver::OnIsCurrentChanged>
is_current_{false};
// Network is considered almost idle when there are no more than 2 network
// connections.
ObservedProperty::
NotifiesOnlyOnChanges<bool, &GraphObserver::OnNetworkAlmostIdleChanged>
network_almost_idle_{false};
// Intervention policy for this frame. These are communicated from the
// renderer process and are controlled by origin trials.
resource_coordinator::mojom::InterventionPolicy
intervention_policy_[static_cast<size_t>(
resource_coordinator::mojom::
PolicyControlledIntervention::kMaxValue) +
1];
DISALLOW_COPY_AND_ASSIGN(FrameNodeImpl);
};
} // namespace performance_manager
#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_FRAME_NODE_IMPL_H_