blob: e943d630d00ad2f0831775a891e8c853eea5c451 [file]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/devtools_durable_msg_collector_manager.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/process_memory_dump.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/network/public/cpp/features.h"
namespace network {
namespace {
// The name of the dump provider.
constexpr const char* kDumpProviderName =
"DevtoolsDurableMessageCollectorManager";
} // namespace
DevtoolsDurableMessageCollectorManager::DevtoolsDurableMessageCollectorManager()
: max_global_buffer_size_(static_cast<uint64_t>(
network::features::kDurableMessagesGlobalBufferSize.Get())) {
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, kDumpProviderName,
base::SingleThreadTaskRunner::GetCurrentDefault());
}
DevtoolsDurableMessageCollectorManager::
~DevtoolsDurableMessageCollectorManager() {
base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
this);
}
void DevtoolsDurableMessageCollectorManager::AddCollector(
mojo::PendingReceiver<network::mojom::DurableMessageCollector> receiver) {
mojo::MakeSelfOwnedReceiver(std::make_unique<DevtoolsDurableMessageCollector>(
weak_factory_.GetWeakPtr()),
std::move(receiver));
}
void DevtoolsDurableMessageCollectorManager::OnCollectorCreated(
DevtoolsDurableMessageCollector* collector) {
collectors_.insert(collector);
}
void DevtoolsDurableMessageCollectorManager::OnCollectorDestroyed(
DevtoolsDurableMessageCollector* collector) {
// An O(n) scan is fine here, because the number of collectors is
// expected to be small.
for (auto it = profile_collectors_.begin();
it != profile_collectors_.end();) {
if (it->second == collector) {
it = profile_collectors_.erase(it);
} else {
++it;
}
}
collectors_.erase(collector);
}
bool DevtoolsDurableMessageCollectorManager::CanAccommodate(size_t size) const {
if (max_global_buffer_size_ == 0) {
// No global limit set, so we can accommodate any size.
return true;
}
if (total_memory_usage_ >= max_global_buffer_size_) {
return false;
}
return size <= max_global_buffer_size_ - total_memory_usage_;
}
void DevtoolsDurableMessageCollectorManager::OnCollectorAddedBytes(
size_t size) {
total_memory_usage_ += size;
}
void DevtoolsDurableMessageCollectorManager::OnCollectorRemovedBytes(
size_t size) {
DCHECK_GE(total_memory_usage_, size);
total_memory_usage_ -= size;
}
void DevtoolsDurableMessageCollectorManager::OnCollectorAddedMessage(
size_t count) {
total_message_count_ += count;
}
void DevtoolsDurableMessageCollectorManager::OnCollectorRemovedMessage(
size_t count) {
DCHECK_GE(total_message_count_, count);
total_message_count_ -= count;
}
bool DevtoolsDurableMessageCollectorManager::OnMemoryDump(
const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) {
base::trace_event::MemoryAllocatorDump* dump =
pmd->CreateAllocatorDump("devtools/durable_message_collectors");
dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
total_memory_usage_);
dump->AddScalar("message_count",
base::trace_event::MemoryAllocatorDump::kUnitsObjects,
total_message_count_);
dump->AddScalar("collector_count",
base::trace_event::MemoryAllocatorDump::kUnitsObjects,
collectors_.size());
return true;
}
std::vector<DevtoolsDurableMessageCollector*>
DevtoolsDurableMessageCollectorManager::GetCollectorsEnabledForProfile(
const base::UnguessableToken& profile_id) {
std::vector<DevtoolsDurableMessageCollector*> collectors;
auto range = profile_collectors_.equal_range(profile_id);
for (auto it = range.first; it != range.second; ++it) {
collectors.push_back(it->second);
}
return collectors;
}
void DevtoolsDurableMessageCollectorManager::EnableForProfile(
const base::UnguessableToken& profile_id,
DevtoolsDurableMessageCollector& collector) {
profile_collectors_.insert({profile_id, &collector});
}
void DevtoolsDurableMessageCollectorManager::DisableForProfile(
const base::UnguessableToken& profile_id,
DevtoolsDurableMessageCollector& collector) {
auto range = profile_collectors_.equal_range(profile_id);
for (auto it = range.first; it != range.second;) {
if (it->second == &collector) {
it = profile_collectors_.erase(it);
} else {
++it;
}
}
}
} // namespace network