blob: fdd2d95e0c483bf9cd6c79f43d7a68f913c43002 [file] [log] [blame]
// Copyright 2022 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.
#include <fidl/examples/routing/echo/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/cpp/service_directory.h>
#include <lib/syslog/cpp/log_settings.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/channel.h>
#include <zircon/processargs.h>
// [START imports]
#include <fuchsia/component/cpp/fidl.h>
#include <fuchsia/component/decl/cpp/fidl.h>
// [END imports]
// Controller instance to manage sequence of asynchronous FIDL operations
// using the fuchsia.component.Realm protocol.
class ChildRequestManager {
public:
explicit ChildRequestManager(std::unique_ptr<sys::ComponentContext> context, async::Loop* loop)
: loop_(loop) {
// Connect to the fuchsia.component.Realm framework protocol
context->svc()->Connect(realm_proxy_.NewRequest());
}
// Start the process to create a dynamic child instance in the collection,
// send a protocol request, then destroy the child instance.
void StartChildRequest(const std::string& message) {
FX_LOGS(INFO) << "Sending request: " << message;
// Save the current message to send
message_ = message;
// Restart the loop
loop_->ResetQuit();
CreateDynamicChild();
}
// [START create_child]
// Use the fuchsia.component.Realm protocol to create a dynamic
// child instance in the collection.
void CreateDynamicChild() {
fuchsia::component::decl::CollectionRef collection_ref = {
.name = "echo",
};
fuchsia::component::decl::Child child_decl;
child_decl.set_name("lifecycle_dynamic");
child_decl.set_url("echo_server#meta/default.cm");
child_decl.set_startup(fuchsia::component::decl::StartupMode::LAZY);
realm_proxy_->CreateChild(std::move(collection_ref), std::move(child_decl),
fuchsia::component::CreateChildArgs(),
[&](fuchsia::component::Realm_CreateChild_Result result) {
ZX_ASSERT(!result.is_err());
FX_LOGS(INFO) << "Dynamic child instance created.";
ConnectDynamicChild();
});
}
// [END create_child]
// [START destroy_child]
// Use the fuchsia.component.Realm protocol to destroy the dynamic
// child instance running in the collection.
void DestroyDynamicChild() {
fuchsia::component::decl::ChildRef child_ref = {
.name = "lifecycle_dynamic",
.collection = "echo",
};
realm_proxy_->DestroyChild(std::move(child_ref),
[&](fuchsia::component::Realm_DestroyChild_Result result) {
ZX_ASSERT(!result.is_err());
FX_LOGS(INFO) << "Dynamic child instance destroyed.";
// Terminate the loop
loop_->Quit();
});
}
// [END destroy_child]
// [START connect_child]
// Use the fuchsia.component.Realm protocol to open the exposed directory of
// the dynamic child instance.
void ConnectDynamicChild() {
fuchsia::component::decl::ChildRef child_ref = {
.name = "lifecycle_dynamic",
.collection = "echo",
};
fidl::InterfaceHandle<fuchsia::io::Directory> exposed_dir;
realm_proxy_->OpenExposedDir(
child_ref, exposed_dir.NewRequest(),
[this, exposed_dir = std::move(exposed_dir)](
fuchsia::component::Realm_OpenExposedDir_Result result) mutable {
ZX_ASSERT(!result.is_err());
std::shared_ptr<sys::ServiceDirectory> svc = std::make_shared<sys::ServiceDirectory>(
sys::ServiceDirectory(std::move(exposed_dir)));
SendEchoRequest(svc);
});
}
// [END connect_child]
// [START echo_send]
// Connect to the fidl.examples.routing.echo capability exposed by the child's
// service directory.
void SendEchoRequest(std::shared_ptr<sys::ServiceDirectory> svc_directory) {
// Connect to the protocol inside the child's exposed directory
svc_directory->Connect(echo_proxy_.NewRequest());
// Send a protocol request
echo_proxy_->EchoString(message_, [&](fidl::StringPtr response) {
FX_LOGS(INFO) << "Server response: " << response;
DestroyDynamicChild();
});
}
// [END echo_send]
private:
std::string message_;
fidl::examples::routing::echo::EchoPtr echo_proxy_;
fuchsia::component::RealmPtr realm_proxy_;
async::Loop* loop_;
};
int main(int argc, const char** argv) {
fuchsia_logging::SetTags({"lifecycle", "example"});
// Create the main async event loop and component context
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
auto context = sys::ComponentContext::Create();
// Connect to the fuchsia.component.Binder capability exposed by the static
// child instance, causing it to start.
FX_LOGS(INFO) << "Starting lifecycle child instance.";
fuchsia::component::BinderPtr binder_proxy;
context->svc()->Connect(binder_proxy.NewRequest());
// Submit a request for each program argument, and wait for the result to
// complete.
auto request_manager = ChildRequestManager(std::move(context), &loop);
for (int i = 1; i < argc; i++) {
request_manager.StartChildRequest(argv[i]);
loop.Run();
}
return 0;
}