[devmgr] Make vfs_exit private to Coordinator

In order to isolate more of Coordinator's dependencies, move vfs_exit
from main.cpp into coordinator.cpp.

Test: Ran Fuchsia and /system/test/ddk tests.
Change-Id: I14592bd2f7438ded87f4136c62df86a367e0e36d
diff --git a/system/core/devmgr/devmgr/coordinator.cpp b/system/core/devmgr/devmgr/coordinator.cpp
index 61f3b60..c8f056d 100644
--- a/system/core/devmgr/devmgr/coordinator.cpp
+++ b/system/core/devmgr/devmgr/coordinator.cpp
@@ -56,16 +56,26 @@
 constexpr char kBootFirmwareDir[] = "/boot/lib/firmware";
 constexpr char kSystemFirmwareDir[] = "/system/lib/firmware";
 
+// Tells VFS to exit by shutting down the fshost.
+void vfs_exit(const zx::event& fshost_event) {
+    zx_status_t status;
+    if ((status = fshost_event.signal(0, FSHOST_SIGNAL_EXIT)) != ZX_OK) {
+        printf("devmgr: Failed to signal VFS exit\n");
+        return;
+    } else if ((status = fshost_event.wait_one(FSHOST_SIGNAL_EXIT_DONE,
+                                               zx::deadline_after(zx::sec(5)),
+                                               nullptr)) != ZX_OK) {
+        printf("devmgr: Failed to wait for VFS exit completion\n");
+    }
+}
+
 } // namespace
 
 namespace devmgr {
 
 uint32_t log_flags = LOG_ERROR | LOG_INFO;
 
-Coordinator::Coordinator(zx::job devhost_job, async_dispatcher_t* dispatcher, bool require_system,
-                         bool asan_drivers)
-    : devhost_job_(std::move(devhost_job)), dispatcher_(dispatcher),
-    require_system_(require_system), asan_drivers_(asan_drivers) {}
+Coordinator::Coordinator(CoordinatorConfig config) : config_(std::move(config)) {}
 
 bool Coordinator::InSuspend() const {
     return suspend_context_.flags() == SuspendContext::Flags::kSuspend;
@@ -213,17 +223,17 @@
     }
 
     if ((len == 6) && !memcmp(cmd, "reboot", 6)) {
-        devmgr_vfs_exit();
+        vfs_exit(config_.fshost_event);
         Suspend(DEVICE_SUSPEND_FLAG_REBOOT);
         return ZX_OK;
     }
     if ((len == 17) && !memcmp(cmd, "reboot-bootloader", 17)) {
-        devmgr_vfs_exit();
+        vfs_exit(config_.fshost_event);
         Suspend(DEVICE_SUSPEND_FLAG_REBOOT_BOOTLOADER);
         return ZX_OK;
     }
     if ((len == 15) && !memcmp(cmd, "reboot-recovery", 15)) {
-        devmgr_vfs_exit();
+        vfs_exit(config_.fshost_event);
         Suspend(DEVICE_SUSPEND_FLAG_REBOOT_RECOVERY);
         return ZX_OK;
     }
@@ -232,7 +242,7 @@
         return ZX_OK;
     }
     if (len == 8 && (!memcmp(cmd, "poweroff", 8) || !memcmp(cmd, "shutdown", 8))) {
-        devmgr_vfs_exit();
+        vfs_exit(config_.fshost_event);
         Suspend(DEVICE_SUSPEND_FLAG_POWEROFF);
         return ZX_OK;
     }
@@ -557,8 +567,8 @@
     }
     dh->set_hrpc(dh_hrpc);
 
-    if ((r = dc_launch_devhost(dh.get(), loader_service_, get_devhost_bin(asan_drivers_), name,
-        hrpc, zx::unowned_job(devhost_job_))) < 0) {
+    if ((r = dc_launch_devhost(dh.get(), loader_service_, get_devhost_bin(config_.asan_drivers),
+        name, hrpc, zx::unowned_job(config_.devhost_job))) < 0) {
         zx_handle_close(dh->hrpc());
         return r;
     }
@@ -718,7 +728,7 @@
 
     dev->wait.set_object(dev->hrpc.get());
     dev->wait.set_trigger(ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED);
-    if ((r = dev->wait.Begin(dispatcher_)) != ZX_OK) {
+    if ((r = dev->wait.Begin(config_.dispatcher)) != ZX_OK) {
         devfs_unpublish(dev.get());
         return r;
     }
@@ -743,7 +753,7 @@
         dev.get(), dev->name, dev->prop_count, dev->args.get(), dev->parent);
 
     if (!invisible) {
-        r = dev->publish_task.Post(dispatcher_);
+        r = dev->publish_task.Post(config_.dispatcher);
         if (r != ZX_OK) {
             return r;
         }
@@ -761,7 +771,7 @@
     if (dev->flags & DEV_CTX_INVISIBLE) {
         dev->flags &= ~DEV_CTX_INVISIBLE;
         devfs_advertise(dev);
-        zx_status_t r = dev->publish_task.Post(dispatcher_);
+        zx_status_t r = dev->publish_task.Post(config_.dispatcher);
         if (r != ZX_OK) {
             return r;
         }
@@ -870,7 +880,8 @@
 
                     if (parent->retries > 0) {
                         // Add device with an exponential backoff.
-                        zx_status_t r = parent->publish_task.PostDelayed(dispatcher_, parent->backoff);
+                        zx_status_t r = parent->publish_task.PostDelayed(config_.dispatcher,
+                                                                         parent->backoff);
                         if (r != ZX_OK) {
                             return r;
                         }
@@ -1957,14 +1968,14 @@
 }
 
 fbl::unique_ptr<Driver> Coordinator::ValidateDriver(fbl::unique_ptr<Driver> drv) {
-    if ((drv->flags & ZIRCON_DRIVER_NOTE_FLAG_ASAN) && !asan_drivers_) {
+    if ((drv->flags & ZIRCON_DRIVER_NOTE_FLAG_ASAN) && !config_.asan_drivers) {
         if (launched_first_devhost_) {
             log(ERROR, "%s (%s) requires ASan: cannot load after boot;"
                 " consider devmgr.devhost.asan=true\n",
                 drv->libname.c_str(), drv->name.c_str());
             return nullptr;
         }
-        asan_drivers_ = true;
+        config_.asan_drivers = true;
     }
     return drv;
 }
@@ -1977,7 +1988,7 @@
     if (!driver) {
         return;
     }
-    async::PostTask(dispatcher_, [this, drv = driver.release()] {
+    async::PostTask(config_.dispatcher, [this, drv = driver.release()] {
         drivers_.push_back(drv);
         BindDriver(drv);
     });
@@ -2029,7 +2040,7 @@
     }
 }
 
-// BindDRiver is called when a new driver becomes available to
+// BindDriver is called when a new driver becomes available to
 // the Coordinator.  Existing devices are inspected to see if the
 // new driver is bindable to them (unless they are already bound).
 void Coordinator::BindDriver(Driver* drv) {
diff --git a/system/core/devmgr/devmgr/coordinator.h b/system/core/devmgr/devmgr/coordinator.h
index 15327b9..fa5b203 100644
--- a/system/core/devmgr/devmgr/coordinator.h
+++ b/system/core/devmgr/devmgr/coordinator.h
@@ -14,6 +14,7 @@
 #include <lib/async/cpp/wait.h>
 #include <lib/fit/function.h>
 #include <lib/zx/channel.h>
+#include <lib/zx/event.h>
 #include <lib/zx/job.h>
 #include <lib/zx/process.h>
 #include <lib/zx/socket.h>
@@ -262,6 +263,19 @@
     const char* sys_device_driver = nullptr;
 };
 
+struct CoordinatorConfig {
+    // Job for all devhosts.
+    zx::job devhost_job;
+    // Event that controls the fshost.
+    zx::event fshost_event;
+    // Async dispatcher for the coordinator.
+    async_dispatcher_t* dispatcher;
+    // Whether we require /system.
+    bool require_system;
+    // Whether we require ASan drivers.
+    bool asan_drivers;
+};
+
 class Coordinator {
 public:
     Coordinator(const Coordinator&) = delete;
@@ -270,8 +284,7 @@
     Coordinator(Coordinator&&) = delete;
     Coordinator& operator=(Coordinator&&) = delete;
 
-    Coordinator(zx::job devhost_job, async_dispatcher_t* dispatcher, bool require_system,
-                bool asan_drivers);
+    explicit Coordinator(CoordinatorConfig config);
 
     zx_status_t InitializeCoreDevices();
 
@@ -337,8 +350,9 @@
     void DriverAddedInit(Driver* drv, const char* version);
     void DriverAddedSys(Driver* drv, const char* version);
 
-    async_dispatcher_t* dispatcher() const { return dispatcher_; }
-    bool require_system() const { return require_system_; }
+    const zx::event& fshost_event() const { return config_.fshost_event; }
+    async_dispatcher_t* dispatcher() const { return config_.dispatcher; }
+    bool require_system() const { return config_.require_system; }
 
     void set_running(bool running) { running_ = running; }
     void set_loader_service(DevhostLoaderService* loader_service) {
@@ -363,11 +377,7 @@
     bool system_loaded() const { return system_loaded_; }
 
 private:
-    zx::job devhost_job_;
-    async_dispatcher_t* dispatcher_;
-    bool require_system_;
-    bool asan_drivers_;
-
+    CoordinatorConfig config_;
     bool running_ = false;
     bool launched_first_devhost_ = false;
     DevhostLoaderService* loader_service_ = nullptr;
diff --git a/system/core/devmgr/devmgr/devmgr.h b/system/core/devmgr/devmgr/devmgr.h
index 95035fb..1adac8e 100644
--- a/system/core/devmgr/devmgr/devmgr.h
+++ b/system/core/devmgr/devmgr/devmgr.h
@@ -28,9 +28,6 @@
 // Clones the channel connected to the root of devfs.
 zx::channel devfs_root_clone();
 
-// Tells VFS to exit by shutting down the fshost.
-void devmgr_vfs_exit();
-
 zx_handle_t get_root_resource();
 zx::job get_sysinfo_job_root();
 
diff --git a/system/core/devmgr/devmgr/main.cpp b/system/core/devmgr/devmgr/main.cpp
index 2eb9a31..0cb38d5 100644
--- a/system/core/devmgr/devmgr/main.cpp
+++ b/system/core/devmgr/devmgr/main.cpp
@@ -64,8 +64,6 @@
     zx::job fuchsia_job;
     zx::channel svchost_outgoing;
 
-    zx::event fshost_event;
-
     zx::channel fs_root;
 } g_handles;
 
@@ -150,13 +148,13 @@
     zx::time deadline = zx::deadline_after(zx::sec(appmgr_timeout));
 
     do {
-        zx_status_t status = g_handles.fshost_event.wait_one(FSHOST_SIGNAL_READY, deadline,
-                                                             nullptr);
+        zx_status_t status = coordinator->fshost_event().wait_one(FSHOST_SIGNAL_READY, deadline,
+                                                                   nullptr);
         if (status == ZX_ERR_TIMED_OUT) {
             if (g_handles.appmgr_server.is_valid()) {
                 if (coordinator->require_system()) {
-                    printf("devmgr: appmgr not launched in %zus, closing appmgr handle\n",
-                           appmgr_timeout);
+                    fprintf(stderr, "devmgr: appmgr not launched in %zus, closing appmgr handle\n",
+                            appmgr_timeout);
                 }
                 g_handles.appmgr_server.reset();
             }
@@ -164,10 +162,13 @@
             continue;
         }
         if (status != ZX_OK) {
-            printf("devmgr: error waiting on fuchsia start event: %d\n", status);
+            fprintf(stderr, "devmgr: error waiting on fuchsia start event: %d\n", status);
             break;
         }
-        g_handles.fshost_event.signal(FSHOST_SIGNAL_READY, 0);
+        status = coordinator->fshost_event().signal(FSHOST_SIGNAL_READY, 0);
+        if (status != ZX_OK) {
+            fprintf(stderr, "devmgr: error signaling fshost: %d\n", status);
+        }
 
         if (!drivers_loaded) {
             // we're starting the appmgr because /system is present
@@ -436,7 +437,8 @@
 
     // pass fuchsia start event to fshost
     zx::event fshost_event_duplicate;
-    if (g_handles.fshost_event.duplicate(ZX_RIGHT_SAME_RIGHTS, &fshost_event_duplicate) == ZX_OK) {
+    if (coordinator->fshost_event().duplicate(ZX_RIGHT_SAME_RIGHTS, &fshost_event_duplicate) ==
+        ZX_OK) {
         handles[n] = fshost_event_duplicate.release();
         types[n++] = PA_HND(PA_USER1, 0);
     }
@@ -753,18 +755,6 @@
     }
 }
 
-void devmgr_vfs_exit() {
-    zx_status_t status;
-    if ((status = g_handles.fshost_event.signal(0, FSHOST_SIGNAL_EXIT)) != ZX_OK) {
-        printf("devmgr: Failed to signal VFS exit\n");
-        return;
-    } else if ((status = g_handles.fshost_event.wait_one(FSHOST_SIGNAL_EXIT_DONE,
-                                                         zx::deadline_after(zx::sec(5)),
-                                                         nullptr)) != ZX_OK) {
-        printf("devmgr: Failed to wait for VFS exit completion\n");
-    }
-}
-
 zx::channel fs_clone(const char* path) {
     if (!strcmp(path, "dev")) {
         return devfs_root_clone();
@@ -805,20 +795,25 @@
 
     fetch_root_resource();
     g_handles.root_job = zx::job::default_job();
+    bool require_system = devmgr::getenv_bool("devmgr.require-system", false);
 
-    zx::job devhost_job;
-    zx_status_t status = CreateDevhostJob(*g_handles.root_job, &devhost_job);
+    async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
+    devmgr::CoordinatorConfig config;
+    config.dispatcher = loop.dispatcher();
+    config.require_system = require_system;
+    config.asan_drivers = devmgr::getenv_bool("devmgr.devhost.asan", false);
+    zx_status_t status = CreateDevhostJob(*g_handles.root_job, &config.devhost_job);
     if (status != ZX_OK) {
-        printf("unable to create devhost job\n");
+        fprintf(stderr, "devmgr: unable to create devhost job: %d\n", status);
+        return 1;
+    }
+    status = zx::event::create(0, &config.fshost_event);
+    if (status != ZX_OK) {
+        fprintf(stderr, "devmgr: unable to create fshost event: %d\n", status);
         return 1;
     }
 
-    async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
-    bool require_system = devmgr::getenv_bool("devmgr.require-system", false);
-    bool asan_drivers = devmgr::getenv_bool("devmgr.devhost.asan", false);
-
-    devmgr::Coordinator coordinator(std::move(devhost_job), loop.dispatcher(), require_system,
-                                    asan_drivers);
+    devmgr::Coordinator coordinator(std::move(config));
     devmgr::devfs_init(&coordinator.root_device(), loop.dispatcher());
 
     // Check if whatever launched devmgr gave a channel to be connected to /dev.
@@ -843,7 +838,6 @@
     }
 
     zx::channel::create(0, &g_handles.appmgr_client, &g_handles.appmgr_server);
-    zx::event::create(0, &g_handles.fshost_event);
 
     char** e = environ;
     while (*e) {