blob: 90640f323c6e18d146f562ef147881b0235701b6 [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/modular/bin/basemgr/session_context_impl.h"
#include <lib/syslog/cpp/macros.h>
#include "src/modular/bin/basemgr/sessions.h"
#include "src/modular/lib/common/async_holder.h"
#include "src/modular/lib/common/teardown.h"
#include "src/modular/lib/modular_config/modular_config_constants.h"
#include "src/modular/lib/pseudo_dir/pseudo_dir_utils.h"
namespace modular {
SessionContextImpl::SessionContextImpl(
fuchsia::sys::Launcher* const launcher, fuchsia::sys::Environment* const base_environment,
fuchsia::modular::session::AppConfig sessionmgr_app_config,
const modular::ModularConfigAccessor* const config_accessor,
fuchsia::ui::views::ViewToken view_token,
fuchsia::sys::ServiceListPtr additional_services_for_sessionmgr,
fuchsia::sys::ServiceList additional_services_for_agents,
GetPresentationCallback get_presentation, OnSessionShutdownCallback on_session_shutdown)
: session_context_binding_(this),
get_presentation_(std::move(get_presentation)),
on_session_shutdown_(std::move(on_session_shutdown)),
weak_factory_(this) {
FX_CHECK(get_presentation_);
FX_CHECK(on_session_shutdown_);
// Delete all existing sessions that have been created with a random ID.
// TODO(fxbug.dev/51752): Remove once there are no sessions with random IDs in use
sessions::DeleteSessionsWithRandomIds(base_environment);
// Determine an ID for the new session and report that it was created to Cobalt.
const auto use_random_id = config_accessor->use_random_session_id();
if (use_random_id) {
FX_LOGS(WARNING) << "DEPRECATED! Starting session with random session ID.";
} else {
FX_LOGS(INFO) << "Starting session with stable session ID.";
}
std::string session_id =
use_random_id ? sessions::GetRandomSessionId() : sessions::GetStableSessionId();
sessions::ReportNewSessionToCobalt(session_id);
// Generate the path to map '/data' for the sessionmgr we are starting
auto data_origin = sessions::GetSessionDirectory(session_id);
// Create a PseudoDir containing startup.config. This directory will be injected into
// sessionmgr's namespace and sessionmgr will read its configurations from there.
auto config_namespace = CreateAndServeConfigNamespace(config_accessor->GetConfigAsJsonString());
// Launch Sessionmgr in the current environment.
sessionmgr_app_ = std::make_unique<AppClient<fuchsia::modular::Lifecycle>>(
launcher, std::move(sessionmgr_app_config), data_origin,
std::move(additional_services_for_sessionmgr), std::move(config_namespace));
// Initialize the Sessionmgr service.
sessionmgr_app_->services().ConnectToService(sessionmgr_.NewRequest());
sessionmgr_->Initialize(session_id, session_context_binding_.NewBinding(),
std::move(additional_services_for_agents), std::move(view_token));
sessionmgr_app_->SetAppErrorHandler([weak_this = weak_factory_.GetWeakPtr()] {
FX_LOGS(ERROR) << "Sessionmgr seems to have crashed unexpectedly. "
<< "Calling on_session_shutdown_().";
// This prevents us from receiving any further requests.
weak_this->session_context_binding_.Unbind();
// Shutdown(), which expects a graceful shutdown of sessionmgr, does not
// apply here because sessionmgr crashed. Move |on_session_shutdown_| on to the stack before
// invoking it, in case the |on_session_shutdown_| deletes |this|.
auto on_session_shutdown = std::move(weak_this->on_session_shutdown_);
on_session_shutdown(ShutDownReason::CRITICAL_FAILURE);
// Don't touch |this|.
});
}
fuchsia::sys::FlatNamespacePtr SessionContextImpl::CreateAndServeConfigNamespace(
std::string config_contents) {
zx::channel config_request_channel;
zx::channel config_dir_channel;
FX_CHECK(zx::channel::create(0u, &config_request_channel, &config_dir_channel) == ZX_OK);
// Host the config file in a PseudoDir
config_dir_ = modular::MakeFilePathWithContents(modular_config::kStartupConfigFilePath,
std::move(config_contents));
config_dir_->Serve(fuchsia::io::OPEN_RIGHT_READABLE, std::move(config_request_channel));
auto flat_namespace = fuchsia::sys::FlatNamespace::New();
flat_namespace->paths.push_back(modular_config::kOverriddenConfigDir);
flat_namespace->directories.push_back(std::move(config_dir_channel));
return flat_namespace;
}
void SessionContextImpl::Shutdown(ShutDownReason reason, fit::function<void()> callback) {
shutdown_callbacks_.push_back(std::move(callback));
if (shutdown_callbacks_.size() > 1) {
FX_LOGS(INFO) << "fuchsia::modular::internal::SessionContext::Shutdown() "
"already called, queuing callback while shutdown is in progress.";
return;
}
// Close the SessionContext channel to ensure no more requests from the
// channel are processed.
session_context_binding_.Unbind();
sessionmgr_app_->Teardown(kSessionmgrTimeout, [weak_this = weak_factory_.GetWeakPtr(), reason] {
// One of the callbacks might delete |SessionContextImpl|, so always guard against
// WeakPtr<SessionContextImpl>.
for (const auto& callback : weak_this->shutdown_callbacks_) {
callback();
if (!weak_this) {
return;
}
}
auto on_session_shutdown = std::move(weak_this->on_session_shutdown_);
on_session_shutdown(reason);
});
}
void SessionContextImpl::GetPresentation(
fidl::InterfaceRequest<fuchsia::ui::policy::Presentation> request) {
get_presentation_(std::move(request));
}
void SessionContextImpl::Restart() {
Shutdown(ShutDownReason::CLIENT_REQUEST, [] {});
}
void SessionContextImpl::RestartDueToCriticalFailure() {
Shutdown(ShutDownReason::CRITICAL_FAILURE, [] {});
}
} // namespace modular