|  | // 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_COMPONENT_CONTEXT_H_ | 
|  | #define LIB_SYS_CPP_COMPONENT_CONTEXT_H_ | 
|  |  | 
|  | #include <lib/sys/cpp/outgoing_directory.h> | 
|  | #include <lib/sys/cpp/service_directory.h> | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | namespace sys { | 
|  |  | 
|  | // Context information that this component received at startup. | 
|  | // | 
|  | // Upon creation, components are given a namespace, which is file system local | 
|  | // to the component. A components namespace lets the component interact with | 
|  | // other components and the system at large. One important part of this | 
|  | // namespace is the directory of services, typically located at "/svc" in the | 
|  | // components namespace. The |ComponentContext| provides an ergonomic interface | 
|  | // to this service bundle through its |svc()| property. | 
|  | // | 
|  | // In addition to receiving services, components can also publish services and | 
|  | // data to other components through their outgoing namespace, which is also a | 
|  | // directory. The |ComponentContext| provides an ergonomic interface for | 
|  | // exposing services and other file system objects through its |outgoing()| | 
|  | // property. | 
|  | // | 
|  | // This class is thread-hostile. | 
|  | // | 
|  | //  # Simple usage | 
|  | // | 
|  | // Instances of this class should be owned and managed on the same thread. | 
|  | // | 
|  | // # Advanced usage | 
|  | // | 
|  | // You can use a background thread to service this class provided: | 
|  | // async_dispatcher_t for the background thread is stopped or suspended | 
|  | // prior to destroying the class object. | 
|  | // | 
|  | // # Example | 
|  | // | 
|  | // The |ComponentContext| object is typically created early in the startup | 
|  | // sequence for components, typically after creating the |async::Loop| for the | 
|  | // main thread. | 
|  | // | 
|  | // ``` | 
|  | // int main(int argc, const char** argv) { | 
|  | //   async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread); | 
|  | //   auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory(); | 
|  | //   my::App app(std::move(context)) | 
|  | //   loop.Run(); | 
|  | //   return 0; | 
|  | // } | 
|  | // ``` | 
|  | class ComponentContext final { | 
|  | public: | 
|  | // Creates a component context that uses |svc| for incoming services. Callers | 
|  | // can call |OutgoingDirectory::Serve()| if they wish to publish the outgoing | 
|  | // directory to a channel they provide. | 
|  | // | 
|  | // This constructor is rarely used directly. Instead, most clients create a | 
|  | // component context using the |Create()| static method. | 
|  | explicit ComponentContext(std::shared_ptr<ServiceDirectory> svc, | 
|  | async_dispatcher_t* dispatcher = nullptr); | 
|  |  | 
|  | // Creates a component context that uses |svc| for incoming services and immediately | 
|  | // binds the local outgoing directory implementation to |outgoing_directory_request|. Callers | 
|  | // SHOULD make all modifications to |outgoing()| before |dispatcher| starts processing incoming | 
|  | // requests. Exceptions to this guideline are rare. | 
|  | ComponentContext(std::shared_ptr<ServiceDirectory> svc, | 
|  | fidl::InterfaceRequest<fuchsia::io::Directory> outgoing_directory_request, | 
|  | async_dispatcher_t* dispatcher = nullptr); | 
|  |  | 
|  | ~ComponentContext(); | 
|  |  | 
|  | // ComponentContext objects cannot be copied. | 
|  | ComponentContext(const ComponentContext&) = delete; | 
|  | ComponentContext& operator=(const ComponentContext&) = delete; | 
|  |  | 
|  | // Creates a component context from the process startup info without binding a channel | 
|  | // handle to the outgoing directory. Clients wishing to serve the outgoing directory MUST | 
|  | // call either |outgoing()->ServeFromStartupInfo()| to serve to the PA_DIRECTORY_REQUEST | 
|  | // handle. | 
|  | // | 
|  | // Callers SHOULD make all modifications to |outgoing()| before calling one of the above | 
|  | // Serve methods. Exceptions to this guideline are rare. | 
|  | // | 
|  | // Call this function once during process initialization to retrieve the | 
|  | // handles supplied to the component by the component manager. This function | 
|  | // consumes some of those handles, which means subsequent calls to this | 
|  | // function will not return a functional component context. | 
|  | // | 
|  | // Prefer creating the |ComponentContext| in the |main| function for a | 
|  | // component and passing the context to a class named "App" which encapsulates | 
|  | // the main logic of the program. This pattern makes testing easier because | 
|  | // tests can pass a fake |ComponentContext| from |ComponentContextProvider| to | 
|  | // the |App| class to inject dependencies. | 
|  | // | 
|  | // The returned unique_ptr is never null. | 
|  | // | 
|  | // # Example | 
|  | // | 
|  | // ``` | 
|  | // int main(int argc, const char** argv) { | 
|  | //   async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread); | 
|  | //   auto context = sys::ComponentContext::Create(); | 
|  | //   my::App app(context.get()) | 
|  | //   app.PerformAsyncInitialization(/*when_init_done=*/[context = context.get()] { | 
|  | //     // Delaying serving of the out/ directory to here ensures no race condition | 
|  | //     // exists between clients looking for entries in out/ before app | 
|  | //     // initialization has had a chance to create them. | 
|  | //     context->outgoing()->ServeFromStartupInfo(); | 
|  | //   }); | 
|  | //   loop.Run(); | 
|  | //   return 0; | 
|  | // } | 
|  | // ``` | 
|  | static std::unique_ptr<ComponentContext> Create(); | 
|  |  | 
|  | // Equivalent to |Create()| followed immediately by |outgoing()->ServeFromStartupInfo()|. | 
|  | // | 
|  | // Callers SHOULD make all modifications to |outgoing()| before the thread default | 
|  | // async_dispatcher_t starts processing incoming requests. Exceptions to this guideline are rare. | 
|  | // | 
|  | // Call this function once during process initialization to retrieve the | 
|  | // handles supplied to the component by the component manager. This function | 
|  | // consumes some of those handles, which means subsequent calls to this | 
|  | // function will not return a functional component context. | 
|  | // | 
|  | // Prefer creating the |ComponentContext| in the |main| function for a | 
|  | // component and passing the context to a class named "App" which encapsulates | 
|  | // the main logic of the program. This pattern makes testing easier because | 
|  | // tests can pass a fake |ComponentContext| from |ComponentContextProvider| to | 
|  | // the |App| class to inject dependencies. | 
|  | // | 
|  | // The returned unique_ptr is never null. | 
|  | // | 
|  | // # Example | 
|  | // | 
|  | // ``` | 
|  | // int main(int argc, const char** argv) { | 
|  | //   async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread); | 
|  | //   auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory(); | 
|  | //   my::App app(std::move(context)) | 
|  | //   loop.Run(); | 
|  | //   return 0; | 
|  | // } | 
|  | // ``` | 
|  | static std::unique_ptr<ComponentContext> CreateAndServeOutgoingDirectory(); | 
|  |  | 
|  | // The component's incoming directory of services from its namespace. | 
|  | // | 
|  | // Use this object to connect to services offered by other components. | 
|  | // | 
|  | // The returned object is thread-safe. | 
|  | // | 
|  | // # Example | 
|  | // | 
|  | // ``` | 
|  | // auto controller = context.svc()->Connect<fuchsia::foo::Controller>(); | 
|  | // ``` | 
|  | const std::shared_ptr<ServiceDirectory>& svc() const { return svc_; } | 
|  |  | 
|  | // The component's outgoing directory. | 
|  | // | 
|  | // Use this object to publish services and data to the component manager and | 
|  | // other components. | 
|  | // | 
|  | // The returned object is thread-safe. | 
|  | // | 
|  | // # Example | 
|  | // | 
|  | // ``` | 
|  | // class App : public fuchsia::foo::Controller { | 
|  | //  public: | 
|  | //   App(std::unique_ptr<ComponentContext> context) | 
|  | //     : context_(std::move(context) { | 
|  | //     context_.outgoing()->AddPublicService(bindings_.GetHandler(this)); | 
|  | //   } | 
|  | // | 
|  | //   // fuchsia::foo::Controller implementation: | 
|  | //   [...] | 
|  | // | 
|  | //  private: | 
|  | //   fidl::BindingSet<fuchsia::foo::Controller> bindings_; | 
|  | // } | 
|  | // ``` | 
|  | const std::shared_ptr<OutgoingDirectory>& outgoing() const { return outgoing_; } | 
|  | std::shared_ptr<OutgoingDirectory>& outgoing() { return outgoing_; } | 
|  |  | 
|  | private: | 
|  | std::shared_ptr<ServiceDirectory> svc_; | 
|  | std::shared_ptr<OutgoingDirectory> outgoing_; | 
|  | zx::channel outgoing_directory_request; | 
|  | }; | 
|  |  | 
|  | }  // namespace sys | 
|  |  | 
|  | #endif  // LIB_SYS_CPP_COMPONENT_CONTEXT_H_ |