blob: bc295a57ca7b18f41868ae2c35e89e54b11531f3 [file] [log] [blame]
// 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/sysmgr/package_updating_loader.h"
#include <fcntl.h>
#include <fuchsia/io/cpp/fidl.h>
#include <lib/fit/function.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>
#include <string>
#include <utility>
#include <fbl/unique_fd.h>
#include "lib/fdio/fd.h"
#include "lib/zx/handle.h"
#include "src/lib/fsl/io/fd.h"
#include "src/lib/fsl/vmo/file.h"
#include "src/lib/fxl/strings/substitute.h"
#include "src/lib/pkg_url/url_resolver.h"
namespace sysmgr {
PackageUpdatingLoader::PackageUpdatingLoader(fuchsia::sys::ServiceProviderPtr service_provider,
async_dispatcher_t* dispatcher)
: service_provider_(std::move(service_provider)),
needs_reconnect_(true) {
PackageUpdatingLoader::~PackageUpdatingLoader() = default;
void PackageUpdatingLoader::Bind(fidl::InterfaceRequest<fuchsia::sys::Loader> request) {
bindings_.AddBinding(this, std::move(request), dispatcher_);
void PackageUpdatingLoader::LoadUrl(std::string url, LoadUrlCallback callback) {
// The updating loader can only update fuchsia-pkg URLs.
component::FuchsiaPkgUrl fuchsia_url;
if (!fuchsia_url.Parse(url)) {
FX_LOGS(ERROR) << "Invalid package URL " << url;
fuchsia::io::DirectoryPtr dir;
auto dir_request = dir.NewRequest(dispatcher_);
auto done_cb = [this, url, fuchsia_url, dir = std::move(dir), callback = std::move(callback)](
fuchsia::pkg::PackageResolver_Resolve_Result result) mutable {
if (result.is_err()) {
// TODO: only fail soft on NOT_FOUND?
FX_VLOGS(1) << "Package update failed with " << result.err()
<< ". Loading package without update: " << url;
PackageLoader::LoadUrl(url, std::move(callback));
fuchsia::sys::Package package;
package.resolved_url = fuchsia_url.ToString(); = dir.Unbind();
if (!fuchsia_url.resource_path().empty()) {
if (!component::LoadPackageResource(fuchsia_url.resource_path(), package)) {
FX_LOGS(ERROR) << "Could not load package resource " << fuchsia_url.resource_path()
<< " from " << fuchsia_url.ToString();
// TODO: if the resolver became unavailable in between the start of this
// method and the following call to Resolve, our reconnection logic won't have
// had a chance to execute, so we'll still block our client's request
// indefinitely. to resolve this we'll maybe need to change the API or undergo
// some more significant refactoring.
resolver_->Resolve(fuchsia_url.package_path(), std::move(dir_request), std::move(done_cb));
void PackageUpdatingLoader::EnsureConnectedToResolver() {
if (needs_reconnect_) {
// the error handler is consumed when an error is encountered, so if we
// need to reconnect then it means we need to reinstall the handler too
resolver_.set_error_handler([this](zx_status_t status) {
FX_LOGS(WARNING) << "Package resolver error handler triggered, marking "
"as needing reconnect. status="
<< status;
needs_reconnect_ = true;
needs_reconnect_ = false;
} // namespace sysmgr