| // 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 "garnet/bin/appmgr/appmgr.h" |
| |
| #include <src/lib/fxl/strings/string_printf.h> |
| |
| #include "lib/sys/cpp/termination_reason.h" |
| |
| using fuchsia::sys::TerminationReason; |
| |
| namespace component { |
| namespace { |
| constexpr char kRootLabel[] = "app"; |
| 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_permanently_failed_(false), |
| storage_watchdog_(StorageWatchdog("/data", "/data/cache")) { |
| // 0. Start storage watchdog for cache storage |
| // TODO(CF-736): improve StorageWatchdog::GetStorageUsage and reenable |
| // storage_watchdog_.Run(dispatcher); |
| // 1. Create root realm. |
| RealmArgs realm_args = RealmArgs::Make( |
| nullptr, kRootLabel, "/data", "/data/cache", args.environment_services, |
| args.run_virtual_console, fuchsia::sys::EnvironmentOptions{}); |
| |
| root_realm_ = Realm::Create(std::move(realm_args)); |
| |
| FXL_CHECK(root_realm_) << "Cannot create root realm "; |
| |
| // 2. Publish outgoing directories. |
| // Publish the root realm's hub directory as 'hub/' and the first nested |
| // realm's (to be created by sysmgr) service directory as 'svc/'. |
| if (args.pa_directory_request != ZX_HANDLE_INVALID) { |
| auto svc = fbl::AdoptRef(new fs::Service([this](zx::channel channel) { |
| return root_realm_->BindFirstNestedRealmSvc(std::move(channel)); |
| })); |
| 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.reset(sysmgr_args_); |
| sysmgr_.events().OnTerminated = [this]( |
| zx_status_t status, |
| TerminationReason termination_reason) { |
| if (termination_reason != TerminationReason::EXITED) { |
| FXL_LOG(ERROR) << "sysmgr launch failed: " |
| << sys::TerminationReasonToString(termination_reason); |
| sysmgr_permanently_failed_ = true; |
| } else if (status == ZX_ERR_INVALID_ARGS) { |
| FXL_LOG(ERROR) << "sysmgr reported invalid arguments"; |
| sysmgr_permanently_failed_ = true; |
| } else { |
| FXL_LOG(ERROR) << "sysmgr exited with status " << status; |
| } |
| }; |
| root_realm_->CreateComponent(std::move(launch_info), sysmgr_.NewRequest()); |
| }; |
| |
| if (!args.retry_sysmgr_crash) { |
| 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_) { |
| FXL_LOG(ERROR) |
| << "sysmgr permanently failed. Check system configuration."; |
| return; |
| } |
| |
| auto delay_duration = sysmgr_backoff_.GetNext(); |
| FXL_LOG(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 |