blob: d81d8dc09cbc6b082b0a47e451c07efdbcdf547e [file] [log] [blame]
// Copyright 2018 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/appmgr.h"
#include "fcntl.h"
#include "lib/fdio/directory.h"
#include "lib/sys/cpp/termination_reason.h"
#include "src/lib/fxl/strings/string_printf.h"
using fuchsia::sys::TerminationReason;
namespace component {
namespace {
constexpr zx::duration kMinSmsmgrBackoff = zx::msec(200);
constexpr zx::duration kMaxSysmgrBackoff = zx::sec(15);
constexpr zx::duration kSysmgrAliveReset = zx::sec(5);
} // namespace
Appmgr::Appmgr(async_dispatcher_t* dispatcher, AppmgrArgs args)
: publish_vfs_(dispatcher),
publish_dir_(fbl::AdoptRef(new fs::PseudoDir())),
sysmgr_url_(std::move(args.sysmgr_url)),
sysmgr_args_(std::move(args.sysmgr_args)),
sysmgr_backoff_(kMinSmsmgrBackoff, kMaxSysmgrBackoff, kSysmgrAliveReset),
sysmgr_retry_crashes_(args.retry_sysmgr_crash),
sysmgr_permanently_failed_(false),
storage_watchdog_(StorageWatchdog("/data", "/data/cache")) {
// 0. Start storage watchdog for cache storage
storage_watchdog_.Run(dispatcher);
// 1. Create root realm.
fxl::UniqueFD appmgr_config_dir(open("/pkgfs/packages/config-data/0/data/appmgr", O_RDONLY));
RealmArgs realm_args = RealmArgs::MakeWithAdditionalServices(
nullptr, internal::kRootLabel, "/data", "/data/cache", "/tmp",
std::move(args.environment_services), args.run_virtual_console,
std::move(args.root_realm_services), fuchsia::sys::EnvironmentOptions{},
std::move(appmgr_config_dir));
root_realm_ = Realm::Create(std::move(realm_args));
FX_CHECK(root_realm_) << "Cannot create root realm ";
// 2. Publish outgoing directories.
// Connect to the tracing service, and then publish the root realm's hub
// directory as 'hub/' and the first nested realm's (to be created by sysmgr)
// service directory as 'svc/'.
zx::channel svc_client_chan, svc_server_chan;
zx_status_t status = zx::channel::create(0, &svc_client_chan, &svc_server_chan);
if (status != ZX_OK) {
FX_LOGS(ERROR) << "failed to create channel: " << status;
return;
}
status = root_realm_->BindFirstNestedRealmSvc(std::move(svc_server_chan));
if (status != ZX_OK) {
FX_LOGS(ERROR) << "failed to bind to root realm services: " << status;
return;
}
status = fdio_service_connect_at(svc_client_chan.get(), "fuchsia.tracing.provider.Registry",
args.trace_server_channel.release());
if (status != ZX_OK) {
FX_LOGS(ERROR) << "failed to connect to tracing: " << status;
// In test environments the tracing registry may not be available. If this
// fails, let's still proceed.
}
if (args.pa_directory_request != ZX_HANDLE_INVALID) {
auto svc = fbl::AdoptRef(new fs::RemoteDir(std::move(svc_client_chan)));
publish_dir_->AddEntry("hub", root_realm_->hub_dir());
publish_dir_->AddEntry("svc", svc);
publish_vfs_.ServeDirectory(publish_dir_, zx::channel(args.pa_directory_request));
}
// 3. Run sysmgr
auto run_sysmgr = [this] {
sysmgr_backoff_.Start();
fuchsia::sys::LaunchInfo launch_info;
launch_info.url = sysmgr_url_;
launch_info.arguments = fidl::Clone(sysmgr_args_);
sysmgr_.events().OnTerminated = [this](zx_status_t status,
TerminationReason termination_reason) {
if (termination_reason != TerminationReason::EXITED) {
FX_LOGS(ERROR) << "sysmgr launch failed: "
<< sys::TerminationReasonToString(termination_reason);
sysmgr_permanently_failed_ = true;
} else if (status == ZX_ERR_INVALID_ARGS) {
FX_LOGS(ERROR) << "sysmgr reported invalid arguments";
sysmgr_permanently_failed_ = true;
} else {
FX_LOGS(ERROR) << "sysmgr exited with status " << status;
}
if (!sysmgr_retry_crashes_) {
FX_CHECK(ZX_OK == status) << "sysmgr retries are disabled and it failed ("
<< sys::TerminationReasonToString(termination_reason)
<< ", status " << status << ")";
}
};
root_realm_->CreateComponent(std::move(launch_info), sysmgr_.NewRequest());
};
if (!sysmgr_retry_crashes_) {
run_sysmgr();
return;
}
async::PostTask(dispatcher, [this, dispatcher, run_sysmgr] {
run_sysmgr();
auto retry_handler = [this, dispatcher, run_sysmgr](zx_status_t error) {
if (sysmgr_permanently_failed_) {
FX_LOGS(ERROR) << "sysmgr permanently failed. Check system configuration.";
return;
}
auto delay_duration = sysmgr_backoff_.GetNext();
FX_LOGS(ERROR) << fxl::StringPrintf("sysmgr failed, restarting in %.3fs",
.001f * delay_duration.to_msecs());
async::PostDelayedTask(dispatcher, run_sysmgr, delay_duration);
};
sysmgr_.set_error_handler(retry_handler);
});
}
Appmgr::~Appmgr() = default;
} // namespace component