blob: 6a721c5c2848677e21239c617ba619922da81daa [file] [log] [blame]
// Copyright 2019 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.
#include "components/performance_manager/performance_manager_registry_impl.h"
#include <utility>
#include "base/stl_util.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_main_thread_observer.h"
#include "components/performance_manager/service_worker_context_adapter.h"
#include "components/performance_manager/worker_watcher.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
namespace performance_manager {
namespace {
PerformanceManagerRegistryImpl* g_instance = nullptr;
} // namespace
PerformanceManagerRegistryImpl::PerformanceManagerRegistryImpl() {
DCHECK(!g_instance);
g_instance = this;
// The registry should be created after the PerformanceManager.
DCHECK(PerformanceManager::IsAvailable());
}
PerformanceManagerRegistryImpl::~PerformanceManagerRegistryImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TearDown() should have been invoked to reset |g_instance| and clear
// |web_contents_| and |render_process_user_data_| prior to destroying the
// registry.
DCHECK(!g_instance);
DCHECK(web_contents_.empty());
DCHECK(render_process_hosts_.empty());
}
// static
PerformanceManagerRegistryImpl* PerformanceManagerRegistryImpl::GetInstance() {
return g_instance;
}
void PerformanceManagerRegistryImpl::AddObserver(
PerformanceManagerMainThreadObserver* observer) {
observers_.AddObserver(observer);
}
void PerformanceManagerRegistryImpl::RemoveObserver(
PerformanceManagerMainThreadObserver* observer) {
observers_.RemoveObserver(observer);
}
void PerformanceManagerRegistryImpl::CreatePageNodeForWebContents(
content::WebContents* web_contents) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto result = web_contents_.insert(web_contents);
if (result.second) {
// Create a PerformanceManagerTabHelper if |web_contents| doesn't already
// have one. Support for multiple calls to CreatePageNodeForWebContents()
// with the same WebContents is required for Devtools -- see comment in
// header file.
PerformanceManagerTabHelper::CreateForWebContents(web_contents);
PerformanceManagerTabHelper* tab_helper =
PerformanceManagerTabHelper::FromWebContents(web_contents);
DCHECK(tab_helper);
tab_helper->SetDestructionObserver(this);
for (auto& observer : observers_)
observer.OnPageNodeCreatedForWebContents(web_contents);
}
}
void PerformanceManagerRegistryImpl::CreateProcessNodeForRenderProcessHost(
content::RenderProcessHost* render_process_host) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto result = render_process_hosts_.insert(render_process_host);
if (result.second) {
// Create a RenderProcessUserData if |render_process_host| doesn't already
// have one.
RenderProcessUserData* user_data =
RenderProcessUserData::CreateForRenderProcessHost(render_process_host);
user_data->SetDestructionObserver(this);
}
}
void PerformanceManagerRegistryImpl::NotifyBrowserContextAdded(
content::BrowserContext* browser_context) {
content::StoragePartition* storage_partition =
content::BrowserContext::GetDefaultStoragePartition(browser_context);
// Create an adapter for the service worker context.
auto insertion_result = service_worker_context_adapters_.emplace(
browser_context, std::make_unique<ServiceWorkerContextAdapter>(
storage_partition->GetServiceWorkerContext()));
DCHECK(insertion_result.second);
ServiceWorkerContextAdapter* service_worker_context_adapter =
insertion_result.first->second.get();
auto worker_watcher = std::make_unique<WorkerWatcher>(
browser_context->UniqueId(),
storage_partition->GetDedicatedWorkerService(),
storage_partition->GetSharedWorkerService(),
service_worker_context_adapter, &process_node_source_,
&frame_node_source_);
bool inserted =
worker_watchers_.emplace(browser_context, std::move(worker_watcher))
.second;
DCHECK(inserted);
}
void PerformanceManagerRegistryImpl::NotifyBrowserContextRemoved(
content::BrowserContext* browser_context) {
auto it = worker_watchers_.find(browser_context);
DCHECK(it != worker_watchers_.end());
it->second->TearDown();
worker_watchers_.erase(it);
// Remove the adapter.
size_t removed = service_worker_context_adapters_.erase(browser_context);
DCHECK_EQ(removed, 1u);
}
void PerformanceManagerRegistryImpl::TearDown() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(g_instance, this);
g_instance = nullptr;
// The registry should be torn down before the PerformanceManager.
DCHECK(PerformanceManager::IsAvailable());
// Destroy WorkerNodes before ProcessNodes, because ProcessNode checks that it
// has no associated WorkerNode when torn down.
for (auto& kv : worker_watchers_) {
kv.second->TearDown();
}
worker_watchers_.clear();
service_worker_context_adapters_.clear();
for (auto* web_contents : web_contents_) {
PerformanceManagerTabHelper* tab_helper =
PerformanceManagerTabHelper::FromWebContents(web_contents);
DCHECK(tab_helper);
// Clear the destruction observer to avoid a nested notification.
tab_helper->SetDestructionObserver(nullptr);
// Destroy the tab helper.
tab_helper->TearDown();
web_contents->RemoveUserData(PerformanceManagerTabHelper::UserDataKey());
}
web_contents_.clear();
for (auto* render_process_host : render_process_hosts_) {
RenderProcessUserData* user_data =
RenderProcessUserData::GetForRenderProcessHost(render_process_host);
DCHECK(user_data);
// Clear the destruction observer to avoid a nested notification.
user_data->SetDestructionObserver(nullptr);
// Destroy the user data.
render_process_host->RemoveUserData(RenderProcessUserData::UserDataKey());
}
render_process_hosts_.clear();
}
void PerformanceManagerRegistryImpl::OnPerformanceManagerTabHelperDestroying(
content::WebContents* web_contents) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const size_t num_removed = web_contents_.erase(web_contents);
DCHECK_EQ(1U, num_removed);
}
void PerformanceManagerRegistryImpl::OnRenderProcessUserDataDestroying(
content::RenderProcessHost* render_process_host) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const size_t num_removed = render_process_hosts_.erase(render_process_host);
DCHECK_EQ(1U, num_removed);
}
} // namespace performance_manager