[modular] Prevent basemgr from shutting down twice.

This happens as a race condition during CQ when a test times out *and*
completes at the same time; in this instance, dev_base_shell calls
BaseShellContext::Shutdown() twice. basemgr should be resilient against
this race.

Testing=ran tests with a smaller timeout and saw that two-time-shutdown
doesn't happen.

Change-Id: I867dc3f84e37eba0eae84c1713206a416b728af1
diff --git a/bin/basemgr/basemgr_impl.cc b/bin/basemgr/basemgr_impl.cc
index 9b50d90..891c5e8 100644
--- a/bin/basemgr/basemgr_impl.cc
+++ b/bin/basemgr/basemgr_impl.cc
@@ -251,12 +251,13 @@
 }
 
 void BasemgrImpl::Shutdown() {
-  // TODO(mesch): Some of these could be done in parallel too.
-  // fuchsia::modular::UserProvider must go first, but the order after user
-  // provider is for now rather arbitrary. We terminate base shell last so
-  // that in tests testing::Teardown() is invoked at the latest possible time.
-  // Right now it just demonstrates that AppTerminate() works as we like it
-  // to.
+  // Prevent the shutdown sequence from running twice.
+  if (state_ == State::TERMINATING) {
+    return;
+  }
+
+  state_ = State::TERMINATING;
+
   FXL_DLOG(INFO) << "fuchsia::modular::BaseShellContext::Shutdown()";
 
   if (settings_.test) {
@@ -267,6 +268,12 @@
         << "======================== [" << settings_.test_name << "] Done";
   }
 
+  // TODO(mesch): Some of these could be done in parallel too.
+  // fuchsia::modular::UserProvider must go first, but the order after user
+  // provider is for now rather arbitrary. We terminate base shell last so
+  // that in tests testing::Teardown() is invoked at the latest possible time.
+  // Right now it just demonstrates that AppTerminate() works as we like it
+  // to.
   user_provider_impl_.Teardown(kUserProviderTimeout, [this] {
     FXL_DLOG(INFO) << "- fuchsia::modular::UserProvider down";
     StopAccountProvider()->Then([this] {
diff --git a/bin/basemgr/basemgr_impl.h b/bin/basemgr/basemgr_impl.h
index c1196af..2eb063a 100644
--- a/bin/basemgr/basemgr_impl.h
+++ b/bin/basemgr/basemgr_impl.h
@@ -155,6 +155,15 @@
 
   std::vector<SessionShellSettings>::size_type active_session_shell_index_{};
 
+  enum class State {
+    // normal mode of operation
+    RUNNING,
+    // basemgr is shutting down.
+    TERMINATING
+  };
+
+  State state_ = State::RUNNING;
+
   FXL_DISALLOW_COPY_AND_ASSIGN(BasemgrImpl);
 };