// Copyright 2013 The Flutter 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 "runner.h"

#include <fcntl.h>
#include <fuchsia/mem/cpp/fidl.h>
#include <lib/async/cpp/task.h>
#include <lib/inspect/cpp/inspect.h>
#include <lib/trace-engine/instrumentation.h>
#include <zircon/status.h>
#include <zircon/types.h>

#include <cstdint>
#include <sstream>
#include <utility>

#include "flutter/fml/make_copyable.h"
#include "flutter/lib/ui/text/font_collection.h"
#include "flutter/runtime/dart_vm.h"
#include "lib/async/default.h"
#include "lib/sys/cpp/component_context.h"
#include "runtime/dart/utils/files.h"
#include "runtime/dart/utils/root_inspect_node.h"
#include "runtime/dart/utils/vmo.h"
#include "runtime/dart/utils/vmservice_object.h"
#include "third_party/icu/source/common/unicode/udata.h"
#include "third_party/skia/include/core/SkGraphics.h"

namespace flutter_runner {

namespace {

static constexpr char kIcuDataPath[] = "/pkg/data/icudtl.dat";

// Environment variable containing the path to the directory containing the
// timezone files.
static constexpr char kICUTZEnv[] = "ICU_TIMEZONE_FILES_DIR";

// The data directory containing ICU timezone data files.
static constexpr char kICUTZDataDir[] = "/config/data/tzdata/icu/44/le";

// Map the memory into the process and return a pointer to the memory.
uintptr_t GetICUData(const fuchsia::mem::Buffer& icu_data) {
  uint64_t data_size = icu_data.size;
  if (data_size > std::numeric_limits<size_t>::max())
    return 0u;

  uintptr_t data = 0u;
  zx_status_t status =
      zx::vmar::root_self()->map(ZX_VM_PERM_READ, 0, icu_data.vmo, 0,
                                 static_cast<size_t>(data_size), &data);
  if (status == ZX_OK) {
    return data;
  }

  return 0u;
}

// Initializes the timezone data if available.  Timezone data file in Fuchsia
// is at a fixed directory path.  Returns true on success.  As a side effect
// sets the value of the environment variable "ICU_TIMEZONE_FILES_DIR" to a
// fixed value which is fuchsia-specific.
bool InitializeTZData() {
  // We need the ability to change the env variable for testing, so not
  // overwriting if set.
  setenv(kICUTZEnv, kICUTZDataDir, 0 /* No overwrite */);

  const std::string tzdata_dir = getenv(kICUTZEnv);
  // Try opening the path to check if present.  No need to verify that it is a
  // directory since ICU loading will return an error if the TZ data path is
  // wrong.
  int fd = openat(AT_FDCWD, tzdata_dir.c_str(), O_RDONLY);
  if (fd < 0) {
    FML_LOG(INFO) << "Could not open: '" << tzdata_dir
                  << "', proceeding without loading the timezone database: "
                  << strerror(errno);
    return false;
  }
  if (close(fd)) {
    FML_LOG(WARNING) << "Could not close: " << tzdata_dir << ": "
                     << strerror(errno);
  }
  return true;
}

// Return value indicates if initialization was successful.
bool InitializeICU() {
  const char* data_path = kIcuDataPath;

  fuchsia::mem::Buffer icu_data;
  if (!dart_utils::VmoFromFilename(data_path, false, &icu_data)) {
    return false;
  }

  uintptr_t data = GetICUData(icu_data);
  if (!data) {
    return false;
  }

  // If the loading fails, soldier on.  The loading is optional as we don't
  // want to crash the engine in transition.
  InitializeTZData();

  // Pass the data to ICU.
  UErrorCode err = U_ZERO_ERROR;
  udata_setCommonData(reinterpret_cast<const char*>(data), &err);
  if (err != U_ZERO_ERROR) {
    FML_LOG(ERROR) << "error loading ICU data: " << err;
    return false;
  }
  return true;
}

}  // namespace

static void SetProcessName() {
  std::stringstream stream;
#if defined(DART_PRODUCT)
  stream << "io.flutter.product_runner.";
#else
  stream << "io.flutter.runner.";
#endif
  if (flutter::DartVM::IsRunningPrecompiledCode()) {
    stream << "aot";
  } else {
    stream << "jit";
  }
  const auto name = stream.str();
  zx::process::self()->set_property(ZX_PROP_NAME, name.c_str(), name.size());
}

static void SetThreadName(const std::string& thread_name) {
  zx::thread::self()->set_property(ZX_PROP_NAME, thread_name.c_str(),
                                   thread_name.size());
}

#if !defined(DART_PRODUCT)
// Register native symbol information for the Dart VM's profiler.
static void RegisterProfilerSymbols(const char* symbols_path,
                                    const char* dso_name) {
  std::string* symbols = new std::string();
  if (dart_utils::ReadFileToString(symbols_path, symbols)) {
    Dart_AddSymbols(dso_name, symbols->data(), symbols->size());
  } else {
    FML_LOG(ERROR) << "Failed to load " << symbols_path;
  }
}
#endif  // !defined(DART_PRODUCT)

Runner::Runner(fml::RefPtr<fml::TaskRunner> task_runner,
               sys::ComponentContext* context)
    : task_runner_(task_runner), context_(context) {
#if !defined(DART_PRODUCT)
  // The VM service isolate uses the process-wide namespace. It writes the
  // vm service protocol port under /tmp. The VMServiceObject exposes that
  // port number to The Hub.
  context_->outgoing()->debug_dir()->AddEntry(
      dart_utils::VMServiceObject::kPortDirName,
      std::make_unique<dart_utils::VMServiceObject>());

  inspect::Inspector* inspector = dart_utils::RootInspectNode::GetInspector();
  inspector->GetRoot().CreateLazyValues(
      "vmservice_port",
      [&]() {
        inspect::Inspector inspector;
        dart_utils::VMServiceObject::LazyEntryVector out;
        dart_utils::VMServiceObject().GetContents(&out);
        std::string name = "";
        if (out.size() > 0) {
          name = out[0].name;
        }
        inspector.GetRoot().CreateString("vm_service_port", name, &inspector);
        return fpromise::make_ok_promise(inspector);
      },
      inspector);

  SetupTraceObserver();
#endif  // !defined(DART_PRODUCT)

  SkGraphics::Init();

  SetupICU();

  SetProcessName();

  SetThreadName("io.flutter.runner.main");

  context_->outgoing()->AddPublicService<fuchsia::sys::Runner>(
      std::bind(&Runner::RegisterComponentV1, this, std::placeholders::_1));
  context_->outgoing()
      ->AddPublicService<fuchsia::component::runner::ComponentRunner>(
          std::bind(&Runner::RegisterComponentV2, this, std::placeholders::_1));

#if !defined(DART_PRODUCT)
  if (Dart_IsPrecompiledRuntime()) {
    RegisterProfilerSymbols("pkg/data/flutter_aot_runner.dartprofilersymbols",
                            "");
  } else {
    RegisterProfilerSymbols("pkg/data/flutter_jit_runner.dartprofilersymbols",
                            "");
  }
#endif  // !defined(DART_PRODUCT)
}

Runner::~Runner() {
  context_->outgoing()->RemovePublicService<fuchsia::sys::Runner>();
  context_->outgoing()
      ->RemovePublicService<fuchsia::component::runner::ComponentRunner>();

#if !defined(DART_PRODUCT)
  trace_observer_->Stop();
#endif  // !defined(DART_PRODUCT)
}

// CF v1 lifecycle methods.

void Runner::RegisterComponentV1(
    fidl::InterfaceRequest<fuchsia::sys::Runner> request) {
  active_components_v1_bindings_.AddBinding(this, std::move(request));
}

void Runner::StartComponent(
    fuchsia::sys::Package package,
    fuchsia::sys::StartupInfo startup_info,
    fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) {
  // TRACE_DURATION currently requires that the string data does not change
  // in the traced scope. Since |package| gets moved in the Component::Create
  // call below, we cannot ensure that |package.resolved_url| does not move or
  // change, so we make a copy to pass to TRACE_DURATION.
  // TODO(PT-169): Remove this copy when TRACE_DURATION reads string arguments
  // eagerly.
  std::string url_copy = package.resolved_url;
  TRACE_EVENT1("flutter", "StartComponent", "url", url_copy.c_str());
  // Notes on component termination: Components typically terminate on the
  // thread on which they were created. This usually means the thread was
  // specifically created to host the component. But we want to ensure that
  // access to the active components collection is made on the same thread. So
  // we capture the runner in the termination callback. There is no risk of
  // there being multiple component runner instances in the process at the same
  // time. So it is safe to use the raw pointer.
  ComponentV1::TerminationCallback termination_callback =
      [component_runner = this](const ComponentV1* component) {
        component_runner->task_runner_->PostTask(
            [component_runner, component]() {
              component_runner->OnComponentV1Terminate(component);
            });
      };

  ActiveComponentV1 active_component = ComponentV1::Create(
      std::move(termination_callback),  // termination callback
      std::move(package),               // component package
      std::move(startup_info),          // startup info
      context_->svc(),                  // runner incoming services
      std::move(controller)             // controller request
  );

  auto key = active_component.component.get();
  active_components_v1_[key] = std::move(active_component);
}

void Runner::OnComponentV1Terminate(const ComponentV1* component) {
  auto app = active_components_v1_.find(component);
  if (app == active_components_v1_.end()) {
    FML_LOG(INFO)
        << "The remote end of the component runner tried to terminate an "
           "component that has already been terminated, possibly because we "
           "initiated the termination";
    return;
  }
  ActiveComponentV1& active_component = app->second;

  // Grab the items out of the entry because we will have to rethread the
  // destruction.
  std::unique_ptr<ComponentV1> component_to_destroy =
      std::move(active_component.component);
  std::unique_ptr<fml::Thread> component_thread =
      std::move(active_component.platform_thread);

  // Delete the entry.
  active_components_v1_.erase(component);

  // Post the task to destroy the component and quit its message loop.
  component_thread->GetTaskRunner()->PostTask(fml::MakeCopyable(
      [instance = std::move(component_to_destroy),
       thread = component_thread.get()]() mutable { instance.reset(); }));

  // Terminate and join the thread's message loop.
  component_thread->Join();
}

// CF v2 lifecycle methods.

void Runner::RegisterComponentV2(
    fidl::InterfaceRequest<fuchsia::component::runner::ComponentRunner>
        request) {
  active_components_v2_bindings_.AddBinding(this, std::move(request));
}

void Runner::Start(
    fuchsia::component::runner::ComponentStartInfo start_info,
    fidl::InterfaceRequest<fuchsia::component::runner::ComponentController>
        controller) {
  // TRACE_DURATION currently requires that the string data does not change
  // in the traced scope. Since |package| gets moved in the ComponentV2::Create
  // call below, we cannot ensure that |package.resolved_url| does not move or
  // change, so we make a copy to pass to TRACE_DURATION.
  // TODO(PT-169): Remove this copy when TRACE_DURATION reads string arguments
  // eagerly.
  FML_LOG(INFO) << "RESOLVED URL V2: " << start_info.resolved_url();
  const std::string url_copy = start_info.resolved_url();
  TRACE_EVENT1("flutter", "Start", "url", url_copy.c_str());

  // Notes on component termination: Components typically terminate on the
  // thread on which they were created. This usually means the thread was
  // specifically created to host the component. But we want to ensure that
  // access to the active components collection is made on the same thread. So
  // we capture the runner in the termination callback. There is no risk of
  // there being multiple component runner instances in the process at the same
  // time. So it is safe to use the raw pointer.
  ComponentV2::TerminationCallback termination_callback =
      [component_runner = this](const ComponentV2* component) {
        component_runner->task_runner_->PostTask(
            [component_runner, component]() {
              component_runner->OnComponentV2Terminate(component);
            });
      };

  ActiveComponentV2 active_component = ComponentV2::Create(
      std::move(termination_callback), std::move(start_info),
      context_->svc() /* runner_incoming_services */, std::move(controller));

  auto key = active_component.component.get();
  active_components_v2_[key] = std::move(active_component);
}

void Runner::OnComponentV2Terminate(const ComponentV2* component) {
  auto active_component_it = active_components_v2_.find(component);
  if (active_component_it == active_components_v2_.end()) {
    FML_LOG(INFO)
        << "The remote end of the component runner tried to terminate an "
           "component that has already been terminated, possibly because we "
           "initiated the termination";
    return;
  }
  ActiveComponentV2& active_component = active_component_it->second;

  // Grab the items out of the entry because we will have to rethread the
  // destruction.
  std::unique_ptr<ComponentV2> component_to_destroy =
      std::move(active_component.component);
  std::unique_ptr<fml::Thread> component_thread =
      std::move(active_component.platform_thread);

  // Delete the entry.
  active_components_v2_.erase(component);

  // Post the task to destroy the component and quit its message loop.
  component_thread->GetTaskRunner()->PostTask(fml::MakeCopyable(
      [instance = std::move(component_to_destroy),
       thread = component_thread.get()]() mutable { instance.reset(); }));

  // Terminate and join the thread's message loop.
  component_thread->Join();
}

void Runner::SetupICU() {
  // Exposes the TZ data setup for testing.  Failing here is not fatal.
  Runner::SetupTZDataInternal();
  if (!Runner::SetupICUInternal()) {
    FML_LOG(ERROR) << "Could not initialize ICU data.";
  }
}

// static
bool Runner::SetupICUInternal() {
  return InitializeICU();
}

// static
bool Runner::SetupTZDataInternal() {
  return InitializeTZData();
}

#if !defined(DART_PRODUCT)
void Runner::SetupTraceObserver() {
  fml::AutoResetWaitableEvent latch;

  fml::TaskRunner::RunNowOrPostTask(task_runner_, [&]() {
    // Running this initialization code on task_runner_ ensures that the call to
    // `async_get_default_dispatcher()` will capture the correct dispatcher.
    trace_observer_ = std::make_unique<trace::TraceObserver>();
    trace_observer_->Start(async_get_default_dispatcher(), [runner = this]() {
      if (!trace_is_category_enabled("dart:profiler")) {
        return;
      }
      if (trace_state() == TRACE_STARTED) {
        runner->prolonged_context_ = trace_acquire_prolonged_context();
        Dart_StartProfiling();
      } else if (trace_state() == TRACE_STOPPING) {
        for (auto& it : runner->active_components_v1_) {
          fml::AutoResetWaitableEvent latch;
          fml::TaskRunner::RunNowOrPostTask(
              it.second.platform_thread->GetTaskRunner(), [&]() {
                it.second.component->WriteProfileToTrace();
                latch.Signal();
              });
          latch.Wait();
        }
        // TODO(fxb/50694): Write v2 component profiles to trace once we're
        // convinced they're stable.
        Dart_StopProfiling();
        trace_release_prolonged_context(runner->prolonged_context_);
      }
    });
    latch.Signal();
  });
  latch.Wait();
}
#endif  // !defined(DART_PRODUCT)

}  // namespace flutter_runner
