// 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 "driver_loader.h"

#include <fcntl.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/fdio/directory.h>
#include <lib/fidl/llcpp/connect_service.h>
#include <lib/service/llcpp/service.h>
#include <sched.h>
#include <unistd.h>
#include <zircon/threads.h>

#include <thread>
#include <variant>

#include <fbl/unique_fd.h>

#include "coordinator.h"
#include "src/devices/bin/driver_manager/manifest_parser.h"
#include "src/devices/lib/log/log.h"

namespace {

// Go through each field in the DriverInfo and copy it with a given allocator.
fuchsia_driver_development::wire::DriverInfo CopyDriverInfo(
    fidl::AnyArena& allocator, fuchsia_driver_development::wire::DriverInfo& driver) {
  auto allocated = fuchsia_driver_development::wire::DriverInfo::Builder(allocator);
  if (driver.has_libname()) {
    allocated.libname(allocator, driver.libname().get());
  }
  if (driver.has_name()) {
    allocated.name(allocator, driver.name().get());
  }
  if (driver.has_url()) {
    allocated.url(allocator, driver.url().get());
  }
  if (driver.has_bind_rules()) {
    if (driver.bind_rules().is_bytecode_v1()) {
      auto vector = fidl::VectorView<fuchsia_device_manager::wire::BindInstruction>(
          allocator, driver.bind_rules().bytecode_v1().count());
      for (size_t i = 0; i < vector.count(); i++) {
        vector[i] = driver.bind_rules().bytecode_v1()[i];
      }
      allocated.bind_rules(
          fuchsia_driver_development::wire::BindRulesBytecode::WithBytecodeV1(allocator, vector));
    }
    if (driver.bind_rules().is_bytecode_v2()) {
      auto vector = fidl::VectorView<uint8_t>(allocator, driver.bind_rules().bytecode_v2().count());
      for (size_t i = 0; i < driver.bind_rules().bytecode_v2().count(); i++) {
        vector[i] = driver.bind_rules().bytecode_v2()[i];
      }
      allocated.bind_rules(fuchsia_driver_development::wire::BindRulesBytecode::WithBytecodeV2(
          allocator, std::move(vector)));
    }
  }
  if (driver.has_package_type()) {
    allocated.package_type(driver.package_type());
  }
  return allocated.Build();
}

zx::status<fdi::wire::MatchedDriverInfo> GetFidlMatchedDriverInfo(fdi::wire::MatchedDriver driver) {
  if (driver.is_device_group_node()) {
    return zx::error(ZX_ERR_NOT_FOUND);
  }

  if (driver.is_composite_driver()) {
    if (!driver.composite_driver().has_driver_info()) {
      return zx::error(ZX_ERR_NOT_FOUND);
    }

    return zx::ok(driver.composite_driver().driver_info());
  }

  return zx::ok(driver.driver());
}

MatchedCompositeDevice CreateMatchedCompositeDevice(
    fdi::wire::MatchedCompositeInfo composite_info) {
  MatchedCompositeDevice composite = {};
  if (composite_info.has_num_nodes()) {
    composite.num_nodes = composite_info.num_nodes();
  }

  if (composite_info.has_node_index()) {
    composite.node = composite_info.node_index();
  }

  if (composite_info.has_composite_name()) {
    composite.name =
        std::string(composite_info.composite_name().data(), composite_info.composite_name().size());
  }

  if (composite_info.has_node_names()) {
    std::vector<std::string> names;
    for (auto& name : composite_info.node_names()) {
      names.push_back(std::string(name.data(), name.size()));
    }
    composite.node_names = std::move(names);
  }

  return composite;
}

zx::status<MatchedDeviceGroupInfo> CreateMatchedDeviceGroupInfo(
    fdi::wire::MatchedDeviceGroupNodeInfo device_group_node_info) {
  // Currently we only support only one device group in the list.
  // TODO(fxb/103208): Update the DFv1 device group implementation so it
  // can handle multiple device groups.
  if (!device_group_node_info.has_device_groups() ||
      device_group_node_info.device_groups().count() != 1) {
    return zx::error(ZX_ERR_INVALID_ARGS);
  }

  auto device_group = device_group_node_info.device_groups().at(0);

  if (!device_group.has_topological_path()) {
    return zx::error(ZX_ERR_INVALID_ARGS);
  }

  if (!device_group.has_node_index()) {
    return zx::error(ZX_ERR_INVALID_ARGS);
  }

  return zx::ok(MatchedDeviceGroupInfo{
      .topological_path = std::string(device_group.topological_path().data(),
                                      device_group.topological_path().size()),
      .node_index = device_group.node_index(),
  });
}

bool ShouldUseUniversalResolver(fdi::wire::DriverPackageType package_type) {
  return package_type == fdi::wire::DriverPackageType::kUniverse ||
         package_type == fdi::wire::DriverPackageType::kCached;
}

}  // namespace

DriverLoader::~DriverLoader() {
  if (system_loading_thread_) {
    system_loading_thread_->join();
  }
}

void DriverLoader::StartSystemLoadingThread(Coordinator* coordinator) {
  if (system_loading_thread_) {
    LOGF(ERROR, "DriverLoader: StartLoadingThread cannot be called twice!\n");
    return;
  }

  system_loading_thread_ = std::thread([coordinator]() {
    fbl::unique_fd fd(open("/system", O_RDONLY));
    if (fd.get() < 0) {
      LOGF(WARNING, "Unable to open '/system', system drivers are disabled");
      return;
    }

    fbl::DoublyLinkedList<std::unique_ptr<Driver>> drivers;

    auto driver_added = [&drivers](Driver* drv, const char* version) {
      std::unique_ptr<Driver> driver(drv);
      LOGF(INFO, "Adding driver '%s' '%s'", driver->name.data(), driver->libname.data());
      if (load_vmo(driver->libname.data(), &driver->dso_vmo)) {
        LOGF(ERROR, "Driver '%s' '%s' could not cache DSO", driver->name.data(),
             driver->libname.data());
      }
      // De-prioritize drivers that are "fallback".
      if (driver->fallback) {
        drivers.push_back(std::move(driver));
      } else {
        drivers.push_front(std::move(driver));
      }
    };

    find_loadable_drivers(coordinator->boot_args(), "/system/driver", driver_added);

    async::PostTask(coordinator->dispatcher(),
                    [coordinator = coordinator, drivers = std::move(drivers)]() mutable {
                      coordinator->AddAndBindDrivers(std::move(drivers));
                      coordinator->BindFallbackDrivers();
                    });
  });

  constexpr char name[] = "driver-loader-thread";
  zx_object_set_property(native_thread_get_zx_handle(system_loading_thread_->native_handle()),
                         ZX_PROP_NAME, name, sizeof(name));
}

const Driver* DriverLoader::LibnameToDriver(std::string_view libname) const {
  for (const auto& drv : driver_index_drivers_) {
    if (libname.compare(drv.libname) == 0) {
      return &drv;
    }
  }
  return nullptr;
}

void DriverLoader::WaitForBaseDrivers(fit::callback<void()> callback) {
  // TODO(dgilhooley): Change this back to an ERROR once DriverIndex is used in all tests.
  if (!driver_index_.is_valid()) {
    LOGF(INFO, "%s: DriverIndex is not initialized", __func__);
    return;
  }

  driver_index_->WaitForBaseDrivers().Then(
      [this, callback = std::move(callback)](
          fidl::WireUnownedResult<fdi::DriverIndex::WaitForBaseDrivers>& result) mutable {
        if (!result.ok()) {
          // Since IsolatedDevmgr doesn't use the ComponentFramework, DriverIndex can be
          // closed before DriverManager during tests, which would mean we would see
          // a ZX_ERR_PEER_CLOSED.
          if (result.status() == ZX_ERR_PEER_CLOSED) {
            LOGF(WARNING, "Connection to DriverIndex closed during WaitForBaseDrivers.");
          } else {
            LOGF(ERROR, "Failed to connect to DriverIndex: %s",
                 result.error().FormatDescription().c_str());
          }

          return;
        }
        include_fallback_drivers_ = true;
        callback();
      });
}

const Driver* DriverLoader::LoadDriverUrl(const std::string& driver_url,
                                          bool use_universe_resolver) {
  // Check if we've already loaded this driver. If we have then return it.
  auto driver = LibnameToDriver(driver_url);
  if (driver != nullptr) {
    return driver;
  }

  // Pick the correct package resolver to use.
  auto resolver = base_resolver_;
  if (use_universe_resolver && universe_resolver_) {
    resolver = universe_resolver_;
  }

  // We've never seen the driver before so add it, then return it.
  auto fetched_driver = resolver->FetchDriver(driver_url);
  if (fetched_driver.is_error()) {
    LOGF(ERROR, "Error fetching driver: %s: %d", driver_url.data(), fetched_driver.error_value());
    return nullptr;
  }
  // It's possible the driver is nullptr if it was disabled.
  if (!fetched_driver.value()) {
    return nullptr;
  }

  // Success. Return driver.
  driver_index_drivers_.push_back(std::move(fetched_driver.value()));
  return &driver_index_drivers_.back();
}

bool DriverLoader::MatchesLibnameDriverIndex(const std::string& driver_url,
                                             std::string_view libname) {
  if (libname.compare(driver_url) == 0) {
    return true;
  }

  auto result = GetPathFromUrl(driver_url);
  if (result.is_error()) {
    return false;
  }

  if (libname.find('/') == std::string_view::npos) {
    std::string abs_libname = std::string("/boot/driver/") + std::string(libname);
    return result.value() == abs_libname;
  }

  return result.value() == libname;
}

zx_status_t DriverLoader::AddDeviceGroup(std::string_view topological_path,
                                         fidl::VectorView<fdf::wire::DeviceGroupNode> nodes) {
  fidl::Arena allocator;
  auto result = driver_index_.sync()->AddDeviceGroup(fidl::StringView(allocator, topological_path),
                                                     std::move(nodes));
  if (!result.ok()) {
    LOGF(ERROR, "DriverIndex::AddDeviceGroup failed: %d", result.status());
  }

  return result.status();
}

const std::vector<MatchedDriver> DriverLoader::MatchDeviceDriverIndex(
    const fbl::RefPtr<Device>& dev, const MatchDeviceConfig& config) {
  if (!driver_index_.is_valid()) {
    return std::vector<MatchedDriver>();
  }

  bool autobind = config.libname.empty();

  fidl::Arena allocator;
  auto& props = dev->props();
  auto& str_props = dev->str_props();
  size_t size = props.size() + str_props.size() + 2;
  if (!autobind) {
    size += 1;
  }
  fidl::VectorView<fdf::wire::NodeProperty> fidl_props(allocator, size);

  size_t index = 0;
  fidl_props[index++] =
      fdf::wire::NodeProperty(allocator)
          .set_key(allocator, fdf::wire::NodePropertyKey::WithIntValue(BIND_PROTOCOL))
          .set_value(allocator, fdf::wire::NodePropertyValue::WithIntValue(dev->protocol_id()));
  fidl_props[index++] =
      fdf::wire::NodeProperty(allocator)
          .set_key(allocator, fdf::wire::NodePropertyKey::WithIntValue(BIND_AUTOBIND))
          .set_value(allocator, fdf::wire::NodePropertyValue::WithIntValue(autobind));
  // If we are looking for a specific driver, we add a property to the device with the
  // name of the driver we are looking for. Drivers can then bind to this.
  if (!autobind) {
    fidl_props[index++] =
        fdf::wire::NodeProperty(allocator)
            .set_key(allocator, fdf::wire::NodePropertyKey::WithStringValue(
                                    allocator, allocator, "fuchsia.compat.LIBNAME"))
            .set_value(allocator, fdf::wire::NodePropertyValue::WithStringValue(
                                      allocator, allocator, config.libname));
  }

  for (size_t i = 0; i < props.size(); i++) {
    fidl_props[index++] =
        fdf::wire::NodeProperty(allocator)
            .set_key(allocator, fdf::wire::NodePropertyKey::WithIntValue(props[i].id))
            .set_value(allocator, fdf::wire::NodePropertyValue::WithIntValue(props[i].value));
  }

  for (size_t i = 0; i < str_props.size(); i++) {
    auto prop = fdf::wire::NodeProperty(allocator).set_key(
        allocator,
        fdf::wire::NodePropertyKey::WithStringValue(allocator, allocator, str_props[i].key));

    switch (str_props[i].value.index()) {
      case StrPropValueType::Integer: {
        prop.set_value(allocator, fdf::wire::NodePropertyValue::WithIntValue(
                                      std::get<StrPropValueType::Integer>(str_props[i].value)));
        break;
      }
      case StrPropValueType::String: {
        prop.set_value(allocator, fdf::wire::NodePropertyValue::WithStringValue(
                                      allocator, allocator,
                                      std::get<StrPropValueType::String>(str_props[i].value)));
        break;
      }
      case StrPropValueType::Bool: {
        prop.set_value(allocator, fdf::wire::NodePropertyValue::WithBoolValue(
                                      std::get<StrPropValueType::Bool>(str_props[i].value)));
        break;
      }
      case StrPropValueType::Enum: {
        prop.set_value(allocator, fdf::wire::NodePropertyValue::WithEnumValue(
                                      allocator, allocator,
                                      std::get<StrPropValueType::Enum>(str_props[i].value)));
        break;
      }
    }

    fidl_props[index++] = prop;
  }

  return MatchPropertiesDriverIndex(fidl_props, config);
}

const std::vector<MatchedDriver> DriverLoader::MatchPropertiesDriverIndex(
    fidl::VectorView<fdf::wire::NodeProperty> props, const MatchDeviceConfig& config) {
  std::vector<MatchedDriver> matched_drivers;
  std::vector<MatchedDriver> matched_fallback_drivers;
  if (!driver_index_.is_valid()) {
    return matched_drivers;
  }

  fidl::Arena allocator;
  fdf::wire::NodeAddArgs args(allocator);
  args.set_properties(allocator, std::move(props));

  auto result = driver_index_.sync()->MatchDriversV1(std::move(args));
  if (!result.ok()) {
    if (result.status() != ZX_OK) {
      LOGF(ERROR, "DriverIndex::MatchDriversV1 failed: %d", result.status());
      return matched_drivers;
    }
  }
  // If there's no driver to match then DriverIndex will return ZX_ERR_NOT_FOUND.
  if (result->is_error()) {
    if (result->error_value() != ZX_ERR_NOT_FOUND) {
      LOGF(ERROR, "DriverIndex: MatchDriversV1 returned error: %d", result->error_value());
    }
    return matched_drivers;
  }

  const auto& drivers = result->value()->drivers;

  for (auto driver : drivers) {
    if (driver.is_device_group_node()) {
      auto device_group = CreateMatchedDeviceGroupInfo(driver.device_group_node());
      if (device_group.is_error()) {
        LOGF(ERROR,
             "DriverIndex: MatchDriverV1 response is missing fields in MatchedDeviceGroupInfo");
        continue;
      }

      matched_drivers.push_back(device_group.value());
      continue;
    }

    auto fidl_driver_info = GetFidlMatchedDriverInfo(driver);
    if (fidl_driver_info.is_error()) {
      LOGF(ERROR, "DriverIndex: MatchedDriversV1 response is missing MatchedDriverInfo");
      continue;
    }

    if (!fidl_driver_info->has_driver_url()) {
      LOGF(ERROR, "DriverIndex: MatchDriversV1 response is missing a driver_url");
      continue;
    }

    if (!fidl_driver_info->has_is_fallback()) {
      LOGF(ERROR, "DriverIndex: MatchDriversV1 response is missing is_fallback");
      continue;
    }

    std::string driver_url(fidl_driver_info->driver_url().get());
    bool use_universe_resolver = false;
    if (fidl_driver_info->has_package_type()) {
      use_universe_resolver = ShouldUseUniversalResolver(fidl_driver_info->package_type());
    }

    auto loaded_driver = LoadDriverUrl(driver_url, use_universe_resolver);
    if (!loaded_driver) {
      continue;
    }

    if (!fidl_driver_info->is_fallback() && config.only_return_base_and_fallback_drivers &&
        IsFuchsiaBootScheme(driver_url)) {
      continue;
    }

    MatchedDriverInfo matched_driver_info = {};
    matched_driver_info.driver = loaded_driver;
    if (fidl_driver_info->has_colocate()) {
      matched_driver_info.colocate = fidl_driver_info->colocate();
    }

    MatchedDriver matched_driver;
    if (driver.is_composite_driver()) {
      matched_driver = MatchedCompositeDriverInfo{
          .composite = CreateMatchedCompositeDevice(driver.composite_driver()),
          .driver_info = matched_driver_info,
      };
    } else {
      matched_driver = matched_driver_info;
    }

    if (config.libname.empty() || MatchesLibnameDriverIndex(driver_url, config.libname)) {
      if (fidl_driver_info->is_fallback()) {
        if (include_fallback_drivers_ || !config.libname.empty()) {
          matched_fallback_drivers.push_back(matched_driver);
        }
      } else {
        matched_drivers.push_back(matched_driver);
      }
    }
  }

  // Fallback drivers need to be at the end of the matched drivers.
  matched_drivers.insert(matched_drivers.end(), matched_fallback_drivers.begin(),
                         matched_fallback_drivers.end());

  return matched_drivers;
}

zx::status<std::vector<fuchsia_driver_development::wire::DriverInfo>> DriverLoader::GetDriverInfo(
    fidl::AnyArena& allocator, fidl::VectorView<fidl::StringView> filter) {
  std::vector<fuchsia_driver_development::wire::DriverInfo> info;

  auto driver_index_client = service::Connect<fuchsia_driver_development::DriverIndex>();
  if (driver_index_client.is_error()) {
    LOGF(WARNING, "Failed to connect to fuchsia_driver_development::DriverIndex\n");
    return driver_index_client.take_error();
  }

  auto endpoints = fidl::CreateEndpoints<fuchsia_driver_development::DriverInfoIterator>();
  if (endpoints.is_error()) {
    LOGF(ERROR, "fidl::CreateEndpoints failed: %s\n", endpoints.status_string());
    return endpoints.take_error();
  }

  auto driver_index = fidl::BindSyncClient(std::move(*driver_index_client));
  auto info_result = driver_index->GetDriverInfo(filter, std::move(endpoints->server));

  // There are still some environments where we can't connect to DriverIndex.
  if (info_result.status() != ZX_OK) {
    LOGF(INFO, "DriverIndex:GetDriverInfo failed: %d\n", info_result.status());
    return zx::error(info_result.status());
  }

  auto iterator = fidl::BindSyncClient(std::move(endpoints->client));
  for (;;) {
    auto next_result = iterator->GetNext();
    if (!next_result.ok()) {
      // This is likely a pipelined error from the GetDriverInfo call above. We unfortunately
      // cannot read the epitaph without using an async call.
      LOGF(ERROR, "DriverInfoIterator.GetNext failed: %s\n",
           next_result.FormatDescription().c_str());
      break;
    }
    if (next_result.value().drivers.count() == 0) {
      // When we receive 0 responses, we are done iterating.
      break;
    }
    // Go through each driver info and create a copy.
    for (auto& driver : next_result.value().drivers) {
      info.push_back(CopyDriverInfo(allocator, driver));
    }
  }

  return zx::ok(std::move(info));
}

std::vector<const Driver*> DriverLoader::GetAllDriverIndexDrivers() {
  std::vector<const Driver*> drivers;

  auto driver_index_client = service::Connect<fuchsia_driver_development::DriverIndex>();
  if (driver_index_client.is_error()) {
    LOGF(WARNING, "Failed to connect to fuchsia_driver_development::DriverIndex\n");
    return drivers;
  }

  auto endpoints = fidl::CreateEndpoints<fuchsia_driver_development::DriverInfoIterator>();
  if (endpoints.is_error()) {
    LOGF(ERROR, "fidl::CreateEndpoints failed: %s\n", endpoints.status_string());
    return drivers;
  }

  auto driver_index = fidl::BindSyncClient(std::move(*driver_index_client));
  auto info_result = driver_index->GetDriverInfo(fidl::VectorView<fidl::StringView>(),
                                                 std::move(endpoints->server));

  // There are still some environments where we can't connect to DriverIndex.
  if (info_result.status() != ZX_OK) {
    LOGF(INFO, "DriverIndex:GetDriverInfo failed: %d\n", info_result.status());
    return drivers;
  }

  auto iterator = fidl::BindSyncClient(std::move(endpoints->client));
  for (;;) {
    auto next_result = iterator->GetNext();
    if (!next_result.ok()) {
      // This is likely a pipelined error from the GetDriverInfo call above. We unfortunately
      // cannot read the epitaph without using an async call.
      LOGF(ERROR, "DriverInfoIterator.GetNext failed: %s\n",
           next_result.FormatDescription().c_str());
      break;
    }
    if (next_result.value().drivers.count() == 0) {
      // When we receive 0 responses, we are done iterating.
      break;
    }
    for (auto driver : next_result.value().drivers) {
      if (!driver.has_libname()) {
        continue;
      }

      std::string url(driver.libname().data(), driver.libname().size());
      bool use_universe_resolver = false;
      if (driver.has_package_type()) {
        use_universe_resolver = ShouldUseUniversalResolver(driver.package_type());
      }

      const Driver* drv = LoadDriverUrl(url, use_universe_resolver);
      if (drv) {
        drivers.push_back(drv);
      }
    }
  }

  return drivers;
}
