blob: 6431f48bc163388e6dd8840a9b8814fb0c6557f8 [file] [log] [blame]
// 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_