blob: 1be845fc59528ec6e3553f401d64c666f73983c4 [file] [log] [blame] [edit]
// Copyright 2016 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/sys/appmgr/runner_holder.h"
#include <lib/fit/function.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <utility>
#include "lib/sys/cpp/termination_reason.h"
#include "src/lib/fsl/vmo/file.h"
#include "src/sys/appmgr/component_controller_impl.h"
#include "src/sys/appmgr/realm.h"
#include "src/sys/appmgr/util.h"
using fuchsia::sys::TerminationReason;
namespace component {
RunnerHolder::RunnerHolder(std::shared_ptr<sys::ServiceDirectory> services,
fuchsia::sys::ComponentControllerPtr controller,
fuchsia::sys::LaunchInfo launch_info, Realm* realm,
fit::function<void()> error_handler)
: services_(std::move(services)),
controller_(std::move(controller)),
error_handler_(std::move(error_handler)),
component_id_counter_(0) {
auto url = launch_info.url;
realm->CreateComponent(std::move(launch_info), controller_.NewRequest(),
[this](std::weak_ptr<ComponentControllerImpl> component) {
CreateComponentCallback(component);
});
controller_.events().OnTerminated = [this, url](int64_t return_code,
TerminationReason termination_reason) {
if (termination_reason != TerminationReason::EXITED) {
FX_LOGS(ERROR) << "Runner (" << url << ") terminating, reason: "
<< sys::HumanReadableTerminationReason(termination_reason);
}
Cleanup();
if (error_handler_) {
error_handler_();
}
};
services_->Connect(runner_.NewRequest());
}
RunnerHolder::~RunnerHolder() = default;
void RunnerHolder::Cleanup() {
impl_object_.reset();
// Terminate all bridges currently owned by this runner.
for (auto& component : components_) {
component.second->SetTerminationReason(TerminationReason::RUNNER_TERMINATED);
}
components_.clear();
}
void RunnerHolder::CreateComponentCallback(std::weak_ptr<ComponentControllerImpl> component) {
impl_object_ = component;
if (auto impl = impl_object_.lock()) {
koid_ = impl->koid();
// update hub
for (auto& n : components_) {
n.second->SetParentJobId(koid_);
impl->AddSubComponentHub(n.second->HubInfo());
}
}
}
void RunnerHolder::StartComponent(
fuchsia::sys::Package package, fuchsia::sys::StartupInfo startup_info,
fxl::RefPtr<Namespace> ns, fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller,
std::optional<zx::channel> package_handle) {
auto url = startup_info.launch_info.url;
const std::string args = Util::GetArgsString(startup_info.launch_info.arguments);
auto channels = Util::BindDirectory(&startup_info.launch_info);
fuchsia::sys::ComponentControllerPtr remote_controller;
auto remote_controller_request = remote_controller.NewRequest();
fxl::RefPtr<Namespace> ns_copy(ns);
// TODO(anmittal): Create better unique instance id, instead of 1,2,3,4,...
auto id = std::to_string(++component_id_counter_);
ns->set_component_id(id);
auto component = std::make_shared<ComponentBridge>(
std::move(controller), std::move(remote_controller), this, url, std::move(args),
Util::GetLabelFromURL(url), id, std::move(ns), std::move(channels.exported_dir),
std::move(channels.client_request), std::move(package_handle));
// update hub
if (auto impl = impl_object_.lock()) {
component->SetParentJobId(koid_);
impl->AddSubComponentHub(component->HubInfo());
}
ns_copy->NotifyComponentStarted(component->url(), component->label(),
component->hub_instance_id());
ComponentBridge* key = component.get();
components_.emplace(key, std::move(component));
runner_->StartComponent(std::move(package), std::move(startup_info),
std::move(remote_controller_request));
}
std::shared_ptr<ComponentBridge> RunnerHolder::ExtractComponent(ComponentBridge* controller) {
auto it = components_.find(controller);
if (it == components_.end()) {
return nullptr;
}
auto component = std::move(it->second);
component->NotifyStopped();
// update hub
if (auto impl = impl_object_.lock()) {
impl->RemoveSubComponentHub(component->HubInfo());
}
components_.erase(it);
return component;
}
} // namespace component