blob: 207b7decb0d3ab472dd56311f734c23db7bf6cb4 [file] [edit]
// Copyright 2026 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.
#ifndef LIB_DRIVER_COMPONENT_CPP_INTERNAL_DRIVER_SERVER2_H_
#define LIB_DRIVER_COMPONENT_CPP_INTERNAL_DRIVER_SERVER2_H_
#include <fidl/fuchsia.driver.framework/cpp/driver/wire.h>
#include <fidl/fuchsia.driver.framework/cpp/type_conversions.h>
#include <lib/driver/component/cpp/driver_base2.h>
#include <lib/driver/component/cpp/start_completer.h>
#include <lib/driver/component/cpp/stop_completer.h>
#include <lib/driver/logging/cpp/logger.h>
#include <lib/driver/symbols/symbols.h>
namespace fdf_internal {
// This will shim a |DriverBase| based driver with the new FIDL based registration.
template <typename DriverBaseImpl>
class DriverServer2 final : public fdf::WireServer<fuchsia_driver_framework::Driver> {
static_assert(std::is_base_of_v<fdf::DriverBase2, DriverBaseImpl>,
"The driver type must implement the fdf::DriverBase2 class.");
static_assert(!std::is_abstract_v<DriverBaseImpl>,
"The driver class must not be abstract. Try making it a final class to "
"see the unimplemented pure virtual methods. Eg: "
"class Driver final : public fdf::DriverBase2");
static_assert(std::is_default_constructible_v<DriverBaseImpl>,
"The driver must be default constructible from. ");
public:
// Initialize the fuchsia_driver_framework::Driver server.
static void* initialize(fdf_handle_t server_handle) {
fdf_dispatcher_t* dispatcher = fdf_dispatcher_get_current_dispatcher();
DriverServer2* driver_server = new DriverServer2(dispatcher, server_handle);
return driver_server;
}
// Destroy the fuchsia_driver_framework::Driver server.
static void destroy(void* token) {
DriverServer2* driver_server = static_cast<DriverServer2*>(token);
delete driver_server;
}
DriverServer2(fdf_dispatcher_t* dispatcher, fdf_handle_t server_handle)
: dispatcher_(dispatcher), driver_(std::make_unique<DriverBaseImpl>()) {
binding_.emplace(dispatcher_,
fdf::ServerEnd<fuchsia_driver_framework::Driver>(fdf::Channel(server_handle)),
this, fidl::kIgnoreBindingClosure);
}
~DriverServer2() final = default;
void Start(StartRequestView request, fdf::Arena& arena,
StartCompleter::Sync& completer) override {
fdf::DriverContext context(fidl::ToNatural(request->start_args));
driver_->DriverBaseInternalInit(context, fdf::UnownedSynchronizedDispatcher(dispatcher_));
fdf::StartCompleter start_completer(
[reply_arena = std::move(arena), reply_completer = completer.ToAsync()](
zx::result<> result) mutable { reply_completer.buffer(reply_arena).Reply(result); });
// Post a task to do this so that the WireServerDispatcher, the caller of this method,
// can clean up correctly. Otherwise the destruction of the arena from the callback could
// run too early, causing use-after-frees during the cleanup of the request.
async::PostTask(fdf_dispatcher_get_async_dispatcher(dispatcher_),
[this, context = std::move(context),
inner_completer = std::move(start_completer)]() mutable {
driver_->Start(std::move(context), std::move(inner_completer));
});
}
void Stop(fdf::Arena& arena, StopCompleter::Sync& completer) override {
ZX_ASSERT(driver_);
driver_->Stop(fdf::StopCompleter([this](zx::result<> result) { StopBinding(); }));
}
#if FUCHSIA_API_LEVEL_AT_LEAST(HEAD)
void Suspend(fdf::Arena& arena, SuspendCompleter::Sync& completer) override {
ZX_ASSERT(driver_);
fdf::SuspendCompleter suspend_completer(
[reply_arena = std::move(arena), reply_completer = completer.ToAsync()](
zx::result<> result) mutable { reply_completer.buffer(reply_arena).Reply(result); });
driver_->SystemSuspend(std::move(suspend_completer));
}
void Resume(ResumeRequestView request, fdf::Arena& arena,
ResumeCompleter::Sync& completer) override {
ZX_ASSERT(driver_);
fdf::ResumeCompleter resume_completer(
[reply_arena = std::move(arena), reply_completer = completer.ToAsync()](
zx::result<> result) mutable { reply_completer.buffer(reply_arena).Reply(result); });
std::optional<fuchsia_power_broker::LeaseToken> lease;
if (request->power_element_lease.is_valid()) {
lease.emplace(std::move(request->power_element_lease));
}
driver_->SystemResume(std::move(lease), std::move(resume_completer));
}
#endif
void handle_unknown_method(fidl::UnknownMethodMetadata<fuchsia_driver_framework::Driver> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override {
if (driver_) {
FDF_LOGL(INFO, driver_->logger(), "fdf::Driver server received unknown method.");
}
}
void* GetDriverBaseImpl() {
if (driver_) {
return driver_.get();
}
return nullptr;
}
private:
void StopBinding() {
if (fdf_dispatcher_get_current_dispatcher() == dispatcher_) {
binding_.reset();
return;
}
async::PostTask(fdf_dispatcher_get_async_dispatcher(dispatcher_),
[this]() { binding_.reset(); });
}
fdf_dispatcher_t* dispatcher_;
std::optional<fdf::ServerBinding<fuchsia_driver_framework::Driver>> binding_;
std::unique_ptr<fdf::DriverBase2> driver_;
};
} // namespace fdf_internal
#endif // LIB_DRIVER_COMPONENT_CPP_INTERNAL_DRIVER_SERVER2_H_