[sessionctl] Enable logging in a guest user.

This allows users to log in a guest user by running
fx shell sessionctl login_guest

TEST=manual: fx shell sessionctl login_guest
MF-172 #comment Enable logging in a guest user.

Change-Id: I9923a8638b6e821b97e1f0a2dd8196679b7b1d38
diff --git a/bin/basemgr/basemgr_impl.cc b/bin/basemgr/basemgr_impl.cc
index 00bd8df..faa5a8e 100644
--- a/bin/basemgr/basemgr_impl.cc
+++ b/bin/basemgr/basemgr_impl.cc
@@ -512,8 +512,7 @@
               });
 
           user_provider_impl_->PreviousUsers(
-              [this](
-                  std::vector<fuchsia::modular::auth::Account> accounts) {
+              [this](std::vector<fuchsia::modular::auth::Account> accounts) {
                 std::vector<FuturePtr<>> did_remove_users;
                 did_remove_users.reserve(accounts.size());
 
@@ -544,4 +543,9 @@
 
 void BasemgrImpl::RestartSession() { user_provider_impl_->RestartSession(); }
 
+void BasemgrImpl::LoginAsGuest() {
+  fuchsia::modular::UserLoginParams params;
+  user_provider_impl_->Login(std::move(params));
+}
+
 }  // namespace modular
diff --git a/bin/basemgr/basemgr_impl.h b/bin/basemgr/basemgr_impl.h
index be0f6ee..5ed6d84 100644
--- a/bin/basemgr/basemgr_impl.h
+++ b/bin/basemgr/basemgr_impl.h
@@ -134,6 +134,9 @@
   // |BasemgrDebug|
   void RestartSession() override;
 
+  // |BasemgrDebug|
+  void LoginAsGuest() override;
+
   const modular::BasemgrSettings& settings_;  // Not owned nor copied.
   const std::vector<SessionShellSettings>& session_shell_settings_;
   fuchsia::modular::AppConfig session_shell_config_;
diff --git a/bin/sessionctl/logger.cc b/bin/sessionctl/logger.cc
index 5caa25b..9cfca00 100644
--- a/bin/sessionctl/logger.cc
+++ b/bin/sessionctl/logger.cc
@@ -61,8 +61,7 @@
 }
 
 std::string Logger::GenerateJsonLogString(
-    const std::string& command,
-    const std::vector<std::string>& params) const {
+    const std::string& command, const std::vector<std::string>& params) const {
   rapidjson::Document document = GetDocument(command);
 
   // Generate array of |params| strings.
diff --git a/bin/sessionctl/main.cc b/bin/sessionctl/main.cc
index ce19a09..792a674 100644
--- a/bin/sessionctl/main.cc
+++ b/bin/sessionctl/main.cc
@@ -5,9 +5,11 @@
 #include <dirent.h>
 #include <glob.h>
 #include <sys/types.h>
+#include <chrono>
 #include <iostream>
 #include <regex>
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <fuchsia/modular/cpp/fidl.h>
@@ -94,6 +96,9 @@
 list_stories
   List all the stories in the current session.
 
+login_guest
+  Logs in a guest user.
+
 restart_session
   Restarts the current session.)";
 }
@@ -170,6 +175,46 @@
   return basemgr;
 }
 
+// Returns true if a guest user was logged in.
+bool LoginAsGuest(bool has_running_sessions,
+                  fuchsia::modular::internal::BasemgrDebug* basemgr,
+                  modular::Logger logger) {
+  if (has_running_sessions) {
+    logger.LogError(modular::kLoginGuestCommandString,
+                    "A user is already logged in. You may log a guest user out "
+                    "by running 'sessionctl restart_session' or you may issue "
+                    "any other sessionctl command.");
+    return false;
+  }
+
+  basemgr->LoginAsGuest();
+  logger.Log(modular::kLoginGuestCommandString, std::vector<std::string>());
+  return true;
+}
+
+// Returns true if a guest user was logged in.
+bool LoginDefaultGuestUser(fuchsia::modular::internal::BasemgrDebug* basemgr,
+                           modular::Logger logger,
+                           std::vector<DebugService>* sessions,
+                           std::string cmd) {
+  std::cout << "Logging in as a guest user in the absence of running sessions."
+            << std::endl;
+  LoginAsGuest(/*has_running_sessions=*/false, basemgr, logger);
+
+  // Wait 2 seconds to allow sessionmgr to initialize
+  std::this_thread::sleep_for(std::chrono::seconds(2));
+  std::cout << "Finding sessions..." << std::endl;
+  *sessions = FindAllSessions();
+
+  if (sessions->empty()) {
+    logger.LogError(cmd,
+                    "Unable find a running session after logging in. "
+                    "Please try your command again.");
+    return false;
+  }
+  return true;
+}
+
 int main(int argc, const char** argv) {
   async::Loop loop(&kAsyncLoopConfigAttachToThread);
 
@@ -188,12 +233,25 @@
   }
 
   auto sessions = FindAllSessions();
-  if (sessions.empty()) {
-    logger.LogError(
-        cmd, "Could not find a running sessionmgr. Is the user logged in?");
+
+  // Continue with log in flow if user issued a login_guest command
+  if (cmd == modular::kLoginGuestCommandString) {
+    if (LoginAsGuest(/*has_running_sessions=*/!sessions.empty(), basemgr.get(),
+                     logger)) {
+      return 0;
+    }
     return 1;
   }
 
+  // Log in a guest user if no session is found before continuing to execute
+  // the requested command
+  if (sessions.empty()) {
+    // Exit here if no sessions were found after logging in a guest user
+    if (!LoginDefaultGuestUser(basemgr.get(), logger, &sessions, cmd)) {
+      return 1;
+    }
+  }
+
   if (!command_line.HasOption(modular::kJsonOutFlagString)) {
     std::cout << "Found the following sessions:\n\n";
     for (const auto& session : sessions) {
diff --git a/bin/sessionctl/session_ctl_app.cc b/bin/sessionctl/session_ctl_app.cc
index 11b7956..f25db72 100644
--- a/bin/sessionctl/session_ctl_app.cc
+++ b/bin/sessionctl/session_ctl_app.cc
@@ -136,11 +136,10 @@
 
 std::string SessionCtlApp::ExecuteListStoriesCommand() {
   async::PostTask(dispatcher_, [this]() mutable {
-    puppet_master_->GetStories(
-        [this](std::vector<std::string> story_names) {
-          logger_.Log(kListStoriesCommandString, std::move(story_names));
-          on_command_executed_();
-        });
+    puppet_master_->GetStories([this](std::vector<std::string> story_names) {
+      logger_.Log(kListStoriesCommandString, std::move(story_names));
+      on_command_executed_();
+    });
   });
 
   return "";
@@ -171,9 +170,8 @@
   return command;
 }
 
-std::vector<fuchsia::modular::StoryCommand>
-SessionCtlApp::MakeAddModCommands(const std::string& mod_url,
-                                  const std::string& mod_name) {
+std::vector<fuchsia::modular::StoryCommand> SessionCtlApp::MakeAddModCommands(
+    const std::string& mod_url, const std::string& mod_name) {
   fuchsia::modular::Intent intent;
   intent.handler = mod_url;
 
diff --git a/bin/sessionctl/session_ctl_constants.h b/bin/sessionctl/session_ctl_constants.h
index 7ccc0c3..df09d2e 100644
--- a/bin/sessionctl/session_ctl_constants.h
+++ b/bin/sessionctl/session_ctl_constants.h
@@ -10,8 +10,9 @@
 // Commands available to SessionCtlApp.
 constexpr char kAddModCommandString[] = "add_mod";
 constexpr char kDeleteStoryCommandString[] = "delete_story";
-constexpr char kRemoveModCommandString[] = "remove_mod";
 constexpr char kListStoriesCommandString[] = "list_stories";
+constexpr char kLoginGuestCommandString[] = "login_guest";
+constexpr char kRemoveModCommandString[] = "remove_mod";
 constexpr char kRestartSessionCommandString[] = "restart_session";
 
 // Flags to pass to SessionCtlApp.
diff --git a/public/fidl/fuchsia.modular.internal/basemgr_debug.fidl b/public/fidl/fuchsia.modular.internal/basemgr_debug.fidl
index 91efe4d..44e6527 100644
--- a/public/fidl/fuchsia.modular.internal/basemgr_debug.fidl
+++ b/public/fidl/fuchsia.modular.internal/basemgr_debug.fidl
@@ -8,5 +8,9 @@
 // state within the `basemgr` process.
 [Discoverable]
 interface BasemgrDebug {
+    // Restarts the current session.
     RestartSession();
+
+    // Logs in as a guest user.
+    LoginAsGuest();
 };