| // Copyright 2016 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 GARNET_BIN_APPMGR_COMPONENT_CONTROLLER_IMPL_H_ |
| #define GARNET_BIN_APPMGR_COMPONENT_CONTROLLER_IMPL_H_ |
| |
| #include <fs/pseudo-dir.h> |
| #include <fuchsia/inspect/cpp/fidl.h> |
| #include <fuchsia/sys/cpp/fidl.h> |
| #include <lib/async/cpp/wait.h> |
| #include <lib/zx/process.h> |
| #include <zircon/assert.h> |
| |
| #include <vector> |
| |
| #include "garnet/bin/appmgr/component_container.h" |
| #include "garnet/bin/appmgr/debug_info_retriever.h" |
| #include "garnet/bin/appmgr/hub/component_hub.h" |
| #include "garnet/bin/appmgr/hub/hub_info.h" |
| #include "garnet/bin/appmgr/namespace.h" |
| #include "garnet/bin/appmgr/system_objects_directory.h" |
| #include "lib/fidl/cpp/binding.h" |
| |
| namespace component { |
| |
| typedef fit::function<void(int64_t, fuchsia::sys::TerminationReason, |
| fuchsia::sys::ComponentController_EventSender*)> |
| TerminationCallback; |
| |
| // ComponentRequestWrapper wraps failure behavior in the event a Component fails |
| // to start. It wraps the behavior of binding to an incoming interface request |
| // and sending error events to clients before closing the channel. |
| // If there is no error, the wrapped request and callback may be Extract()ed |
| // and bound to a concrete interface. |
| // TODO(CP-84): Solve the general problem this solves. |
| class ComponentRequestWrapper { |
| public: |
| explicit ComponentRequestWrapper( |
| fidl::InterfaceRequest<fuchsia::sys::ComponentController> request, |
| TerminationCallback callback, int64_t default_return = -1, |
| fuchsia::sys::TerminationReason default_reason = |
| fuchsia::sys::TerminationReason::UNKNOWN); |
| ~ComponentRequestWrapper(); |
| ComponentRequestWrapper(ComponentRequestWrapper&& other); |
| void operator=(ComponentRequestWrapper&& other); |
| |
| void SetReturnValues(int64_t return_code, |
| fuchsia::sys::TerminationReason reason); |
| |
| bool Extract( |
| fidl::InterfaceRequest<fuchsia::sys::ComponentController>* out_request, |
| TerminationCallback* out_callback) { |
| if (!active_) { |
| return false; |
| } |
| *out_request = std::move(request_); |
| *out_callback = std::move(callback_); |
| active_ = false; |
| return true; |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ComponentRequestWrapper); |
| |
| private: |
| fidl::InterfaceRequest<fuchsia::sys::ComponentController> request_; |
| TerminationCallback callback_; |
| int64_t return_code_; |
| fuchsia::sys::TerminationReason reason_; |
| bool active_ = true; |
| }; |
| |
| // Construct a callback that forwards termination information back over an |
| // incoming ComponentController_EventSender , if it exists. |
| TerminationCallback MakeForwardingTerminationCallback(); |
| |
| // FailedComponentController implements the component controller interface for |
| // components that failed to start. This class serves the purpose of actually |
| // binding to a ComponentController channel and passing back a termination |
| // event. |
| class FailedComponentController : public fuchsia::sys::ComponentController { |
| public: |
| FailedComponentController( |
| int64_t return_code, fuchsia::sys::TerminationReason termination_reason, |
| TerminationCallback termination_callback, |
| fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller); |
| virtual ~FailedComponentController(); |
| void Kill() override; |
| void Detach() override; |
| |
| private: |
| fidl::Binding<fuchsia::sys::ComponentController> binding_; |
| int64_t return_code_; |
| fuchsia::sys::TerminationReason termination_reason_; |
| TerminationCallback termination_callback_; |
| }; |
| |
| class ComponentControllerBase : public fuchsia::sys::ComponentController { |
| public: |
| ComponentControllerBase( |
| fidl::InterfaceRequest<fuchsia::sys::ComponentController> request, |
| std::string url, std::string args, std::string label, |
| std::string hub_instance_id, fxl::RefPtr<Namespace> ns, |
| zx::channel exported_dir, zx::channel client_request); |
| virtual ~ComponentControllerBase() override; |
| |
| public: |
| HubInfo HubInfo(); |
| const std::string& label() const { return label_; } |
| const fbl::RefPtr<fs::PseudoDir>& hub_dir() const { return hub_.dir(); } |
| |
| // |fuchsia::sys::ComponentController| implementation: |
| void Detach() override; |
| |
| protected: |
| ComponentHub* hub() { return &hub_; } |
| |
| // Returns the incoming services from the namespace. |
| const fbl::RefPtr<ServiceProviderDirImpl>& incoming_services() const { |
| ZX_DEBUG_ASSERT(ns_); |
| return ns_->services(); |
| }; |
| |
| fidl::Binding<fuchsia::sys::ComponentController> binding_; |
| |
| private: |
| std::string label_; |
| std::string hub_instance_id_; |
| |
| ComponentHub hub_; |
| |
| fxl::RefPtr<Namespace> ns_; |
| |
| fuchsia::io::NodePtr cloned_exported_dir_; |
| |
| fuchsia::io::DirectoryPtr exported_dir_; |
| |
| fuchsia::inspect::InspectPtr inspect_checker_; |
| }; |
| |
| class ComponentControllerImpl : public ComponentControllerBase { |
| public: |
| ComponentControllerImpl( |
| fidl::InterfaceRequest<fuchsia::sys::ComponentController> request, |
| ComponentContainer<ComponentControllerImpl>* container, zx::job job, |
| zx::process process, std::string url, std::string args, std::string label, |
| fxl::RefPtr<Namespace> ns, zx::channel exported_dir, |
| zx::channel client_request, TerminationCallback termination_callback); |
| ~ComponentControllerImpl() override; |
| |
| const std::string& koid() const { return koid_; } |
| |
| zx_status_t AddSubComponentHub(const component::HubInfo& hub_info); |
| zx_status_t RemoveSubComponentHub(const component::HubInfo& hub_info); |
| |
| // |fuchsia::sys::ComponentController| implementation: |
| void Kill() override; |
| |
| private: |
| void Handler(async_dispatcher_t* dispatcher, async::WaitBase* wait, |
| zx_status_t status, const zx_packet_signal* signal); |
| |
| bool SendReturnCodeIfTerminated(); |
| |
| ComponentContainer<ComponentControllerImpl>* container_; |
| zx::job job_; |
| zx::process process_; |
| const std::string koid_; |
| |
| async::WaitMethod<ComponentControllerImpl, &ComponentControllerImpl::Handler> |
| wait_; |
| |
| TerminationCallback termination_callback_; |
| |
| SystemObjectsDirectory system_objects_directory_; |
| |
| fidl::BindingSet<fuchsia::inspect::Inspect, |
| std::shared_ptr<component::Object>> |
| system_directory_bindings_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(ComponentControllerImpl); |
| }; |
| |
| // This class acts as a bridge between the components created by ComponentRunner |
| // and |request|. |
| class ComponentBridge : public ComponentControllerBase { |
| public: |
| ComponentBridge( |
| fidl::InterfaceRequest<fuchsia::sys::ComponentController> request, |
| fuchsia::sys::ComponentControllerPtr remote_controller, |
| ComponentContainer<ComponentBridge>* container, std::string url, |
| std::string args, std::string label, std::string hub_instance_id, |
| fxl::RefPtr<Namespace> ns, zx::channel exported_dir, |
| zx::channel client_request, TerminationCallback termination_callback); |
| |
| ~ComponentBridge() override; |
| |
| void SetParentJobId(const std::string& id); |
| |
| // Set the termination reason for this bridge. |
| // This should be used when a runner itself terminates and needs to report |
| // back a failure over the bridge when it is closed. |
| void SetTerminationReason(fuchsia::sys::TerminationReason termination_reason); |
| |
| // |fuchsia::sys::ComponentController| implementation: |
| void Kill() override; |
| |
| void OnTerminated(OnTerminatedCallback callback) { |
| on_terminated_event_ = std::move(callback); |
| } |
| |
| private: |
| fuchsia::sys::ComponentControllerPtr remote_controller_; |
| ComponentContainer<ComponentBridge>* container_; |
| TerminationCallback termination_callback_; |
| fuchsia::sys::TerminationReason termination_reason_; |
| OnTerminatedCallback on_terminated_event_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(ComponentBridge); |
| }; |
| |
| } // namespace component |
| |
| #endif // GARNET_BIN_APPMGR_COMPONENT_CONTROLLER_IMPL_H_ |