#include "base/posix/eintr_wrapper.h"
#include "build/build_config.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/notreached.h"
#include "base/task/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
#include "services/tracing/public/cpp/system_tracing_service.h"
#include "third_party/perfetto/include/perfetto/ext/tracing/ipc/default_socket.h"
namespace tracing {
using ::perfetto::base::UnixSocket;
namespace {
class UnixSocketEventListener : public UnixSocket::EventListener {
public:
using OpenProducerSocketCallback =
SystemTracingService::OpenProducerSocketCallback;
explicit UnixSocketEventListener(OpenProducerSocketCallback callback)
: callback_(std::move(callback)),
callback_sequence_(base::SequencedTaskRunner::GetCurrentDefault()) {}
~UnixSocketEventListener() override = default;
void Connect() {
auto* task_runner = tracing::PerfettoTracedProcess::Get()->GetTaskRunner();
if (!task_runner->RunsTasksOnCurrentThread()) {
task_runner->PostTask([self = this]() { self->Connect(); });
return;
}
std::string socket_name = perfetto::GetProducerSocket();
socket_ = perfetto::base::UnixSocket::Connect(
socket_name, this, task_runner, perfetto::base::SockFamily::kUnix,
perfetto::base::SockType::kStream);
}
void SetOnConnectCallbackForTesting(
SystemTracingService::OnConnectCallback on_connect_callback) {
on_connect_callback_for_testing_ = std::move(on_connect_callback);
}
private:
void RunCallback(base::File fd) {
if (!callback_)
return;
callback_sequence_->PostTask(
FROM_HERE, base::BindOnce(
[](OpenProducerSocketCallback callback, base::File fd) {
std::move(callback).Run(std::move(fd));
},
std::move(callback_), std::move(fd)));
delete this;
}
void OnNewIncomingConnection(
UnixSocket* self,
std::unique_ptr<UnixSocket> new_connection) override {
NOTREACHED();
}
void OnConnect(UnixSocket* self, bool connected) override {
DCHECK(self == socket_.get());
if (on_connect_callback_for_testing_)
callback_sequence_->PostTask(
FROM_HERE,
base::BindOnce(
[](SystemTracingService::OnConnectCallback callback,
bool connected) { std::move(callback).Run(connected); },
std::move(on_connect_callback_for_testing_), connected));
if (!connected)
return RunCallback(base::File());
base::File fd(self->ReleaseSocket().ReleaseFd().release());
DCHECK(connected == fd.IsValid());
RunCallback(std::move(fd));
}
void OnDisconnect(UnixSocket* self) override { RunCallback(base::File()); }
void OnDataAvailable(UnixSocket* self) override {
}
std::unique_ptr<UnixSocket> socket_;
OpenProducerSocketCallback callback_;
SystemTracingService::OnConnectCallback on_connect_callback_for_testing_;
scoped_refptr<base::SequencedTaskRunner> callback_sequence_;
};
}
SystemTracingService::SystemTracingService() = default;
SystemTracingService::~SystemTracingService() = default;
mojo::PendingRemote<mojom::SystemTracingService>
SystemTracingService::BindAndPassPendingRemote() {
DCHECK(!receiver_.is_bound());
auto pending_remote = receiver_.BindNewPipeAndPassRemote();
receiver_.set_disconnect_handler(base::BindOnce(
&SystemTracingService::OnConnectionError, base::Unretained(this)));
return pending_remote;
}
void SystemTracingService::OnConnectionError() {
receiver_.reset();
}
void SystemTracingService::OpenProducerSocket(
OpenProducerSocketCallback callback) {
auto* connect_listener = new UnixSocketEventListener(std::move(callback));
connect_listener->Connect();
}
void SystemTracingService::OpenProducerSocketForTesting(
OpenProducerSocketCallback callback,
OnConnectCallback on_connect_callback) {
auto* connect_listener = new UnixSocketEventListener(std::move(callback));
connect_listener->SetOnConnectCallbackForTesting(
std::move(on_connect_callback));
connect_listener->Connect();
}
}