[devmgr] Split Device into its own source files

In an effort to split coordinator.cpp into smaller, more understandable
pieces, split out Device into its own source files.

Test: Ran Fuchsia and /system/test/ddk tests.
Change-Id: Ie60d49435bff2877de30abb0c61f4e72f1a5ac1b
diff --git a/system/core/devmgr/devmgr/coordinator.cpp b/system/core/devmgr/devmgr/coordinator.cpp
index fe083f6..61f3b60 100644
--- a/system/core/devmgr/devmgr/coordinator.cpp
+++ b/system/core/devmgr/devmgr/coordinator.cpp
@@ -544,11 +544,6 @@
     return ZX_OK;
 }
 
-Devhost::Devhost()
-    : hrpc_(ZX_HANDLE_INVALID), proc_(ZX_HANDLE_INVALID), koid_(0), refcount_(0),
-      flags_(0), parent_(nullptr) {
-}
-
 zx_status_t Coordinator::NewDevhost(const char* name, Devhost* parent, Devhost** out) {
     auto dh = fbl::make_unique<Devhost>();
     if (dh == nullptr) {
@@ -637,15 +632,6 @@
     delete dev;
 }
 
-Device::Device(Coordinator* coord)
-    : coordinator(coord), publish_task([this] { coordinator->HandleNewDevice(this); }) {}
-
-Device::~Device() {
-    // TODO: cancel any pending rpc responses.  This clear is a hack to prevent
-    // pending's dtor from asserting.
-    pending.clear();
-}
-
 // Add a new device to a parent device (same devhost)
 // New device is published in devfs.
 // Caller closes handles on error, so we don't have to.
@@ -831,7 +817,7 @@
         // A side-effect of this is that the devhost will be released,
         // as well as any proxy devices.
         if (forced) {
-            dh->flags() |= DEV_HOST_DYING;
+            dh->flags() |= Devhost::Flags::kDying;
 
             Device* next;
             Device* last = nullptr;
@@ -876,7 +862,8 @@
                 // THEN we will want to rebind our parent
                 if (!(parent->flags & DEV_CTX_DEAD) &&
                     (parent->flags & DEV_CTX_MUST_ISOLATE) &&
-                    ((parent->host == nullptr) || !(parent->host->flags() & DEV_HOST_DYING))) {
+                    ((parent->host == nullptr) ||
+                    !(parent->host->flags() & Devhost::Flags::kDying))) {
 
                     log(DEVLC, "devcoord: bus device %p name='%s' is unbound\n",
                         parent, parent->name);
@@ -1458,39 +1445,6 @@
     return ZX_OK;
 }
 
-// handle inbound messages from devhost to devices
-void Device::HandleRpc(Device* dev, async_dispatcher_t* dispatcher,
-                      async::WaitBase* wait, zx_status_t status,
-                      const zx_packet_signal_t* signal) {
-    if (status != ZX_OK) {
-        log(ERROR, "devcoord: Device::HandleRpc aborting, saw status %d\n", status);
-        return;
-    }
-
-    if (signal->observed & ZX_CHANNEL_READABLE) {
-        zx_status_t r;
-        if ((r = dev->coordinator->HandleDeviceRead(dev)) < 0) {
-            if (r != ZX_ERR_STOP) {
-                log(ERROR, "devcoord: device %p name='%s' rpc status: %d\n",
-                    dev, dev->name, r);
-            }
-            dev->coordinator->RemoveDevice(dev, true);
-            // Do not start waiting again on this device's channel again
-            return;
-        }
-        Device::BeginWait(dev, dispatcher);
-        return;
-    }
-    if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
-        log(ERROR, "devcoord: device %p name='%s' disconnected!\n", dev, dev->name);
-        dev->coordinator->RemoveDevice(dev, true);
-        // Do not start waiting again on this device's channel again
-        return;
-    }
-    log(ERROR, "devcoord: no work? %08x\n", signal->observed);
-    Device::BeginWait(dev, dispatcher);
-}
-
 // send message to devhost, requesting the creation of a device
 static zx_status_t dh_create_device(Device* dev, Devhost* dh,
                                     const char* args, zx::handle rpc_proxy) {
@@ -1767,7 +1721,7 @@
         return r;
     }
 
-    dh->flags() |= DEV_HOST_SUSPEND;
+    dh->flags() |= Devhost::Flags::kSuspend;
 
     auto pending = fbl::make_unique<PendingOperation>(PendingOperation::Op::kSuspend, ctx);
     if (pending == nullptr) {
diff --git a/system/core/devmgr/devmgr/coordinator.h b/system/core/devmgr/devmgr/coordinator.h
index 2fa6e8a..15327b9 100644
--- a/system/core/devmgr/devmgr/coordinator.h
+++ b/system/core/devmgr/devmgr/coordinator.h
@@ -11,9 +11,7 @@
 #include <fbl/string.h>
 #include <fbl/unique_ptr.h>
 #include <fbl/vector.h>
-#include <lib/async/cpp/task.h>
 #include <lib/async/cpp/wait.h>
-#include <lib/async-loop/cpp/loop.h>
 #include <lib/fit/function.h>
 #include <lib/zx/channel.h>
 #include <lib/zx/job.h>
@@ -23,160 +21,20 @@
 
 #include <utility>
 
+#include "device.h"
 #include "metadata.h"
 
 namespace devmgr {
 
-class Coordinator;
-class Devhost;
 class DevhostLoaderService;
-struct Devnode;
-class SuspendContext;
-
-class PendingOperation {
-public:
-    enum struct Op : uint32_t {
-        kBind = 1,
-        kSuspend = 2,
-    };
-
-    PendingOperation(Op op, SuspendContext* context) : op_(op), context_(context) {}
-
-    struct Node {
-        static fbl::DoublyLinkedListNodeState<fbl::unique_ptr<PendingOperation>>& node_state(
-            PendingOperation& obj) {
-            return obj.node_;
-        }
-    };
-
-    Op op() const { return op_; }
-    SuspendContext* context() const { return context_; }
-
-private:
-    fbl::DoublyLinkedListNodeState<fbl::unique_ptr<PendingOperation>> node_;
-
-    Op op_;
-    SuspendContext* context_;
-};
-
-#define DEV_HOST_DYING 1
-#define DEV_HOST_SUSPEND 2
-
-struct Device {
-    explicit Device(Coordinator* coord);
-    ~Device();
-
-    // Begins waiting in |dispatcher| on |dev->wait|.  This transfers a
-    // reference of |dev| to the dispatcher.  The dispatcher returns ownership
-    // when the of that reference when the handler is invoked.
-    // TODO(teisenbe/kulakowski): Make this take a RefPtr
-    static zx_status_t BeginWait(Device* dev, async_dispatcher_t* dispatcher) {
-        // TODO(teisenbe/kulakowski): Once this takes a refptr, we should leak a
-        // ref in the success case (to present the ref owned by the dispatcher).
-        return dev->wait.Begin(dispatcher);
-    }
-
-    // Entrypoint for the RPC handler that captures the pointer ownership
-    // semantics.
-    void HandleRpcEntry(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
-                        const zx_packet_signal_t* signal) {
-        // TODO(teisenbe/kulakowski): Perform the appropriate dance to construct
-        // a RefPtr from |this| without a net-increase in refcount, to represent
-        // the dispatcher passing ownership of its reference to the handler
-        HandleRpc(this, dispatcher, wait, status, signal);
-    }
-
-    // TODO(teisenbe/kulakowski): Make this take a RefPtr
-    static void HandleRpc(Device* dev, async_dispatcher_t* dispatcher,
-                          async::WaitBase* wait, zx_status_t status,
-                          const zx_packet_signal_t* signal);
-
-    Coordinator* coordinator;
-    zx::channel hrpc;
-    uint32_t flags = 0;
-
-    async::WaitMethod<Device, &Device::HandleRpcEntry> wait{this};
-    async::TaskClosure publish_task;
-
-    Devhost* host = nullptr;
-    const char* name = nullptr;
-    const char* libname = nullptr;
-    fbl::unique_ptr<const char[]> args;
-    // The backoff between each driver retry. This grows exponentially.
-    zx::duration backoff = zx::msec(250);
-    // The number of retries left for the driver.
-    uint32_t retries = 4;
-    mutable int32_t refcount_ = 0;
-    uint32_t protocol_id = 0;
-    uint32_t prop_count = 0;
-    Devnode* self = nullptr;
-    Devnode* link = nullptr;
-    Device* parent = nullptr;
-    Device* proxy = nullptr;
-
-    // For attaching as an open connection to the proxy device,
-    // or once the device becomes visible.
-    zx::channel client_remote;
-
-    // listnode for this device in its parent's
-    // list-of-children
-    fbl::DoublyLinkedListNodeState<Device*> node;
-    struct Node {
-        static fbl::DoublyLinkedListNodeState<Device*>& node_state(
-            Device& obj) {
-            return obj.node;
-        }
-    };
-
-    // listnode for this device in its devhost's
-    // list-of-devices
-    fbl::DoublyLinkedListNodeState<Device*> dhnode;
-    struct DevhostNode {
-        static fbl::DoublyLinkedListNodeState<Device*>& node_state(
-            Device& obj) {
-            return obj.dhnode;
-        }
-    };
-
-    // list of all child devices of this device
-    fbl::DoublyLinkedList<Device*, Node> children;
-
-    // list of outstanding requests from the devcoord
-    // to this device's devhost, awaiting a response
-    fbl::DoublyLinkedList<fbl::unique_ptr<PendingOperation>, PendingOperation::Node> pending;
-
-    // listnode for this device in the all devices list
-    fbl::DoublyLinkedListNodeState<Device*> anode;
-    struct AllDevicesNode {
-        static fbl::DoublyLinkedListNodeState<Device*>& node_state(
-            Device& obj) {
-            return obj.anode;
-        }
-    };
-
-    // Metadata entries associated to this device.
-    fbl::DoublyLinkedList<fbl::unique_ptr<Metadata>, Metadata::Node> metadata;
-
-    fbl::unique_ptr<zx_device_prop_t[]> props;
-
-    // Allocation backing |name| and |libname|
-    fbl::unique_ptr<char[]> name_alloc_;
-
-    // The AddRef and Release functions follow the contract for fbl::RefPtr.
-    void AddRef() const {
-        ++refcount_;
-    }
-
-    // Returns true when the last reference has been released.
-    bool Release() const {
-        const int32_t rc = refcount_;
-        --refcount_;
-        return rc == 1;
-    }
-};
 
 class Devhost {
 public:
+    enum Flags : uint32_t {
+        kDying = 1 << 0,
+        kSuspend = 1 << 1,
+    };
+
     struct AllDevhostsNode {
         static fbl::DoublyLinkedListNodeState<Devhost*>& node_state(
             Devhost& obj) {
@@ -196,8 +54,6 @@
         }
     };
 
-    Devhost();
-
     zx_handle_t hrpc() const { return hrpc_; }
     void set_hrpc(zx_handle_t hrpc) { hrpc_ = hrpc; }
     zx::unowned_process proc() const { return zx::unowned_process(proc_); }
@@ -225,12 +81,12 @@
 
 private:
     async::Wait wait_;
-    zx_handle_t hrpc_;
+    zx_handle_t hrpc_ = ZX_HANDLE_INVALID;
     zx::process proc_;
-    zx_koid_t koid_;
-    mutable int32_t refcount_;
-    uint32_t flags_;
-    Devhost* parent_;
+    zx_koid_t koid_ = 0;
+    mutable int32_t refcount_ = 0;
+    uint32_t flags_ = 0;
+    Devhost* parent_ = nullptr;
 
     // list of all devices on this devhost
     fbl::DoublyLinkedList<Device*, Device::DevhostNode> devices_;
@@ -250,13 +106,12 @@
 
 class SuspendContext {
 public:
-    enum struct Flags : uint32_t {
+    enum class Flags : uint32_t {
         kRunning = 0u,
         kSuspend = 1u,
     };
 
-    SuspendContext() {
-    }
+    SuspendContext() = default;
 
     SuspendContext(Coordinator* coordinator,
                    Flags flags, uint32_t sflags, zx::socket socket,
diff --git a/system/core/devmgr/devmgr/device.cpp b/system/core/devmgr/devmgr/device.cpp
new file mode 100644
index 0000000..23641da
--- /dev/null
+++ b/system/core/devmgr/devmgr/device.cpp
@@ -0,0 +1,54 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device.h"
+
+#include "../shared/log.h"
+#include "coordinator.h"
+
+namespace devmgr {
+
+Device::Device(Coordinator* coord)
+    : coordinator(coord), publish_task([this] { coordinator->HandleNewDevice(this); }) {}
+
+Device::~Device() {
+    // TODO: cancel any pending rpc responses.  This clear is a hack to prevent
+    // pending's dtor from asserting.
+    pending.clear();
+}
+
+// Handle inbound messages from devhost to devices
+void Device::HandleRpc(Device* dev, async_dispatcher_t* dispatcher,
+                      async::WaitBase* wait, zx_status_t status,
+                      const zx_packet_signal_t* signal) {
+    if (status != ZX_OK) {
+        log(ERROR, "devcoord: Device::HandleRpc aborting, saw status %d\n", status);
+        return;
+    }
+
+    if (signal->observed & ZX_CHANNEL_READABLE) {
+        zx_status_t r;
+        if ((r = dev->coordinator->HandleDeviceRead(dev)) < 0) {
+            if (r != ZX_ERR_STOP) {
+                log(ERROR, "devcoord: device %p name='%s' rpc status: %d\n",
+                    dev, dev->name, r);
+            }
+            dev->coordinator->RemoveDevice(dev, true);
+            // Do not start waiting again on this device's channel again
+            return;
+        }
+        Device::BeginWait(dev, dispatcher);
+        return;
+    }
+    if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
+        log(ERROR, "devcoord: device %p name='%s' disconnected!\n", dev, dev->name);
+        dev->coordinator->RemoveDevice(dev, true);
+        // Do not start waiting again on this device's channel again
+        return;
+    }
+    log(ERROR, "devcoord: no work? %08x\n", signal->observed);
+    Device::BeginWait(dev, dispatcher);
+}
+
+} // namespace devmgr
diff --git a/system/core/devmgr/devmgr/device.h b/system/core/devmgr/devmgr/device.h
new file mode 100644
index 0000000..a39db45
--- /dev/null
+++ b/system/core/devmgr/devmgr/device.h
@@ -0,0 +1,160 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <ddk/device.h>
+#include <lib/async/cpp/task.h>
+#include <lib/async/cpp/wait.h>
+#include <lib/zx/channel.h>
+
+#include "metadata.h"
+
+namespace devmgr {
+
+class Coordinator;
+class Devhost;
+struct Devnode;
+class SuspendContext;
+
+class PendingOperation {
+public:
+    enum class Op : uint32_t {
+        kBind = 1,
+        kSuspend = 2,
+    };
+
+    PendingOperation(Op op, SuspendContext* context) : op_(op), context_(context) {}
+
+    struct Node {
+        static fbl::DoublyLinkedListNodeState<fbl::unique_ptr<PendingOperation>>& node_state(
+            PendingOperation& obj) {
+            return obj.node_;
+        }
+    };
+
+    Op op() const { return op_; }
+    SuspendContext* context() const { return context_; }
+
+private:
+    fbl::DoublyLinkedListNodeState<fbl::unique_ptr<PendingOperation>> node_;
+
+    Op op_;
+    SuspendContext* context_;
+};
+
+struct Device {
+    explicit Device(Coordinator* coord);
+    ~Device();
+
+    // Begins waiting in |dispatcher| on |dev->wait|.  This transfers a
+    // reference of |dev| to the dispatcher.  The dispatcher returns ownership
+    // when the of that reference when the handler is invoked.
+    // TODO(teisenbe/kulakowski): Make this take a RefPtr
+    static zx_status_t BeginWait(Device* dev, async_dispatcher_t* dispatcher) {
+        // TODO(teisenbe/kulakowski): Once this takes a refptr, we should leak a
+        // ref in the success case (to present the ref owned by the dispatcher).
+        return dev->wait.Begin(dispatcher);
+    }
+
+    // Entrypoint for the RPC handler that captures the pointer ownership
+    // semantics.
+    void HandleRpcEntry(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
+                        const zx_packet_signal_t* signal) {
+        // TODO(teisenbe/kulakowski): Perform the appropriate dance to construct
+        // a RefPtr from |this| without a net-increase in refcount, to represent
+        // the dispatcher passing ownership of its reference to the handler
+        HandleRpc(this, dispatcher, wait, status, signal);
+    }
+
+    // TODO(teisenbe/kulakowski): Make this take a RefPtr
+    static void HandleRpc(Device* dev, async_dispatcher_t* dispatcher,
+                          async::WaitBase* wait, zx_status_t status,
+                          const zx_packet_signal_t* signal);
+
+    Coordinator* coordinator;
+    zx::channel hrpc;
+    uint32_t flags = 0;
+
+    async::WaitMethod<Device, &Device::HandleRpcEntry> wait{this};
+    async::TaskClosure publish_task;
+
+    Devhost* host = nullptr;
+    const char* name = nullptr;
+    const char* libname = nullptr;
+    fbl::unique_ptr<const char[]> args;
+    // The backoff between each driver retry. This grows exponentially.
+    zx::duration backoff = zx::msec(250);
+    // The number of retries left for the driver.
+    uint32_t retries = 4;
+    mutable int32_t refcount_ = 0;
+    uint32_t protocol_id = 0;
+    uint32_t prop_count = 0;
+    Devnode* self = nullptr;
+    Devnode* link = nullptr;
+    Device* parent = nullptr;
+    Device* proxy = nullptr;
+
+    // For attaching as an open connection to the proxy device,
+    // or once the device becomes visible.
+    zx::channel client_remote;
+
+    // listnode for this device in its parent's
+    // list-of-children
+    fbl::DoublyLinkedListNodeState<Device*> node;
+    struct Node {
+        static fbl::DoublyLinkedListNodeState<Device*>& node_state(
+            Device& obj) {
+            return obj.node;
+        }
+    };
+
+    // listnode for this device in its devhost's
+    // list-of-devices
+    fbl::DoublyLinkedListNodeState<Device*> dhnode;
+    struct DevhostNode {
+        static fbl::DoublyLinkedListNodeState<Device*>& node_state(
+            Device& obj) {
+            return obj.dhnode;
+        }
+    };
+
+    // list of all child devices of this device
+    fbl::DoublyLinkedList<Device*, Node> children;
+
+    // list of outstanding requests from the devcoord
+    // to this device's devhost, awaiting a response
+    fbl::DoublyLinkedList<fbl::unique_ptr<PendingOperation>, PendingOperation::Node> pending;
+
+    // listnode for this device in the all devices list
+    fbl::DoublyLinkedListNodeState<Device*> anode;
+    struct AllDevicesNode {
+        static fbl::DoublyLinkedListNodeState<Device*>& node_state(
+            Device& obj) {
+            return obj.anode;
+        }
+    };
+
+    // Metadata entries associated to this device.
+    fbl::DoublyLinkedList<fbl::unique_ptr<Metadata>, Metadata::Node> metadata;
+
+    fbl::unique_ptr<zx_device_prop_t[]> props;
+
+    // Allocation backing |name| and |libname|
+    fbl::unique_ptr<char[]> name_alloc_;
+
+    // The AddRef and Release functions follow the contract for fbl::RefPtr.
+    void AddRef() const {
+        ++refcount_;
+    }
+
+    // Returns true when the last reference has been released.
+    bool Release() const {
+        const int32_t rc = refcount_;
+        --refcount_;
+        return rc == 1;
+    }
+};
+
+} // namespace devmgr
diff --git a/system/core/devmgr/devmgr/main.cpp b/system/core/devmgr/devmgr/main.cpp
index 200bb99..2eb9a31 100644
--- a/system/core/devmgr/devmgr/main.cpp
+++ b/system/core/devmgr/devmgr/main.cpp
@@ -28,6 +28,7 @@
 #include <zircon/syscalls/object.h>
 #include <zircon/syscalls/policy.h>
 
+#include <lib/async-loop/cpp/loop.h>
 #include <lib/devmgr-launcher/processargs.h>
 #include <lib/fdio/io.h>
 #include <lib/fdio/namespace.h>
diff --git a/system/core/devmgr/rules.mk b/system/core/devmgr/rules.mk
index 3175cd8..91fbeb6 100644
--- a/system/core/devmgr/rules.mk
+++ b/system/core/devmgr/rules.mk
@@ -18,6 +18,7 @@
     $(LOCAL_DIR)/devmgr/coordinator.cpp \
     $(LOCAL_DIR)/devmgr/devfs.cpp \
     $(LOCAL_DIR)/devmgr/devhost-loader-service.cpp \
+    $(LOCAL_DIR)/devmgr/device.cpp \
     $(LOCAL_DIR)/devmgr/drivers.cpp \
     $(LOCAL_DIR)/devmgr/fidl.cpp \
     $(LOCAL_DIR)/shared/env.cpp \