blob: c127329edff52b3eb2a7c065ddc901c94e99dde6 [file] [log] [blame] [edit]
// 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.
#include "src/modular/lib/fidl/app_client.h"
#include <fcntl.h>
#include <fuchsia/sys/cpp/fidl.h>
#include <lib/fdio/cpp/caller.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/fdio/limits.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/processargs.h>
#include <fbl/unique_fd.h>
#include "lib/sys/cpp/service_directory.h"
#include "src/lib/files/directory.h"
namespace modular {
AppClientBase::AppClientBase(fuchsia::sys::Launcher* const launcher,
fuchsia::modular::session::AppConfig config,
fuchsia::sys::ServiceListPtr additional_services,
fuchsia::sys::FlatNamespacePtr flat_namespace,
const std::optional<std::string>& data_origin)
: AsyncHolderBase(config.url()) {
fidl::InterfaceHandle<fuchsia::io::Directory> handle;
fuchsia::sys::LaunchInfo launch_info = {
.url = config.url(),
.directory_request = handle.NewRequest(),
};
services_ = sys::ServiceDirectory(std::move(handle));
std::vector<std::string> args;
if (config.has_args()) {
launch_info.arguments.emplace();
for (const auto& arg : config.args()) {
launch_info.arguments->push_back(arg);
}
}
if (data_origin.has_value()) {
ZX_ASSERT(!data_origin.value().empty());
if (!files::CreateDirectory(data_origin.value())) {
FX_LOGS(ERROR) << "Unable to create directory at " << data_origin.value();
return;
}
launch_info.flat_namespace = std::make_unique<fuchsia::sys::FlatNamespace>();
launch_info.flat_namespace->paths.push_back("/data");
fbl::unique_fd dir(open(data_origin.value().c_str(), O_DIRECTORY | O_RDONLY));
if (!dir.is_valid()) {
FX_LOGS(ERROR) << "Unable to open directory at " << data_origin.value()
<< ". errno: " << errno;
return;
}
fdio_cpp::FdioCaller caller(std::move(dir));
zx::result channel = caller.take_directory();
if (channel.is_error()) {
FX_PLOGS(ERROR, channel.status_value())
<< "Unable create a handle from " << data_origin.value();
return;
}
launch_info.flat_namespace->directories.emplace_back(channel.value().TakeChannel());
}
if (additional_services) {
launch_info.additional_services = std::move(additional_services);
}
if (flat_namespace) {
if (!launch_info.flat_namespace) {
launch_info.flat_namespace = std::make_unique<fuchsia::sys::FlatNamespace>();
}
for (size_t i = 0; i < flat_namespace->paths.size(); ++i) {
launch_info.flat_namespace->paths.push_back(flat_namespace->paths[i]);
launch_info.flat_namespace->directories.push_back(std::move(flat_namespace->directories[i]));
}
}
launcher->CreateComponent(std::move(launch_info), component_controller_.NewRequest());
}
AppClientBase::~AppClientBase() = default;
void AppClientBase::ImplTeardown(fit::function<void()> done) {
// If the component is not running, it's not serving the lifecycle service, so don't try to
// teardown gracefully.
if (!component_controller_) {
done();
return;
}
LifecycleServiceTerminate(std::move(done));
}
void AppClientBase::ImplReset() {
component_controller_.Unbind();
UnbindLifecycleService();
}
void AppClientBase::SetAppErrorHandler(fit::function<void()> error_handler) {
component_controller_.set_error_handler(
[error_handler = std::move(error_handler)](zx_status_t status) { error_handler(); });
}
void AppClientBase::LifecycleServiceTerminate(fit::function<void()> /* done */) {}
void AppClientBase::UnbindLifecycleService() {}
template <>
void AppClient<fuchsia::modular::Lifecycle>::LifecycleServiceTerminate(fit::function<void()> done) {
if (lifecycle_service()) {
SetAppErrorHandler(std::move(done));
lifecycle_service()->Terminate();
} else {
// If the lifecycle channel is already closed, the component has no way to receive
// a terminate signal, so don't bother waiting.
done();
}
}
} // namespace modular