blob: 599c296c517ee5e9403b1f6b2fe9ce1723617354 [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.
#include "garnet/bin/sysmgr/delegating_loader.h"
#include <lib/async/default.h>
#include "lib/fidl/cpp/clone.h"
#include "lib/svc/cpp/services.h"
namespace sysmgr {
namespace {
std::string GetScheme(const std::string& url) {
size_t pos = url.find(':');
if (pos == std::string::npos)
return std::string();
return url.substr(0, pos);
}
} // namespace
// static
std::unique_ptr<DelegatingLoader> DelegatingLoader::MakeWithParentFallback(
Config::ServiceMap delegates, fuchsia::sys::Launcher* delegate_launcher,
fuchsia::sys::LoaderPtr fallback) {
return std::unique_ptr<DelegatingLoader>(new DelegatingLoader(
std::move(delegates), delegate_launcher, std::move(fallback),
std::unordered_set<std::string>{}, nullptr));
}
// static
std::unique_ptr<DelegatingLoader>
DelegatingLoader::MakeWithPackageUpdatingFallback(
Config::ServiceMap delegates, fuchsia::sys::Launcher* delegate_launcher,
std::unordered_set<std::string> update_dependency_urls,
fuchsia::sys::ServiceProviderPtr env_services) {
return std::unique_ptr<DelegatingLoader>(new DelegatingLoader(
std::move(delegates), delegate_launcher, nullptr,
std::move(update_dependency_urls), std::move(env_services)));
}
DelegatingLoader::DelegatingLoader(
Config::ServiceMap delegates, fuchsia::sys::Launcher* delegate_launcher,
fuchsia::sys::LoaderPtr fallback,
std::unordered_set<std::string> update_dependency_urls,
fuchsia::sys::ServiceProviderPtr env_services)
: delegate_launcher_(delegate_launcher),
parent_fallback_(std::move(fallback)) {
for (auto& pair : delegates) {
auto& record = delegate_instances_[pair.second->url];
record.launch_info = std::move(pair.second);
delegates_by_scheme_[pair.first] = &record;
}
if (env_services) {
fuchsia::pkg::PackageResolverPtr resolver;
package_updating_fallback_ = std::make_unique<PackageUpdatingLoader>(
std::move(update_dependency_urls), std::move(env_services),
async_get_default_dispatcher());
}
}
DelegatingLoader::~DelegatingLoader() = default;
void DelegatingLoader::LoadUrl(std::string url, LoadUrlCallback callback) {
std::string scheme = GetScheme(url);
if (!scheme.empty()) {
auto it = delegates_by_scheme_.find(scheme);
if (it != delegates_by_scheme_.end()) {
auto* record = it->second;
if (!record->loader) {
StartDelegate(record);
}
record->loader->LoadUrl(url, std::move(callback));
return;
}
}
if (package_updating_fallback_) {
package_updating_fallback_->LoadUrl(url, std::move(callback));
} else {
parent_fallback_->LoadUrl(url, std::move(callback));
}
}
void DelegatingLoader::StartDelegate(LoaderRecord* record) {
component::Services services;
fuchsia::sys::LaunchInfo dup_launch_info;
dup_launch_info.url = record->launch_info->url;
fidl::Clone(record->launch_info->arguments, &dup_launch_info.arguments);
dup_launch_info.directory_request = services.NewRequest();
delegate_launcher_->CreateComponent(std::move(dup_launch_info),
record->controller.NewRequest());
record->loader = services.ConnectToService<fuchsia::sys::Loader>();
record->loader.set_error_handler([this, record](zx_status_t status) {
// proactively kill the loader app entirely if its Loader died on
// us
record->controller.Unbind();
});
}
} // namespace sysmgr