| // 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 <iterator> |
| #include <utility> |
| |
| #include "base/stl_util.h" |
| #include "components/performance_manager/embedder/binders.h" |
| #include "components/performance_manager/performance_manager_tab_helper.h" |
| #include "components/performance_manager/public/mojom/coordination_unit.mojom.h" |
| #include "components/performance_manager/public/performance_manager.h" |
| #include "components/performance_manager/public/performance_manager_main_thread_mechanism.h" |
| #include "components/performance_manager/public/performance_manager_main_thread_observer.h" |
| #include "components/performance_manager/public/performance_manager_owned.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/navigation_throttle.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()); |
| DCHECK(pm_owned_.empty()); |
| DCHECK(pm_registered_.empty()); |
| // TODO(crbug.com/1084611): |observers_| and |mechanisms_| should also be |
| // empty by now! |
| } |
| |
| // static |
| PerformanceManagerRegistryImpl* PerformanceManagerRegistryImpl::GetInstance() { |
| return g_instance; |
| } |
| |
| void PerformanceManagerRegistryImpl::AddObserver( |
| PerformanceManagerMainThreadObserver* observer) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| observers_.AddObserver(observer); |
| } |
| |
| void PerformanceManagerRegistryImpl::RemoveObserver( |
| PerformanceManagerMainThreadObserver* observer) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| observers_.RemoveObserver(observer); |
| } |
| |
| void PerformanceManagerRegistryImpl::AddMechanism( |
| PerformanceManagerMainThreadMechanism* mechanism) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| mechanisms_.AddObserver(mechanism); |
| } |
| |
| void PerformanceManagerRegistryImpl::RemoveMechanism( |
| PerformanceManagerMainThreadMechanism* mechanism) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| mechanisms_.RemoveObserver(mechanism); |
| } |
| |
| bool PerformanceManagerRegistryImpl::HasMechanism( |
| PerformanceManagerMainThreadMechanism* mechanism) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| return mechanisms_.HasObserver(mechanism); |
| } |
| |
| void PerformanceManagerRegistryImpl::PassToPM( |
| std::unique_ptr<PerformanceManagerOwned> pm_owned) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| pm_owned_.PassObject(std::move(pm_owned)); |
| } |
| |
| std::unique_ptr<PerformanceManagerOwned> |
| PerformanceManagerRegistryImpl::TakeFromPM(PerformanceManagerOwned* pm_owned) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| return pm_owned_.TakeObject(pm_owned); |
| } |
| |
| void PerformanceManagerRegistryImpl::RegisterObject( |
| PerformanceManagerRegistered* pm_object) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| pm_registered_.RegisterObject(pm_object); |
| } |
| |
| void PerformanceManagerRegistryImpl::UnregisterObject( |
| PerformanceManagerRegistered* pm_object) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| pm_registered_.UnregisterObject(pm_object); |
| } |
| |
| PerformanceManagerRegistered* |
| PerformanceManagerRegistryImpl::GetRegisteredObject(uintptr_t type_id) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| return pm_registered_.GetRegisteredObject(type_id); |
| } |
| |
| void PerformanceManagerRegistryImpl::CreatePageNodeForWebContents( |
| content::WebContents* web_contents) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| auto result = web_contents_.insert(web_contents); |
| DCHECK(result.second); |
| |
| 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); |
| } |
| |
| PerformanceManagerRegistryImpl::Throttles |
| PerformanceManagerRegistryImpl::CreateThrottlesForNavigation( |
| content::NavigationHandle* handle) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| Throttles combined_throttles; |
| for (auto& mechanism : mechanisms_) { |
| Throttles throttles = mechanism.CreateThrottlesForNavigation(handle); |
| combined_throttles.insert(combined_throttles.end(), |
| std::make_move_iterator(throttles.begin()), |
| std::make_move_iterator(throttles.end())); |
| } |
| return combined_throttles; |
| } |
| |
| void PerformanceManagerRegistryImpl::NotifyBrowserContextAdded( |
| content::BrowserContext* browser_context) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| 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:: |
| CreateProcessNodeAndExposeInterfacesToRendererProcess( |
| service_manager::BinderRegistry* registry, |
| content::RenderProcessHost* render_process_host) { |
| registry->AddInterface(base::BindRepeating(&BindProcessCoordinationUnit, |
| render_process_host->GetID()), |
| base::SequencedTaskRunnerHandle::Get()); |
| |
| // Ideally this would strictly be a "Create", but when a |
| // RenderFrameHost is "resurrected" with a new process it will |
| // already have user data attached. This will happen on renderer |
| // crash. |
| EnsureProcessNodeForRenderProcessHost(render_process_host); |
| } |
| |
| void PerformanceManagerRegistryImpl::ExposeInterfacesToRenderFrame( |
| mojo::BinderMapWithContext<content::RenderFrameHost*>* map) { |
| map->Add<performance_manager::mojom::DocumentCoordinationUnit>( |
| base::BindRepeating(&BindDocumentCoordinationUnit)); |
| } |
| |
| void PerformanceManagerRegistryImpl::NotifyBrowserContextRemoved( |
| content::BrowserContext* browser_context) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| 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_); |
| |
| // The registry should be torn down before the PerformanceManager. |
| DCHECK(PerformanceManager::IsAvailable()); |
| |
| // Notify any observers of the tear down. This lets them unregister things, |
| // etc. |
| for (auto& observer : observers_) |
| observer.OnBeforePerformanceManagerDestroyed(); |
| |
| DCHECK_EQ(g_instance, this); |
| g_instance = nullptr; |
| |
| // 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(); |
| |
| // Tear down PM owned objects. This lets them clear up object registrations, |
| // observers, mechanisms, etc. |
| pm_owned_.ReleaseObjects(); |
| |
| DCHECK(pm_owned_.empty()); |
| DCHECK(pm_registered_.empty()); |
| // TODO(crbug.com/1084611): |observers_| and |mechanisms_| should also be |
| // empty by now! |
| } |
| |
| 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); |
| } |
| |
| void PerformanceManagerRegistryImpl::EnsureProcessNodeForRenderProcessHost( |
| 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); |
| } |
| } |
| |
| } // namespace performance_manager |