blob: e54548c37de3d6ca02dc4ed7b9c3ed9a825245d0 [file] [log] [blame]
// Copyright 2015 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 "content/browser/devtools/protocol/memory_handler.h"
#include <cinttypes>
#include "base/bind.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/sampling_heap_profiler/module_cache.h"
#include "base/sampling_heap_profiler/sampling_heap_profiler.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/bind_interface_helpers.h"
#include "content/public/common/child_process_host.h"
namespace content {
namespace protocol {
MemoryHandler::MemoryHandler()
: DevToolsDomainHandler(Memory::Metainfo::domainName),
process_host_id_(ChildProcessHost::kInvalidUniqueID),
weak_factory_(this) {}
MemoryHandler::~MemoryHandler() {}
void MemoryHandler::Wire(UberDispatcher* dispatcher) {
Memory::Dispatcher::wire(dispatcher, this);
}
void MemoryHandler::SetRenderer(int process_host_id,
RenderFrameHostImpl* frame_host) {
process_host_id_ = process_host_id;
}
Response MemoryHandler::GetBrowserSamplingProfile(
std::unique_ptr<Memory::SamplingProfile>* out_profile) {
base::ModuleCache module_cache;
auto samples = std::make_unique<Array<Memory::SamplingProfileNode>>();
std::vector<base::SamplingHeapProfiler::Sample> raw_samples =
base::SamplingHeapProfiler::Get()->GetSamples(0);
for (auto& sample : raw_samples) {
auto stack = std::make_unique<Array<String>>();
for (const void* frame : sample.stack) {
uintptr_t address = reinterpret_cast<uintptr_t>(frame);
module_cache.GetModuleForAddress(address); // Populates module_cache.
stack->emplace_back(base::StringPrintf("0x%" PRIxPTR, address));
}
samples->emplace_back(Memory::SamplingProfileNode::Create()
.SetSize(sample.size)
.SetTotal(sample.total)
.SetStack(std::move(stack))
.Build());
}
auto modules = std::make_unique<Array<Memory::Module>>();
for (const auto* module : module_cache.GetModules()) {
modules->emplace_back(
Memory::Module::Create()
.SetName(base::StringPrintf(
"%" PRFilePath, module->GetDebugBasename().value().c_str()))
.SetUuid(module->GetId())
.SetBaseAddress(
base::StringPrintf("0x%" PRIxPTR, module->GetBaseAddress()))
.SetSize(static_cast<double>(module->GetSize()))
.Build());
}
*out_profile = Memory::SamplingProfile::Create()
.SetSamples(std::move(samples))
.SetModules(std::move(modules))
.Build();
return Response::OK();
}
Response MemoryHandler::SetPressureNotificationsSuppressed(
bool suppressed) {
base::MemoryPressureListener::SetNotificationsSuppressed(suppressed);
return Response::OK();
}
Response MemoryHandler::SimulatePressureNotification(
const std::string& level) {
base::MemoryPressureListener::MemoryPressureLevel parsed_level;
if (level == protocol::Memory::PressureLevelEnum::Moderate) {
parsed_level = base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
} else if (level == protocol::Memory::PressureLevelEnum::Critical) {
parsed_level = base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
} else {
return Response::InvalidParams(base::StringPrintf(
"Invalid memory pressure level '%s'", level.c_str()));
}
// Simulate memory pressure notification in the browser process.
base::MemoryPressureListener::SimulatePressureNotification(parsed_level);
return Response::OK();
}
void MemoryHandler::PrepareForLeakDetection(
std::unique_ptr<PrepareForLeakDetectionCallback> callback) {
if (leak_detection_callback_) {
callback->sendFailure(
Response::Error("Another leak detection in progress"));
return;
}
RenderProcessHost* process = RenderProcessHost::FromID(process_host_id_);
if (!process) {
callback->sendFailure(Response::Error("No process to detect leaks in"));
return;
}
leak_detection_callback_ = std::move(callback);
BindInterface(process, &leak_detector_);
leak_detector_.set_connection_error_handler(base::BindOnce(
&MemoryHandler::OnLeakDetectorIsGone, base::Unretained(this)));
leak_detector_->PerformLeakDetection(base::BindOnce(
&MemoryHandler::OnLeakDetectionComplete, weak_factory_.GetWeakPtr()));
}
void MemoryHandler::OnLeakDetectionComplete(
blink::mojom::LeakDetectionResultPtr result) {
leak_detection_callback_->sendSuccess();
leak_detection_callback_.reset();
leak_detector_.reset();
}
void MemoryHandler::OnLeakDetectorIsGone() {
leak_detection_callback_->sendFailure(
Response::Error("Failed to run leak detection"));
leak_detection_callback_.reset();
leak_detector_.reset();
}
} // namespace protocol
} // namespace content