| // 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 LIB_APP_DRIVER_CPP_MODULE_DRIVER_H_ |
| #define LIB_APP_DRIVER_CPP_MODULE_DRIVER_H_ |
| |
| #include <memory> |
| |
| #include <fuchsia/modular/cpp/fidl.h> |
| #include <fuchsia/sys/cpp/fidl.h> |
| #include <fuchsia/ui/app/cpp/fidl.h> |
| #include <fuchsia/ui/viewsv1/cpp/fidl.h> |
| #include <lib/async/cpp/task.h> |
| #include <lib/async/default.h> |
| #include <lib/component/cpp/startup_context.h> |
| #include <lib/fidl/cpp/binding.h> |
| #include <lib/fidl/cpp/interface_request.h> |
| #include <lib/fxl/logging.h> |
| #include <lib/lifecycle/cpp/lifecycle_impl.h> |
| |
| namespace modular { |
| |
| // This interface is passed to the |Impl| object that ModuleDriver initializes. |
| class ModuleHost { |
| public: |
| virtual component::StartupContext* startup_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::viewsv1::ViewProvider> |
| // view_provider_request); |
| // |
| // // Called by ModuleDriver. Call |done| once shutdown sequence is |
| // // complete, at which point |this| will be deleted. |
| // void Terminate(const std::function<void()>& done); |
| // |
| // Example: |
| // |
| // class HelloWorldModule { |
| // public: |
| // HelloWorldModule( |
| // modular::ModuleHost* module_host, |
| // fidl::InterfaceRequest<fuchsia::ui::viewsv1::ViewProvider> |
| // view_provider_request) {} |
| // |
| // // Called by ModuleDriver. |
| // void Terminate(const std::function<void()>& done) { done(); } |
| // }; |
| // |
| // int main(int argc, const char** argv) { |
| // async::Loop loop(&kAsyncLoopConfigAttachToThread); |
| // auto context = component::StartupContext::CreateFromStartupInfo(); |
| // modular::ModuleDriver<HelloWorldApp> driver(context.get(), |
| // [&loop] { loop.Quit(); }); |
| // loop.Run(); |
| // return 0; |
| // } |
| template <typename Impl> |
| class ModuleDriver : LifecycleImpl::Delegate, ModuleHost { |
| public: |
| ModuleDriver(component::StartupContext* const context, |
| std::function<void()> on_terminated) |
| : context_(context), |
| lifecycle_impl_(context->outgoing().deprecated_services(), this), |
| on_terminated_(std::move(on_terminated)) { |
| context_->ConnectToEnvironmentService(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)); |
| }); |
| |
| context_->outgoing().AddPublicService<fuchsia::ui::viewsv1::ViewProvider>( |
| [this](fidl::InterfaceRequest<fuchsia::ui::viewsv1::ViewProvider> |
| request) { |
| impl_ = std::make_unique<Impl>(static_cast<ModuleHost*>(this), |
| std::move(request)); |
| }); |
| } |
| |
| private: |
| // |ModuleHost| |
| component::StartupContext* startup_context() override { return context_; } |
| |
| // |ModuleHost| |
| fuchsia::modular::ModuleContext* module_context() override { |
| FXL_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_(); |
| } |
| } |
| |
| component::StartupContext* const context_; |
| LifecycleImpl lifecycle_impl_; |
| std::function<void()> on_terminated_; |
| fuchsia::modular::ModuleContextPtr module_context_; |
| |
| std::unique_ptr<Impl> impl_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(ModuleDriver); |
| }; |
| |
| } // namespace modular |
| |
| #endif // LIB_APP_DRIVER_CPP_MODULE_DRIVER_H_ |