blob: 2bfdfac2c17877c98be76ebe29244237dd1a942e [file] [log] [blame] [edit]
// Copyright 2020 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 SRC_DEVICES_LIB_FIDL_DEVICE_SERVER_H_
#define SRC_DEVICES_LIB_FIDL_DEVICE_SERVER_H_
#include <fidl/fuchsia.device/cpp/wire.h>
#include <fidl/fuchsia.io/cpp/wire_test_base.h>
#include <lib/ddk/device.h>
#include <lib/fidl/cpp/wire/internal/server_details.h>
namespace devfs_fidl {
class DeviceInterface : public fidl::WireServer<fuchsia_device::Controller> {
public:
// Have the `DeviceInterface` log this error. This lets the `DeviceInterface`
// add extra context around the error, and supports logging in both the DFv1
// and DFv2 environments.
virtual void LogError(const char* error) = 0;
virtual bool IsUnbound() = 0;
virtual bool MessageOp(fidl::IncomingHeaderAndMessage msg, device_fidl_txn_t txn) = 0;
};
class DeviceServer {
public:
// `device` must outlive `DeviceServer`.
DeviceServer(DeviceInterface& device, async_dispatcher_t* dispatcher);
void ConnectToController(fidl::ServerEnd<fuchsia_device::Controller> server_end);
void ConnectToDeviceFidl(zx::channel channel);
void ServeMultiplexed(zx::channel channel, bool include_node, bool include_controller);
// Asynchronously close all connections and call `callback` when all connections have completed
// their teardown. Must not be called with `callback != nullptr` while a previous `callback` is
// pending.
void CloseAllConnections(fit::callback<void()> callback);
private:
void Serve(zx::channel channel, fidl::internal::IncomingMessageDispatcher* impl);
class MessageDispatcher : public fidl::internal::IncomingMessageDispatcher {
public:
MessageDispatcher(DeviceServer& parent, bool multiplex_node, bool multiplex_controller);
private:
void dispatch_message(fidl::IncomingHeaderAndMessage&& msg, fidl::Transaction* txn,
fidl::internal::MessageStorageViewBase* storage_view) override;
class Node : public fidl::testing::WireTestBase<fuchsia_io::Node> {
public:
explicit Node(MessageDispatcher& parent);
private:
void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override;
void Close(CloseCompleter::Sync& completer) override;
void Query(QueryCompleter::Sync& completer) override;
void Clone(CloneRequestView request, CloneCompleter::Sync& completer) override;
MessageDispatcher& parent_;
};
Node node_{*this};
DeviceServer& parent_;
const bool multiplex_node_;
const bool multiplex_controller_;
};
DeviceInterface& controller_;
async_dispatcher_t* const dispatcher_;
MessageDispatcher device_{*this, false, false};
MessageDispatcher device_and_node_{*this, true, false};
MessageDispatcher device_and_controller_{*this, false, true};
MessageDispatcher device_and_node_and_controller_{*this, true, true};
// Note: this protocol is a lie with respect to the bindings below; some of them speak the stated
// protocol, some speak the device-specific protocol, others speak a mix of protocols multiplexed
// at run-time. The protocol is not particularly important as this collection is only used to
// synchronize the destruction of all its bindings in response to driver lifecycle events.
using TypeErasedProtocol = fuchsia_device::Controller;
std::unordered_map<zx_handle_t, fidl::ServerBindingRef<TypeErasedProtocol>> bindings_;
// Set via `CloseAllConnections` and called when all bindings have completed their teardown.
std::optional<fit::callback<void()>> callback_;
};
} // namespace devfs_fidl
#endif // SRC_DEVICES_LIB_FIDL_DEVICE_SERVER_H_