| // 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 "peridot/bin/basemgr/session_context_impl.h" |
| |
| #include <fcntl.h> |
| #include <lib/fidl/cpp/synchronous_interface_ptr.h> |
| #include <lib/fsl/io/fd.h> |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "peridot/lib/common/async_holder.h" |
| #include "peridot/lib/common/teardown.h" |
| #include "peridot/lib/fidl/array_to_string.h" |
| #include "peridot/lib/modular_config/modular_config_constants.h" |
| #include "src/lib/files/directory.h" |
| #include "src/lib/files/unique_fd.h" |
| |
| namespace modular { |
| |
| SessionContextImpl::SessionContextImpl( |
| fuchsia::sys::Launcher* const launcher, std::string session_id, |
| fuchsia::modular::AppConfig sessionmgr_config, |
| fuchsia::modular::AppConfig session_shell_config, |
| fuchsia::modular::AppConfig story_shell_config, |
| bool use_session_shell_for_story_shell_factory, |
| fidl::InterfaceHandle<fuchsia::auth::TokenManager> ledger_token_manager, |
| fidl::InterfaceHandle<fuchsia::auth::TokenManager> agent_token_manager, |
| fuchsia::modular::auth::AccountPtr account, |
| fuchsia::ui::views::ViewToken view_token, |
| 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)) { |
| FXL_CHECK(get_presentation_); |
| FXL_CHECK(on_session_shutdown_); |
| |
| // TODO(MF-280): We should replace USER* with SESSION* below. However, this |
| // will lose existing user data, so the timing needs to be considered. |
| // 0. Generate the path to map '/data' for the sessionmgr we are starting. |
| std::string data_origin = std::string("/data/modular/USER_") + session_id; |
| |
| FXL_LOG(INFO) << "SESSIONMGR DATA ORIGIN IS " << data_origin; |
| |
| // 1. Create a PseudoDir containing startup.config. This directory will be |
| // injected into sessionmgr's namespace and sessionmgr will read its |
| // configurations from there. |
| auto flat_namespace = MakeConfigNamespace(); |
| |
| // 2. Launch Sessionmgr in the current environment. |
| sessionmgr_app_ = std::make_unique<AppClient<fuchsia::modular::Lifecycle>>( |
| launcher, std::move(sessionmgr_config), data_origin, |
| /* additional_services= */ nullptr, std::move(flat_namespace)); |
| |
| // 3. Initialize the Sessionmgr service. |
| sessionmgr_app_->services().ConnectToService(sessionmgr_.NewRequest()); |
| sessionmgr_->Initialize( |
| session_id, std::move(account), std::move(session_shell_config), |
| std::move(story_shell_config), use_session_shell_for_story_shell_factory, |
| std::move(ledger_token_manager), std::move(agent_token_manager), |
| session_context_binding_.NewBinding(), std::move(view_token)); |
| |
| sessionmgr_app_->SetAppErrorHandler([this] { |
| FXL_LOG(ERROR) << "Sessionmgr seems to have crashed unexpectedly. " |
| << "Calling on_session_shutdown_()."; |
| // This prevents us from receiving any further requests. |
| session_context_binding_.Unbind(); |
| |
| // Shutdown(), which expects a graceful shutdown of sessionmgr, does not |
| // apply here because sessionmgr crashed. Just run |on_session_shutdown_| |
| // directly. |
| on_session_shutdown_(/* logout_users= */ false); |
| }); |
| } |
| |
| fuchsia::sys::FlatNamespacePtr SessionContextImpl::MakeConfigNamespace() { |
| // Determine where basemgr is reading configs from |
| std::string config_dir = modular_config::kOverriddenConfigDir; |
| if (!files::IsDirectory(config_dir)) { |
| config_dir = modular_config::kDefaultConfigDir; |
| if (!files::IsDirectory(config_dir)) { |
| return nullptr; |
| } |
| } |
| // Clone basemgr's config directory. |
| fxl::UniqueFD dir(open(config_dir.c_str(), O_DIRECTORY | O_RDONLY)); |
| auto flat_namespace = fuchsia::sys::FlatNamespace::New(); |
| flat_namespace->paths.push_back(modular_config::kOverriddenConfigDir); |
| flat_namespace->directories.push_back( |
| fsl::CloneChannelFromFileDescriptor(dir.get())); |
| return flat_namespace; |
| } |
| |
| // TODO(MF-120): Replace method in favor of letting sessionmgr launch base |
| // shell via SessionUserProvider. |
| void SessionContextImpl::Shutdown(bool logout_users, |
| fit::function<void()> callback) { |
| shutdown_callbacks_.push_back(std::move(callback)); |
| if (shutdown_callbacks_.size() > 1) { |
| FXL_LOG(INFO) |
| << "fuchsia::modular::internal::SessionContext::Shutdown() " |
| "already called, queuing callback while shutdown is in progress."; |
| return; |
| } |
| |
| // This should prevent us from receiving any further requests. |
| session_context_binding_.Unbind(); |
| |
| sessionmgr_app_->Teardown(kSessionmgrTimeout, [this, logout_users] { |
| for (const auto& callback : shutdown_callbacks_) { |
| callback(); |
| } |
| |
| on_session_shutdown_(logout_users); |
| }); |
| } |
| |
| void SessionContextImpl::GetPresentation( |
| fidl::InterfaceRequest<fuchsia::ui::policy::Presentation> request) { |
| get_presentation_(std::move(request)); |
| } |
| |
| FuturePtr<> SessionContextImpl::SwapSessionShell( |
| fuchsia::modular::AppConfig session_shell_config) { |
| auto future = Future<>::Create("SwapSessionShell"); |
| sessionmgr_->SwapSessionShell(std::move(session_shell_config), |
| future->Completer()); |
| return future; |
| } |
| |
| void SessionContextImpl::Logout() { |
| Shutdown(/* logout_users= */ true, [] {}); |
| } |
| |
| void SessionContextImpl::Shutdown() { |
| Shutdown(/* logout_users= */ false, [] {}); |
| } |
| |
| } // namespace modular |