Commit 48a6993d authored by Chris Hamilton's avatar Chris Hamilton Committed by Commit Bot

[PM] Wire up openers in graph.

This adds dashed links w/ arrows to the graph, indicating opener/openee
embedder/embeddee relationships. It also makes pinned nodes visually
distinct by changing their stroke color.

BUG=1085129

Change-Id: I0bd75a90c83a735b7d56ff2905d7d3d7b7be6e84
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2227369
Commit-Queue: Chris Hamilton <chrisha@chromium.org>
Reviewed-by: default avatarWill Harris <wfh@chromium.org>
Reviewed-by: default avatarJoe Mason <joenotcharles@chromium.org>
Cr-Commit-Position: refs/heads/master@{#774935}
parent c3e0f26b
...@@ -316,11 +316,22 @@ class GraphNode { ...@@ -316,11 +316,22 @@ class GraphNode {
return -200; return -200;
} }
/** @return {!Array<number>} */ /** @return {!Array<number>} an array of node ids. */
get linkTargets() { get linkTargets() {
return []; return [];
} }
/**
* Dashed links express ownership relationships. An object can own multiple
* things, but be owned by exactly one (per relationship type). As such, the
* relationship is expressed on the *owned* object. These links are drawn with
* an arrow at the beginning of the link, pointing to the owned object.
* @return {!Array<number>} an array of node ids.
*/
get dashedLinkTargets() {
return [];
}
/** /**
* Selects a color string from an id. * Selects a color string from an id.
* @param {number} id The id the returned color is selected from. * @param {number} id The id the returned color is selected from.
...@@ -370,6 +381,14 @@ class PageNode extends GraphNode { ...@@ -370,6 +381,14 @@ class PageNode extends GraphNode {
get manyBodyStrength() { get manyBodyStrength() {
return -600; return -600;
} }
/** override */
get dashedLinkTargets() {
if (this.page.openerFrameId) {
return [this.page.openerFrameId];
}
return [];
}
} }
class FrameNode extends GraphNode { class FrameNode extends GraphNode {
...@@ -590,6 +609,12 @@ class Graph { ...@@ -590,6 +609,12 @@ class Graph {
*/ */
this.linkGroup_ = null; this.linkGroup_ = null;
/**
* A selection for the top-level <g> node that contains all dashed edges.
* @private {d3.selection}
*/
this.dashedLinkGroup_ = null;
/** @private {!Map<number, !GraphNode>} */ /** @private {!Map<number, !GraphNode>} */
this.nodes_ = new Map(); this.nodes_ = new Map();
...@@ -599,6 +624,12 @@ class Graph { ...@@ -599,6 +624,12 @@ class Graph {
*/ */
this.links_ = []; this.links_ = [];
/**
* The dashed links.
* @private {!Array<!d3.ForceLink>}
*/
this.dashedLinks_ = [];
/** /**
* The host window. * The host window.
* @private {Window} * @private {Window}
...@@ -655,8 +686,9 @@ class Graph { ...@@ -655,8 +686,9 @@ class Graph {
// Create the <g> elements that host nodes and links. // Create the <g> elements that host nodes and links.
// The link groups are created first so that all links end up behind nodes. // The link groups are created first so that all links end up behind nodes.
const svg = d3.select(this.svg_); const svg = d3.select(this.svg_);
this.toolTipLinkGroup_ = svg.append('g').attr('class', 'toolTipLinks'); this.toolTipLinkGroup_ = svg.append('g').attr('class', 'tool-tip-links');
this.linkGroup_ = svg.append('g').attr('class', 'links'); this.linkGroup_ = svg.append('g').attr('class', 'links');
this.dashedLinkGroup_ = svg.append('g').attr('class', 'dashed-links');
this.nodeGroup_ = svg.append('g').attr('class', 'nodes'); this.nodeGroup_ = svg.append('g').attr('class', 'nodes');
this.separatorGroup_ = svg.append('g').attr('class', 'separators'); this.separatorGroup_ = svg.append('g').attr('class', 'separators');
...@@ -697,7 +729,11 @@ class Graph { ...@@ -697,7 +729,11 @@ class Graph {
/** @override */ /** @override */
pageChanged(page) { pageChanged(page) {
const pageNode = /** @type {!PageNode} */ (this.nodes_.get(page.id)); const pageNode = /** @type {!PageNode} */ (this.nodes_.get(page.id));
// Page node dashed links may change dynamically, so account for that here.
this.removeDashedNodeLinks_(pageNode);
pageNode.page = page; pageNode.page = page;
this.addDashedNodeLinks_(pageNode);
} }
/** @override */ /** @override */
...@@ -732,6 +768,7 @@ class Graph { ...@@ -732,6 +768,7 @@ class Graph {
// Remove any links, and then the node itself. // Remove any links, and then the node itself.
this.removeNodeLinks_(node); this.removeNodeLinks_(node);
this.removeDashedNodeLinks_(node);
this.nodes_.delete(nodeId); this.nodes_.delete(nodeId);
} }
...@@ -776,11 +813,21 @@ class Graph { ...@@ -776,11 +813,21 @@ class Graph {
* @private * @private
*/ */
removeNodeLinks_(node) { removeNodeLinks_(node) {
// Filter away any links to or from the deleted node. // Filter away any links to or from the provided node.
this.links_ = this.links_.filter( this.links_ = this.links_.filter(
link => link.source !== node && link.target !== node); link => link.source !== node && link.target !== node);
} }
/**
* @param {!GraphNode} node
* @private
*/
removeDashedNodeLinks_(node) {
// Filter away any dashed links to or from the provided node.
this.dashedLinks_ = this.dashedLinks_.filter(
link => link.source !== node && link.target !== node);
}
/** /**
* @param {!Object<string>} nodeDescriptions * @param {!Object<string>} nodeDescriptions
* @private * @private
...@@ -915,10 +962,18 @@ class Graph { ...@@ -915,10 +962,18 @@ class Graph {
// Select the links. // Select the links.
const link = this.linkGroup_.selectAll('line').data(this.links_); const link = this.linkGroup_.selectAll('line').data(this.links_);
// Add new links. // Add new links.
link.enter().append('line').attr('stroke-width', 1); link.enter().append('line');
// Remove dead links. // Remove dead links.
link.exit().remove(); link.exit().remove();
// Select the dashed links.
const dashedLink =
this.dashedLinkGroup_.selectAll('line').data(this.dashedLinks_);
// Add new dashed links.
dashedLink.enter().append('line');
// Remove dead dashed links.
dashedLink.exit().remove();
// Select the nodes, except for any dead ones that are still transitioning. // Select the nodes, except for any dead ones that are still transitioning.
const nodes = Array.from(this.nodes_.values()); const nodes = Array.from(this.nodes_.values());
const node = const node =
...@@ -931,6 +986,7 @@ class Graph { ...@@ -931,6 +986,7 @@ class Graph {
.call(this.drag_) .call(this.drag_)
.on('click', this.onGraphNodeClick_.bind(this)); .on('click', this.onGraphNodeClick_.bind(this));
const circles = newNodes.append('circle') const circles = newNodes.append('circle')
.attr('id', d => `circle-${d.id}`)
.attr('r', kNodeRadius * 1.5) .attr('r', kNodeRadius * 1.5)
.attr('fill', 'green'); // New nodes appear green. .attr('fill', 'green'); // New nodes appear green.
...@@ -981,9 +1037,11 @@ class Graph { ...@@ -981,9 +1037,11 @@ class Graph {
// Update and restart the simulation if the graph changed. // Update and restart the simulation if the graph changed.
if (!node.enter().empty() || !node.exit().empty() || if (!node.enter().empty() || !node.exit().empty() ||
!link.enter().empty() || !link.exit().empty()) { !link.enter().empty() || !link.exit().empty() ||
!dashedLink.enter().empty() || !dashedLink.exit().empty()) {
this.simulation_.nodes(nodes); this.simulation_.nodes(nodes);
this.simulation_.force('link').links(this.links_); const links = this.links_.concat(this.dashedLinks_);
this.simulation_.force('link').links(links);
this.restartSimulation_(); this.restartSimulation_();
} }
...@@ -1000,6 +1058,12 @@ class Graph { ...@@ -1000,6 +1058,12 @@ class Graph {
.attr('x2', d => d.target.x) .attr('x2', d => d.target.x)
.attr('y2', d => d.target.y); .attr('y2', d => d.target.y);
const dashedLines = this.dashedLinkGroup_.selectAll('line');
dashedLines.attr('x1', d => d.source.x)
.attr('y1', d => d.source.y)
.attr('x2', d => d.target.x)
.attr('y2', d => d.target.y);
this.updateToolTipLinks(); this.updateToolTipLinks();
} }
...@@ -1013,6 +1077,7 @@ class Graph { ...@@ -1013,6 +1077,7 @@ class Graph {
addNode_(node) { addNode_(node) {
this.nodes_.set(node.id, node); this.nodes_.set(node.id, node);
this.addNodeLinks_(node); this.addNodeLinks_(node);
this.addDashedNodeLinks_(node);
node.setInitialPosition(this.width_, this.height_); node.setInitialPosition(this.width_, this.height_);
} }
...@@ -1023,8 +1088,7 @@ class Graph { ...@@ -1023,8 +1088,7 @@ class Graph {
* @private * @private
*/ */
addNodeLinks_(node) { addNodeLinks_(node) {
const linkTargets = node.linkTargets; for (const linkTarget of node.linkTargets) {
for (const linkTarget of linkTargets) {
const target = this.nodes_.get(linkTarget); const target = this.nodes_.get(linkTarget);
if (target) { if (target) {
this.links_.push({source: node, target: target}); this.links_.push({source: node, target: target});
...@@ -1032,6 +1096,21 @@ class Graph { ...@@ -1032,6 +1096,21 @@ class Graph {
} }
} }
/**
* Adds all the dashed links for a node to the graph.
*
* @param {!GraphNode} node
* @private
*/
addDashedNodeLinks_(node) {
for (const dashedLinkTarget of node.dashedLinkTargets) {
const target = this.nodes_.get(dashedLinkTarget);
if (target) {
this.dashedLinks_.push({source: node, target: target});
}
}
}
/** /**
* @param {!GraphNode} d The dragged node. * @param {!GraphNode} d The dragged node.
* @private * @private
...@@ -1068,6 +1147,9 @@ class Graph { ...@@ -1068,6 +1147,9 @@ class Graph {
d.fx = null; d.fx = null;
d.fy = null; d.fy = null;
} }
// Toggle the pinned class as appropriate for the circle backing this node.
d3.select(`#circle-${d.id}`).classed('pinned', d.fx != null);
} }
/** /**
......
...@@ -21,6 +21,20 @@ URL. As result, this document needs to be self-contained, hence inline scripts. ...@@ -21,6 +21,20 @@ URL. As result, this document needs to be self-contained, hence inline scripts.
.links line { .links line {
stroke: #999; stroke: #999;
stroke-opacity: 0.6; stroke-opacity: 0.6;
stroke-width: 1;
}
.dashed-links line {
marker-start: url(#arrowToSource);
stroke: #999;
stroke-dasharray: 3;
stroke-opacity: 0.6;
stroke-width: 1;
}
#arrowToSource {
fill: #999;
stroke: #999;
} }
.nodes circle { .nodes circle {
...@@ -28,6 +42,10 @@ URL. As result, this document needs to be self-contained, hence inline scripts. ...@@ -28,6 +42,10 @@ URL. As result, this document needs to be self-contained, hence inline scripts.
stroke-width: 1.5px; stroke-width: 1.5px;
} }
.nodes circle.pinned {
stroke: red;
}
.dead image { .dead image {
display: none; display: none;
} }
...@@ -70,6 +88,13 @@ ${javascript_file} ...@@ -70,6 +88,13 @@ ${javascript_file}
</head> </head>
<body> <body>
<div id="toolTips" width="100%" height="100%"></div> <div id="toolTips" width="100%" height="100%"></div>
<svg id="graphBody" width="100%" height="100%"></svg> <svg id="graphBody" width="100%" height="100%">
<defs>
<marker id="arrowToSource" viewBox="0 -5 10 10" refX="-12" refY="0"
markerWidth="9" markerHeight="6" orient="auto">
<path d="M15,-7 L0,0 L15,7" />
</marker>
</defs>
</svg>
</body> </body>
</html> </html>
...@@ -9,14 +9,16 @@ import "mojo/public/mojom/base/process_id.mojom"; ...@@ -9,14 +9,16 @@ import "mojo/public/mojom/base/process_id.mojom";
import "mojo/public/mojom/base/time.mojom"; import "mojo/public/mojom/base/time.mojom";
import "url/mojom/url.mojom"; import "url/mojom/url.mojom";
// Identical to content::Visibility. // Identical to content::Visibility. Sent from browser to the chrome://discards
// WebUI.
enum LifecycleUnitVisibility { enum LifecycleUnitVisibility {
HIDDEN = 0, HIDDEN = 0,
OCCLUDED = 1, OCCLUDED = 1,
VISIBLE = 2, VISIBLE = 2,
}; };
// Discard related information about a single tab in a browser. // Discard related information about a single tab in a browser. Sent from
// browser to the chrome://discards WebUI.
struct TabDiscardsInfo { struct TabDiscardsInfo {
// The URL associated with the tab. This corresponds to GetLastCommittedURL, // The URL associated with the tab. This corresponds to GetLastCommittedURL,
// and is also what is visible in the Omnibox for a given tab. // and is also what is visible in the Omnibox for a given tab.
...@@ -98,12 +100,16 @@ interface DetailsProvider { ...@@ -98,12 +100,16 @@ interface DetailsProvider {
Discard() => (); Discard() => ();
}; };
// Represents the momentary state of a Page node. // Represents the momentary state of a Page node. Sent from browser to the
// chrome://discards WebUI via the GraphChangeStream (defined below).
struct PageInfo { struct PageInfo {
int64 id; int64 id;
url.mojom.Url main_frame_url; url.mojom.Url main_frame_url;
// The id of the frame that "opened" this page, if any.
int64 opener_frame_id;
// This field is a dictionary of values, where each value is generated by // This field is a dictionary of values, where each value is generated by
// a performance_manager::NodeDataDescriber implementation and keyed by the // a performance_manager::NodeDataDescriber implementation and keyed by the
// name it registered with. The intent is for each describer to describe // name it registered with. The intent is for each describer to describe
...@@ -112,46 +118,74 @@ struct PageInfo { ...@@ -112,46 +118,74 @@ struct PageInfo {
string description_json; string description_json;
}; };
// Represents the momentary state of a Frame node. // Represents the momentary state of a Frame node. Sent from browser to the
// chrome://discards WebUI via the GraphChangeStream (defined below).
struct FrameInfo { struct FrameInfo {
int64 id; int64 id;
// The last committed URL of this frame.
url.mojom.Url url; url.mojom.Url url;
// The ID of the page node this frame is associated with.
int64 page_id; int64 page_id;
// The ID of the parent frame, if there is one. If not, this is a main frame.
int64 parent_frame_id; int64 parent_frame_id;
// The ID of the process in which this frame is hosted.
int64 process_id; int64 process_id;
// See PageInfo::description_json. // See PageInfo::description_json.
string description_json; string description_json;
}; };
// Represents the momentary state of a Process node. // Represents the momentary state of a Process node. Sent from browser to the
// chrome://discards WebUI via the GraphChangeStream (defined below).
struct ProcessInfo { struct ProcessInfo {
int64 id; int64 id;
// The PID of the process associated with this node.
mojo_base.mojom.ProcessId pid; mojo_base.mojom.ProcessId pid;
// The private memory usage of this process in KB.
uint64 private_footprint_kb; uint64 private_footprint_kb;
// See PageInfo::description_json. // See PageInfo::description_json.
string description_json; string description_json;
}; };
// Represents the momentary state of a Worker node. // Represents the momentary state of a Worker node. Sent from browser to the
// chrome://discards WebUI via the GraphChangeStream (defined below).
struct WorkerInfo { struct WorkerInfo {
int64 id; int64 id;
// The URL of the worker.
url.mojom.Url url; url.mojom.Url url;
// The ID of the process is which this worker is hosted.
int64 process_id; int64 process_id;
// An array of frames (by ID) that are clients of this worker (the worker is
// doing work on behalf of this frame). See
// WorkerNode::GetClientFrames() for details.
array<int64> client_frame_ids; array<int64> client_frame_ids;
// An array of other workers (by ID) that are clients of this worker (the
// worker is doing work on behalf of these other workers). See
// WorkerNode::GetClientWorkers() for details.
array<int64> client_worker_ids; array<int64> client_worker_ids;
// An array of workers (by ID) that are children of this worker. This can
// occur with shared and service workers owning their own dedicated workers.
// See WorkerNode::GetChildWorkers() for details.
array<int64> child_worker_ids; array<int64> child_worker_ids;
// See PageInfo::description_json. // See PageInfo::description_json.
string description_json; string description_json;
}; };
// Used to transport favicon data. // Used to transport favicon data. Sent from browser to the chrome://discards
// WebUI via the GraphChangeStream (defined below).
struct FavIconInfo { struct FavIconInfo {
int64 node_id; int64 node_id;
...@@ -161,7 +195,11 @@ struct FavIconInfo { ...@@ -161,7 +195,11 @@ struct FavIconInfo {
}; };
// Implement to receive a stream of notifications when performance manager // Implement to receive a stream of notifications when performance manager
// graph nodes are created, changed or deleted. // graph nodes are created, changed or deleted. Implemented in Javascript code
// running in the chrome://discards WebUI, with data routed to it from an
// observer of the performance_manager::Graph in the browser. The implementation
// is injected into the browser via the browser-exposed GraphDump interface,
// defined below.
interface GraphChangeStream { interface GraphChangeStream {
// The |frame| was created. // The |frame| was created.
FrameCreated(FrameInfo frame); FrameCreated(FrameInfo frame);
...@@ -190,7 +228,8 @@ interface GraphChangeStream { ...@@ -190,7 +228,8 @@ interface GraphChangeStream {
}; };
// This interface allows subscribing to a stream of events that track the state // This interface allows subscribing to a stream of events that track the state
// of the performance manager graph. // of the performance manager graph. Implemented in browser code, and used from
// Javascript code running in the chrome://discards WebUI.
interface GraphDump { interface GraphDump {
// Subscribes |change_subscriber| to a graph change stream. // Subscribes |change_subscriber| to a graph change stream.
SubscribeToChanges(pending_remote<GraphChangeStream> change_subscriber); SubscribeToChanges(pending_remote<GraphChangeStream> change_subscriber);
......
...@@ -192,31 +192,18 @@ void DiscardsGraphDumpImpl::SubscribeToChanges( ...@@ -192,31 +192,18 @@ void DiscardsGraphDumpImpl::SubscribeToChanges(
} }
// Send creation notifications for all existing nodes. // Send creation notifications for all existing nodes.
for (const performance_manager::ProcessNode* process_node : SendNotificationToAllNodes(/* created = */ true);
graph_->GetAllProcessNodes())
SendProcessNotification(process_node, true); // It is entirely possible for there to be circular link references between
// nodes that already existed at the point this object was created (the loop
for (const performance_manager::PageNode* page_node : // was closed after the two nodes themselves were created). We don't have the
graph_->GetAllPageNodes()) { // exact order of historical events that led to the current graph state, so we
SendPageNotification(page_node, true); // simply fire off a node changed notification for all nodes after the node
StartPageFaviconRequest(page_node); // creation. This ensures that all targets exist the second time through, and
// any loops are closed. Afterwards any newly created loops will be properly
// Dispatch preorder frame notifications. // maintained as node creation/destruction/link events will be fed to the
for (const performance_manager::FrameNode* main_frame_node : // graph in the proper order.
page_node->GetMainFrameNodes()) { SendNotificationToAllNodes(/* created = */ false);
ForFrameAndOffspring(
main_frame_node,
[this](const performance_manager::FrameNode* frame_node) {
this->SendFrameNotification(frame_node, true);
this->StartFrameFaviconRequest(frame_node);
});
}
}
for (const performance_manager::WorkerNode* worker_node :
graph_->GetAllWorkerNodes()) {
SendWorkerNotification(worker_node, true);
}
// Subscribe to subsequent notifications. // Subscribe to subsequent notifications.
graph_->AddFrameNodeObserver(this); graph_->AddFrameNodeObserver(this);
...@@ -304,6 +291,18 @@ void DiscardsGraphDumpImpl::OnBeforePageNodeRemoved( ...@@ -304,6 +291,18 @@ void DiscardsGraphDumpImpl::OnBeforePageNodeRemoved(
RemoveNode(page_node); RemoveNode(page_node);
} }
void DiscardsGraphDumpImpl::OnOpenerFrameNodeChanged(
const performance_manager::PageNode* page_node,
const performance_manager::FrameNode*,
OpenedType) {
// This notification can arrive for a page node that has already been
// removed, because it fires as part of the |page_node| destructor. If that's
// the case then ignore this silently.
if (!HasNode(page_node))
return;
SendPageNotification(page_node, false);
}
void DiscardsGraphDumpImpl::OnFaviconUpdated( void DiscardsGraphDumpImpl::OnFaviconUpdated(
const performance_manager::PageNode* page_node) { const performance_manager::PageNode* page_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
...@@ -390,13 +389,19 @@ void DiscardsGraphDumpImpl::RemoveNode(const performance_manager::Node* node) { ...@@ -390,13 +389,19 @@ void DiscardsGraphDumpImpl::RemoveNode(const performance_manager::Node* node) {
DCHECK_EQ(1u, erased); DCHECK_EQ(1u, erased);
} }
bool DiscardsGraphDumpImpl::HasNode(
const performance_manager::Node* node) const {
return node_ids_.find(node) != node_ids_.end();
}
int64_t DiscardsGraphDumpImpl::GetNodeId( int64_t DiscardsGraphDumpImpl::GetNodeId(
const performance_manager::Node* node) { const performance_manager::Node* node) const {
if (node == nullptr) if (node == nullptr)
return 0; return 0;
DCHECK(node_ids_.find(node) != node_ids_.end()); auto it = node_ids_.find(node);
return node_ids_[node].GetUnsafeValue(); DCHECK(it != node_ids_.end());
return it->second.GetUnsafeValue();
} }
DiscardsGraphDumpImpl::FaviconRequestHelper* DiscardsGraphDumpImpl::FaviconRequestHelper*
...@@ -436,6 +441,36 @@ void DiscardsGraphDumpImpl::StartFrameFaviconRequest( ...@@ -436,6 +441,36 @@ void DiscardsGraphDumpImpl::StartFrameFaviconRequest(
GetNodeId(frame_node))); GetNodeId(frame_node)));
} }
void DiscardsGraphDumpImpl::SendNotificationToAllNodes(bool created) {
for (const performance_manager::ProcessNode* process_node :
graph_->GetAllProcessNodes())
SendProcessNotification(process_node, created);
for (const performance_manager::PageNode* page_node :
graph_->GetAllPageNodes()) {
SendPageNotification(page_node, created);
if (created)
StartPageFaviconRequest(page_node);
// Dispatch preorder frame notifications.
for (const performance_manager::FrameNode* main_frame_node :
page_node->GetMainFrameNodes()) {
ForFrameAndOffspring(
main_frame_node,
[this, created](const performance_manager::FrameNode* frame_node) {
this->SendFrameNotification(frame_node, created);
if (created)
this->StartFrameFaviconRequest(frame_node);
});
}
}
for (const performance_manager::WorkerNode* worker_node :
graph_->GetAllWorkerNodes()) {
SendWorkerNotification(worker_node, created);
}
}
void DiscardsGraphDumpImpl::SendFrameNotification( void DiscardsGraphDumpImpl::SendFrameNotification(
const performance_manager::FrameNode* frame, const performance_manager::FrameNode* frame,
bool created) { bool created) {
...@@ -458,10 +493,11 @@ void DiscardsGraphDumpImpl::SendFrameNotification( ...@@ -458,10 +493,11 @@ void DiscardsGraphDumpImpl::SendFrameNotification(
frame_info->description_json = frame_info->description_json =
ToJSON(graph_->GetNodeDataDescriberRegistry()->DescribeNodeData(frame)); ToJSON(graph_->GetNodeDataDescriberRegistry()->DescribeNodeData(frame));
if (created) if (created) {
change_subscriber_->FrameCreated(std::move(frame_info)); change_subscriber_->FrameCreated(std::move(frame_info));
else } else {
change_subscriber_->FrameChanged(std::move(frame_info)); change_subscriber_->FrameChanged(std::move(frame_info));
}
} }
void DiscardsGraphDumpImpl::SendPageNotification( void DiscardsGraphDumpImpl::SendPageNotification(
...@@ -473,6 +509,7 @@ void DiscardsGraphDumpImpl::SendPageNotification( ...@@ -473,6 +509,7 @@ void DiscardsGraphDumpImpl::SendPageNotification(
page_info->id = GetNodeId(page_node); page_info->id = GetNodeId(page_node);
page_info->main_frame_url = page_node->GetMainFrameUrl(); page_info->main_frame_url = page_node->GetMainFrameUrl();
page_info->opener_frame_id = GetNodeId(page_node->GetOpenerFrameNode());
page_info->description_json = ToJSON( page_info->description_json = ToJSON(
graph_->GetNodeDataDescriberRegistry()->DescribeNodeData(page_node)); graph_->GetNodeDataDescriberRegistry()->DescribeNodeData(page_node));
......
...@@ -110,12 +110,10 @@ class DiscardsGraphDumpImpl : public discards::mojom::GraphDump, ...@@ -110,12 +110,10 @@ class DiscardsGraphDumpImpl : public discards::mojom::GraphDump,
void OnPageNodeAdded(const performance_manager::PageNode* page_node) override; void OnPageNodeAdded(const performance_manager::PageNode* page_node) override;
void OnBeforePageNodeRemoved( void OnBeforePageNodeRemoved(
const performance_manager::PageNode* page_node) override; const performance_manager::PageNode* page_node) override;
// Ignored for now.
// TODO(chrisha): Wire this relationship up with a dotted line!
void OnOpenerFrameNodeChanged( void OnOpenerFrameNodeChanged(
const performance_manager::PageNode* page_node, const performance_manager::PageNode* page_node,
const performance_manager::FrameNode* previous_opener, const performance_manager::FrameNode* previous_opener,
OpenedType previous_opened_type) override {} OpenedType previous_opened_type) override;
void OnIsVisibleChanged( void OnIsVisibleChanged(
const performance_manager::PageNode* page_node) override {} // Ignored. const performance_manager::PageNode* page_node) override {} // Ignored.
void OnIsAudibleChanged( void OnIsAudibleChanged(
...@@ -195,7 +193,8 @@ class DiscardsGraphDumpImpl : public discards::mojom::GraphDump, ...@@ -195,7 +193,8 @@ class DiscardsGraphDumpImpl : public discards::mojom::GraphDump,
void AddNode(const performance_manager::Node* node); void AddNode(const performance_manager::Node* node);
void RemoveNode(const performance_manager::Node* node); void RemoveNode(const performance_manager::Node* node);
int64_t GetNodeId(const performance_manager::Node* node); bool HasNode(const performance_manager::Node* node) const;
int64_t GetNodeId(const performance_manager::Node* node) const;
FaviconRequestHelper* EnsureFaviconRequestHelper(); FaviconRequestHelper* EnsureFaviconRequestHelper();
...@@ -203,6 +202,7 @@ class DiscardsGraphDumpImpl : public discards::mojom::GraphDump, ...@@ -203,6 +202,7 @@ class DiscardsGraphDumpImpl : public discards::mojom::GraphDump,
void StartFrameFaviconRequest( void StartFrameFaviconRequest(
const performance_manager::FrameNode* frame_node); const performance_manager::FrameNode* frame_node);
void SendNotificationToAllNodes(bool created);
void SendFrameNotification(const performance_manager::FrameNode* frame, void SendFrameNotification(const performance_manager::FrameNode* frame,
bool created); bool created);
void SendPageNotification(const performance_manager::PageNode* page, void SendPageNotification(const performance_manager::PageNode* page,
......
...@@ -212,8 +212,9 @@ TEST_F(DiscardsGraphDumpImplTest, ChangeStream) { ...@@ -212,8 +212,9 @@ TEST_F(DiscardsGraphDumpImplTest, ChangeStream) {
task_environment.RunUntilIdle(); task_environment.RunUntilIdle();
// Validate that the initial graph state dump is complete. // Validate that the initial graph state dump is complete. Note that there is
EXPECT_EQ(0u, change_stream.num_changes()); // an update for each node as part of the initial state dump.
EXPECT_EQ(8u, change_stream.num_changes());
EXPECT_EQ(8u, change_stream.id_set().size()); EXPECT_EQ(8u, change_stream.id_set().size());
EXPECT_EQ(2u, change_stream.process_map().size()); EXPECT_EQ(2u, change_stream.process_map().size());
...@@ -277,7 +278,7 @@ TEST_F(DiscardsGraphDumpImplTest, ChangeStream) { ...@@ -277,7 +278,7 @@ TEST_F(DiscardsGraphDumpImplTest, ChangeStream) {
task_environment.RunUntilIdle(); task_environment.RunUntilIdle();
// Main frame navigation results in a notification for the url. // Main frame navigation results in a notification for the url.
EXPECT_EQ(1u, change_stream.num_changes()); EXPECT_EQ(9u, change_stream.num_changes());
EXPECT_FALSE(base::Contains(change_stream.id_set(), child_frame_id)); EXPECT_FALSE(base::Contains(change_stream.id_set(), child_frame_id));
const auto main_page_it = change_stream.page_map().find( const auto main_page_it = change_stream.page_map().find(
......
...@@ -175,7 +175,8 @@ class PageNodeObserver { ...@@ -175,7 +175,8 @@ class PageNodeObserver {
// Invoked when this page has been assigned an opener, had the opener change, // Invoked when this page has been assigned an opener, had the opener change,
// or had the opener removed. This can happen if a page is opened via // or had the opener removed. This can happen if a page is opened via
// window.open, webviews, portals, etc, or when that relationship is // window.open, webviews, portals, etc, or when that relationship is
// subsequently severed or reparented. // subsequently severed or reparented. Note that this can be invoked *after*
// OnBeforePageNodeRemoved() if a page disappears while still attached.
virtual void OnOpenerFrameNodeChanged(const PageNode* page_node, virtual void OnOpenerFrameNodeChanged(const PageNode* page_node,
const FrameNode* previous_opener, const FrameNode* previous_opener,
OpenedType previous_opened_type) = 0; OpenedType previous_opened_type) = 0;
......
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