[devmgr] Move dc_asan_drivers out of global scope

Move dc_asan_drivers and dc_launched_first_devhost out of global scope,
and into Coordinator.

Test: Ran Fuchsia and /system/test/ddk tests.
Change-Id: I7d4ca3031025c41c18520501c1ec2383a1adc66f
diff --git a/system/core/devmgr/devmgr/coordinator.cpp b/system/core/devmgr/devmgr/coordinator.cpp
index f814506..fe083f6 100644
--- a/system/core/devmgr/devmgr/coordinator.cpp
+++ b/system/core/devmgr/devmgr/coordinator.cpp
@@ -62,12 +62,10 @@
 
 uint32_t log_flags = LOG_ERROR | LOG_INFO;
 
-bool dc_asan_drivers = false;
-bool dc_launched_first_devhost = false;
-
-Coordinator::Coordinator(zx::job devhost_job, async_dispatcher_t* dispatcher, bool require_system)
+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) {}
+    require_system_(require_system), asan_drivers_(asan_drivers) {}
 
 bool Coordinator::InSuspend() const {
     return suspend_context_.flags() == SuspendContext::Flags::kSuspend;
@@ -426,14 +424,14 @@
     }
 }
 
-static const char* get_devhost_bin() {
+static const char* get_devhost_bin(bool asan_drivers) {
     // If there are any ASan drivers, use the ASan-supporting devhost for
     // all drivers because even a devhost launched initially with just a
     // non-ASan driver might later load an ASan driver.  One day we might
     // be able to be more flexible about which drivers must get loaded into
     // the same devhost and thus be able to use both ASan and non-ASan
     // devhosts at the same time when only a subset of drivers use ASan.
-    if (dc_asan_drivers)
+    if (asan_drivers)
         return "/boot/bin/devhost.asan";
     return "/boot/bin/devhost";
 }
@@ -479,9 +477,8 @@
 }
 
 static zx_status_t dc_launch_devhost(Devhost* host, DevhostLoaderService* loader_service,
-                                     const char* name, zx_handle_t hrpc, zx::unowned_job devhost_job) {
-    const char* devhost_bin = get_devhost_bin();
-
+                                     const char* devhost_bin, const char* name, zx_handle_t hrpc,
+                                     zx::unowned_job devhost_job) {
     launchpad_t* lp;
     launchpad_create_with_jobs(devhost_job->get(), 0, name, &lp);
     launchpad_load_from_file(lp, devhost_bin);
@@ -544,8 +541,6 @@
     log(INFO, "devcoord: launch devhost '%s': pid=%zu\n",
         name, host->koid());
 
-    dc_launched_first_devhost = true;
-
     return ZX_OK;
 }
 
@@ -567,10 +562,12 @@
     }
     dh->set_hrpc(dh_hrpc);
 
-    if ((r = dc_launch_devhost(dh.get(), loader_service_, name, hrpc, zx::unowned_job(devhost_job_))) < 0) {
+    if ((r = dc_launch_devhost(dh.get(), loader_service_, get_devhost_bin(asan_drivers_), name,
+        hrpc, zx::unowned_job(devhost_job_))) < 0) {
         zx_handle_close(dh->hrpc());
         return r;
     }
+    launched_first_devhost_ = true;
 
     if (parent) {
         dh->set_parent(parent);
@@ -2005,34 +2002,79 @@
         (memcmp(&root_device_binding, drv->binding.get(), sizeof(root_device_binding)) == 0);
 }
 
-// DriverAddedInit is called from driver enumeration during
-// startup and before the devcoordinator starts running.  Enumerated
-// drivers are added directly to the all-drivers or fallback list.
-//
-// TODO: fancier priorities
-void Coordinator::DriverAddedInit(Driver* drv, const char* version) {
-    if (version[0] == '*') {
-        // fallback driver, load only if all else fails
-        fallback_drivers_.push_front(drv);
-    } else if (version[0] == '!') {
-        // debugging / development hack
-        // prioritize drivers with version "!..." over others
-        drivers_.push_front(drv);
-    } else {
-        drivers_.push_back(drv);
+fbl::unique_ptr<Driver> Coordinator::ValidateDriver(fbl::unique_ptr<Driver> drv) {
+    if ((drv->flags & ZIRCON_DRIVER_NOTE_FLAG_ASAN) && !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;
     }
+    return drv;
 }
 
 // DriverAdded is called when a driver is added after the
 // devcoordinator has started.  The driver is added to the new-drivers
 // list and work is queued to process it.
 void Coordinator::DriverAdded(Driver* drv, const char* version) {
-    async::PostTask(dispatcher_, [this, drv] {
+    auto driver = ValidateDriver(fbl::unique_ptr<Driver>(drv));
+    if (!driver) {
+        return;
+    }
+    async::PostTask(dispatcher_, [this, drv = driver.release()] {
         drivers_.push_back(drv);
         BindDriver(drv);
     });
 }
 
+// DriverAddedInit is called from driver enumeration during
+// startup and before the devcoordinator starts running.  Enumerated
+// drivers are added directly to the all-drivers or fallback list.
+//
+// TODO: fancier priorities
+void Coordinator::DriverAddedInit(Driver* drv, const char* version) {
+    auto driver = ValidateDriver(fbl::unique_ptr<Driver>(drv));
+    if (!driver) {
+        return;
+    }
+    if (version[0] == '*') {
+        // fallback driver, load only if all else fails
+        fallback_drivers_.push_front(driver.release());
+    } else if (version[0] == '!') {
+        // debugging / development hack
+        // prioritize drivers with version "!..." over others
+        drivers_.push_front(driver.release());
+    } else {
+        drivers_.push_back(driver.release());
+    }
+}
+
+// Drivers added during system scan (from the dedicated thread)
+// are added to system_drivers for bulk processing once
+// CTL_ADD_SYSTEM is sent.
+//
+// TODO: fancier priority management
+void Coordinator::DriverAddedSys(Driver* drv, const char* version) {
+    auto driver = ValidateDriver(fbl::unique_ptr<Driver>(drv));
+    if (!driver) {
+        return;
+    }
+    log(INFO, "devmgr: adding system driver '%s' '%s'\n", driver->name.c_str(),
+        driver->libname.c_str());
+    if (load_vmo(driver->libname.c_str(), &driver->dso_vmo)) {
+        log(ERROR, "devmgr: system driver '%s' '%s' could not cache DSO\n", driver->name.c_str(),
+            driver->libname.c_str());
+    }
+    if (version[0] == '*') {
+        // de-prioritize drivers that are "fallback"
+        system_drivers_.push_back(driver.release());
+    } else {
+        system_drivers_.push_front(driver.release());
+    }
+}
+
 // 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).
@@ -2108,26 +2150,6 @@
     drivers_.splice(drivers_.end(), fallback_drivers_);
 }
 
-// Drivers added during system scan (from the dedicated thread)
-// are added to system_drivers for bulk processing once
-// CTL_ADD_SYSTEM is sent.
-//
-// TODO: fancier priority management
-void Coordinator::DriverAddedSys(Driver* drv, const char* version) {
-    log(INFO, "devmgr: adding system driver '%s' '%s'\n", drv->name.c_str(), drv->libname.c_str());
-
-    if (load_vmo(drv->libname.c_str(), &drv->dso_vmo)) {
-        log(ERROR, "devmgr: system driver '%s' '%s' could not cache DSO\n", drv->name.c_str(),
-            drv->libname.c_str());
-    }
-    if (version[0] == '*') {
-        // de-prioritize drivers that are "fallback"
-        system_drivers_.push_back(drv);
-    } else {
-        system_drivers_.push_front(drv);
-    }
-}
-
 void coordinator_setup(Coordinator* coordinator, DevmgrArgs args) {
     log(INFO, "devmgr: coordinator_setup()\n");
 
@@ -2152,8 +2174,6 @@
     coordinator->set_suspend_fallback(getenv_bool("devmgr.suspend-timeout-fallback", false));
     coordinator->set_suspend_debug(getenv_bool("devmgr.suspend-timeout-debug", false));
 
-    dc_asan_drivers = getenv_bool("devmgr.devhost.asan", false);
-
     zx_status_t status = coordinator->InitializeCoreDevices();
     if (status != ZX_OK) {
         log(ERROR, "devmgr: failed to initialize core devices\n");
diff --git a/system/core/devmgr/devmgr/coordinator.h b/system/core/devmgr/devmgr/coordinator.h
index 59d5b93..2fa6e8a 100644
--- a/system/core/devmgr/devmgr/coordinator.h
+++ b/system/core/devmgr/devmgr/coordinator.h
@@ -415,7 +415,8 @@
     Coordinator(Coordinator&&) = delete;
     Coordinator& operator=(Coordinator&&) = delete;
 
-    Coordinator(zx::job devhost_job, async_dispatcher_t* dispatcher, bool require_system);
+    Coordinator(zx::job devhost_job, async_dispatcher_t* dispatcher, bool require_system,
+                bool asan_drivers);
 
     zx_status_t InitializeCoreDevices();
 
@@ -510,8 +511,10 @@
     zx::job devhost_job_;
     async_dispatcher_t* dispatcher_;
     bool require_system_;
+    bool asan_drivers_;
 
     bool running_ = false;
+    bool launched_first_devhost_ = false;
     DevhostLoaderService* loader_service_ = nullptr;
     // This socket is used by DmPrintf for output, and DmPrintf can be called in
     // the context of a const member function, therefore it is also const. Given
@@ -547,6 +550,8 @@
     bool suspend_debug_ = false;
     bool system_available_ = false;
     bool system_loaded_ = false;
+
+    fbl::unique_ptr<Driver> ValidateDriver(fbl::unique_ptr<Driver> drv);
 };
 
 void coordinator_setup(Coordinator* coordinator, DevmgrArgs args);
@@ -561,9 +566,6 @@
                     zx_device_prop_t* props, size_t prop_count,
                     bool autobind);
 
-extern bool dc_asan_drivers;
-extern bool dc_launched_first_devhost;
-
 // Methods for composing FIDL RPCs to the devhosts
 zx_status_t dh_send_remove_device(const Device* dev);
 zx_status_t dh_send_create_device(Device* dev, Devhost* dh, zx::channel rpc, zx::vmo driver,
diff --git a/system/core/devmgr/devmgr/drivers.cpp b/system/core/devmgr/devmgr/drivers.cpp
index 31c4c29..5eca592 100644
--- a/system/core/devmgr/devmgr/drivers.cpp
+++ b/system/core/devmgr/devmgr/drivers.cpp
@@ -20,20 +20,18 @@
 
 #include <zircon/driver/binding.h>
 
-namespace devmgr {
-
 namespace {
 
 struct AddContext {
     const char* libname;
-    DriverLoadCallback func;
+    devmgr::DriverLoadCallback func;
 };
 
 bool is_driver_disabled(const char* name) {
     // driver.<driver_name>.disable
     char opt[16 + DRIVER_NAME_LEN_MAX];
     snprintf(opt, 16 + DRIVER_NAME_LEN_MAX, "driver.%s.disable", name);
-    return getenv_bool(opt, false);
+    return devmgr::getenv_bool(opt, false);
 }
 
 void found_driver(zircon_driver_note_payload_t* note,
@@ -49,19 +47,7 @@
         return;
     }
 
-    const char* libname = context->libname;
-
-    if ((note->flags & ZIRCON_DRIVER_NOTE_FLAG_ASAN) && !dc_asan_drivers) {
-        if (dc_launched_first_devhost) {
-            log(ERROR, "%s (%s) requires ASan: cannot load after boot;"
-                " consider devmgr.devhost.asan=true\n",
-                libname, note->name);
-            return;
-        }
-        dc_asan_drivers = true;
-    }
-
-    auto drv = fbl::make_unique<Driver>();
+    auto drv = fbl::make_unique<devmgr::Driver>();
     if (drv == nullptr) {
         return;
     }
@@ -76,7 +62,7 @@
     drv->binding_size = static_cast<uint32_t>(bindlen);
 
     drv->flags = note->flags;
-    drv->libname.Set(libname);
+    drv->libname.Set(context->libname);
     drv->name.Set(note->name);
 
 #if VERBOSE_DRIVER_LOAD
@@ -96,6 +82,8 @@
 
 } // namespace
 
+namespace devmgr {
+
 void find_loadable_drivers(const char* path, DriverLoadCallback func) {
 
     DIR* dir = opendir(path);
diff --git a/system/core/devmgr/devmgr/main.cpp b/system/core/devmgr/devmgr/main.cpp
index cd5cc27..200bb99 100644
--- a/system/core/devmgr/devmgr/main.cpp
+++ b/system/core/devmgr/devmgr/main.cpp
@@ -814,8 +814,10 @@
 
     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);
+    devmgr::Coordinator coordinator(std::move(devhost_job), loop.dispatcher(), require_system,
+                                    asan_drivers);
     devmgr::devfs_init(&coordinator.root_device(), loop.dispatcher());
 
     // Check if whatever launched devmgr gave a channel to be connected to /dev.