[basemgr] Support factory reset logic in basemgr.

- This will be renamed to "Erase User Data" to be more accurate

- Factory reset needs to be facilitated at a lower level and needs to
reset at a greater scope i.e removing from blobfs packages not in the
pre-install set

SU-97 #done

TESTED: manually tested factory reset
Change-Id: I97d8373b2db6f2015b5e9e6bea8e9b13916bbd73
diff --git a/bin/basemgr/BUILD.gn b/bin/basemgr/BUILD.gn
index 1742abb..d98ba4c 100644
--- a/bin/basemgr/BUILD.gn
+++ b/bin/basemgr/BUILD.gn
@@ -31,6 +31,7 @@
   deps = [
     ":lib",
     "//garnet/public/fidl/fuchsia.auth",
+    "//garnet/public/fidl/fuchsia.devicesettings",
     "//garnet/public/fidl/fuchsia.sys",
     "//garnet/public/fidl/fuchsia.ui.policy",
     "//garnet/public/fidl/fuchsia.ui.viewsv1",
@@ -50,6 +51,7 @@
     "//peridot/public/fidl/fuchsia.modular",
     "//peridot/public/fidl/fuchsia.modular.auth",
     "//peridot/public/fidl/fuchsia.modular.internal",
+    "//peridot/public/lib/async/cpp:future",
     "//zircon/public/lib/async-loop-cpp",
     "//zircon/public/lib/trace-provider",
   ]
diff --git a/bin/basemgr/basemgr_impl.cc b/bin/basemgr/basemgr_impl.cc
index b2b74ac..43ebbe4 100644
--- a/bin/basemgr/basemgr_impl.cc
+++ b/bin/basemgr/basemgr_impl.cc
@@ -39,12 +39,14 @@
     fuchsia::sys::Launcher* const launcher,
     fuchsia::modular::BasemgrMonitorPtr monitor,
     fuchsia::ui::policy::PresenterPtr presenter,
+    fuchsia::devicesettings::DeviceSettingsManagerPtr device_settings_manager,
     std::function<void()> on_shutdown)
     : settings_(settings),
       session_shell_settings_(session_shell_settings),
       launcher_(launcher),
       monitor_(std::move(monitor)),
       presenter_(std::move(presenter)),
+      device_settings_manager_(std::move(device_settings_manager)),
       on_shutdown_(std::move(on_shutdown)),
       user_provider_impl_("UserProviderImpl"),
       base_shell_context_binding_(this),
@@ -269,24 +271,7 @@
       authentication_context_provider_binding_.NewBinding().Bind(),
       settings_.enable_garnet_token_manager, this));
 
-  // If the session shell settings specifies it, auto-login as the first
-  // authenticated user.
-  if (active_session_shell_settings_index_ < session_shell_settings_.size() &&
-      session_shell_settings_[active_session_shell_settings_index_]
-          .auto_login) {
-    user_provider_impl_->PreviousUsers(
-        [this](fidl::VectorPtr<fuchsia::modular::auth::Account> accounts) {
-          if (accounts->empty()) {
-            StartBaseShell();
-          } else {
-            fuchsia::modular::UserLoginParams params;
-            params.account_id = accounts->at(0).id;
-            user_provider_impl_->Login(std::move(params));
-          }
-        });
-  } else {
-    StartBaseShell();
-  }
+  ShowSetupOrLogin();
 
   ReportEvent(ModularEvent::BOOTED_TO_BASEMGR);
 }
@@ -537,4 +522,77 @@
   session_shell_config_ = std::move(session_shell_config);
 }
 
+void BasemgrImpl::ShowSetupOrLogin() {
+  auto show_setup_or_login = [this] {
+    // If the session shell settings specifies it, auto-login as the first
+    // authenticated user. Otherwise, start the base shell to launch setup.
+    if (active_session_shell_settings_index_ < session_shell_settings_.size() &&
+        session_shell_settings_[active_session_shell_settings_index_]
+            .auto_login) {
+      user_provider_impl_->PreviousUsers(
+          [this](fidl::VectorPtr<fuchsia::modular::auth::Account> accounts) {
+            if (accounts->empty()) {
+              StartBaseShell();
+            } else {
+              fuchsia::modular::UserLoginParams params;
+              params.account_id = accounts->at(0).id;
+              user_provider_impl_->Login(std::move(params));
+            }
+          });
+    } else {
+      StartBaseShell();
+    }
+  };
+
+  // TODO(MF-134): Improve the factory reset logic by deleting more than just
+  // the user data.
+  // If the device needs factory reset, remove all the users before proceeding
+  // with setup.
+  device_settings_manager_.set_error_handler(
+      [show_setup_or_login](zx_status_t status) { show_setup_or_login(); });
+  device_settings_manager_->GetInteger(
+      kFactoryResetKey,
+      [this, show_setup_or_login](int factory_reset_value,
+                                  fuchsia::devicesettings::Status status) {
+        if (status == fuchsia::devicesettings::Status::ok &&
+            factory_reset_value > 0) {
+          // Unset the factory reset flag.
+          device_settings_manager_->SetInteger(
+              kFactoryResetKey, 0, [](bool result) {
+                if (!result) {
+                  FXL_LOG(WARNING) << "Factory reset flag was not updated.";
+                }
+              });
+
+          user_provider_impl_->PreviousUsers(
+              [this](
+                  fidl::VectorPtr<fuchsia::modular::auth::Account> accounts) {
+                std::vector<FuturePtr<>> did_remove_users;
+                did_remove_users.reserve(accounts->size());
+
+                for (const auto& account : *accounts) {
+                  auto did_remove_user = Future<>::Create(
+                      "BasemgrImpl.ShowSetupOrLogin.did_remove_user");
+                  user_provider_impl_->RemoveUser(
+                      account.id,
+                      [did_remove_user](fidl::StringPtr error_code) {
+                        if (error_code) {
+                          FXL_LOG(WARNING) << "Account was not removed during "
+                                              "factory reset. Error code: "
+                                           << error_code;
+                        }
+                        did_remove_user->Complete();
+                      });
+                  did_remove_users.emplace_back(did_remove_user);
+                }
+
+                Wait("BasemgrImpl.ShowSetupOrLogin.Wait", did_remove_users)
+                    ->Then([this] { StartBaseShell(); });
+              });
+        } else {
+          show_setup_or_login();
+        }
+      });
+}
+
 }  // namespace modular
diff --git a/bin/basemgr/basemgr_impl.h b/bin/basemgr/basemgr_impl.h
index a977f3a..4310ba0 100644
--- a/bin/basemgr/basemgr_impl.h
+++ b/bin/basemgr/basemgr_impl.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include <fuchsia/auth/cpp/fidl.h>
+#include <fuchsia/devicesettings/cpp/fidl.h>
 #include <fuchsia/modular/auth/cpp/fidl.h>
 #include <fuchsia/modular/cpp/fidl.h>
 #include <fuchsia/sys/cpp/fidl.h>
@@ -52,6 +53,8 @@
   // |launcher| Environment service for creating component instances.
   // |monitor| Service that monitors how many basemgr instances are active.
   // |presenter| Service to initialize the presentation.
+  // |device_settings_manager| Service to look-up whether device needs factory
+  // reset.
   // |on_shutdown| Callback invoked when this basemgr instance is shutdown.
   explicit BasemgrImpl(
       const modular::BasemgrSettings& settings,
@@ -59,6 +62,7 @@
       fuchsia::sys::Launcher* const launcher,
       fuchsia::modular::BasemgrMonitorPtr monitor,
       fuchsia::ui::policy::PresenterPtr presenter,
+      fuchsia::devicesettings::DeviceSettingsManagerPtr device_settings_manager,
       std::function<void()> on_shutdown);
 
   ~BasemgrImpl() override;
@@ -128,6 +132,8 @@
 
   void ToggleClipping();
 
+  void ShowSetupOrLogin();
+
   // Updates the session shell app config to the active session shell. Done once
   // on initialization and every time the session shells are swapped.
   void UpdateSessionShellConfig();
@@ -146,6 +152,8 @@
   fuchsia::modular::BasemgrMonitorPtr monitor_;
   // Used to initialize the presentation.
   fuchsia::ui::policy::PresenterPtr presenter_;
+  // Used to look-up whether device needs a factory reset.
+  fuchsia::devicesettings::DeviceSettingsManagerPtr device_settings_manager_;
   std::function<void()> on_shutdown_;
 
   AsyncHolder<UserProviderImpl> user_provider_impl_;
diff --git a/bin/basemgr/main.cc b/bin/basemgr/main.cc
index 8b15229..161acfd 100644
--- a/bin/basemgr/main.cc
+++ b/bin/basemgr/main.cc
@@ -54,13 +54,16 @@
   context->ConnectToEnvironmentService(monitor.NewRequest());
   fuchsia::ui::policy::PresenterPtr presenter;
   context->ConnectToEnvironmentService(presenter.NewRequest());
+  fuchsia::devicesettings::DeviceSettingsManagerPtr device_settings_manager;
+  context->ConnectToEnvironmentService(device_settings_manager.NewRequest());
 
-  modular::BasemgrImpl basemgr(settings, session_shell_settings,
-                               context->launcher().get(), std::move(monitor),
-                               std::move(presenter), [&loop, &cobalt_cleanup] {
-                                 cobalt_cleanup.call();
-                                 loop.Quit();
-                               });
+  modular::BasemgrImpl basemgr(
+      settings, session_shell_settings, context->launcher().get(),
+      std::move(monitor), std::move(presenter),
+      std::move(device_settings_manager), [&loop, &cobalt_cleanup] {
+        cobalt_cleanup.call();
+        loop.Quit();
+      });
   loop.Run();
 
   return 0;
diff --git a/bin/basemgr/meta/basemgr.cmx b/bin/basemgr/meta/basemgr.cmx
index 2e208bb..048fd31 100644
--- a/bin/basemgr/meta/basemgr.cmx
+++ b/bin/basemgr/meta/basemgr.cmx
@@ -8,6 +8,7 @@
         ],
         "services": [
             "fuchsia.cobalt.LoggerFactory",
+            "fuchsia.devicesettings.DeviceSettingsManager",
             "fuchsia.modular.BasemgrMonitor",
             "fuchsia.ui.policy.Presenter",
             "fuchsia.sys.Launcher",
diff --git a/bin/basemgr/user_provider_impl.h b/bin/basemgr/user_provider_impl.h
index 0663cea..7cc9401 100644
--- a/bin/basemgr/user_provider_impl.h
+++ b/bin/basemgr/user_provider_impl.h
@@ -82,15 +82,15 @@
   // |fuchsia::modular::UserProvider|, also called by |basemgr_impl|.
   void PreviousUsers(PreviousUsersCallback callback) override;
 
+  // |fuchsia::modular::UserProvider|, also called by |basemgr_impl|.
+  void RemoveUser(fidl::StringPtr account_id,
+                  RemoveUserCallback callback) override;
+
  private:
   // |fuchsia::modular::UserProvider|
   void AddUser(fuchsia::modular::auth::IdentityProvider identity_provider,
                AddUserCallback callback) override;
 
-  // |fuchsia::modular::UserProvider|
-  void RemoveUser(fidl::StringPtr account_id,
-                  RemoveUserCallback callback) override;
-
   // |fuchsia::auth::AuthenticationContextProvider|
   void GetAuthenticationUIContext(
       fidl::InterfaceRequest<fuchsia::auth::AuthenticationUIContext> request)
diff --git a/lib/common/names.h b/lib/common/names.h
index af2fb01..9c9fd22 100644
--- a/lib/common/names.h
+++ b/lib/common/names.h
@@ -13,12 +13,18 @@
 constexpr char kRootModuleName[] = "root";
 
 // The service name of the Presentation service that is routed between
-// BaseShell and SessionShell. The same service exchange between SessionShell and
-// StoryShell uses the SessionShellPresentationProvider service, which is
+// BaseShell and SessionShell. The same service exchange between SessionShell
+// and StoryShell uses the SessionShellPresentationProvider service, which is
 // discoverable.
 // TODO(SCN-595): mozart.Presentation is being renamed to ui.Presenter.
 constexpr char kPresentationService[] = "mozart.Presentation";
 
+// TODO(MF-134): This key is duplicated in
+// topaz/lib/settings/lib/device_info.dart. Remove this key once factory reset
+// is provided to topaz as a service.
+// The key for factory reset toggles.
+constexpr char kFactoryResetKey[] = "FactoryReset";
+
 }  // namespace modular
 
 #endif  // PERIDOT_LIB_COMMON_NAMES_H_