blob: 83c72834646ca4f7047ea07a029bc8106b355ea0 [file] [log] [blame]
// Copyright 2016 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 <algorithm>
#include <iostream>
#include "garnet/bin/trace_manager/trace_manager.h"
#include "lib/fsl/tasks/message_loop.h"
using namespace tracing::internal;
namespace tracing {
namespace {
const fxl::TimeDelta kStopTimeout = fxl::TimeDelta::FromSeconds(20);
static constexpr uint32_t kMinBufferSizeMegabytes = 1;
static constexpr uint32_t kMaxBufferSizeMegabytes = 32;
std::string SanitizeLabel(const fidl::String& label) {
std::string result =
label.get().substr(0, tracing::TraceRegistry::kLabelMaxLength);
if (result.empty())
result = "unnamed";
return result;
}
} // namespace
TraceManager::TraceManager(app::ApplicationContext* context,
const Config& config)
: context_(context), config_(config) {
// TODO(jeffbrown): We should do this in StartTracing() and take care
// to restart any crashed providers. We should also wait briefly to ensure
// that these providers have registered themselves before replying that
// tracing has started.
LaunchConfiguredProviders();
}
TraceManager::~TraceManager() = default;
void TraceManager::StartTracing(TraceOptionsPtr options,
zx::socket output,
const StartTracingCallback& start_callback) {
if (session_) {
FXL_LOG(ERROR) << "Trace already in progress";
return;
}
uint32_t buffer_size_megabytes = std::min(
std::max(options->buffer_size_megabytes_hint, kMinBufferSizeMegabytes),
kMaxBufferSizeMegabytes);
FXL_LOG(INFO) << "Starting trace with " << buffer_size_megabytes
<< " MB buffers";
session_ = fxl::MakeRefCounted<TraceSession>(
std::move(output), std::move(options->categories),
buffer_size_megabytes * 1024 * 1024, [this]() { session_ = nullptr; });
for (auto& bundle : providers_) {
session_->AddProvider(&bundle);
}
session_->WaitForProvidersToStart(
start_callback,
fxl::TimeDelta::FromMilliseconds(options->start_timeout_milliseconds));
}
void TraceManager::StopTracing() {
if (!session_)
return;
FXL_LOG(INFO) << "Stopping trace";
session_->Stop(
[this]() {
FXL_LOG(INFO) << "Stopped trace";
session_ = nullptr;
},
kStopTimeout);
}
void TraceManager::DumpProvider(uint32_t provider_id, zx::socket output) {
for (const auto& provider : providers_) {
if (provider.id == provider_id) {
FXL_LOG(INFO) << "Dumping provider: " << provider;
provider.provider->Dump(std::move(output));
return;
}
}
FXL_LOG(ERROR) << "Failed to dump provider " << provider_id
<< ", provider not found";
}
void TraceManager::GetKnownCategories(
const GetKnownCategoriesCallback& callback) {
callback(
fidl::Map<fidl::String, fidl::String>::From(config_.known_categories()));
}
void TraceManager::GetRegisteredProviders(
const GetRegisteredProvidersCallback& callback) {
fidl::Array<TraceProviderInfoPtr> results;
results.resize(0u);
for (const auto& provider : providers_) {
auto info = TraceProviderInfo::New();
info->label = provider.label;
info->id = provider.id;
results.push_back(std::move(info));
}
callback(std::move(results));
}
void TraceManager::RegisterTraceProvider(
fidl::InterfaceHandle<TraceProvider> handle,
const fidl::String& label) {
FXL_VLOG(1) << "Registering provider with label: " << label;
auto it = providers_.emplace(
providers_.end(),
TraceProviderBundle{TraceProviderPtr::Create(std::move(handle)),
next_provider_id_++, SanitizeLabel(label)});
it->provider.set_connection_error_handler([this, it]() {
if (session_)
session_->RemoveDeadProvider(&(*it));
providers_.erase(it);
});
if (session_)
session_->AddProvider(&(*it));
}
void TraceManager::LaunchConfiguredProviders() {
if (config_.providers().empty())
return;
if (!context_->launcher()) {
FXL_LOG(ERROR)
<< "Cannot access application launcher to launch configured providers";
return;
}
for (const auto& pair : config_.providers()) {
// TODO(jeffbrown): Only do this if the provider isn't already running.
// Also keep track of the provider so we can kill it when the trace
// manager exits or restart it if needed.
FXL_VLOG(1) << "Starting configured provider: " << pair.first;
FXL_VLOG(2) << "URL: " << pair.second->url;
if (FXL_VLOG_IS_ON(2)) {
std::string args;
for (const auto& arg : pair.second->arguments) {
args += " ";
args += arg;
}
FXL_VLOG(2) << "Args:" << args;
}
auto launch_info = app::ApplicationLaunchInfo::New();
launch_info->url = pair.second->url;
launch_info->arguments = pair.second->arguments.Clone();
context_->launcher()->CreateApplication(std::move(launch_info), nullptr);
}
}
} // namespace tracing