| // 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 LIB_SYS_CPP_OUTGOING_DIRECTORY_H_ |
| #define LIB_SYS_CPP_OUTGOING_DIRECTORY_H_ |
| |
| #include <lib/async/dispatcher.h> |
| #include <lib/fit/function.h> |
| #include <lib/sys/service/cpp/service.h> |
| #include <lib/sys/service/cpp/service_handler.h> |
| #include <lib/vfs/cpp/pseudo_dir.h> |
| #include <lib/vfs/cpp/service.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| namespace sys { |
| |
| // The directory provided by this component to the component manager. |
| // |
| // A component's outgoing directory contains services, data, and other objects |
| // that can be consumed by either the component manager itself or by other |
| // components in the system. |
| // |
| // The outgoing directory contains several subdirectories with well-known |
| // names: |
| // |
| // * svc. This directory contains the services offered by this component to |
| // other components. |
| // * debug. This directory contains arbitrary debugging output offered by this |
| // component. |
| // |
| // The outgoing directory may optionally contain other directories constructed |
| // using |GetOrCreateDirectory|. Common optional directories include: |
| // |
| // * objects. This directory contains Inspect API files and interfaces for use |
| // in component inspection. |
| // |
| // This class is thread-hostile. |
| // |
| // # Simple usage |
| // |
| // Instances of this class should be owned and managed on the same thread |
| // that services their connections. |
| // |
| // # Advanced usage |
| // |
| // You can use a background thread to service connections provided: |
| // async_dispatcher_t for the background thread is stopped or suspended |
| // prior to destroying the class object. |
| class OutgoingDirectory final { |
| public: |
| OutgoingDirectory(); |
| ~OutgoingDirectory(); |
| |
| // Outgoing objects cannot be copied. |
| OutgoingDirectory(const OutgoingDirectory&) = delete; |
| OutgoingDirectory& operator=(const OutgoingDirectory&) = delete; |
| |
| // Starts serving the outgoing directory on the given channel. |
| // |
| // This object will implement the |fuchsia.io.Directory| interface using this |
| // channel. |
| // |
| // If |dispatcher| is NULL, this object will serve the outgoing directory |
| // using the |async_dispatcher_t| from |async_get_default_dispatcher()|. |
| // |
| // # Errors |
| // |
| // ZX_ERR_BAD_HANDLE: |directory_request| is not a valid handle. |
| // |
| // ZX_ERR_ACCESS_DENIED: |directory_request| has insufficient rights. |
| // |
| // TODO: Document more errors. |
| zx_status_t Serve(zx::channel directory_request, async_dispatcher_t* dispatcher = nullptr); |
| |
| // Starts serving the outgoing directory on the channel provided to this |
| // process at startup as |PA_DIRECTORY_REQUEST|. |
| // |
| // This object will implement the |fuchsia.io.Directory| interface using this |
| // channel. |
| // |
| // If |dispatcher| is NULL, this object will serve the outgoing directory |
| // using the |async_dispatcher_t| from |async_get_default_dispatcher()|. |
| // |
| // # Errors |
| // |
| // ZX_ERR_BAD_HANDLE: the process did not receive a |PA_DIRECTORY_REQUEST| |
| // startup handle or it was already taken. |
| // |
| // ZX_ERR_ACCESS_DENIED: |directory_request| has insufficient rights. |
| // |
| // TODO: Document more errors. |
| zx_status_t ServeFromStartupInfo(async_dispatcher_t* dispatcher = nullptr); |
| |
| // Adds the specified interface to the set of public interfaces. |
| // |
| // Adds a supported service with the given |service_name|, using the given |
| // |interface_request_handler|. |interface_request_handler| should |
| // remain valid for the lifetime of this object. |
| // |
| // # Errors |
| // |
| // ZX_ERR_ALREADY_EXISTS: The public directory already contains an entry for |
| // this service. |
| // |
| // # Example |
| // |
| // ``` |
| // fidl::BindingSet<fuchsia::foo::Controller> bindings; |
| // outgoing.AddPublicService(bindings.GetHandler(this)); |
| // ``` |
| template <typename Interface> |
| zx_status_t AddPublicService(fidl::InterfaceRequestHandler<Interface> handler, |
| std::string service_name = Interface::Name_) const { |
| return AddPublicService(std::make_unique<vfs::Service>(std::move(handler)), |
| std::move(service_name)); |
| } |
| |
| // Adds the specified service to the set of public services. |
| // |
| // Adds a supported service with the given |service_name|, using the given |
| // |service|. |
| // |
| // # Errors |
| // |
| // ZX_ERR_ALREADY_EXISTS: The public directory already contains an entry for |
| // this service. |
| zx_status_t AddPublicService(std::unique_ptr<vfs::Service> service, |
| std::string service_name) const; |
| |
| // Removes the specified interface from the set of public interfaces. |
| // |
| // # Errors |
| // |
| // ZX_ERR_NOT_FOUND: The public directory does not contain an entry for this |
| // service. |
| // |
| // # Example |
| // |
| // ``` |
| // outgoing.RemovePublicService<fuchsia::foo::Controller>(); |
| // ``` |
| template <typename Interface> |
| zx_status_t RemovePublicService(const std::string& name = Interface::Name_) const { |
| return svc_->RemoveEntry(name); |
| } |
| |
| // Adds an instance of a service. |
| // |
| // A |handler| is added to provide an |instance| of a service. |
| // |
| // # Errors |
| // |
| // ZX_ERR_ALREADY_EXISTS: The instance already exists. |
| // |
| // # Example |
| // |
| // ``` |
| // ServiceHandler handler; |
| // handler.AddMember("my-member", ...); |
| // outgoing.AddService<MyService>(std::move(handler), "my-instance"); |
| // ``` |
| template <typename Service> |
| zx_status_t AddService(ServiceHandler handler, std::string instance = kDefaultInstance) const { |
| return AddNamedService(std::move(handler), Service::Name, std::move(instance)); |
| } |
| |
| // Adds an instance of a service. |
| // |
| // A |handler| is added to provide an |instance| of a |service|. |
| // |
| // # Errors |
| // |
| // ZX_ERR_ALREADY_EXISTS: The instance already exists. |
| zx_status_t AddNamedService(ServiceHandler handler, std::string service, |
| std::string instance = kDefaultInstance) const; |
| |
| // Removes an instance of a service. |
| // |
| // # Errors |
| // |
| // ZX_ERR_NOT_FOUND: The instance was not found. |
| // |
| // # Example |
| // |
| // ``` |
| // outgoing.RemoveService<MyService>("my-instance"); |
| // ``` |
| template <typename Service> |
| zx_status_t RemoveService(const std::string& instance) const { |
| return RemoveNamedService(Service::Name, instance); |
| } |
| |
| // Removes an instance of a service. |
| // |
| // # Errors |
| // |
| // ZX_ERR_NOT_FOUND: The instance was not found. |
| zx_status_t RemoveNamedService(const std::string& service, const std::string& instance) const; |
| |
| // Gets the root directory. |
| // |
| // The returned directory is owned by this class. |
| vfs::PseudoDir* root_dir() const { return root_.get(); } |
| |
| // Gets the directory to publish debug data. |
| // |
| // The returned directory is owned by this class. |
| vfs::PseudoDir* debug_dir() const { return debug_; } |
| |
| // Gets a subdirectory with the given |name|, creates it if it does not |
| // already exist. |
| // |
| // The returned directory is owned by this class. |
| vfs::PseudoDir* GetOrCreateDirectory(const std::string& name); |
| |
| private: |
| // The root of the outgoing directory itself. |
| std::unique_ptr<vfs::PseudoDir> root_; |
| |
| // The service subdirectory of the root directory. |
| // |
| // The underlying |vfs::PseudoDir| object is owned by |root_|. |
| vfs::PseudoDir* svc_; |
| |
| // The debug subdirectory of the root directory. |
| // |
| // The underlying |vfs::PseudoDir| object is owned by |root_|. |
| vfs::PseudoDir* debug_; |
| }; |
| |
| } // namespace sys |
| |
| #endif // LIB_SYS_CPP_OUTGOING_DIRECTORY_H_ |