blob: 3407e4d8c25ad60c6611c32704f5f436a7f0fbfc [file] [log] [blame]
// Copyright 2017 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 "chrome/profiling/memlog_connection_manager.h"
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread.h"
#include "chrome/profiling/allocation_tracker.h"
#include "chrome/profiling/memlog_stream_parser.h"
#include "chrome/profiling/profiling_globals.h"
namespace profiling {
struct MemlogConnectionManager::Connection {
Connection(AllocationTracker::CompleteCallback complete_cb,
int process_id,
scoped_refptr<MemlogReceiverPipe> p)
: thread(base::StringPrintf("Proc %d thread", process_id)),
pipe(p),
tracker(std::move(complete_cb)) {}
~Connection() {
// The parser may outlive this class because it's refcounted, make sure no
// callbacks are issued.
parser->DisconnectReceivers();
}
base::Thread thread;
scoped_refptr<MemlogReceiverPipe> pipe;
scoped_refptr<MemlogStreamParser> parser;
AllocationTracker tracker;
};
MemlogConnectionManager::MemlogConnectionManager() {}
MemlogConnectionManager::~MemlogConnectionManager() {
// Clear the callback since the server is refcounted and may outlive us.
server_->set_on_new_connection(
MemlogReceiverPipeServer::NewConnectionCallback());
}
void MemlogConnectionManager::StartConnections(const std::string& pipe_id) {
server_ = new MemlogReceiverPipeServer(
ProfilingGlobals::Get()->GetIORunner(), pipe_id,
base::BindRepeating(&MemlogConnectionManager::OnNewConnection,
base::Unretained(this)));
server_->Start();
}
void MemlogConnectionManager::OnStartMojoControl() {
ProfilingGlobals::Get()->GetIORunner()->PostTask(
FROM_HERE,
base::Bind(
&ProfilingProcess::EnsureMojoStarted,
base::Unretained(ProfilingGlobals::Get()->GetProfilingProcess())));
ProfilingGlobals::Get()->GetIORunner()->PostTask(
FROM_HERE, base::Bind(&ProfilingProcess::AttachPipeServer,
base::Unretained(
ProfilingGlobals::Get()->GetProfilingProcess()),
server_));
}
void MemlogConnectionManager::OnNewConnection(
scoped_refptr<MemlogReceiverPipe> new_pipe,
int sender_pid) {
// Task to post to clean up the connection. Don't need to retain |this| since
// it wil be called by objects owned by the MemlogConnectionManager.
AllocationTracker::CompleteCallback complete_cb =
base::BindOnce(&MemlogConnectionManager::OnConnectionCompleteThunk,
base::Unretained(this),
base::MessageLoop::current()->task_runner(), sender_pid);
std::unique_ptr<Connection> connection = base::MakeUnique<Connection>(
std::move(complete_cb), sender_pid, new_pipe);
connection->thread.Start();
connection->parser = new MemlogStreamParser(this, &connection->tracker);
new_pipe->SetReceiver(connection->thread.task_runner(), connection->parser);
connections_[sender_pid] = std::move(connection);
}
void MemlogConnectionManager::OnConnectionComplete(int process_id) {
auto found = connections_.find(process_id);
CHECK(found != connections_.end());
connections_.erase(found);
// When all connections are closed, exit.
if (connections_.empty())
ProfilingGlobals::Get()->QuitWhenIdle();
}
// Posts back to the given thread the connection complete message.
void MemlogConnectionManager::OnConnectionCompleteThunk(
scoped_refptr<base::SingleThreadTaskRunner> main_loop,
int process_id) {
// This code is called by the allocation tracker which is owned by the
// connection manager. When we tell the connection manager a connection is
// done, we know the conncetion manager will still be in scope.
main_loop->PostTask(FROM_HERE,
base::Bind(&MemlogConnectionManager::OnConnectionComplete,
base::Unretained(this), process_id));
}
} // namespace profiling