| // 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 |