blob: 59ebe61f76ab3b3c1c513975e78f6c57e166da58 [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/page_signal_receiver.h"
#include "base/no_destructor.h"
#include "base/time/time.h"
#include "content/public/common/service_manager_connection.h"
#include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
#include "services/resource_coordinator/public/mojom/service_constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace resource_coordinator {
// static
bool PageSignalReceiver::IsEnabled() {
// Check that service_manager is active and Resource Coordinator is enabled.
return content::ServiceManagerConnection::GetForProcess() != nullptr;
}
PageSignalReceiver::PageSignalReceiver() : binding_(this) {}
PageSignalReceiver::~PageSignalReceiver() = default;
void PageSignalReceiver::NotifyPageAlmostIdle(
const PageNavigationIdentity& page_navigation_id) {
DCHECK(IsPageAlmostIdleSignalEnabled());
NotifyObserversIfKnownCu(page_navigation_id,
&PageSignalObserver::OnPageAlmostIdle);
}
void PageSignalReceiver::NotifyRendererIsBloated(
const PageNavigationIdentity& page_navigation_id) {
NotifyObserversIfKnownCu(page_navigation_id,
&PageSignalObserver::OnRendererIsBloated);
}
void PageSignalReceiver::SetExpectedTaskQueueingDuration(
const PageNavigationIdentity& page_navigation_id,
base::TimeDelta duration) {
NotifyObserversIfKnownCu(
page_navigation_id,
&PageSignalObserver::OnExpectedTaskQueueingDurationSet, duration);
}
void PageSignalReceiver::SetLifecycleState(
const PageNavigationIdentity& page_navigation_id,
mojom::LifecycleState state) {
NotifyObserversIfKnownCu(page_navigation_id,
&PageSignalObserver::OnLifecycleStateChanged, state);
}
void PageSignalReceiver::NotifyNonPersistentNotificationCreated(
const PageNavigationIdentity& page_navigation_id) {
NotifyObserversIfKnownCu(
page_navigation_id,
&PageSignalObserver::OnNonPersistentNotificationCreated);
}
void PageSignalReceiver::OnLoadTimePerformanceEstimate(
const PageNavigationIdentity& page_navigation_id,
base::TimeDelta load_duration,
base::TimeDelta cpu_usage_estimate,
uint64_t private_footprint_kb_estimate) {
NotifyObserversIfKnownCu(
page_navigation_id, &PageSignalObserver::OnLoadTimePerformanceEstimate,
load_duration, cpu_usage_estimate, private_footprint_kb_estimate);
}
void PageSignalReceiver::AddObserver(PageSignalObserver* observer) {
// When PageSignalReceiver starts to have observer, construct the mojo
// channel.
if (!binding_.is_bound()) {
content::ServiceManagerConnection* service_manager_connection =
content::ServiceManagerConnection::GetForProcess();
// Ensure service_manager is active before trying to connect to it.
if (service_manager_connection) {
service_manager::Connector* connector =
service_manager_connection->GetConnector();
mojom::PageSignalGeneratorPtr page_signal_generator_ptr;
connector->BindInterface(mojom::kServiceName,
mojo::MakeRequest(&page_signal_generator_ptr));
mojom::PageSignalReceiverPtr page_signal_receiver_ptr;
binding_.Bind(mojo::MakeRequest(&page_signal_receiver_ptr));
page_signal_generator_ptr->AddReceiver(
std::move(page_signal_receiver_ptr));
}
}
observers_.AddObserver(observer);
}
void PageSignalReceiver::RemoveObserver(PageSignalObserver* observer) {
observers_.RemoveObserver(observer);
}
void PageSignalReceiver::AssociateCoordinationUnitIDWithWebContents(
const CoordinationUnitID& cu_id,
content::WebContents* web_contents) {
cu_id_web_contents_map_[cu_id] = web_contents;
}
void PageSignalReceiver::SetNavigationID(content::WebContents* web_contents,
int64_t navigation_id) {
DCHECK_NE(nullptr, web_contents);
web_contents_navigation_id_map_[web_contents] = navigation_id;
}
void PageSignalReceiver::RemoveCoordinationUnitID(
const CoordinationUnitID& cu_id) {
auto it = cu_id_web_contents_map_.find(cu_id);
DCHECK(it != cu_id_web_contents_map_.end());
web_contents_navigation_id_map_.erase(it->second);
cu_id_web_contents_map_.erase(it);
}
int64_t PageSignalReceiver::GetNavigationIDForWebContents(
content::WebContents* web_contents) {
DCHECK_NE(nullptr, web_contents);
auto it = web_contents_navigation_id_map_.find(web_contents);
if (it == web_contents_navigation_id_map_.end())
return 0;
return it->second;
}
template <typename Method, typename... Params>
void PageSignalReceiver::NotifyObserversIfKnownCu(
const PageNavigationIdentity& page_navigation_id,
Method m,
Params... params) {
auto web_contents_iter =
cu_id_web_contents_map_.find(page_navigation_id.page_cu_id);
if (web_contents_iter == cu_id_web_contents_map_.end())
return;
// An observer can make web_contents_iter invalid by mutating
// the cu_id_web_contents_map_.
content::WebContents* web_contents = web_contents_iter->second;
for (auto& observer : observers_) {
(observer.*m)(web_contents, page_navigation_id,
std::forward<Params>(params)...);
}
}
} // namespace resource_coordinator