// Copyright 2021 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 "src/graphics/bin/vulkan_loader/app.h"

#include <lib/async-loop/default.h>
#include <lib/async/cpp/task.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/io.h>
#include <lib/vfs/cpp/remote_dir.h>

#include "src/graphics/bin/vulkan_loader/goldfish_device.h"
#include "src/graphics/bin/vulkan_loader/icd_component.h"
#include "src/graphics/bin/vulkan_loader/magma_device.h"
#include "src/lib/storage/vfs/cpp/remote_dir.h"
#include "src/lib/storage/vfs/cpp/service.h"

LoaderApp::LoaderApp(sys::ComponentContext* context, async_dispatcher_t* dispatcher)
    : context_(context),
      dispatcher_(dispatcher),
      inspector_(context),
      device_fs_(dispatcher),
      manifest_fs_(dispatcher),
      fdio_loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {
  fdio_loop_.StartThread("fdio_loop");
  inspector_.Health().StartingUp();
  devices_node_ = inspector_.root().CreateChild("devices");
  icds_node_ = inspector_.root().CreateChild("icds");
  manifest_fs_root_node_ = fbl::MakeRefCounted<fs::PseudoDir>();
}
LoaderApp::~LoaderApp() {}

zx_status_t LoaderApp::InitDeviceFs() {
  device_root_node_ = fbl::MakeRefCounted<fs::PseudoDir>();

  const char* kDevClassList[] = {"gpu", "goldfish-pipe", "goldfish-control",
                                 "goldfish-address-space", "goldfish-sync"};

  auto class_node = fbl::MakeRefCounted<fs::PseudoDir>();
  device_root_node_->AddEntry("class", class_node);

  for (const char* dev_class : kDevClassList) {
    fidl::InterfaceHandle<fuchsia::io::Directory> gpu_dir;
    std::string input_path = std::string("/dev/class/") + dev_class;
    zx_status_t status = fdio_open(input_path.c_str(),
                                   static_cast<uint32_t>(fuchsia::io::OpenFlags::RIGHT_READABLE |
                                                         fuchsia::io::OpenFlags::RIGHT_WRITABLE),
                                   gpu_dir.NewRequest().TakeChannel().release());
    if (status != ZX_OK) {
      FX_PLOGS(ERROR, status) << "Failed to open " << input_path;
      return status;
    }

    class_node->AddEntry(dev_class,
                         fbl::MakeRefCounted<fs::RemoteDir>(
                             fidl::ClientEnd<fuchsia_io::Directory>(gpu_dir.TakeChannel())));
  }

  zx::channel client, server;
  zx_status_t status = zx::channel::create(0, &client, &server);
  if (status != ZX_OK) {
    return status;
  }
  auto devfs_out = std::make_unique<vfs::RemoteDir>(std::move(client));
  if ((status = ServeDeviceFs(std::move(server))) != ZX_OK) {
    return status;
  }
  context_->outgoing()->debug_dir()->AddEntry("device-fs", std::move(devfs_out));
  return ZX_OK;
}

zx_status_t LoaderApp::ServeDeviceFs(zx::channel dir_request) {
  auto options = fs::VnodeConnectionOptions::ReadWrite();
  return device_fs_.Serve(device_root_node_, std::move(dir_request), options);
}

zx_status_t LoaderApp::ServeManifestFs(zx::channel dir_request) {
  auto options = fs::VnodeConnectionOptions::ReadWrite();
  return manifest_fs_.Serve(manifest_fs_root_node_, std::move(dir_request), options);
}

zx_status_t LoaderApp::InitManifestFs() {
  zx::channel client, server;
  zx_status_t status = zx::channel::create(0, &client, &server);
  if (status != ZX_OK) {
    return status;
  }
  auto devfs_out = std::make_unique<vfs::RemoteDir>(std::move(client));
  if ((status = ServeManifestFs(std::move(server))) != ZX_OK) {
    return status;
  }
  context_->outgoing()->debug_dir()->AddEntry("manifest-fs", std::move(devfs_out));
  return ZX_OK;
}

zx_status_t LoaderApp::InitDeviceWatcher() {
  FIT_DCHECK_IS_THREAD_VALID(main_thread_);
  auto gpu_watcher_token = GetPendingActionToken();
  gpu_watcher_ = fsl::DeviceWatcher::CreateWithIdleCallback(
      "/dev/class/gpu",
      [this](int dir_fd, const std::string filename) {
        if (filename == ".") {
          return;
        }
        auto device = MagmaDevice::Create(this, dir_fd, filename, &devices_node_);
        if (device) {
          devices_.emplace_back(std::move(device));
        }
      },
      [gpu_watcher_token = std::move(gpu_watcher_token)]() {
        // Idle callback and gpu_watcher_token will be destroyed on idle.
      });
  if (!gpu_watcher_)
    return ZX_ERR_INTERNAL;
  auto goldfish_watcher_token = GetPendingActionToken();
  goldfish_watcher_ = fsl::DeviceWatcher::CreateWithIdleCallback(
      "/dev/class/goldfish-pipe",
      [this](int dir_fd, const std::string filename) {
        if (filename == ".") {
          return;
        }
        auto device = GoldfishDevice::Create(this, dir_fd, filename, &devices_node_);
        if (device) {
          devices_.emplace_back(std::move(device));
        }
      },
      [goldfish_watcher_token = std::move(goldfish_watcher_token)]() {
        // Idle callback and goldfish_watcher_token will be destroyed on idle.
      });
  if (!goldfish_watcher_)
    return ZX_ERR_INTERNAL;
  return ZX_OK;
}

void LoaderApp::RemoveDevice(GpuDevice* device) {
  FIT_DCHECK_IS_THREAD_VALID(main_thread_);
  auto it = std::remove_if(devices_.begin(), devices_.end(),
                           [device](const std::unique_ptr<GpuDevice>& unique_device) {
                             return device == unique_device.get();
                           });
  devices_.erase(it, devices_.end());
}

std::shared_ptr<IcdComponent> LoaderApp::CreateIcdComponent(std::string component_url) {
  FIT_DCHECK_IS_THREAD_VALID(main_thread_);
  if (icd_components_.find(component_url) != icd_components_.end())
    return icd_components_[component_url];
  icd_components_[component_url] = IcdComponent::Create(context_, this, &icds_node_, component_url);
  return icd_components_[component_url];
}

void LoaderApp::NotifyIcdsChanged() {
  // This can be called on any thread.
  std::lock_guard lock(pending_action_mutex_);
  NotifyIcdsChangedLocked();
}

void LoaderApp::NotifyIcdsChangedLocked() {
  if (icd_notification_pending_)
    return;
  icd_notification_pending_ = true;
  async::PostTask(dispatcher_, [this]() { this->NotifyIcdsChangedOnMainThread(); });
}

void LoaderApp::NotifyIcdsChangedOnMainThread() {
  FIT_DCHECK_IS_THREAD_VALID(main_thread_);
  {
    std::lock_guard lock(pending_action_mutex_);
    icd_notification_pending_ = false;
  }
  bool have_icd = false;
  for (auto& device : devices_) {
    have_icd |= device->icd_list().UpdateCurrentComponent();
  }
  if (have_icd) {
    inspector_.Health().Ok();
  }
  for (auto& observer : observer_list_)
    observer.OnIcdListChanged(this);
}

std::optional<zx::vmo> LoaderApp::GetMatchingIcd(const std::string& name) {
  FIT_DCHECK_IS_THREAD_VALID(main_thread_);
  for (auto& device : devices_) {
    auto res = device->icd_list().GetVmoMatchingSystemLib(name);
    if (res) {
      return std::optional<zx::vmo>(std::move(res));
    }
  }
  {
    std::lock_guard lock(pending_action_mutex_);
    // If not actions are pending then assume there will never be a match.
    if (pending_action_count_ == 0) {
      return zx::vmo();
    }
  }
  return {};
}

std::unique_ptr<LoaderApp::PendingActionToken> LoaderApp::GetPendingActionToken() {
  return std::unique_ptr<PendingActionToken>(new PendingActionToken(this));
}

LoaderApp::PendingActionToken::~PendingActionToken() {
  std::lock_guard lock(app_->pending_action_mutex_);
  if (--app_->pending_action_count_ == 0) {
    app_->NotifyIcdsChangedLocked();
  }
}
