blob: 11cdbe537149c0b0a42b770046318726b5e4ae39 [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/memory/memory_pressure_controller.h"
#include "base/bind.h"
#include "content/browser/memory/memory_message_filter.h"
#include "content/public/browser/browser_thread.h"
namespace content {
MemoryPressureController::MemoryPressureController() {}
MemoryPressureController::~MemoryPressureController() {}
void MemoryPressureController::OnMemoryMessageFilterAdded(
MemoryMessageFilter* filter) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Add the message filter to the set of all memory message filters and check
// that it wasn't there beforehand.
const bool success =
memory_message_filters_.insert(
std::make_pair(filter->process_host(), filter))
.second;
DCHECK(success);
// There's no need to send a message to the child process if memory pressure
// notifications are not suppressed.
if (base::MemoryPressureListener::AreNotificationsSuppressed())
filter->SendSetPressureNotificationsSuppressed(true);
}
void MemoryPressureController::OnMemoryMessageFilterRemoved(
MemoryMessageFilter* filter) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Remove the message filter from the set of all memory message filters,
// ensuring that it was there beforehand.
auto it = memory_message_filters_.find(filter->process_host());
DCHECK(it != memory_message_filters_.end());
DCHECK_EQ(filter, it->second);
memory_message_filters_.erase(it);
}
// static
MemoryPressureController* MemoryPressureController::GetInstance() {
return base::Singleton<
MemoryPressureController,
base::LeakySingletonTraits<MemoryPressureController>>::get();
}
void MemoryPressureController::SetPressureNotificationsSuppressedInAllProcesses(
bool suppressed) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
// Note that passing base::Unretained(this) is safe here because the
// controller is a leaky singleton.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&MemoryPressureController::
SetPressureNotificationsSuppressedInAllProcesses,
base::Unretained(this), suppressed));
return;
}
// Enable/disable suppressing memory notifications in the browser process.
base::MemoryPressureListener::SetNotificationsSuppressed(suppressed);
// Enable/disable suppressing memory notifications in all child processes.
for (const auto& filter_pair : memory_message_filters_)
filter_pair.second->SendSetPressureNotificationsSuppressed(suppressed);
}
void MemoryPressureController::SimulatePressureNotificationInAllProcesses(
base::MemoryPressureListener::MemoryPressureLevel level) {
DCHECK_NE(level, base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
// Note that passing base::Unretained(this) is safe here because the
// controller is a leaky singleton.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&MemoryPressureController::
SimulatePressureNotificationInAllProcesses,
base::Unretained(this), level));
return;
}
// Simulate memory pressure notification in the browser process.
base::MemoryPressureListener::SimulatePressureNotification(level);
// Simulate memory pressure notification in all child processes.
for (const auto& filter_pair : memory_message_filters_)
filter_pair.second->SendSimulatePressureNotification(level);
}
void MemoryPressureController::SendPressureNotification(
const BrowserChildProcessHost* child_process_host,
base::MemoryPressureListener::MemoryPressureLevel level) {
SendPressureNotificationImpl(child_process_host, level);
}
void MemoryPressureController::SendPressureNotification(
const RenderProcessHost* render_process_host,
base::MemoryPressureListener::MemoryPressureLevel level) {
SendPressureNotificationImpl(render_process_host, level);
}
void MemoryPressureController::SendPressureNotificationImpl(
const void* child_process_host,
base::MemoryPressureListener::MemoryPressureLevel level) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
// Note that passing base::Unretained(this) is safe here because the
// controller is a leaky singleton. It's also safe to pass an untyped
// child process pointer as the address is only used as a key for lookup in
// a map; at no point is it dereferenced.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&MemoryPressureController::SendPressureNotificationImpl,
base::Unretained(this), child_process_host, level));
return;
}
if (base::MemoryPressureListener::AreNotificationsSuppressed())
return;
// Find the appropriate message filter and dispatch the message.
auto it = memory_message_filters_.find(child_process_host);
if (it != memory_message_filters_.end())
it->second->SendPressureNotification(level);
}
} // namespace content