Commit 3117283f authored by Patrick Monette's avatar Patrick Monette Committed by Commit Bot

Reland "[PM] Add support for dedicated workers"

This is a reland of dec0aa0b

To make it easier to reland, this CL now only adds the worker nodes to
the PM graph but does not set the connection to its client frame.

Original change's description:
> [PM] Add support for dedicated workers
>
> The WorkerWatcher observes dedicated workers through the
> DedicatedWorkerService interface.
>
> Change-Id: If62d911e500def7ebb905311485a8d89eeaca8df
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1992208
> Reviewed-by: Sigurður Ásgeirsson <siggi@chromium.org>
> Commit-Queue: Patrick Monette <pmonette@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#736411}

Change-Id: I7d11799402eb7871e5b8dcbb1b682996eaf12b6f
Bug: 993029
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2037498Reviewed-by: default avatarSigurður Ásgeirsson <siggi@chromium.org>
Commit-Queue: Patrick Monette <pmonette@chromium.org>
Cr-Commit-Position: refs/heads/master@{#739401}
parent e43867d3
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "components/performance_manager/performance_manager_registry_impl.h" #include "components/performance_manager/performance_manager_registry_impl.h"
#include <utility>
#include "base/stl_util.h" #include "base/stl_util.h"
#include "components/performance_manager/performance_manager_tab_helper.h" #include "components/performance_manager/performance_manager_tab_helper.h"
#include "components/performance_manager/public/performance_manager.h" #include "components/performance_manager/public/performance_manager.h"
...@@ -90,12 +92,14 @@ void PerformanceManagerRegistryImpl::CreateProcessNodeForRenderProcessHost( ...@@ -90,12 +92,14 @@ void PerformanceManagerRegistryImpl::CreateProcessNodeForRenderProcessHost(
void PerformanceManagerRegistryImpl::NotifyBrowserContextAdded( void PerformanceManagerRegistryImpl::NotifyBrowserContextAdded(
content::BrowserContext* browser_context) { content::BrowserContext* browser_context) {
content::StoragePartition* storage_partition =
content::BrowserContext::GetDefaultStoragePartition(browser_context);
std::unique_ptr<WorkerWatcher> worker_watcher = std::unique_ptr<WorkerWatcher> worker_watcher =
std::make_unique<WorkerWatcher>( std::make_unique<WorkerWatcher>(
browser_context->UniqueId(), browser_context->UniqueId(),
content::BrowserContext::GetDefaultStoragePartition(browser_context) storage_partition->GetDedicatedWorkerService(),
->GetSharedWorkerService(), storage_partition->GetSharedWorkerService(), &process_node_source_,
&process_node_source_, &frame_node_source_); &frame_node_source_);
auto result = browser_contexts_with_worker_watcher_.insert( auto result = browser_contexts_with_worker_watcher_.insert(
{browser_context->UniqueId(), std::move(worker_watcher)}); {browser_context->UniqueId(), std::move(worker_watcher)});
DCHECK(result.second); DCHECK(result.second);
......
...@@ -322,13 +322,7 @@ int64_t PerformanceManagerTabHelper::LastNavigationId() const { ...@@ -322,13 +322,7 @@ int64_t PerformanceManagerTabHelper::LastNavigationId() const {
FrameNodeImpl* PerformanceManagerTabHelper::GetFrameNode( FrameNodeImpl* PerformanceManagerTabHelper::GetFrameNode(
content::RenderFrameHost* render_frame_host) { content::RenderFrameHost* render_frame_host) {
auto it = frames_.find(render_frame_host); auto it = frames_.find(render_frame_host);
if (it == frames_.end()) { return it != frames_.end() ? it->second.get() : nullptr;
// Avoid dereferencing an invalid iterator because it produces hard to debug
// crashes.
NOTREACHED();
return nullptr;
}
return it->second.get();
} }
void PerformanceManagerTabHelper::AddObserver(Observer* observer) { void PerformanceManagerTabHelper::AddObserver(Observer* observer) {
......
...@@ -81,7 +81,8 @@ class PerformanceManagerTabHelper ...@@ -81,7 +81,8 @@ class PerformanceManagerTabHelper
void SetUkmSourceIdForTesting(ukm::SourceId id) { ukm_source_id_ = id; } void SetUkmSourceIdForTesting(ukm::SourceId id) { ukm_source_id_ = id; }
// Retrieves the frame node associated with |render_frame_host|. // Retrieves the frame node associated with |render_frame_host|. Returns
// nullptr if none exist for that frame.
FrameNodeImpl* GetFrameNode(content::RenderFrameHost* render_frame_host); FrameNodeImpl* GetFrameNode(content::RenderFrameHost* render_frame_host);
class Observer : public base::CheckedObserver { class Observer : public base::CheckedObserver {
......
...@@ -223,4 +223,28 @@ TEST_F(PerformanceManagerTabHelperTest, PageIsAudible) { ...@@ -223,4 +223,28 @@ TEST_F(PerformanceManagerTabHelperTest, PageIsAudible) {
ExpectPageIsAudible(false); ExpectPageIsAudible(false);
} }
TEST_F(PerformanceManagerTabHelperTest, GetFrameNode) {
SetContents(CreateTestWebContents());
auto* tab_helper =
PerformanceManagerTabHelper::FromWebContents(web_contents());
ASSERT_TRUE(tab_helper);
// GetFrameNode() can return nullptr. In this test, it is achieved by using an
// empty RenderFrameHost.
auto* empty_frame = web_contents()->GetMainFrame();
DCHECK(empty_frame);
auto* empty_frame_node = tab_helper->GetFrameNode(empty_frame);
EXPECT_FALSE(empty_frame_node);
// This navigation will create a frame node.
auto* new_frame = content::NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL(kParentUrl));
DCHECK(new_frame);
auto* new_frame_node = tab_helper->GetFrameNode(new_frame);
EXPECT_TRUE(new_frame_node);
}
} // namespace performance_manager } // namespace performance_manager
...@@ -47,21 +47,27 @@ void RemoveWorkersFromFrameNode( ...@@ -47,21 +47,27 @@ void RemoveWorkersFromFrameNode(
WorkerWatcher::WorkerWatcher( WorkerWatcher::WorkerWatcher(
const std::string& browser_context_id, const std::string& browser_context_id,
content::DedicatedWorkerService* dedicated_worker_service,
content::SharedWorkerService* shared_worker_service, content::SharedWorkerService* shared_worker_service,
ProcessNodeSource* process_node_source, ProcessNodeSource* process_node_source,
FrameNodeSource* frame_node_source) FrameNodeSource* frame_node_source)
: browser_context_id_(browser_context_id), : browser_context_id_(browser_context_id),
dedicated_worker_service_observer_(this),
shared_worker_service_observer_(this), shared_worker_service_observer_(this),
process_node_source_(process_node_source), process_node_source_(process_node_source),
frame_node_source_(frame_node_source) { frame_node_source_(frame_node_source) {
DCHECK(dedicated_worker_service);
DCHECK(shared_worker_service); DCHECK(shared_worker_service);
DCHECK(process_node_source_); DCHECK(process_node_source_);
DCHECK(frame_node_source_); DCHECK(frame_node_source_);
dedicated_worker_service_observer_.Add(dedicated_worker_service);
shared_worker_service_observer_.Add(shared_worker_service); shared_worker_service_observer_.Add(shared_worker_service);
} }
WorkerWatcher::~WorkerWatcher() { WorkerWatcher::~WorkerWatcher() {
DCHECK(frame_node_child_workers_.empty()); DCHECK(frame_node_child_workers_.empty());
DCHECK(dedicated_worker_nodes_.empty());
DCHECK(!dedicated_worker_service_observer_.IsObservingSources());
DCHECK(shared_worker_nodes_.empty()); DCHECK(shared_worker_nodes_.empty());
DCHECK(!shared_worker_service_observer_.IsObservingSources()); DCHECK(!shared_worker_service_observer_.IsObservingSources());
} }
...@@ -87,16 +93,54 @@ void WorkerWatcher::TearDown() { ...@@ -87,16 +93,54 @@ void WorkerWatcher::TearDown() {
// Then clean all the worker nodes. // Then clean all the worker nodes.
std::vector<std::unique_ptr<NodeBase>> nodes; std::vector<std::unique_ptr<NodeBase>> nodes;
nodes.reserve(shared_worker_nodes_.size()); nodes.reserve(dedicated_worker_nodes_.size() + shared_worker_nodes_.size());
for (auto& node : dedicated_worker_nodes_)
nodes.push_back(std::move(node.second));
dedicated_worker_nodes_.clear();
for (auto& node : shared_worker_nodes_) for (auto& node : shared_worker_nodes_)
nodes.push_back(std::move(node.second)); nodes.push_back(std::move(node.second));
shared_worker_nodes_.clear(); shared_worker_nodes_.clear();
PerformanceManagerImpl::GetInstance()->BatchDeleteNodes(std::move(nodes)); PerformanceManagerImpl::GetInstance()->BatchDeleteNodes(std::move(nodes));
dedicated_worker_service_observer_.RemoveAll();
shared_worker_service_observer_.RemoveAll(); shared_worker_service_observer_.RemoveAll();
} }
void WorkerWatcher::OnWorkerStarted(
content::DedicatedWorkerId dedicated_worker_id,
int worker_process_id,
content::GlobalFrameRoutingId ancestor_render_frame_host_id) {
// TODO(https://crbug.com/993029): Plumb through the URL and the DevTools
// token.
auto worker_node = PerformanceManagerImpl::GetInstance()->CreateWorkerNode(
browser_context_id_, WorkerNode::WorkerType::kDedicated,
process_node_source_->GetProcessNode(worker_process_id),
base::UnguessableToken::Create());
bool inserted = dedicated_worker_nodes_
.emplace(dedicated_worker_id, std::move(worker_node))
.second;
DCHECK(inserted);
// TODO(pmonette): Connect |worker_node| to its client frame.
}
void WorkerWatcher::OnBeforeWorkerTerminated(
content::DedicatedWorkerId dedicated_worker_id,
content::GlobalFrameRoutingId ancestor_render_frame_host_id) {
auto it = dedicated_worker_nodes_.find(dedicated_worker_id);
DCHECK(it != dedicated_worker_nodes_.end());
auto worker_node = std::move(it->second);
// TODO(pmonette): Disconnect |worker_node| from its client frame.
#if DCHECK_IS_ON()
DCHECK(!base::Contains(clients_to_remove_, worker_node.get()));
#endif // DCHECK_IS_ON()
PerformanceManagerImpl::GetInstance()->DeleteNode(std::move(worker_node));
dedicated_worker_nodes_.erase(it);
}
void WorkerWatcher::OnWorkerStarted( void WorkerWatcher::OnWorkerStarted(
const content::SharedWorkerInstance& instance, const content::SharedWorkerInstance& instance,
int worker_process_id, int worker_process_id,
...@@ -126,31 +170,41 @@ void WorkerWatcher::OnBeforeWorkerTerminated( ...@@ -126,31 +170,41 @@ void WorkerWatcher::OnBeforeWorkerTerminated(
void WorkerWatcher::OnClientAdded( void WorkerWatcher::OnClientAdded(
const content::SharedWorkerInstance& instance, const content::SharedWorkerInstance& instance,
content::GlobalFrameRoutingId render_frame_host_id) { content::GlobalFrameRoutingId render_frame_host_id) {
AddClientFrame(GetSharedWorkerNode(instance), render_frame_host_id);
}
void WorkerWatcher::OnClientRemoved(
const content::SharedWorkerInstance& instance,
content::GlobalFrameRoutingId render_frame_host_id) {
RemoveClientFrame(GetSharedWorkerNode(instance), render_frame_host_id);
}
void WorkerWatcher::AddClientFrame(
WorkerNodeImpl* worker_node,
content::GlobalFrameRoutingId client_render_frame_host_id) {
FrameNodeImpl* frame_node = FrameNodeImpl* frame_node =
frame_node_source_->GetFrameNode(render_frame_host_id); frame_node_source_->GetFrameNode(client_render_frame_host_id);
DCHECK(frame_node); DCHECK(frame_node);
// Connect the nodes in the PM graph. // Connect the nodes in the PM graph.
WorkerNodeImpl* worker_node = GetSharedWorkerNode(instance);
PerformanceManagerImpl::CallOnGraphImpl( PerformanceManagerImpl::CallOnGraphImpl(
FROM_HERE, FROM_HERE,
base::BindOnce(&AddWorkerToFrameNode, frame_node, worker_node)); base::BindOnce(&AddWorkerToFrameNode, frame_node, worker_node));
// Keep track of the shared workers that this frame is a client to. // Keep track of the shared workers that this frame is a client to.
if (AddChildWorker(render_frame_host_id, worker_node)) { if (AddChildWorker(client_render_frame_host_id, worker_node)) {
frame_node_source_->SubscribeToFrameNode( frame_node_source_->SubscribeToFrameNode(
render_frame_host_id, client_render_frame_host_id,
base::BindOnce(&WorkerWatcher::OnBeforeFrameNodeRemoved, base::BindOnce(&WorkerWatcher::OnBeforeFrameNodeRemoved,
base::Unretained(this), render_frame_host_id)); base::Unretained(this), client_render_frame_host_id));
} }
} }
void WorkerWatcher::OnClientRemoved( void WorkerWatcher::RemoveClientFrame(
const content::SharedWorkerInstance& instance, WorkerNodeImpl* worker_node,
content::GlobalFrameRoutingId render_frame_host_id) { content::GlobalFrameRoutingId client_render_frame_host_id) {
WorkerNodeImpl* worker_node = GetSharedWorkerNode(instance);
FrameNodeImpl* frame_node = FrameNodeImpl* frame_node =
frame_node_source_->GetFrameNode(render_frame_host_id); frame_node_source_->GetFrameNode(client_render_frame_host_id);
// It's possible that the frame was destroyed before receiving the // It's possible that the frame was destroyed before receiving the
// OnClientRemoved() for all of its child shared worker. Nothing to do in // OnClientRemoved() for all of its child shared worker. Nothing to do in
...@@ -180,8 +234,8 @@ void WorkerWatcher::OnClientRemoved( ...@@ -180,8 +234,8 @@ void WorkerWatcher::OnClientRemoved(
// Remove |worker_node| from the set of workers that this frame is a client // Remove |worker_node| from the set of workers that this frame is a client
// of. // of.
if (RemoveChildWorker(render_frame_host_id, worker_node)) if (RemoveChildWorker(client_render_frame_host_id, worker_node))
frame_node_source_->UnsubscribeFromFrameNode(render_frame_host_id); frame_node_source_->UnsubscribeFromFrameNode(client_render_frame_host_id);
} }
void WorkerWatcher::OnBeforeFrameNodeRemoved( void WorkerWatcher::OnBeforeFrameNodeRemoved(
...@@ -241,6 +295,16 @@ bool WorkerWatcher::RemoveChildWorker( ...@@ -241,6 +295,16 @@ bool WorkerWatcher::RemoveChildWorker(
return false; return false;
} }
WorkerNodeImpl* WorkerWatcher::GetDedicatedWorkerNode(
content::DedicatedWorkerId dedicated_worker_id) {
auto it = dedicated_worker_nodes_.find(dedicated_worker_id);
if (it == dedicated_worker_nodes_.end()) {
NOTREACHED();
return nullptr;
}
return it->second.get();
}
WorkerNodeImpl* WorkerWatcher::GetSharedWorkerNode( WorkerNodeImpl* WorkerWatcher::GetSharedWorkerNode(
const content::SharedWorkerInstance& instance) { const content::SharedWorkerInstance& instance) {
auto it = shared_worker_nodes_.find(instance); auto it = shared_worker_nodes_.find(instance);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/scoped_observer.h" #include "base/scoped_observer.h"
#include "content/public/browser/dedicated_worker_service.h"
#include "content/public/browser/global_routing_id.h" #include "content/public/browser/global_routing_id.h"
#include "content/public/browser/shared_worker_service.h" #include "content/public/browser/shared_worker_service.h"
...@@ -30,11 +31,12 @@ class WorkerNodeImpl; ...@@ -30,11 +31,12 @@ class WorkerNodeImpl;
// This class keeps track of running workers of all types for a single browser // This class keeps track of running workers of all types for a single browser
// context and handles the ownership of the worker nodes. // context and handles the ownership of the worker nodes.
// //
// TODO(https://crbug.com/993029): Add support for dedicated workers and service // TODO(https://crbug.com/993029): Add support for service workers.
// workers. class WorkerWatcher : public content::DedicatedWorkerService::Observer,
class WorkerWatcher : public content::SharedWorkerService::Observer { public content::SharedWorkerService::Observer {
public: public:
WorkerWatcher(const std::string& browser_context_id, WorkerWatcher(const std::string& browser_context_id,
content::DedicatedWorkerService* dedicated_worker_service,
content::SharedWorkerService* shared_worker_service, content::SharedWorkerService* shared_worker_service,
ProcessNodeSource* process_node_source, ProcessNodeSource* process_node_source,
FrameNodeSource* frame_node_source); FrameNodeSource* frame_node_source);
...@@ -44,6 +46,15 @@ class WorkerWatcher : public content::SharedWorkerService::Observer { ...@@ -44,6 +46,15 @@ class WorkerWatcher : public content::SharedWorkerService::Observer {
// destroyed on the PM graph. // destroyed on the PM graph.
void TearDown(); void TearDown();
// content::DedicatedWorkerService::Observer:
void OnWorkerStarted(
content::DedicatedWorkerId dedicated_worker_id,
int worker_process_id,
content::GlobalFrameRoutingId ancestor_render_frame_host_id) override;
void OnBeforeWorkerTerminated(
content::DedicatedWorkerId dedicated_worker_id,
content::GlobalFrameRoutingId ancestor_render_frame_host_id) override;
// content::SharedWorkerService::Observer: // content::SharedWorkerService::Observer:
void OnWorkerStarted(const content::SharedWorkerInstance& instance, void OnWorkerStarted(const content::SharedWorkerInstance& instance,
int worker_process_id, int worker_process_id,
...@@ -60,6 +71,13 @@ class WorkerWatcher : public content::SharedWorkerService::Observer { ...@@ -60,6 +71,13 @@ class WorkerWatcher : public content::SharedWorkerService::Observer {
private: private:
friend class WorkerWatcherTest; friend class WorkerWatcherTest;
void AddClientFrame(
WorkerNodeImpl* worker_node,
content::GlobalFrameRoutingId client_render_frame_host_id);
void RemoveClientFrame(
WorkerNodeImpl* worker_node,
content::GlobalFrameRoutingId client_render_frame_host_id);
void OnBeforeFrameNodeRemoved( void OnBeforeFrameNodeRemoved(
content::GlobalFrameRoutingId render_frame_host_id, content::GlobalFrameRoutingId render_frame_host_id,
FrameNodeImpl* frame_node); FrameNodeImpl* frame_node);
...@@ -70,12 +88,19 @@ class WorkerWatcher : public content::SharedWorkerService::Observer { ...@@ -70,12 +88,19 @@ class WorkerWatcher : public content::SharedWorkerService::Observer {
WorkerNodeImpl* child_worker_node); WorkerNodeImpl* child_worker_node);
// Helper function to retrieve an existing shared worker node. // Helper function to retrieve an existing shared worker node.
WorkerNodeImpl* GetDedicatedWorkerNode(
content::DedicatedWorkerId dedicated_worker_id);
WorkerNodeImpl* GetSharedWorkerNode( WorkerNodeImpl* GetSharedWorkerNode(
const content::SharedWorkerInstance& instance); const content::SharedWorkerInstance& instance);
// The ID of the BrowserContext who owns the shared worker service. // The ID of the BrowserContext who owns the shared worker service.
const std::string browser_context_id_; const std::string browser_context_id_;
// Observes the DedicatedWorkerService for this browser context.
ScopedObserver<content::DedicatedWorkerService,
content::DedicatedWorkerService::Observer>
dedicated_worker_service_observer_;
// Observes the SharedWorkerService for this browser context. // Observes the SharedWorkerService for this browser context.
ScopedObserver<content::SharedWorkerService, ScopedObserver<content::SharedWorkerService,
content::SharedWorkerService::Observer> content::SharedWorkerService::Observer>
...@@ -88,6 +113,10 @@ class WorkerWatcher : public content::SharedWorkerService::Observer { ...@@ -88,6 +113,10 @@ class WorkerWatcher : public content::SharedWorkerService::Observer {
// frame ID. Also allows to subscribe to a frame's deletion notification. // frame ID. Also allows to subscribe to a frame's deletion notification.
FrameNodeSource* const frame_node_source_; FrameNodeSource* const frame_node_source_;
// Maps each dedicated worker ID to its worker node.
base::flat_map<content::DedicatedWorkerId, std::unique_ptr<WorkerNodeImpl>>
dedicated_worker_nodes_;
// Maps each SharedWorkerInstance to its worker node. // Maps each SharedWorkerInstance to its worker node.
base::flat_map<content::SharedWorkerInstance, std::unique_ptr<WorkerNodeImpl>> base::flat_map<content::SharedWorkerInstance, std::unique_ptr<WorkerNodeImpl>>
shared_worker_nodes_; shared_worker_nodes_;
......
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