[sessionctl] Add ability to restart session
This uses basemgr to restart the current session by logging out the
current user. The authenticated user will be automatically logged back in.
TEST=manual: fx shell sessionctl restart_session
Change-Id: Iab5139b2ff5870d2d2d0a4d7e74bc275e3f2c5b9
diff --git a/bin/basemgr/basemgr_impl.cc b/bin/basemgr/basemgr_impl.cc
index 2d122a1..51ed71e 100644
--- a/bin/basemgr/basemgr_impl.cc
+++ b/bin/basemgr/basemgr_impl.cc
@@ -62,6 +62,11 @@
BasemgrImpl::~BasemgrImpl() = default;
+void BasemgrImpl::Connect(
+ fidl::InterfaceRequest<fuchsia::modular::internal::BasemgrDebug> request) {
+ basemgr_bindings_.AddBinding(this, std::move(request));
+}
+
void BasemgrImpl::InitializePresentation(
fidl::InterfaceHandle<fuchsia::ui::viewsv1token::ViewOwner> view_owner) {
if (settings_.test && !settings_.enable_presenter) {
@@ -251,13 +256,13 @@
// to.
user_provider_impl_.Teardown(kUserProviderTimeout, [this] {
FXL_DLOG(INFO) << "- fuchsia::modular::UserProvider down";
- StopTokenManagerFactoryApp()->Then([this] {
- FXL_DLOG(INFO) << "- fuchsia::auth::TokenManagerFactory down";
- StopBaseShell()->Then([this] {
- FXL_LOG(INFO) << "Clean Shutdown";
- on_shutdown_();
- });
+ StopTokenManagerFactoryApp()->Then([this] {
+ FXL_DLOG(INFO) << "- fuchsia::auth::TokenManagerFactory down";
+ StopBaseShell()->Then([this] {
+ FXL_LOG(INFO) << "Clean Shutdown";
+ on_shutdown_();
});
+ });
});
}
@@ -526,4 +531,6 @@
});
}
+void BasemgrImpl::RestartSession() { user_provider_impl_->RestartSession(); }
+
} // namespace modular
diff --git a/bin/basemgr/basemgr_impl.h b/bin/basemgr/basemgr_impl.h
index 6f4ad89..be0f6ee 100644
--- a/bin/basemgr/basemgr_impl.h
+++ b/bin/basemgr/basemgr_impl.h
@@ -40,6 +40,7 @@
// 3) Manages the lifecycle of sessions, represented as |sessionmgr| processes.
class BasemgrImpl : fuchsia::modular::BaseShellContext,
fuchsia::auth::AuthenticationContextProvider,
+ fuchsia::modular::internal::BasemgrDebug,
fuchsia::ui::policy::KeyboardCaptureListenerHACK,
modular::UserProviderImpl::Delegate {
public:
@@ -64,6 +65,9 @@
~BasemgrImpl() override;
+ void Connect(
+ fidl::InterfaceRequest<fuchsia::modular::internal::BasemgrDebug> request);
+
private:
void InitializePresentation(
fidl::InterfaceHandle<fuchsia::ui::viewsv1token::ViewOwner> view_owner);
@@ -127,6 +131,9 @@
// on initialization and every time the session shells are swapped.
void UpdateSessionShellConfig();
+ // |BasemgrDebug|
+ void RestartSession() override;
+
const modular::BasemgrSettings& settings_; // Not owned nor copied.
const std::vector<SessionShellSettings>& session_shell_settings_;
fuchsia::modular::AppConfig session_shell_config_;
@@ -145,6 +152,7 @@
AsyncHolder<UserProviderImpl> user_provider_impl_;
+ fidl::BindingSet<fuchsia::modular::internal::BasemgrDebug> basemgr_bindings_;
fidl::Binding<fuchsia::modular::BaseShellContext> base_shell_context_binding_;
fidl::Binding<fuchsia::auth::AuthenticationContextProvider>
authentication_context_provider_binding_;
diff --git a/bin/basemgr/main.cc b/bin/basemgr/main.cc
index cf22c78..e1b89be 100644
--- a/bin/basemgr/main.cc
+++ b/bin/basemgr/main.cc
@@ -27,6 +27,8 @@
return modular::InitializeCobalt(dispatcher, context);
};
+constexpr char kBasemgrDir[] = "basemgr";
+
int main(int argc, const char** argv) {
auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);
if (command_line.HasOption("help")) {
@@ -55,13 +57,23 @@
fuchsia::devicesettings::DeviceSettingsManagerPtr device_settings_manager;
context->ConnectToEnvironmentService(device_settings_manager.NewRequest());
- modular::BasemgrImpl basemgr(settings, session_shell_settings,
- context->launcher().get(), std::move(presenter),
- std::move(device_settings_manager),
- [&loop, &cobalt_cleanup] {
- cobalt_cleanup.call();
- loop.Quit();
- });
+ modular::BasemgrImpl basemgr(
+ settings, session_shell_settings, context->launcher().get(),
+ std::move(presenter), std::move(device_settings_manager),
+ [&loop, &cobalt_cleanup, &context] {
+ cobalt_cleanup.call();
+ context->outgoing().debug_dir()->RemoveEntry(kBasemgrDir);
+ loop.Quit();
+ });
+ context->outgoing().debug_dir()->AddEntry(
+ kBasemgrDir,
+ fbl::AdoptRef(new fs::Service([&basemgr](zx::channel channel) {
+ fidl::InterfaceRequest<fuchsia::modular::internal::BasemgrDebug>
+ request(std::move(channel));
+ basemgr.Connect(std::move(request));
+ return ZX_OK;
+ })));
+
loop.Run();
return 0;
diff --git a/bin/basemgr/user_provider_impl.cc b/bin/basemgr/user_provider_impl.cc
index 7b9475a..7bfb4e4 100644
--- a/bin/basemgr/user_provider_impl.cc
+++ b/bin/basemgr/user_provider_impl.cc
@@ -492,10 +492,10 @@
auto account_id = account ? account->id.get() : GetRandomId();
FXL_DLOG(INFO) << "Login() User:" << account_id;
- // Instead of passing token_manager_factory all the way to agents and
- // runners with all auth provider configurations, send two
- // |fuchsia::auth::TokenManager| handles, one for ledger and one for agents
- // for the given user account |account_id|.
+ // Instead of passing token_manager_factory all the way to agents and
+ // runners with all auth provider configurations, send two
+ // |fuchsia::auth::TokenManager| handles, one for ledger and one for agents
+ // for the given user account |account_id|.
fuchsia::auth::TokenManagerPtr ledger_token_manager =
CreateTokenManager(account_id);
fuchsia::auth::TokenManagerPtr agent_token_manager =
@@ -508,10 +508,10 @@
auto controller = std::make_unique<UserControllerImpl>(
launcher_, CloneStruct(sessionmgr_), CloneStruct(session_shell_),
- CloneStruct(story_shell_),
- std::move(ledger_token_manager), std::move(agent_token_manager),
- std::move(account), std::move(view_owner), std::move(service_provider),
- std::move(params.user_controller), [this](UserControllerImpl* c) {
+ CloneStruct(story_shell_), std::move(ledger_token_manager),
+ std::move(agent_token_manager), std::move(account), std::move(view_owner),
+ std::move(service_provider), std::move(params.user_controller),
+ [this](UserControllerImpl* c) {
user_controllers_.erase(c);
delegate_->DidLogout();
});
@@ -534,4 +534,20 @@
return user_controller->SwapSessionShell(std::move(session_shell_config));
}
+void UserProviderImpl::RestartSession() {
+ // Callback to log the user back in if login is not automatic
+ auto login = [this] {
+ if (user_controllers_.size() < 1 && users_storage_) {
+ auto account = Convert(users_storage_->users()->Get(0));
+
+ fuchsia::modular::UserLoginParams params;
+ params.account_id = account->id;
+ Login(std::move(params));
+ }
+ };
+
+ // Log the user out to shut down sessionmgr
+ user_controllers_.begin()->first->Logout(login);
+}
+
} // namespace modular
diff --git a/bin/basemgr/user_provider_impl.h b/bin/basemgr/user_provider_impl.h
index a7839ad..815315b 100644
--- a/bin/basemgr/user_provider_impl.h
+++ b/bin/basemgr/user_provider_impl.h
@@ -75,6 +75,10 @@
FuturePtr<> SwapSessionShell(
fuchsia::modular::AppConfig session_shell_config);
+ // Restarts the current session by logging out the current user and logging
+ // that user back in.
+ void RestartSession();
+
// |fuchsia::modular::UserProvider|, also called by |basemgr_impl|.
void Login(fuchsia::modular::UserLoginParams params) override;
diff --git a/bin/sessionctl/BUILD.gn b/bin/sessionctl/BUILD.gn
index 26c7fcd..7bdf776 100644
--- a/bin/sessionctl/BUILD.gn
+++ b/bin/sessionctl/BUILD.gn
@@ -20,6 +20,7 @@
"//garnet/public/lib/fxl",
"//peridot/lib/rapidjson",
"//peridot/public/fidl/fuchsia.modular",
+ "//peridot/public/fidl/fuchsia.modular.internal",
"//peridot/public/lib/async/cpp:future",
"//zircon/public/lib/async-loop-cpp",
"//zircon/public/lib/fdio",
@@ -45,6 +46,7 @@
deps = [
"//peridot/lib/rapidjson",
"//peridot/public/fidl/fuchsia.modular",
+ "//peridot/public/fidl/fuchsia.modular.internal",
"//peridot/public/lib/async/cpp:future",
"//zircon/public/lib/async-loop-cpp",
]
diff --git a/bin/sessionctl/main.cc b/bin/sessionctl/main.cc
index 900a4b9..4ee5456 100644
--- a/bin/sessionctl/main.cc
+++ b/bin/sessionctl/main.cc
@@ -11,6 +11,7 @@
#include <vector>
#include <fuchsia/modular/cpp/fidl.h>
+#include <fuchsia/modular/internal/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/future.h>
#include <lib/async/cpp/task.h>
@@ -28,44 +29,11 @@
using ::fuchsia::modular::PuppetMaster;
using ::fuchsia::modular::PuppetMasterPtr;
-struct ActiveSession {
+struct DebugService {
std::string name;
std::string service_path;
};
-void FindSessionsForPath(const char* glob_str, const char* regex_str,
- std::vector<ActiveSession>* sessions) {
- glob_t globbuf;
- bool sessionmgr_exists = glob(glob_str, 0, nullptr, &globbuf) == 0;
- std::regex name_regex(regex_str);
- if (sessionmgr_exists) {
- for (size_t i = 0; i < globbuf.gl_pathc; ++i) {
- ActiveSession s;
- s.service_path = globbuf.gl_pathv[i];
- std::smatch match;
- FXL_CHECK(std::regex_search(s.service_path, match, name_regex))
- << s.service_path;
- s.name = match[1];
- sessions->push_back(std::move(s));
- }
- globfree(&globbuf);
- }
-}
-
-// Returns a list of all running sessions.
-std::vector<ActiveSession> FindAllSessions() {
- const char kRegex[] = "/sessionmgr.cmx/(\\d+)";
- // See peridot/bin/sessionmgr/sessionmgr_impl.cc's definition of
- // kSessionCtlDir for "sessionctl". These must match.
- std::vector<ActiveSession> sessions;
- FindSessionsForPath("/hub/c/sessionmgr.cmx/*/out/debug/sessionctl", kRegex,
- &sessions);
-
- FindSessionsForPath("/hub/r/sys/*/c/sessionmgr.cmx/*/out/debug/sessionctl",
- kRegex, &sessions);
- return sessions;
-}
-
std::string GetUsage() {
return R"(sessionctl <flags> <command> <argument>
Example:
@@ -124,10 +92,47 @@
The name of the story.
list_stories
- List all the stories in the current session.)";
+ List all the stories in the current session.
+
+restart_session
+ Restarts the current session.)";
}
-PuppetMasterPtr ConnectToPuppetMaster(const ActiveSession& session) {
+void FindDebugServicesForPath(const char* glob_str, const char* regex_str,
+ std::vector<DebugService>* services) {
+ glob_t globbuf;
+ bool service_exists = glob(glob_str, 0, nullptr, &globbuf) == 0;
+ std::regex name_regex(regex_str);
+ if (service_exists) {
+ for (size_t i = 0; i < globbuf.gl_pathc; ++i) {
+ DebugService s;
+ s.service_path = globbuf.gl_pathv[i];
+ std::smatch match;
+ FXL_CHECK(std::regex_search(s.service_path, match, name_regex))
+ << s.service_path;
+ s.name = match[1];
+ services->push_back(std::move(s));
+ }
+ globfree(&globbuf);
+ }
+}
+
+// Returns a list of all running sessions.
+std::vector<DebugService> FindAllSessions() {
+ const char kRegex[] = "/sessionmgr.cmx/(\\d+)";
+ // See peridot/bin/sessionmgr/sessionmgr_impl.cc's definition of
+ // kSessionCtlDir for "sessionctl". These must match.
+ std::vector<DebugService> sessions;
+ FindDebugServicesForPath("/hub/c/sessionmgr.cmx/*/out/debug/sessionctl",
+ kRegex, &sessions);
+
+ FindDebugServicesForPath(
+ "/hub/r/sys/*/c/sessionmgr.cmx/*/out/debug/sessionctl", kRegex,
+ &sessions);
+ return sessions;
+}
+
+PuppetMasterPtr ConnectToPuppetMaster(const DebugService& session) {
PuppetMasterPtr puppet_master;
auto request = puppet_master.NewRequest().TakeChannel();
std::string service_path = session.service_path + "/" + PuppetMaster::Name_;
@@ -138,6 +143,25 @@
return puppet_master;
}
+fuchsia::modular::internal::BasemgrDebugPtr ConnectToBasemgr() {
+ fuchsia::modular::internal::BasemgrDebugPtr basemgr;
+ auto request = basemgr.NewRequest().TakeChannel();
+
+ std::vector<DebugService> services;
+ FindDebugServicesForPath("/hub/c/basemgr/*/out/debug/basemgr", "basemgr",
+ &services);
+ // There should only be one basemgr
+ FXL_CHECK(services.size() == 1);
+
+ std::string service_path = services[0].service_path;
+ if (fdio_service_connect(service_path.c_str(), request.get()) != ZX_OK) {
+ FXL_LOG(FATAL) << "Could not connect to basemgr service in "
+ << service_path;
+ }
+
+ return basemgr;
+}
+
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToThread);
@@ -165,10 +189,13 @@
std::cout << std::endl;
}
+ auto basemgr = ConnectToBasemgr();
+
// To get a PuppetMaster service for a session, use the following code:
PuppetMasterPtr puppet_master = ConnectToPuppetMaster(sessions[0]);
- modular::SessionCtlApp app(puppet_master.get(), logger, loop.dispatcher(),
- [&loop] { loop.Quit(); });
+
+ modular::SessionCtlApp app(basemgr.get(), puppet_master.get(), logger,
+ loop.dispatcher(), [&loop] { loop.Quit(); });
std::string parsing_error = app.ExecuteCommand(cmd, command_line);
if (parsing_error == modular::kGetUsageErrorString) {
diff --git a/bin/sessionctl/session_ctl_app.cc b/bin/sessionctl/session_ctl_app.cc
index f05a8e6..e9ffbb6 100644
--- a/bin/sessionctl/session_ctl_app.cc
+++ b/bin/sessionctl/session_ctl_app.cc
@@ -8,10 +8,12 @@
namespace modular {
SessionCtlApp::SessionCtlApp(
+ fuchsia::modular::internal::BasemgrDebug* const basemgr,
fuchsia::modular::PuppetMaster* const puppet_master,
const modular::Logger& logger, async_dispatcher_t* const dispatcher,
const std::function<void()>& on_command_executed)
- : puppet_master_(puppet_master),
+ : basemgr_(basemgr),
+ puppet_master_(puppet_master),
logger_(logger),
dispatcher_(dispatcher),
on_command_executed_(on_command_executed) {}
@@ -26,6 +28,8 @@
return ExecuteDeleteStoryCommand(command_line);
} else if (cmd == kListStoriesCommandString) {
return ExecuteListStoriesCommand();
+ } else if (cmd == kRestartSessionCommandString) {
+ return ExecuteRestartSessionCommand();
} else {
return kGetUsageErrorString;
}
@@ -142,6 +146,14 @@
return "";
}
+std::string SessionCtlApp::ExecuteRestartSessionCommand() {
+ basemgr_->RestartSession();
+ logger_.Log(kRestartSessionCommandString, nullptr);
+ on_command_executed_();
+
+ return "";
+}
+
fuchsia::modular::StoryCommand SessionCtlApp::MakeFocusStoryCommand() {
fuchsia::modular::StoryCommand command;
fuchsia::modular::SetFocusState set_focus_state;
@@ -240,16 +252,4 @@
return fut;
}
-std::string SessionCtlApp::GenerateMissingFlagString(
- const std::vector<std::string>& missing_flags) {
- std::string error;
- if (!missing_flags.empty()) {
- error += "flags missing:";
- for (auto flag : missing_flags) {
- error += " --" + flag;
- }
- }
- return error;
-}
-
} // namespace modular
diff --git a/bin/sessionctl/session_ctl_app.h b/bin/sessionctl/session_ctl_app.h
index 58e39e0..20fabb9 100644
--- a/bin/sessionctl/session_ctl_app.h
+++ b/bin/sessionctl/session_ctl_app.h
@@ -9,6 +9,7 @@
#include <string>
#include <fuchsia/modular/cpp/fidl.h>
+#include <fuchsia/modular/internal/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/future.h>
#include <lib/async/cpp/task.h>
@@ -26,29 +27,32 @@
public:
// Constructs a SessionCtlApp which can read and execute session commands.
// |puppet_master| The interface used to execute commands.
+ // |basemgr| The basemgr to use to restart sessions.
// |command_line| The command line used to read commands and arguments.
// |logger| The logger used to log the results of commands.
// |dispatcher| The dispatcher which is used to post the command tasks.
// |on_command_executed| A callback which is called whenever a command has
// finished executing.
- explicit SessionCtlApp(fuchsia::modular::PuppetMaster* const puppet_master,
- const modular::Logger& logger,
- async_dispatcher_t* const dispatcher,
- const std::function<void()>& on_command_executed);
+ explicit SessionCtlApp(
+ fuchsia::modular::internal::BasemgrDebug* const basemgr,
+ fuchsia::modular::PuppetMaster* const puppet_master,
+ const modular::Logger& logger, async_dispatcher_t* const dispatcher,
+ const std::function<void()>& on_command_executed);
// Dispatches the |cmd| and returns an empty string on success, "GetUsage" if
// |cmd| is not valid, and a string of missing flags on failure.
std::string ExecuteCommand(std::string cmd,
const fxl::CommandLine& command_line);
+ private:
// Executes the respective command and returns an empty string on success and
// a string of missing flags on failure.
std::string ExecuteAddModCommand(const fxl::CommandLine& command_line);
std::string ExecuteRemoveModCommand(const fxl::CommandLine& command_line);
std::string ExecuteDeleteStoryCommand(const fxl::CommandLine& command_line);
std::string ExecuteListStoriesCommand();
+ std::string ExecuteRestartSessionCommand();
- private:
// Focus the story to which the mod we are adding belongs.
fuchsia::modular::StoryCommand MakeFocusStoryCommand();
@@ -82,6 +86,7 @@
std::string GenerateMissingFlagString(
const std::vector<std::string>& missing_flags);
+ fuchsia::modular::internal::BasemgrDebug* const basemgr_;
fuchsia::modular::PuppetMaster* const puppet_master_;
fuchsia::modular::StoryPuppetMasterPtr story_puppet_master_;
const fxl::CommandLine command_line_;
diff --git a/bin/sessionctl/session_ctl_app_unittest.cc b/bin/sessionctl/session_ctl_app_unittest.cc
index e40575c..2b998e5 100644
--- a/bin/sessionctl/session_ctl_app_unittest.cc
+++ b/bin/sessionctl/session_ctl_app_unittest.cc
@@ -37,8 +37,8 @@
SessionCtlApp CreateSessionCtl(fxl::CommandLine command_line) {
logger_ =
std::make_unique<Logger>(command_line.HasOption(kJsonOutFlagString));
- SessionCtlApp sessionctl(puppet_master_impl_.get(), *(logger_.get()),
- async_get_default_dispatcher(),
+ SessionCtlApp sessionctl(nullptr /* basemgr */, puppet_master_impl_.get(),
+ *(logger_.get()), async_get_default_dispatcher(),
[&] { done_ = true; });
return sessionctl;
}
diff --git a/bin/sessionctl/session_ctl_constants.h b/bin/sessionctl/session_ctl_constants.h
index 890a223..9bcc580 100644
--- a/bin/sessionctl/session_ctl_constants.h
+++ b/bin/sessionctl/session_ctl_constants.h
@@ -12,6 +12,7 @@
constexpr char kDeleteStoryCommandString[] = "delete_story";
constexpr char kRemoveModCommandString[] = "remove_mod";
constexpr char kListStoriesCommandString[] = "list_stories";
+constexpr char kRestartSessionCommandString[] = "restart_session";
// Flags to pass to SessionCtlApp.
constexpr char kJsonOutFlagString[] = "json_out";
diff --git a/public/fidl/fuchsia.modular.internal/BUILD.gn b/public/fidl/fuchsia.modular.internal/BUILD.gn
index 06a0781..3391903 100644
--- a/public/fidl/fuchsia.modular.internal/BUILD.gn
+++ b/public/fidl/fuchsia.modular.internal/BUILD.gn
@@ -8,6 +8,7 @@
cpp_legacy_callbacks = true
sources = [
+ "basemgr_debug.fidl",
"sessionmgr.fidl",
"story_data.fidl",
]
diff --git a/public/fidl/fuchsia.modular.internal/basemgr_debug.fidl b/public/fidl/fuchsia.modular.internal/basemgr_debug.fidl
new file mode 100644
index 0000000..91efe4d
--- /dev/null
+++ b/public/fidl/fuchsia.modular.internal/basemgr_debug.fidl
@@ -0,0 +1,12 @@
+// 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.
+
+library fuchsia.modular.internal;
+
+// A debug interface exposed by `basemgr` to allow developer tools to control
+// state within the `basemgr` process.
+[Discoverable]
+interface BasemgrDebug {
+ RestartSession();
+};