blob: 0e65e44669ce4ad405d215c2f9dd8cf50b6a54be [file]
// Copyright 2022 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 <dlfcn.h>
#include <fidl/fuchsia.device/cpp/wire.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/ddk/debug.h>
#include <lib/driver/component/cpp/start_args.h>
#include <lib/fdf/cpp/env.h>
#include <lib/fdio/directory.h>
#include <lib/zx/vmo.h>
#include <zircon/dlfcn.h>
#include <zircon/status.h>
#include <optional>
#include "src/devices/bin/driver_host/driver_host.h"
#include "src/devices/lib/log/log.h"
namespace fdf {
using namespace fuchsia_driver_framework;
}
void internal::DriverHostControllerConnection::Start(StartRequestView request,
StartCompleter::Sync& completer) {
auto callback = [this, request = std::move(request->driver),
completer = completer.ToAsync()](zx::result<dfv2::LoadedDriver> loaded) mutable {
if (loaded.is_error()) {
completer.Close(loaded.error_value());
}
async_dispatcher_t* driver_async_dispatcher = loaded->dispatcher.async_dispatcher();
// Task to start the driver. Post this to the driver dispatcher thread.
auto start_task = [this, request = std::move(request), completer = std::move(completer),
loaded = std::move(*loaded)]() mutable {
// Start the driver.
loaded.driver->Start(
std::move(loaded.start_args), std::move(loaded.dispatcher),
[this, driver = loaded.driver, request = std::move(request)](auto result) mutable {
if (result.is_error()) {
LOGF(ERROR, "Failed to start driver '%s': %s", driver->url().data(),
result.status_string());
// If we fail to start the driver, we need to initiate shutting down the dispatcher.
driver->ShutdownDispatcher();
return;
}
LOGF(INFO, "Started '%s'", driver->url().data());
auto unbind_callback = [this](dfv2::Driver* driver, fidl::UnbindInfo info,
fidl::ServerEnd<fuchsia_driver_host::Driver> server) {
if (!info.is_user_initiated()) {
LOGF(WARNING, "Unexpected stop of driver '%s': %s", driver->url().data(),
info.FormatDescription().data());
}
// Request the driver runtime shutdown all dispatchers owned by the driver.
// Once we get the callback, we will stop the driver.
auto driver_shutdown = std::make_unique<fdf_env::DriverShutdown>();
auto driver_shutdown_ptr = driver_shutdown.get();
auto shutdown_callback =
[this, driver_shutdown = std::move(driver_shutdown), driver,
server = std::move(server)](const void* shutdown_driver) mutable {
ZX_ASSERT(driver == shutdown_driver);
// This removes the driver's unique_ptr from the list, which will
// run the destructor and call the driver's Stop hook.
driver_host_context_->RemoveDriver(*driver);
// Send the epitaph to the driver runner letting it know we stopped
// the driver correctly.
server.Close(ZX_OK);
};
// We always expect this call to succeed, as we should be the only entity
// that attempts to forcibly shutdown drivers.
ZX_ASSERT(ZX_OK == driver_shutdown_ptr->Begin(driver, std::move(shutdown_callback)));
};
auto binding =
fidl::BindServer(driver_host_context_->loop().dispatcher(), std::move(request),
driver.get(), std::move(unbind_callback));
driver->set_binding(std::move(binding));
this->driver_host_context_->AddDriver(std::move(driver));
});
};
async::PostTask(driver_async_dispatcher, std::move(start_task));
};
dfv2::LoadDriver(fidl::ToNatural(request->start_args), driver_host_context_->loop().dispatcher(),
std::move(callback));
}