// Copyright 2018 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 "managed_environment.h"

#include <fuchsia/boot/cpp/fidl.h>
#include <fuchsia/diagnostics/cpp/fidl.h>
#include <fuchsia/kernel/cpp/fidl.h>
#include <fuchsia/logger/cpp/fidl.h>
#include <fuchsia/netemul/guest/cpp/fidl.h>

#include <random>

#include <sdk/lib/sys/cpp/termination_reason.h>

#include "src/lib/fxl/strings/string_printf.h"

namespace netemul {

namespace {
// Start the Log and LogSink service (the same component publishses both
// services))
constexpr const char* kLogServiceURLNoKlog =
    "fuchsia-pkg://fuchsia.com/archivist-for-embedding#meta/archivist-for-embedding.cmx";
constexpr const char* kLogServiceURLWithKlog =
    "fuchsia-pkg://fuchsia.com/archivist-for-embedding#meta/archivist-with-klog.cmx";
constexpr const char* kLogServices[] = {fuchsia::logger::LogSink::Name_,
                                        fuchsia::logger::Log::Name_,
                                        fuchsia::diagnostics::ArchiveAccessor::Name_};
}  // namespace

using sys::testing::EnclosingEnvironment;
using sys::testing::EnvironmentServices;

ManagedEnvironment::~ManagedEnvironment() {
  // The environment should be torn down before anything its child components may depend on
  // (i.e. loggers, virtual devices, etc.).
  //
  // Tearing down the loggers before we tear down the environment may cause a rust component
  // to panic when it tries to write to stdout/stderr after their sockets have been closed
  // (https://github.com/rust-lang/rust/blob/f6072ca/src/libstd/io/stdio.rs#L878).
  env_ = nullptr;

  // Always destroy loggers next so they can consume all outstanding messages.
  loggers_ = nullptr;
}

ManagedEnvironment::Ptr ManagedEnvironment::CreateRoot(const fuchsia::sys::EnvironmentPtr& parent,
                                                       const SandboxEnv::Ptr& sandbox_env,
                                                       Options options) {
  auto ret = ManagedEnvironment::Ptr(new ManagedEnvironment(sandbox_env));
  ret->Create(parent, std::move(options));
  return ret;
}

ManagedEnvironment::ManagedEnvironment(const SandboxEnv::Ptr& sandbox_env)
    : sandbox_env_(sandbox_env), ready_(false) {}

sys::testing::EnclosingEnvironment& ManagedEnvironment::environment() { return *env_; }

void ManagedEnvironment::GetLauncher(::fidl::InterfaceRequest<::fuchsia::sys::Launcher> launcher) {
  launcher_->Bind(std::move(launcher));
}

void ManagedEnvironment::CreateChildEnvironment(fidl::InterfaceRequest<FManagedEnvironment> me,
                                                Options options) {
  ManagedEnvironment::Ptr np(new ManagedEnvironment(sandbox_env_));
  fuchsia::sys::EnvironmentPtr env;
  env_->ConnectToService(env.NewRequest());
  np->Create(env, std::move(options), this);
  np->bindings_.AddBinding(np.get(), std::move(me));

  children_.emplace_back(std::move(np));
}

void ManagedEnvironment::Create(const fuchsia::sys::EnvironmentPtr& parent,
                                ManagedEnvironment::Options options,
                                const ManagedEnvironment* managed_parent) {
  // Nested environments without a name are not allowed, if empty name is
  // provided, replace it with a default *randomized* value.
  // Randomness there is necessary due to appmgr rules for environments with
  // same name.
  if (!options.has_name() || options.name().empty()) {
    std::random_device rnd;
    options.set_name(fxl::StringPrintf("netemul-env-%08x", rnd()));
  }

  // Start LogListener for this environment
  log_listener_ =
      LogListener::Create(std::move(*options.mutable_logger_options()), options.name(), nullptr);

  auto services = EnvironmentServices::Create(parent);

  services->SetServiceTerminatedCallback([this, name = options.name()](
                                             const std::string& service, int64_t exit_code,
                                             fuchsia::sys::TerminationReason reason) {
    FX_LOGS(WARNING) << "Service " << service << " exited on environment " << name << " with ("
                     << exit_code << ") reason: " << sys::HumanReadableTerminationReason(reason);
    if (sandbox_env_->events().service_terminated) {
      sandbox_env_->events().service_terminated(service, exit_code, reason);
    }
  });

  if (log_listener_) {
    loggers_ = std::make_unique<ManagedLoggerCollection>(options.name(),
                                                         log_listener_->GetLogListenerImpl());
  } else {
    loggers_ = std::make_unique<ManagedLoggerCollection>(options.name(), nullptr);
  }

  // Add network context service.
  services->AddService(sandbox_env_->network_context().GetHandler());
  // Add Bus service.
  services->AddService(sandbox_env_->sync_manager().GetHandler());
  // Add managed environment itself as a handler.
  services->AddService(bindings_.GetHandler(this));
  // Add shared tun service.
  services->AddService(fidl::InterfaceRequestHandler<fuchsia::net::tun::Control>(
      [this](fidl::InterfaceRequest<fuchsia::net::tun::Control> request) {
        sandbox_env_->ConnectNetworkTun(std::move(request));
      }));

  bool enable_klog = LogListener::IsKlogsEnabled(options);
  if (enable_klog) {
    services->AddService(fidl::InterfaceRequestHandler<fuchsia::boot::ReadOnlyLog>(
        [this](fidl::InterfaceRequest<fuchsia::boot::ReadOnlyLog> request) {
          // Connect the sandbox to our namespace rather than its sandbox parent.
          sandbox_env_->ConnectToReadOnlyLog(std::move(request));
        }));
  }

  const char* log_service_url;
  if (enable_klog) {
    log_service_url = kLogServiceURLWithKlog;
  } else {
    log_service_url = kLogServiceURLNoKlog;
  }

  // Inject all services provided by LogService.
  for (const auto* svc : kLogServices) {
    // Inject Log service
    services->AddServiceWithLaunchInfo(
        log_service_url,
        [this, log_service_url]() {
          fuchsia::sys::LaunchInfo linfo;
          linfo.url = log_service_url;
          linfo.out = loggers_->CreateLogger(log_service_url, false);
          linfo.err = loggers_->CreateLogger(log_service_url, true);
          loggers_->IncrementCounter();
          return linfo;
        },
        svc);
  }

  // Allow hypervisor resource for virtualization.
  services->AllowParentService(fuchsia::kernel::HypervisorResource::Name_);

  // prepare service configurations:
  service_config_.clear();
  if (options.has_inherit_parent_launch_services() && options.inherit_parent_launch_services() &&
      managed_parent != nullptr) {
    for (const auto& a : managed_parent->service_config_) {
      LaunchService clone;
      a.Clone(&clone);
      service_config_.push_back(std::move(clone));
    }
  }

  if (options.has_services()) {
    std::move(options.mutable_services()->begin(), options.mutable_services()->end(),
              std::back_inserter(service_config_));
  }

  // push all the allowable launch services:
  for (const auto& svc : service_config_) {
    LaunchService copy;
    ZX_ASSERT(svc.Clone(&copy) == ZX_OK);
    services->AddServiceWithLaunchInfo(
        svc.url,
        [this, svc = std::move(copy)]() {
          fuchsia::sys::LaunchInfo linfo;
          linfo.url = svc.url;
          linfo.arguments = svc.arguments;

          if (!launcher_->MakeServiceLaunchInfo(&linfo)) {
            // NOTE: we can just log an return code of MakeServiceLaunchInfo here, since those are
            // caused by fuchsia::sys::Loader errors that will happen again once we return the
            // launch info. That failure, in turn, will be caught by the service termination
            // callback installed in the services instance.
            FX_LOGS(ERROR) << "Make service launch info failed";
          }
          return linfo;
        },
        svc.name);
  }

  if (auto guest = sandbox_env_->guest_env_.lock()) {
    services->AddService<fuchsia::netemul::guest::GuestDiscovery>(
        [guest = std::move(guest)](
            fidl::InterfaceRequest<fuchsia::netemul::guest::GuestDiscovery> request) {
          guest->ConnectToService(fuchsia::netemul::guest::GuestDiscovery::Name_,
                                  request.TakeChannel());
        });
  }

  if (options.has_devices()) {
    // save all handles for virtual devices
    for (auto& dev : *options.mutable_devices()) {
      virtual_devices_.AddEntry(dev.path, dev.device.Bind());
    }
  }

  fuchsia::sys::EnvironmentOptions sub_options = {.inherit_parent_services = false,
                                                  .use_parent_runners = false,
                                                  .kill_on_oom = true,
                                                  .delete_storage_on_death = true};

  env_ = EnclosingEnvironment::Create(options.name(), parent, std::move(services), sub_options);

  env_->SetRunningChangedCallback([this](bool running) {
    ready_ = true;
    if (running) {
      for (auto& r : pending_requests_) {
        Bind(std::move(r));
      }
      pending_requests_.clear();
      if (running_callback_) {
        running_callback_();
      }
    } else {
      FX_LOGS(ERROR) << "Underlying enclosed Environment stopped running";
      running_callback_ = nullptr;
      children_.clear();
      pending_requests_.clear();
      env_ = nullptr;
      launcher_ = nullptr;
      bindings_.CloseAll();
    }
  });

  launcher_ = std::make_unique<ManagedLauncher>(this);

  // If we have one, bind our log listener to this environment.
  // We do this after creation of log listener because
  // we need to make sure the environment is created first,
  // but managed logger needs our implementation of LogListenerImpl.
  if (log_listener_) {
    ZX_ASSERT(log_listener_->Bindable());
    log_listener_->BindToLogService(this);
  }
}

zx::channel ManagedEnvironment::OpenVdevDirectory(std::string path) {
  return virtual_devices_.OpenAsDirectory(std::move(path));
}

void ManagedEnvironment::Bind(fidl::InterfaceRequest<ManagedEnvironment::FManagedEnvironment> req) {
  if (ready_) {
    bindings_.AddBinding(this, std::move(req));
  } else if (env_) {
    pending_requests_.push_back(std::move(req));
  } else {
    req.Close(ZX_ERR_INTERNAL);
  }
}

ManagedLoggerCollection& ManagedEnvironment::loggers() {
  ZX_ASSERT(loggers_);
  return *loggers_;
}

void ManagedEnvironment::ConnectToService(std::string name, zx::channel req) {
  env_->ConnectToService(name, std::move(req));
}

void ManagedEnvironment::AddDevice(fuchsia::netemul::environment::VirtualDevice device) {
  virtual_devices_.AddEntry(std::move(device.path), device.device.Bind());
}

void ManagedEnvironment::RemoveDevice(std::string path) {
  virtual_devices_.RemoveEntry(std::move(path));
}

}  // namespace netemul
