| // Copyright 2017 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_MODULAR_LIB_APP_DRIVER_CPP_MODULE_DRIVER_H_ | |
| #define SRC_MODULAR_LIB_APP_DRIVER_CPP_MODULE_DRIVER_H_ | |
| #include <fuchsia/modular/cpp/fidl.h> | |
| #include <fuchsia/sys/cpp/fidl.h> | |
| #include <fuchsia/ui/app/cpp/fidl.h> | |
| #include <lib/async/cpp/task.h> | |
| #include <lib/async/default.h> | |
| #include <lib/fidl/cpp/binding.h> | |
| #include <lib/fidl/cpp/interface_request.h> | |
| #include <lib/sys/cpp/component_context.h> | |
| #include <lib/syslog/cpp/macros.h> | |
| #include <memory> | |
| #include <src/modular/lib/lifecycle/cpp/lifecycle_impl.h> | |
| namespace modular { | |
| // This interface is passed to the |Impl| object that ModuleDriver initializes. | |
| class ModuleHost { | |
| public: | |
| virtual sys::ComponentContext* component_context() = 0; | |
| virtual fuchsia::modular::ModuleContext* module_context() = 0; | |
| }; | |
| // ModuleDriver provides a way to write modules and participate in application | |
| // lifecycle. The |Impl| class supplied to ModuleDriver is instantiated when the | |
| // Module and ViewProvider services have both been requested by the framework. | |
| // | |
| // Usage: | |
| // The |Impl| class must implement: | |
| // | |
| // // A constructor with the following signature: | |
| // Constructor( | |
| // modular::ModuleHost* module_host, | |
| // fidl::InterfaceRequest<fuchsia::ui::app::ViewProvider> | |
| // view_provider_request); | |
| // | |
| // // Called by ModuleDriver. Call |done| once shutdown sequence is | |
| // // complete, at which point |this| will be deleted. | |
| // void Terminate(fit::function<void()> done); | |
| // | |
| // Example: | |
| // | |
| // class HelloWorldModule { | |
| // public: | |
| // HelloWorldModule( | |
| // modular::ModuleHost* module_host, | |
| // fidl::InterfaceRequest<fuchsia::ui::app::ViewProvider> | |
| // view_provider_request) {} | |
| // | |
| // // Called by ModuleDriver. | |
| // void Terminate(fit::function<void()> done) { done(); } | |
| // }; | |
| // | |
| // int main(int argc, const char** argv) { | |
| // async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread); | |
| // auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory(); | |
| // modular::ModuleDriver<HelloWorldApp> driver(context.get(), | |
| // [&loop] { loop.Quit(); }); | |
| // loop.Run(); | |
| // return 0; | |
| // } | |
| template <typename Impl> | |
| class ModuleDriver : LifecycleImpl::Delegate, ModuleHost { | |
| public: | |
| ModuleDriver(sys::ComponentContext* const context, fit::function<void()> on_terminated) | |
| : context_(context), | |
| lifecycle_impl_(context->outgoing(), this), | |
| on_terminated_(std::move(on_terminated)) { | |
| context_->svc()->Connect(module_context_.NewRequest()); | |
| context_->outgoing()->AddPublicService<fuchsia::ui::app::ViewProvider>( | |
| [this](fidl::InterfaceRequest<fuchsia::ui::app::ViewProvider> request) { | |
| impl_ = std::make_unique<Impl>(static_cast<ModuleHost*>(this), std::move(request)); | |
| }); | |
| } | |
| private: | |
| // |ModuleHost| | |
| sys::ComponentContext* component_context() override { return context_; } | |
| // |ModuleHost| | |
| fuchsia::modular::ModuleContext* module_context() override { | |
| FX_DCHECK(module_context_); | |
| return module_context_.get(); | |
| } | |
| // |LifecycleImpl::Delegate| | |
| void Terminate() override { | |
| // It's possible that we process the |fuchsia::modular::Lifecycle.Terminate| | |
| // message before the |Module.Initialize| message, even when both messages | |
| // are ready to be processed at the same time. In this case, because |impl_| | |
| // hasn't been instantiated yet, we cannot delegate the | |
| // |fuchsia::modular::Lifecycle.Terminate| message. | |
| if (impl_) { | |
| impl_->Terminate([this] { | |
| // Cf. AppDriver::Terminate(). | |
| async::PostTask(async_get_default_dispatcher(), [this] { | |
| impl_.reset(); | |
| on_terminated_(); | |
| }); | |
| }); | |
| } else { | |
| on_terminated_(); | |
| } | |
| } | |
| sys::ComponentContext* const context_; | |
| LifecycleImpl lifecycle_impl_; | |
| fit::function<void()> on_terminated_; | |
| fuchsia::modular::ModuleContextPtr module_context_; | |
| std::unique_ptr<Impl> impl_; | |
| FXL_DISALLOW_COPY_AND_ASSIGN(ModuleDriver); | |
| }; | |
| } // namespace modular | |
| #endif // SRC_MODULAR_LIB_APP_DRIVER_CPP_MODULE_DRIVER_H_ |