// 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 "garnet/bin/trace_manager/trace_manager.h"

#include <lib/zx/time.h>

#include <algorithm>
#include <iostream>

#include "fuchsia/sys/cpp/fidl.h"
#include "lib/fidl/cpp/clone.h"

namespace tracing {
namespace {

// For large traces or when verbosity is on it can take awhile to write out
// all the records. E.g., ipm_provider can take 40 seconds with --verbose=2
constexpr zx::duration kStopTimeout = zx::sec(60);
constexpr uint32_t kMinBufferSizeMegabytes = 1;
constexpr uint32_t kMaxBufferSizeMegabytes = 64;

// These defaults are copied from fuchsia.tracing/trace_controller.fidl.
constexpr uint32_t kDefaultBufferSizeMegabytesHint = 4;
constexpr uint32_t kDefaultStartTimeoutMilliseconds = 5000;
constexpr fuchsia::tracing::controller::BufferingMode kDefaultBufferingMode =
    fuchsia::tracing::controller::BufferingMode::ONESHOT;

uint32_t ConstrainBufferSize(uint32_t buffer_size_megabytes) {
  return std::min(std::max(buffer_size_megabytes, kMinBufferSizeMegabytes),
                  kMaxBufferSizeMegabytes);
}

}  // namespace

TraceManager::TraceManager(sys::ComponentContext* 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(
    fuchsia::tracing::controller::TraceOptions options, zx::socket output,
    StartTracingCallback start_callback) {
  if (session_) {
    FXL_LOG(ERROR) << "Trace already in progress";
    return;
  }

  uint32_t default_buffer_size_megabytes = kDefaultBufferSizeMegabytesHint;
  if (options.has_buffer_size_megabytes_hint()) {
    const uint32_t buffer_size_mb_hint = options.buffer_size_megabytes_hint();
    default_buffer_size_megabytes = ConstrainBufferSize(buffer_size_mb_hint);
  }

  TraceProviderSpecMap provider_specs;
  if (options.has_provider_specs()) {
    for (const auto& it : options.provider_specs()) {
      provider_specs[it.name()] =
          TraceProviderSpec{it.buffer_size_megabytes_hint()};
    }
  }

  fuchsia::tracing::controller::BufferingMode tracing_buffering_mode =
      kDefaultBufferingMode;
  if (options.has_buffering_mode()) {
    tracing_buffering_mode = options.buffering_mode();
  }
  fuchsia::tracelink::BufferingMode tracelink_buffering_mode;
  const char* mode_name;
  switch (tracing_buffering_mode) {
    case fuchsia::tracing::controller::BufferingMode::ONESHOT:
      tracelink_buffering_mode = fuchsia::tracelink::BufferingMode::ONESHOT;
      mode_name = "oneshot";
      break;
    case fuchsia::tracing::controller::BufferingMode::CIRCULAR:
      tracelink_buffering_mode = fuchsia::tracelink::BufferingMode::CIRCULAR;
      mode_name = "circular";
      break;
    case fuchsia::tracing::controller::BufferingMode::STREAMING:
      tracelink_buffering_mode = fuchsia::tracelink::BufferingMode::STREAMING;
      mode_name = "streaming";
      break;
    default:
      FXL_LOG(ERROR) << "Invalid buffering mode: "
                     << static_cast<unsigned>(tracing_buffering_mode);
      return;
  }

  FXL_LOG(INFO) << "Starting trace with " << default_buffer_size_megabytes
                << " MB buffers, buffering mode=" << mode_name;
  if (provider_specs.size() > 0) {
    FXL_LOG(INFO) << "Provider overrides:";
    for (const auto& it : provider_specs) {
      FXL_LOG(INFO) << it.first << ": buffer size "
                    << it.second.buffer_size_megabytes << " MB";
    }
  }

  std::vector<::std::string> categories;
  if (options.has_categories()) {
    categories = std::move(options.categories());
  }
  session_ = fxl::MakeRefCounted<TraceSession>(
      std::move(output), std::move(categories), default_buffer_size_megabytes,
      tracelink_buffering_mode, std::move(provider_specs),
      [this]() { session_ = nullptr; });

  session_->QueueTraceInfo();
  for (auto& bundle : providers_) {
    session_->AddProvider(&bundle);
  }

  trace_running_ = true;

  uint64_t start_timeout_milliseconds = kDefaultStartTimeoutMilliseconds;
  if (options.has_start_timeout_milliseconds()) {
    start_timeout_milliseconds = options.start_timeout_milliseconds();
  }
  session_->WaitForProvidersToStart(std::move(start_callback),
                                    zx::msec(start_timeout_milliseconds));
}

void TraceManager::StopTracing() {
  if (!session_)
    return;
  trace_running_ = false;

  FXL_LOG(INFO) << "Stopping trace";
  session_->Stop(
      [this]() {
        FXL_LOG(INFO) << "Stopped trace";
        session_ = nullptr;
      },
      kStopTimeout);
}

void TraceManager::GetKnownCategories(GetKnownCategoriesCallback callback) {
  fidl::VectorPtr<fuchsia::tracing::controller::KnownCategory> known_categories;
  for (const auto& it : config_.known_categories()) {
    known_categories.push_back(
        fuchsia::tracing::controller::KnownCategory{it.first, it.second});
  }
  callback(std::move(known_categories));
}

void TraceManager::RegisterTraceProviderWorker(
    fidl::InterfaceHandle<fuchsia::tracelink::Provider> provider, uint64_t pid,
    fidl::StringPtr name) {
  FXL_VLOG(2) << "Registering provider {" << pid << ":" << name.get() << "}";
  auto it = providers_.emplace(
      providers_.end(),
      TraceProviderBundle{provider.Bind(), next_provider_id_++, pid,
                          name.get()});

  it->provider.set_error_handler([this, it](zx_status_t status) {
    if (session_)
      session_->RemoveDeadProvider(&(*it));
    providers_.erase(it);
  });

  if (session_)
    session_->AddProvider(&(*it));
}

void TraceManager::RegisterTraceProviderDeprecated(
    fidl::InterfaceHandle<fuchsia::tracelink::Provider> provider) {
  RegisterTraceProviderWorker(std::move(provider), ZX_KOID_INVALID,
                              fidl::StringPtr(""));
}

void TraceManager::RegisterTraceProvider(
    fidl::InterfaceHandle<fuchsia::tracelink::Provider> provider, uint64_t pid,
    std::string name) {
  RegisterTraceProviderWorker(std::move(provider), pid, std::move(name));
}

void TraceManager::RegisterTraceProviderSynchronously(
    fidl::InterfaceHandle<fuchsia::tracelink::Provider> provider, uint64_t pid,
    std::string name, RegisterTraceProviderSynchronouslyCallback callback) {
  RegisterTraceProviderWorker(std::move(provider), pid, std::move(name));
  callback(ZX_OK, trace_running_);
}

void TraceManager::LaunchConfiguredProviders() {
  if (config_.providers().empty())
    return;

  fuchsia::sys::LauncherPtr launcher;
  context_->svc()->Connect(launcher.NewRequest());

  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;
    }
    fuchsia::sys::LaunchInfo launch_info;
    launch_info.url = pair.second->url;
    fidl::Clone(pair.second->arguments, &launch_info.arguments);
    launcher->CreateComponent(std::move(launch_info), nullptr);
  }
}

}  // namespace tracing
