| // Copyright 2019 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_TESTING_FAKE_DDK_INCLUDE_LIB_FAKE_DDK_FIDL_HELPER_H_ |
| #define SRC_DEVICES_TESTING_FAKE_DDK_INCLUDE_LIB_FAKE_DDK_FIDL_HELPER_H_ |
| |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/fidl/llcpp/server.h> |
| #include <lib/fidl/llcpp/transaction.h> |
| #include <lib/zx/channel.h> |
| #include <zircon/fidl.h> |
| |
| #include <optional> |
| #include <variant> |
| |
| #include <ddktl/fidl.h> |
| #include <fbl/algorithm.h> |
| |
| #include "lib/async-loop/loop.h" |
| |
| namespace fake_ddk { |
| |
| typedef zx_status_t(MessageOp)(void* ctx, fidl_incoming_msg_t* msg, fidl_txn_t* txn); |
| |
| ddk::internal::Transaction MakeDdkInternalTransaction(fidl::Transaction* txn); |
| ddk::internal::Transaction MakeDdkInternalTransaction(std::unique_ptr<fidl::Transaction> txn); |
| |
| std::variant<::fidl::Transaction*, std::unique_ptr<::fidl::Transaction>> FromDdkInternalTransaction( |
| ddk::internal::Transaction* txn); |
| |
| // Helper class to call fidl handlers in unit tests |
| // Use in conjunction with fake ddk |
| // |
| // Example usage: |
| // // After device_add call |
| // <fidl_client_function> ( <fake_ddk>.FidlClient().get(), <args>); |
| // |
| // Note: It is assumed that only one device add is done per fake ddk instance |
| // |
| // This can also be used stand alone |
| // Example standalone usage: |
| // DeviceX *dev; |
| // FidlMessenger fidl; |
| // fidl.SetMessageOp((void *)dev, |
| // [](void* ctx, fidl_incoming_msg_t* msg, fidl_txn_t* txn) -> |
| // zx_status_t { |
| // return static_cast<Device*>(ctx)->DdkMessage(msg, txn)}); |
| // <fidl_client_function> ( <fake_ddk>.local().get(), <args>); |
| // |
| class FidlMessenger : public fidl::internal::IncomingMessageDispatcher { |
| public: |
| // This is necessary for fidl::BindServer to work. It is usually auto-generated by LLCPP server |
| // bindings. Future evolution of LLCPP may cause this code to break. |
| using _EnclosingProtocol = FidlMessenger; |
| using Interface = FidlMessenger; |
| class WeakEventSender { |
| public: |
| explicit WeakEventSender(std::weak_ptr<fidl::internal::AsyncBinding> binding) |
| : binding_(std::move(binding)) {} |
| std::weak_ptr<fidl::internal::AsyncBinding> binding_; |
| }; |
| class EventSender { |
| public: |
| explicit EventSender(::fidl::ServerEnd<FidlMessenger> server_end) |
| : server_end_(std::move(server_end.channel())) {} |
| |
| const ::zx::channel& channel() const { return server_end_.channel(); } |
| ::zx::channel& channel() { return server_end_.channel(); } |
| |
| private: |
| ::fidl::ServerEnd<FidlMessenger> server_end_; |
| }; |
| |
| explicit FidlMessenger() : loop_(&kAsyncLoopConfigNeverAttachToThread) {} |
| explicit FidlMessenger(const async_loop_config_t* config) : loop_(config) {} |
| virtual ~FidlMessenger() { |
| if (binding_) |
| binding_->Unbind(); |
| } |
| |
| // Local channel to send FIDL client messages |
| zx::channel& local() { return local_; } |
| |
| ::fidl::DispatchResult Dispatch(fidl_incoming_msg_t* msg, ::fidl::Transaction* txn); |
| |
| // This is necessary for fidl::BindServer to work. It is usually auto-generated by LLCPP server |
| // bindings. Future evolution of LLCPP may cause this code to break. |
| ::fidl::DispatchResult dispatch_message(fidl_incoming_msg_t* msg, |
| ::fidl::Transaction* txn) final { |
| return Dispatch(msg, txn); |
| } |
| |
| // Set handlers to be called when FIDL message is received |
| // - Message operation context |op_ctx| and |op| must outlive FidlMessenger |
| // - If `remote` is empty, FidlHandler will create a new channel, storing the local endpoint in |
| // `local` for the client to retrieve later and binding the remote endpoint to the server. |
| // Otherwise, the endpoint in `remote` will be bound to the server, and FidlHandler will |
| // assume the client has retained the local endpoint. |
| zx_status_t SetMessageOp(void* op_ctx, MessageOp* op, |
| std::optional<zx::channel> remote = std::nullopt); |
| |
| private: |
| MessageOp* message_op_ = nullptr; |
| void* op_ctx_ = nullptr; |
| // Channel to mimic RPC |
| zx::channel local_; |
| // Server binding |
| std::unique_ptr<fidl::ServerBindingRef<FidlMessenger>> binding_; |
| // Dispatcher for fidl messages |
| async::Loop loop_; |
| }; |
| |
| } // namespace fake_ddk |
| |
| #endif // SRC_DEVICES_TESTING_FAKE_DDK_INCLUDE_LIB_FAKE_DDK_FIDL_HELPER_H_ |