blob: 867556473eef5a19b391ad786d7c78af84f8889e [file] [log] [blame]
// Copyright 2017 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 "chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.h"
#include "base/task/post_task.h"
#include "base/time/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/performance_manager/graph/frame_node_impl.h"
#include "chrome/browser/performance_manager/graph/page_node_impl.h"
#include "chrome/browser/performance_manager/graph/process_node_impl.h"
#include "chrome/browser/resource_coordinator/resource_coordinator_parts.h"
#include "chrome/browser/resource_coordinator/tab_load_tracker.h"
#include "chrome/browser/resource_coordinator/tab_manager_stats_collector.h"
#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
#include "chrome/browser/resource_coordinator/utils.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
namespace resource_coordinator {
// A helper class for accessing TabLoadTracker. TabLoadTracker can't directly
// friend TabManager::ResourceCoordinatorSignalObserver as it's a nested class
// and can't be forward declared.
class TabManagerResourceCoordinatorSignalObserverHelper {
public:
static void OnPageAlmostIdle(content::WebContents* web_contents) {
// This object is create on demand, so always exists.
TabLoadTracker::Get()->OnPageAlmostIdle(web_contents);
}
};
TabManager::ResourceCoordinatorSignalObserver::
ResourceCoordinatorSignalObserver(
const base::WeakPtr<TabManager>& tab_manager)
: tab_manager_(tab_manager) {}
TabManager::ResourceCoordinatorSignalObserver::
~ResourceCoordinatorSignalObserver() = default;
bool TabManager::ResourceCoordinatorSignalObserver::ShouldObserve(
const NodeBase* node) {
return node->id().type == resource_coordinator::CoordinationUnitType::kPage ||
node->id().type ==
resource_coordinator::CoordinationUnitType::kProcess;
}
void TabManager::ResourceCoordinatorSignalObserver::OnPageAlmostIdleChanged(
PageNodeImpl* page_node) {
// Only notify of changes to almost idle.
if (!page_node->page_almost_idle())
return;
// Forward the notification over to the UI thread.
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&OnPageAlmostIdleOnUi, tab_manager_,
page_node->contents_proxy(), page_node->navigation_id()));
}
void TabManager::ResourceCoordinatorSignalObserver::
OnExpectedTaskQueueingDurationSample(ProcessNodeImpl* process_node) {
// Report this measurement to all pages that are hosting a main frame in
// the process that was sampled.
const base::TimeDelta& duration =
process_node->expected_task_queueing_duration();
for (auto* frame_node : process_node->GetFrameNodes()) {
if (!frame_node->IsMainFrame())
continue;
auto* page_node = frame_node->page_node();
// Forward the notification over to the UI thread.
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&OnExpectedTaskQueueingDurationSampleOnUi, tab_manager_,
page_node->contents_proxy(), page_node->navigation_id(),
duration));
}
}
// static
content::WebContents*
TabManager::ResourceCoordinatorSignalObserver::GetContentsForDispatch(
const base::WeakPtr<TabManager>& tab_manager,
const base::WeakPtr<WebContentsProxy>& contents_proxy,
int64_t navigation_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!tab_manager.get() || !contents_proxy.get() ||
contents_proxy.get()->LastNavigationId() != navigation_id) {
return nullptr;
}
return contents_proxy.get()->GetWebContents();
}
// static
void TabManager::ResourceCoordinatorSignalObserver::OnPageAlmostIdleOnUi(
const base::WeakPtr<TabManager>& tab_manager,
const base::WeakPtr<WebContentsProxy>& contents_proxy,
int64_t navigation_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (auto* contents =
GetContentsForDispatch(tab_manager, contents_proxy, navigation_id)) {
TabManagerResourceCoordinatorSignalObserverHelper::OnPageAlmostIdle(
contents);
}
}
// static
void TabManager::ResourceCoordinatorSignalObserver::
OnExpectedTaskQueueingDurationSampleOnUi(
const base::WeakPtr<TabManager>& tab_manager,
const base::WeakPtr<WebContentsProxy>& contents_proxy,
int64_t navigation_id,
base::TimeDelta duration) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (auto* contents =
GetContentsForDispatch(tab_manager, contents_proxy, navigation_id)) {
// This object is create on demand, so always exists.
g_browser_process->GetTabManager()
->stats_collector()
->RecordExpectedTaskQueueingDuration(contents, duration);
}
}
} // namespace resource_coordinator