blob: 74e6b665fc2ab40a1384da96290a8aee42760231 [file] [log] [blame]
Patrick Monette6c6de3882019-10-09 02:59:321// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Patrick Monette9a905082020-01-07 18:37:355#include "components/performance_manager/worker_watcher.h"
Patrick Monette6c6de3882019-10-09 02:59:326
7#include <utility>
8#include <vector>
9
10#include "components/performance_manager/frame_node_source.h"
11#include "components/performance_manager/graph/frame_node_impl.h"
12#include "components/performance_manager/graph/worker_node_impl.h"
13#include "components/performance_manager/performance_manager_impl.h"
14#include "components/performance_manager/process_node_source.h"
Patrick Monette6c6de3882019-10-09 02:59:3215
16namespace performance_manager {
17
18namespace {
19
20// Helper function to add |worker_node| as a child to |frame_node| on the PM
21// sequence.
22void AddWorkerToFrameNode(FrameNodeImpl* frame_node,
Patrick Monettef3b262a2020-03-26 17:00:2823 WorkerNodeImpl* worker_node) {
Patrick Monette6c6de3882019-10-09 02:59:3224 worker_node->AddClientFrame(frame_node);
25}
26
27// Helper function to remove |worker_node| from |frame_node| on the PM sequence.
28void RemoveWorkerFromFrameNode(FrameNodeImpl* frame_node,
Patrick Monettef3b262a2020-03-26 17:00:2829 WorkerNodeImpl* worker_node) {
Patrick Monette6c6de3882019-10-09 02:59:3230 worker_node->RemoveClientFrame(frame_node);
31}
32
33// Helper function to remove all |worker_nodes| from |frame_node| on the PM
34// sequence.
35void RemoveWorkersFromFrameNode(
36 FrameNodeImpl* frame_node,
Patrick Monettef3b262a2020-03-26 17:00:2837 const base::flat_set<WorkerNodeImpl*>& worker_nodes) {
Patrick Monette6c6de3882019-10-09 02:59:3238 for (auto* worker_node : worker_nodes)
39 worker_node->RemoveClientFrame(frame_node);
40}
41
Patrick Monetteba8336672020-02-24 21:27:5442// Helper function that posts a task on the PM sequence that will invoke
43// OnFinalResponseURLDetermined() on |worker_node|.
44void SetFinalResponseURL(WorkerNodeImpl* worker_node, const GURL& url) {
45 PerformanceManagerImpl::CallOnGraphImpl(
Patrick Monettef3b262a2020-03-26 17:00:2846 FROM_HERE, base::BindOnce(&WorkerNodeImpl::OnFinalResponseURLDetermined,
47 base::Unretained(worker_node), url));
Patrick Monetteba8336672020-02-24 21:27:5448}
49
Patrick Monette6c6de3882019-10-09 02:59:3250} // namespace
51
Patrick Monette9a905082020-01-07 18:37:3552WorkerWatcher::WorkerWatcher(
Patrick Monette6c6de3882019-10-09 02:59:3253 const std::string& browser_context_id,
Patrick Monette3117283f2020-02-07 15:49:1554 content::DedicatedWorkerService* dedicated_worker_service,
Patrick Monette6c6de3882019-10-09 02:59:3255 content::SharedWorkerService* shared_worker_service,
Patrick Monette0fa96872020-03-26 18:16:5356 content::ServiceWorkerContext* service_worker_context,
Patrick Monette6c6de3882019-10-09 02:59:3257 ProcessNodeSource* process_node_source,
58 FrameNodeSource* frame_node_source)
59 : browser_context_id_(browser_context_id),
Patrick Monette6c6de3882019-10-09 02:59:3260 process_node_source_(process_node_source),
61 frame_node_source_(frame_node_source) {
Patrick Monette3117283f2020-02-07 15:49:1562 DCHECK(dedicated_worker_service);
Patrick Monette6c6de3882019-10-09 02:59:3263 DCHECK(shared_worker_service);
Patrick Monette0fa96872020-03-26 18:16:5364 DCHECK(service_worker_context);
Patrick Monette6c6de3882019-10-09 02:59:3265 DCHECK(process_node_source_);
66 DCHECK(frame_node_source_);
Patrick Monette3117283f2020-02-07 15:49:1567 dedicated_worker_service_observer_.Add(dedicated_worker_service);
Patrick Monette6c6de3882019-10-09 02:59:3268 shared_worker_service_observer_.Add(shared_worker_service);
Patrick Monette0fa96872020-03-26 18:16:5369 service_worker_context_observer_.Add(service_worker_context);
Patrick Monette6c6de3882019-10-09 02:59:3270}
71
Patrick Monette9a905082020-01-07 18:37:3572WorkerWatcher::~WorkerWatcher() {
Patrick Monette6c6de3882019-10-09 02:59:3273 DCHECK(frame_node_child_workers_.empty());
Patrick Monette3117283f2020-02-07 15:49:1574 DCHECK(dedicated_worker_nodes_.empty());
75 DCHECK(!dedicated_worker_service_observer_.IsObservingSources());
Patrick Monette9a905082020-01-07 18:37:3576 DCHECK(shared_worker_nodes_.empty());
Patrick Monette6c6de3882019-10-09 02:59:3277 DCHECK(!shared_worker_service_observer_.IsObservingSources());
Patrick Monette0fa96872020-03-26 18:16:5378 DCHECK(service_worker_nodes_.empty());
79 DCHECK(!service_worker_context_observer_.IsObservingSources());
Patrick Monette6c6de3882019-10-09 02:59:3280}
81
Patrick Monette9a905082020-01-07 18:37:3582void WorkerWatcher::TearDown() {
Patrick Monette6c6de3882019-10-09 02:59:3283 // First clear client-child relations between frames and workers.
84 for (auto& kv : frame_node_child_workers_) {
Patrick Monette7364e6972020-01-09 22:56:0285 const content::GlobalFrameRoutingId& render_frame_host_id = kv.first;
Patrick Monette6c6de3882019-10-09 02:59:3286 base::flat_set<WorkerNodeImpl*>& child_workers = kv.second;
87
Patrick Monette7364e6972020-01-09 22:56:0288 frame_node_source_->UnsubscribeFromFrameNode(render_frame_host_id);
Patrick Monette6c6de3882019-10-09 02:59:3289
90 // Disconnect all child workers from |frame_node|.
Patrick Monette7364e6972020-01-09 22:56:0291 FrameNodeImpl* frame_node =
92 frame_node_source_->GetFrameNode(render_frame_host_id);
Patrick Monette6c6de3882019-10-09 02:59:3293 DCHECK(frame_node);
94 DCHECK(!child_workers.empty());
95 PerformanceManagerImpl::CallOnGraphImpl(
96 FROM_HERE,
97 base::BindOnce(&RemoveWorkersFromFrameNode, frame_node, child_workers));
98 }
99 frame_node_child_workers_.clear();
100
101 // Then clean all the worker nodes.
102 std::vector<std::unique_ptr<NodeBase>> nodes;
Patrick Monette0fa96872020-03-26 18:16:53103 nodes.reserve(dedicated_worker_nodes_.size() + shared_worker_nodes_.size() +
104 service_worker_nodes_.size());
105
Patrick Monette3117283f2020-02-07 15:49:15106 for (auto& node : dedicated_worker_nodes_)
107 nodes.push_back(std::move(node.second));
108 dedicated_worker_nodes_.clear();
Patrick Monette0fa96872020-03-26 18:16:53109
Patrick Monette9a905082020-01-07 18:37:35110 for (auto& node : shared_worker_nodes_)
Patrick Monette6c6de3882019-10-09 02:59:32111 nodes.push_back(std::move(node.second));
Patrick Monette9a905082020-01-07 18:37:35112 shared_worker_nodes_.clear();
Patrick Monette6c6de3882019-10-09 02:59:32113
Patrick Monette0fa96872020-03-26 18:16:53114 for (auto& node : service_worker_nodes_)
115 nodes.push_back(std::move(node.second));
116 service_worker_nodes_.clear();
117
Patrick Monette4e141242020-03-20 00:41:43118 PerformanceManagerImpl::BatchDeleteNodes(std::move(nodes));
Patrick Monette6c6de3882019-10-09 02:59:32119
Patrick Monette3117283f2020-02-07 15:49:15120 dedicated_worker_service_observer_.RemoveAll();
Patrick Monette6c6de3882019-10-09 02:59:32121 shared_worker_service_observer_.RemoveAll();
Patrick Monette0fa96872020-03-26 18:16:53122 service_worker_context_observer_.RemoveAll();
Patrick Monette6c6de3882019-10-09 02:59:32123}
124
Patrick Monette9a905082020-01-07 18:37:35125void WorkerWatcher::OnWorkerStarted(
Patrick Monette3117283f2020-02-07 15:49:15126 content::DedicatedWorkerId dedicated_worker_id,
127 int worker_process_id,
128 content::GlobalFrameRoutingId ancestor_render_frame_host_id) {
129 // TODO(https://crbug.com/993029): Plumb through the URL and the DevTools
130 // token.
Patrick Monette4e141242020-03-20 00:41:43131 auto worker_node = PerformanceManagerImpl::CreateWorkerNode(
Patrick Monette3117283f2020-02-07 15:49:15132 browser_context_id_, WorkerNode::WorkerType::kDedicated,
133 process_node_source_->GetProcessNode(worker_process_id),
134 base::UnguessableToken::Create());
135 bool inserted = dedicated_worker_nodes_
136 .emplace(dedicated_worker_id, std::move(worker_node))
137 .second;
138 DCHECK(inserted);
Patrick Monetted72c6ea2020-03-26 15:56:30139
140 // TODO(pmonette): Connect |worker_node| to its client frame.
Patrick Monette3117283f2020-02-07 15:49:15141}
142
143void WorkerWatcher::OnBeforeWorkerTerminated(
144 content::DedicatedWorkerId dedicated_worker_id,
145 content::GlobalFrameRoutingId ancestor_render_frame_host_id) {
146 auto it = dedicated_worker_nodes_.find(dedicated_worker_id);
147 DCHECK(it != dedicated_worker_nodes_.end());
Patrick Monette8e70db42020-03-25 19:07:05148
Patrick Monetted72c6ea2020-03-26 15:56:30149 auto worker_node = std::move(it->second);
150 // TODO(pmonette): Disconnect |worker_node| from its client frame.
Patrick Monette3117283f2020-02-07 15:49:15151#if DCHECK_IS_ON()
152 DCHECK(!base::Contains(clients_to_remove_, worker_node.get()));
153#endif // DCHECK_IS_ON()
Patrick Monette8e70db42020-03-25 19:07:05154 PerformanceManagerImpl::DeleteNode(std::move(worker_node));
Patrick Monetted72c6ea2020-03-26 15:56:30155
156 dedicated_worker_nodes_.erase(it);
Patrick Monette3117283f2020-02-07 15:49:15157}
158
Patrick Monetteba8336672020-02-24 21:27:54159void WorkerWatcher::OnFinalResponseURLDetermined(
160 content::DedicatedWorkerId dedicated_worker_id,
161 const GURL& url) {
162 SetFinalResponseURL(GetDedicatedWorkerNode(dedicated_worker_id), url);
163}
164
Patrick Monette3117283f2020-02-07 15:49:15165void WorkerWatcher::OnWorkerStarted(
Patrick Monettea376d3b02020-02-24 18:33:39166 content::SharedWorkerId shared_worker_id,
Patrick Monette6c6de3882019-10-09 02:59:32167 int worker_process_id,
168 const base::UnguessableToken& dev_tools_token) {
Patrick Monette4e141242020-03-20 00:41:43169 auto worker_node = PerformanceManagerImpl::CreateWorkerNode(
Patrick Monette6c6de3882019-10-09 02:59:32170 browser_context_id_, WorkerNode::WorkerType::kShared,
Patrick Monetteeb6c1eee2020-02-04 20:42:48171 process_node_source_->GetProcessNode(worker_process_id), dev_tools_token);
Patrick Monette6c6de3882019-10-09 02:59:32172 bool inserted =
Patrick Monettea376d3b02020-02-24 18:33:39173 shared_worker_nodes_.emplace(shared_worker_id, std::move(worker_node))
174 .second;
Patrick Monette6c6de3882019-10-09 02:59:32175 DCHECK(inserted);
176}
177
Patrick Monette9a905082020-01-07 18:37:35178void WorkerWatcher::OnBeforeWorkerTerminated(
Patrick Monettea376d3b02020-02-24 18:33:39179 content::SharedWorkerId shared_worker_id) {
180 auto it = shared_worker_nodes_.find(shared_worker_id);
Patrick Monette9a905082020-01-07 18:37:35181 DCHECK(it != shared_worker_nodes_.end());
Patrick Monette6c6de3882019-10-09 02:59:32182
183 auto worker_node = std::move(it->second);
184#if DCHECK_IS_ON()
185 DCHECK(!base::Contains(clients_to_remove_, worker_node.get()));
186#endif // DCHECK_IS_ON()
Patrick Monette4e141242020-03-20 00:41:43187 PerformanceManagerImpl::DeleteNode(std::move(worker_node));
Patrick Monette6c6de3882019-10-09 02:59:32188
Patrick Monette9a905082020-01-07 18:37:35189 shared_worker_nodes_.erase(it);
Patrick Monette6c6de3882019-10-09 02:59:32190}
191
Patrick Monetteba8336672020-02-24 21:27:54192void WorkerWatcher::OnFinalResponseURLDetermined(
193 content::SharedWorkerId shared_worker_id,
194 const GURL& url) {
195 SetFinalResponseURL(GetSharedWorkerNode(shared_worker_id), url);
196}
197
Patrick Monette7364e6972020-01-09 22:56:02198void WorkerWatcher::OnClientAdded(
Patrick Monettea376d3b02020-02-24 18:33:39199 content::SharedWorkerId shared_worker_id,
Patrick Monette7364e6972020-01-09 22:56:02200 content::GlobalFrameRoutingId render_frame_host_id) {
Patrick Monettea376d3b02020-02-24 18:33:39201 AddClientFrame(GetSharedWorkerNode(shared_worker_id), render_frame_host_id);
Patrick Monette897d08b2020-02-04 14:24:00202}
203
Marc Treib70854a72020-02-04 17:19:52204void WorkerWatcher::OnClientRemoved(
Patrick Monettea376d3b02020-02-24 18:33:39205 content::SharedWorkerId shared_worker_id,
Marc Treib70854a72020-02-04 17:19:52206 content::GlobalFrameRoutingId render_frame_host_id) {
Patrick Monettea376d3b02020-02-24 18:33:39207 RemoveClientFrame(GetSharedWorkerNode(shared_worker_id),
208 render_frame_host_id);
Patrick Monette3117283f2020-02-07 15:49:15209}
210
Patrick Monette0fa96872020-03-26 18:16:53211void WorkerWatcher::OnVersionStartedRunning(
212 int64_t version_id,
213 const content::ServiceWorkerRunningInfo& running_info) {
214 // TODO(pmonette): Plumb in the DevTools token.
215 auto worker_node = PerformanceManagerImpl::CreateWorkerNode(
216 browser_context_id_, WorkerNode::WorkerType::kService,
217 process_node_source_->GetProcessNode(running_info.render_process_id),
218 base::UnguessableToken());
219 bool inserted =
220 service_worker_nodes_.emplace(version_id, std::move(worker_node)).second;
221 DCHECK(inserted);
222}
223
224void WorkerWatcher::OnVersionStoppedRunning(int64_t version_id) {
225 auto it = service_worker_nodes_.find(version_id);
226 DCHECK(it != service_worker_nodes_.end());
227
228 auto worker_node = std::move(it->second);
229#if DCHECK_IS_ON()
230 DCHECK(!base::Contains(clients_to_remove_, worker_node.get()));
231#endif // DCHECK_IS_ON()
232 PerformanceManagerImpl::DeleteNode(std::move(worker_node));
233
234 service_worker_nodes_.erase(it);
235}
236
Patrick Monette3117283f2020-02-07 15:49:15237void WorkerWatcher::AddClientFrame(
238 WorkerNodeImpl* worker_node,
239 content::GlobalFrameRoutingId client_render_frame_host_id) {
Patrick Monette897d08b2020-02-04 14:24:00240 FrameNodeImpl* frame_node =
Patrick Monette3117283f2020-02-07 15:49:15241 frame_node_source_->GetFrameNode(client_render_frame_host_id);
242 DCHECK(frame_node);
243
244 // Connect the nodes in the PM graph.
245 PerformanceManagerImpl::CallOnGraphImpl(
246 FROM_HERE,
247 base::BindOnce(&AddWorkerToFrameNode, frame_node, worker_node));
248
249 // Keep track of the shared workers that this frame is a client to.
250 if (AddChildWorker(client_render_frame_host_id, worker_node)) {
251 frame_node_source_->SubscribeToFrameNode(
252 client_render_frame_host_id,
253 base::BindOnce(&WorkerWatcher::OnBeforeFrameNodeRemoved,
254 base::Unretained(this), client_render_frame_host_id));
255 }
256}
257
258void WorkerWatcher::RemoveClientFrame(
259 WorkerNodeImpl* worker_node,
260 content::GlobalFrameRoutingId client_render_frame_host_id) {
261 FrameNodeImpl* frame_node =
262 frame_node_source_->GetFrameNode(client_render_frame_host_id);
Patrick Monette6c6de3882019-10-09 02:59:32263
264 // It's possible that the frame was destroyed before receiving the
265 // OnClientRemoved() for all of its child shared worker. Nothing to do in
266 // that case because OnBeforeFrameNodeRemoved() took care of removing this
267 // client from its child worker nodes.
268 if (!frame_node) {
269#if DCHECK_IS_ON()
270 // These debug only checks ensure that this code path is only taken if
271 // OnBeforeFrameNodeRemoved() was already called for that frame.
272 auto it = clients_to_remove_.find(worker_node);
273 DCHECK(it != clients_to_remove_.end());
274
275 int& count = it->second;
276 DCHECK_GT(count, 0);
277 --count;
278
279 if (count == 0)
280 clients_to_remove_.erase(it);
281#endif // DCHECK_IS_ON()
282 return;
283 }
284
285 // Disconnect the node.
286 PerformanceManagerImpl::CallOnGraphImpl(
287 FROM_HERE,
288 base::BindOnce(&RemoveWorkerFromFrameNode, frame_node, worker_node));
289
290 // Remove |worker_node| from the set of workers that this frame is a client
291 // of.
Patrick Monette3117283f2020-02-07 15:49:15292 if (RemoveChildWorker(client_render_frame_host_id, worker_node))
293 frame_node_source_->UnsubscribeFromFrameNode(client_render_frame_host_id);
Patrick Monette6c6de3882019-10-09 02:59:32294}
295
Patrick Monette7364e6972020-01-09 22:56:02296void WorkerWatcher::OnBeforeFrameNodeRemoved(
297 content::GlobalFrameRoutingId render_frame_host_id,
298 FrameNodeImpl* frame_node) {
299 auto it = frame_node_child_workers_.find(render_frame_host_id);
Patrick Monette6c6de3882019-10-09 02:59:32300 DCHECK(it != frame_node_child_workers_.end());
301
302 // Clean up all child workers of this frame node.
303 base::flat_set<WorkerNodeImpl*> child_workers = std::move(it->second);
304 frame_node_child_workers_.erase(it);
305
306 // Disconnect all child workers from |frame_node|.
307 DCHECK(!child_workers.empty());
308 PerformanceManagerImpl::CallOnGraphImpl(
309 FROM_HERE,
310 base::BindOnce(&RemoveWorkersFromFrameNode, frame_node, child_workers));
311
312#if DCHECK_IS_ON()
313 for (WorkerNodeImpl* worker_node : child_workers) {
314 // Now expect that this frame will be removed as a client for each worker
315 // in |child_workers|.
316 // Note: the [] operator is intentionally used to default initialize the
317 // count to zero if needed.
318 clients_to_remove_[worker_node]++;
319 }
320#endif // DCHECK_IS_ON()
321}
322
Patrick Monette7364e6972020-01-09 22:56:02323bool WorkerWatcher::AddChildWorker(
324 content::GlobalFrameRoutingId render_frame_host_id,
325 WorkerNodeImpl* child_worker_node) {
Patrick Monette6c6de3882019-10-09 02:59:32326 auto insertion_result =
Patrick Monette7364e6972020-01-09 22:56:02327 frame_node_child_workers_.insert({render_frame_host_id, {}});
Patrick Monette6c6de3882019-10-09 02:59:32328
329 auto& child_workers = insertion_result.first->second;
330 bool inserted = child_workers.insert(child_worker_node).second;
331 DCHECK(inserted);
332
333 return insertion_result.second;
334}
335
Patrick Monette7364e6972020-01-09 22:56:02336bool WorkerWatcher::RemoveChildWorker(
337 content::GlobalFrameRoutingId render_frame_host_id,
338 WorkerNodeImpl* child_worker_node) {
339 auto it = frame_node_child_workers_.find(render_frame_host_id);
Patrick Monette6c6de3882019-10-09 02:59:32340 DCHECK(it != frame_node_child_workers_.end());
341 auto& child_workers = it->second;
342
343 size_t removed = child_workers.erase(child_worker_node);
344 DCHECK_EQ(removed, 1u);
345
346 if (child_workers.empty()) {
347 frame_node_child_workers_.erase(it);
348 return true;
349 }
350 return false;
351}
352
Patrick Monette3117283f2020-02-07 15:49:15353WorkerNodeImpl* WorkerWatcher::GetDedicatedWorkerNode(
354 content::DedicatedWorkerId dedicated_worker_id) {
355 auto it = dedicated_worker_nodes_.find(dedicated_worker_id);
356 if (it == dedicated_worker_nodes_.end()) {
357 NOTREACHED();
358 return nullptr;
359 }
360 return it->second.get();
361}
362
Patrick Monette9a905082020-01-07 18:37:35363WorkerNodeImpl* WorkerWatcher::GetSharedWorkerNode(
Patrick Monettea376d3b02020-02-24 18:33:39364 content::SharedWorkerId shared_worker_id) {
365 auto it = shared_worker_nodes_.find(shared_worker_id);
Patrick Monette9a905082020-01-07 18:37:35366 if (it == shared_worker_nodes_.end()) {
Patrick Monette6c6de3882019-10-09 02:59:32367 NOTREACHED();
368 return nullptr;
369 }
370 return it->second.get();
371}
372
Patrick Monette0fa96872020-03-26 18:16:53373WorkerNodeImpl* WorkerWatcher::GetServiceWorkerNode(int64_t version_id) {
374 auto it = service_worker_nodes_.find(version_id);
375 if (it == service_worker_nodes_.end()) {
376 NOTREACHED();
377 return nullptr;
378 }
379 return it->second.get();
380}
381
Patrick Monette6c6de3882019-10-09 02:59:32382} // namespace performance_manager