blob: 142edba279637cb3a7f239cbc7bf75693d3262c2 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/compute_pressure/web_contents_pressure_manager_proxy.h"
#include <optional>
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/unguessable_token.h"
#include "content/public/browser/device_service.h"
#include "services/device/public/mojom/pressure_manager.mojom.h"
#include "services/device/public/mojom/pressure_update.mojom.h"
namespace content {
WebContentsPressureManagerProxy::WebContentsPressureManagerProxy(
WebContents* web_contents)
: WebContentsUserData<WebContentsPressureManagerProxy>(*web_contents) {}
WebContentsPressureManagerProxy::~WebContentsPressureManagerProxy() {
// Explicitly clear all observers here. In general, this class will outlive
// its observers (PressureServiceForDedicatedWorker and
// PressureServiceForFrame), but in some cases (e.g. active PressureObserver
// instances in both a shared worker and a dedicated worker may cause
// the PressureServiceForDedicatedWorker to be destroyed only when its
// DedicatedWorkerHost's RenderProcessHost is destroyed, which happens
// after this object is destroyed) this is not true.
// The condition above can be reproduced by ComputePressureBrowserTest when
// SupportsSharedWorker() is true and shared workers are used.
observers_.Clear();
}
// static
WebContentsPressureManagerProxy* WebContentsPressureManagerProxy::GetOrCreate(
WebContents* web_contents) {
WebContentsUserData<WebContentsPressureManagerProxy>::CreateForWebContents(
web_contents);
return WebContentsUserData<WebContentsPressureManagerProxy>::FromWebContents(
web_contents);
}
void WebContentsPressureManagerProxy::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void WebContentsPressureManagerProxy::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
std::unique_ptr<ScopedVirtualPressureSourceForDevTools>
WebContentsPressureManagerProxy::CreateVirtualPressureSourceForDevTools(
device::mojom::PressureSource source,
device::mojom::VirtualPressureSourceMetadataPtr metadata) {
if (virtual_pressure_sources_tokens_.contains(source)) {
return nullptr;
}
auto virtual_pressure_source =
base::WrapUnique(new ScopedVirtualPressureSourceForDevTools(
source, std::move(metadata), weak_ptr_factory_.GetWeakPtr()));
virtual_pressure_sources_tokens_[source] = virtual_pressure_source->token();
observers_.Notify(&Observer::DidAddVirtualPressureSource,
virtual_pressure_source->source());
return virtual_pressure_source;
}
std::optional<base::UnguessableToken>
WebContentsPressureManagerProxy::GetTokenFor(
device::mojom::PressureSource source) const {
auto it = virtual_pressure_sources_tokens_.find(source);
if (it == virtual_pressure_sources_tokens_.end()) {
return std::nullopt;
}
return it->second;
}
void WebContentsPressureManagerProxy::EnsureDeviceServiceConnection() {
if (pressure_manager_) {
return;
}
GetDeviceService().BindPressureManager(
pressure_manager_.BindNewPipeAndPassReceiver());
pressure_manager_.reset_on_disconnect();
}
device::mojom::PressureManager*
WebContentsPressureManagerProxy::GetPressureManager() {
EnsureDeviceServiceConnection();
return pressure_manager_.get();
}
void WebContentsPressureManagerProxy::
OnScopedVirtualPressureSourceDevToolsDeletion(
const ScopedVirtualPressureSourceForDevTools& virtual_pressure_source) {
auto it =
virtual_pressure_sources_tokens_.find(virtual_pressure_source.source());
CHECK(it != virtual_pressure_sources_tokens_.end());
CHECK_EQ(it->second, virtual_pressure_source.token());
virtual_pressure_sources_tokens_.erase(it);
observers_.Notify(&Observer::DidRemoveVirtualPressureSource,
virtual_pressure_source.source());
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(WebContentsPressureManagerProxy);
ScopedVirtualPressureSourceForDevTools::ScopedVirtualPressureSourceForDevTools(
device::mojom::PressureSource source,
device::mojom::VirtualPressureSourceMetadataPtr metadata,
base::WeakPtr<WebContentsPressureManagerProxy>
web_contents_pressure_manager_proxy)
: source_(source),
token_(base::UnguessableToken::Create()),
web_contents_pressure_manager_proxy_(
std::move(web_contents_pressure_manager_proxy)) {
web_contents_pressure_manager_proxy_->GetPressureManager()
->AddVirtualPressureSource(token_, source, std::move(metadata),
base::DoNothing());
}
ScopedVirtualPressureSourceForDevTools::
~ScopedVirtualPressureSourceForDevTools() {
if (web_contents_pressure_manager_proxy_) {
web_contents_pressure_manager_proxy_->GetPressureManager()
->RemoveVirtualPressureSource(token_, source_, base::DoNothing());
web_contents_pressure_manager_proxy_
->OnScopedVirtualPressureSourceDevToolsDeletion(*this);
}
}
device::mojom::PressureSource ScopedVirtualPressureSourceForDevTools::source()
const {
return source_;
}
base::UnguessableToken ScopedVirtualPressureSourceForDevTools::token() const {
return token_;
}
void ScopedVirtualPressureSourceForDevTools::UpdateVirtualPressureSourceData(
device::mojom::PressureState state,
double own_contribution_estimate,
device::mojom::PressureManager::UpdateVirtualPressureSourceDataCallback
callback) {
if (web_contents_pressure_manager_proxy_) {
web_contents_pressure_manager_proxy_->GetPressureManager()
->UpdateVirtualPressureSourceData(token_, source_, state,
own_contribution_estimate,
std::move(callback));
}
}
} // namespace content