blob: 81728fb356f5ac6c983c1231803e9758f6294a55 [file] [log] [blame]
// Copyright 2023 The Fuchsia 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 "trace_controller.h"
#include <lib/syslog/cpp/macros.h>
#include <lib/trace-provider/start.h>
#include <zircon/errors.h>
#include <fstream>
#include "src/lib/fsl/socket/blocking_drain.h"
fit::result<fit::failed, Tracer> StartTracing(fuchsia_tracing_controller::TraceConfig trace_config,
const char* output_file) {
trace_provider_start();
zx::socket trace_socket, outgoing_socket;
if (zx_status_t status = zx::socket::create(ZX_SOCKET_STREAM, &trace_socket, &outgoing_socket);
status != ZX_OK) {
FX_PLOGS(ERROR, status) << "failed to create zircon socket";
return fit::failed();
}
fidl::SyncClient<fuchsia_tracing_controller::Provisioner> launcher;
{
zx::result launcher_client = component::Connect<fuchsia_tracing_controller::Provisioner>();
if (launcher_client.is_error()) {
FX_PLOGS(ERROR, launcher_client.status_value())
<< "failed to connect to fuchsia.tracing.controller/Provisioner";
return fit::failed();
}
launcher.Bind(std::move(*launcher_client));
}
auto endpoints = fidl::Endpoints<fuchsia_tracing_controller::Session>::Create();
if (fit::result<fidl::OneWayError> response = launcher->InitializeTracing(
{std::move(endpoints.server), std::move(trace_config), std::move(outgoing_socket)});
response.is_error()) {
FX_LOGS(ERROR) << "failed to initialize tracing: " << response.error_value();
return fit::failed();
}
fidl::SyncClient controller{std::move(endpoints.client)};
if (fidl::Result<fuchsia_tracing_controller::Session::StartTracing> response =
controller->StartTracing({});
response.is_error()) {
FX_LOGS(ERROR) << "failed to start tracing: " << response.error_value();
return fit::failed();
}
std::future<zx_status_t> fut = std::async(
std::launch::async,
[](zx::socket trace_socket, std::string output_file) {
std::ofstream ofs(output_file);
if (!fsl::BlockingDrainFrom(std::move(trace_socket), [&](const void* data, uint32_t len) {
const char* begin = static_cast<const char*>(data);
ofs.write(begin, len);
return len;
})) {
FX_LOGS(ERROR) << "failed to write trace bytes to output file";
return ZX_ERR_PEER_CLOSED;
};
return ZX_OK;
},
std::move(trace_socket), output_file);
return fit::ok(Tracer{.controller = std::move(controller), .future = std::move(fut)});
}
fit::result<fit::failed> StopTracing(Tracer tracer) {
fuchsia_tracing_controller::StopOptions stop_options;
stop_options.write_results(true);
if (fidl::Result<fuchsia_tracing_controller::Session::StopTracing> response =
tracer.controller->StopTracing({stop_options});
response.is_error()) {
FX_LOGS(ERROR) << "failed to stop tracing: " << response.error_value();
return fit::failed();
}
tracer.controller = fidl::SyncClient<fuchsia_tracing_controller::Session>();
tracer.future.wait();
if (zx_status_t status = tracer.future.get(); status != ZX_OK) {
FX_PLOGS(ERROR, status) << "error reading trace";
return fit::failed();
}
return fit::ok();
}