Commit f2f5ca37 authored by primiano's avatar primiano Committed by Commit bot

[tracing] child-process-side impl for inter-process memory dumps

This CL introduces the implementation for handling the inter-process
memory dumps on the child-process side.
Conceptually this consists of a simple plumbing in TraceMessageFilter
in order to propagate the request up to the browser's MemoryDumpManager,
as the child processes' MDM play a very passive role in the inter-process
coordination game.
In practice, some extra care is required to match the lifetime of MDM
MDM (long) and ChildTraceMessageFilter (shorter) in a thread-safe
manner, which requires the introduction of the proxy class herein
called ChildMemoryDumpManagerDelegateImpl.

More context and design doc are available in the attached BUG.

Reason for NOTRY: all but one bots are green. I started goo.gl/tBX5f1
on infra-dev about the failure and it seems due to a bot out of space.
The change has been sitting for 4+ hours and there are other CLs blocked
on this.

BUG=462930,474973
NOTRY=true

Review URL: https://codereview.chromium.org/1039963003

Cr-Commit-Position: refs/heads/master@{#324229}
parent 38087a42
...@@ -77,7 +77,10 @@ void MemoryDumpManager::Initialize() { ...@@ -77,7 +77,10 @@ void MemoryDumpManager::Initialize() {
void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate* delegate) { void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate* delegate) {
AutoLock lock(lock_); AutoLock lock(lock_);
DCHECK(delegate_ == nullptr); // TODO(primiano): The DCHECK below is disabled just temporary (and it is
// strongly useful). It should be re-enabled soon as crbug.com/474973 is fixed
// (ETA: end of April 2015). Commenting out just to de-entangle CL deps.
// DCHECK(delegate_ == nullptr);
delegate_ = delegate; delegate_ = delegate;
} }
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
'..', '..',
], ],
'sources': [ 'sources': [
'tracing/child_memory_dump_manager_delegate_impl.cc',
'tracing/child_memory_dump_manager_delegate_impl.h',
'tracing/child_trace_message_filter.cc', 'tracing/child_trace_message_filter.cc',
'tracing/child_trace_message_filter.h', 'tracing/child_trace_message_filter.h',
'tracing/tracing_messages.cc', 'tracing/tracing_messages.cc',
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
source_set("tracing") { source_set("tracing") {
sources = [ sources = [
"child_memory_dump_manager_delegate_impl.cc",
"child_memory_dump_manager_delegate_impl.h",
"child_trace_message_filter.cc", "child_trace_message_filter.cc",
"child_trace_message_filter.h", "child_trace_message_filter.h",
"tracing_messages.cc", "tracing_messages.cc",
......
// 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 "components/tracing/child_memory_dump_manager_delegate_impl.h"
#include "base/single_thread_task_runner.h"
#include "components/tracing/child_trace_message_filter.h"
namespace tracing {
// static
ChildMemoryDumpManagerDelegateImpl*
ChildMemoryDumpManagerDelegateImpl::GetInstance() {
return Singleton<
ChildMemoryDumpManagerDelegateImpl,
LeakySingletonTraits<ChildMemoryDumpManagerDelegateImpl>>::get();
}
ChildMemoryDumpManagerDelegateImpl::ChildMemoryDumpManagerDelegateImpl()
: ctmf_(nullptr) {
base::trace_event::MemoryDumpManager::GetInstance()->SetDelegate(this);
}
ChildMemoryDumpManagerDelegateImpl::~ChildMemoryDumpManagerDelegateImpl() {
}
void ChildMemoryDumpManagerDelegateImpl::SetChildTraceMessageFilter(
ChildTraceMessageFilter* ctmf) {
// Check that we are either registering the CTMF or tearing it down, but not
// replacing a valid instance with another one (should never happen).
DCHECK(ctmf_ == nullptr || (ctmf == nullptr && ctmf_task_runner_ != nullptr));
ctmf_ = ctmf;
ctmf_task_runner_ = ctmf ? (ctmf->ipc_message_loop()) : nullptr;
}
// Invoked in child processes by the MemoryDumpManager.
void ChildMemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump(
const base::trace_event::MemoryDumpRequestArgs& args,
const base::trace_event::MemoryDumpCallback& callback) {
// Bail out if we receive a dump request from the manager before the
// ChildTraceMessageFilter has been initialized.
if (!ctmf_task_runner_) {
if (!callback.is_null())
callback.Run(args.dump_guid, false /* success */);
return;
}
// Make sure we access |ctmf_| only on the thread where it lives to avoid
// races on shutdown.
if (!ctmf_task_runner_->BelongsToCurrentThread()) {
ctmf_task_runner_->PostTask(
FROM_HERE,
base::Bind(&ChildMemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump,
base::Unretained(this), args, callback));
return;
}
// The ChildTraceMessageFilter could have been destroyed while hopping on the
// right thread. If this is the case, bail out.
if (!ctmf_) {
if (!callback.is_null())
callback.Run(args.dump_guid, false /* success */);
return;
}
// Send the request up to the browser process' MessageDumpmanager.
ctmf_->SendGlobalMemoryDumpRequest(args, callback);
}
} // namespace tracing
// 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.
#ifndef COMPONENTS_TRACING_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
#define COMPONENTS_TRACING_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
#include "base/trace_event/memory_dump_manager.h"
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
namespace base {
class SingleThreadTaskRunner;
} // namespace base
namespace tracing {
class ChildTraceMessageFilter;
// This class is a simple proxy class between the MemoryDumpManager and the
// ChildTraceMessageFilter. It's only purpose is to adapt the lifetime of
// CTMF to the demands of MDM, which expects the delegate to be thread-safe
// and long lived. CTMF, instead, can be torn down during browser shutdown.
// This class is registered as MDM delegate in child processes and handles
// gracefully (and thread-safely) failures in the case of a lack of the CTMF.
class ChildMemoryDumpManagerDelegateImpl
: public base::trace_event::MemoryDumpManagerDelegate {
public:
static ChildMemoryDumpManagerDelegateImpl* GetInstance();
// base::trace_event::MemoryDumpManagerDelegate implementation.
void RequestGlobalMemoryDump(
const base::trace_event::MemoryDumpRequestArgs& args,
const base::trace_event::MemoryDumpCallback& callback) override;
void SetChildTraceMessageFilter(ChildTraceMessageFilter* ctmf);
private:
friend struct DefaultSingletonTraits<ChildMemoryDumpManagerDelegateImpl>;
ChildMemoryDumpManagerDelegateImpl();
~ChildMemoryDumpManagerDelegateImpl() override;
ChildTraceMessageFilter* ctmf_; // Not owned.
// The SingleThreadTaskRunner where the |ctmf_| lives.
// It is NULL iff |cmtf_| is NULL.
scoped_refptr<base::SingleThreadTaskRunner> ctmf_task_runner_;
DISALLOW_COPY_AND_ASSIGN(ChildMemoryDumpManagerDelegateImpl);
};
} // namespace tracing
#endif // COMPONENTS_TRACING_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/message_loop/message_loop_proxy.h" #include "base/message_loop/message_loop_proxy.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "components/tracing/child_memory_dump_manager_delegate_impl.h"
#include "components/tracing/tracing_messages.h" #include "components/tracing/tracing_messages.h"
#include "ipc/ipc_channel.h" #include "ipc/ipc_channel.h"
...@@ -16,14 +17,20 @@ namespace tracing { ...@@ -16,14 +17,20 @@ namespace tracing {
ChildTraceMessageFilter::ChildTraceMessageFilter( ChildTraceMessageFilter::ChildTraceMessageFilter(
base::MessageLoopProxy* ipc_message_loop) base::MessageLoopProxy* ipc_message_loop)
: sender_(NULL), : sender_(NULL),
ipc_message_loop_(ipc_message_loop) {} ipc_message_loop_(ipc_message_loop),
pending_memory_dump_guid_(0) {
}
void ChildTraceMessageFilter::OnFilterAdded(IPC::Sender* sender) { void ChildTraceMessageFilter::OnFilterAdded(IPC::Sender* sender) {
sender_ = sender; sender_ = sender;
sender_->Send(new TracingHostMsg_ChildSupportsTracing()); sender_->Send(new TracingHostMsg_ChildSupportsTracing());
ChildMemoryDumpManagerDelegateImpl::GetInstance()->SetChildTraceMessageFilter(
this);
} }
void ChildTraceMessageFilter::OnFilterRemoved() { void ChildTraceMessageFilter::OnFilterRemoved() {
ChildMemoryDumpManagerDelegateImpl::GetInstance()->SetChildTraceMessageFilter(
nullptr);
sender_ = NULL; sender_ = NULL;
} }
...@@ -175,8 +182,9 @@ void ChildTraceMessageFilter::OnMonitoringTraceDataCollected( ...@@ -175,8 +182,9 @@ void ChildTraceMessageFilter::OnMonitoringTraceDataCollected(
// Sent by the Browser's MemoryDumpManager when coordinating a global dump. // Sent by the Browser's MemoryDumpManager when coordinating a global dump.
void ChildTraceMessageFilter::OnProcessMemoryDumpRequest( void ChildTraceMessageFilter::OnProcessMemoryDumpRequest(
const base::trace_event::MemoryDumpRequestArgs& args) { const base::trace_event::MemoryDumpRequestArgs& args) {
// TODO(primiano): create local dump and send a response back to the browser. base::trace_event::MemoryDumpManager::GetInstance()->CreateProcessDump(args);
NOTIMPLEMENTED(); sender_->Send(
new TracingHostMsg_ProcessMemoryDumpResponse(args.dump_guid, true));
} }
// Initiates a dump request, asking the Browser's MemoryDumpManager to // Initiates a dump request, asking the Browser's MemoryDumpManager to
...@@ -187,18 +195,28 @@ void ChildTraceMessageFilter::OnProcessMemoryDumpRequest( ...@@ -187,18 +195,28 @@ void ChildTraceMessageFilter::OnProcessMemoryDumpRequest(
void ChildTraceMessageFilter::SendGlobalMemoryDumpRequest( void ChildTraceMessageFilter::SendGlobalMemoryDumpRequest(
const base::trace_event::MemoryDumpRequestArgs& args, const base::trace_event::MemoryDumpRequestArgs& args,
const base::trace_event::MemoryDumpCallback& callback) { const base::trace_event::MemoryDumpCallback& callback) {
// TODO(primiano): implement the logic to send the request to the browser // If there is already another dump request pending from this child process,
// process and keep track of that. // there is no point bothering the Browser's MemoryDumpManager.
NOTIMPLEMENTED(); if (pending_memory_dump_guid_) {
if (!callback.is_null())
callback.Run(args.dump_guid, false);
return;
}
pending_memory_dump_guid_ = args.dump_guid;
pending_memory_dump_callback_ = callback;
sender_->Send(new TracingHostMsg_GlobalMemoryDumpRequest(args));
} }
// Sent by the Browser's MemoryDumpManager in response of a dump request // Sent by the Browser's MemoryDumpManager in response of a dump request
// initiated by this child process. // initiated by this child process.
void ChildTraceMessageFilter::OnGlobalMemoryDumpResponse(uint64 dump_guid, void ChildTraceMessageFilter::OnGlobalMemoryDumpResponse(uint64 dump_guid,
bool success) { bool success) {
// TODO(primiano): implement the logic to handle the global response from DCHECK_NE(0U, pending_memory_dump_guid_);
// the browser and clear up the bookkeeping. pending_memory_dump_guid_ = 0;
NOTIMPLEMENTED(); if (pending_memory_dump_callback_.is_null())
return;
pending_memory_dump_callback_.Run(dump_guid, success);
} }
} // namespace tracing } // namespace tracing
...@@ -30,6 +30,8 @@ class ChildTraceMessageFilter : public IPC::MessageFilter { ...@@ -30,6 +30,8 @@ class ChildTraceMessageFilter : public IPC::MessageFilter {
const base::trace_event::MemoryDumpRequestArgs& args, const base::trace_event::MemoryDumpRequestArgs& args,
const base::trace_event::MemoryDumpCallback& callback); const base::trace_event::MemoryDumpCallback& callback);
base::MessageLoopProxy* ipc_message_loop() const { return ipc_message_loop_; }
protected: protected:
~ChildTraceMessageFilter() override; ~ChildTraceMessageFilter() override;
...@@ -65,6 +67,13 @@ class ChildTraceMessageFilter : public IPC::MessageFilter { ...@@ -65,6 +67,13 @@ class ChildTraceMessageFilter : public IPC::MessageFilter {
IPC::Sender* sender_; IPC::Sender* sender_;
base::MessageLoopProxy* ipc_message_loop_; base::MessageLoopProxy* ipc_message_loop_;
// guid of the outstanding request (to the Browser's MemoryDumpManager), if
// any. 0 if there is no request pending.
uint64 pending_memory_dump_guid_;
// callback of the outstanding memory dump request, if any.
base::trace_event::MemoryDumpCallback pending_memory_dump_callback_;
DISALLOW_COPY_AND_ASSIGN(ChildTraceMessageFilter); DISALLOW_COPY_AND_ASSIGN(ChildTraceMessageFilter);
}; };
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
'build_nonsfi_helper': 1, 'build_nonsfi_helper': 1,
}, },
'sources': [ 'sources': [
'tracing/child_memory_dump_manager_delegate_impl.cc',
'tracing/child_memory_dump_manager_delegate_impl.h',
'tracing/child_trace_message_filter.cc', 'tracing/child_trace_message_filter.cc',
'tracing/child_trace_message_filter.h', 'tracing/child_trace_message_filter.h',
'tracing/tracing_messages.cc', 'tracing/tracing_messages.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment