blob: b58d9ea90193fc80e53fc18dfb97727e366634a7 [file] [log] [blame]
// 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::Create();
// 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 outgoing
// directory.
//
// 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
// serves outgoing requests over |directory_request|. Callers should be
// careful to publish outgoing service in |outgoing()| before |dispatcher|
// starts processing incoming requests for the outgoing services.
ComponentContext(std::shared_ptr<ServiceDirectory> svc, zx::channel 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.
//
// 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(std::move(context))
// loop.Run();
// return 0;
// }
// ```
static std::unique_ptr<ComponentContext> Create();
// 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_;
};
} // namespace sys
#endif // LIB_SYS_CPP_COMPONENT_CONTEXT_H_