Revised GPIO module interface + GPIO discovery logic

* The GpioHandler class is no longer a static singleton, rather an
  ordinary object with a dynamic guard against multiple instances. This
  makes testing/mocking a lot easier and simplifies implementation.

* It uses a basic, mockable udev interface; the module comes with
  complete unit testing of the discovery mechanism.

* Corresponding changes to user classes, including UpdateAttempter and
  UpdateCheckScheduler.

Note that the implementation of the test mode signaling protocol is
currently a no-op, always returning false, and hence has no effect on
the update process yet. This mechanism will be implemented in a later
CL.

BUG=chromium-os:25397
TEST=Builds and passes unit tests (including new ones)

Change-Id: I2f6254db6799ff5ef8616314890833f6e3269ff6
Reviewed-on: https://gerrit.chromium.org/gerrit/22869
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Tested-by: Gilad Arnold <garnold@chromium.org>
Commit-Ready: Gilad Arnold <garnold@chromium.org>
diff --git a/udev_interface.h b/udev_interface.h
new file mode 100644
index 0000000..b9765a8
--- /dev/null
+++ b/udev_interface.h
@@ -0,0 +1,193 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UDEV_INTERFACE_H__
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UDEV_INTERFACE_H__
+
+#include <libudev.h>
+
+#include "update_engine/utils.h"
+
+// An interface for libudev calls, allowing to easily mock it.
+
+namespace chromeos_update_engine {
+
+// An interface for libudev methods that are being used in update engine.
+//
+// TODO(garnold) As is, this is a pretty lame indirection layer that otherwise
+// does not provide any better abstraction than the existing libudev API. Done
+// properly, we should replace it with encapsulated udev, enumerate and device
+// objects, and hide initialization, reference handling and iterators in ways
+// more appropriate to an object-oriented setting...
+class UdevInterface {
+ public:
+  // Interfaces for various udev closers. All of these are merely containers for
+  // a single pointer to some udev handle, which invoke the provided interface's
+  // unref method and nullify the handle upon destruction. It should suffice for
+  // derivative (concrete) interfaces to implement the various unref methods to
+  // fit their needs, making these closers behave as expected.
+  class UdevCloser {
+   public:
+    explicit UdevCloser(UdevInterface* udev_iface, struct udev** udev_p)
+        : udev_iface_(udev_iface), udev_p_(udev_p) {
+      CHECK(udev_iface && udev_p);
+    }
+    virtual ~UdevCloser() {
+      if (*udev_p_) {
+        udev_iface_->Unref(*udev_p_);
+        *udev_p_ = NULL;
+      }
+    }
+   protected:
+    UdevInterface* udev_iface_;
+    struct udev** udev_p_;
+   private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(UdevCloser);
+  };
+
+  class UdevEnumerateCloser {
+   public:
+    explicit UdevEnumerateCloser(UdevInterface* udev_iface,
+                                 struct udev_enumerate** udev_enum_p)
+        : udev_iface_(udev_iface), udev_enum_p_(udev_enum_p) {
+      CHECK(udev_iface && udev_enum_p);
+    }
+    virtual ~UdevEnumerateCloser() {
+      if (*udev_enum_p_) {
+        udev_iface_->EnumerateUnref(*udev_enum_p_);
+        *udev_enum_p_ = NULL;
+      }
+    }
+   protected:
+    UdevInterface* udev_iface_;
+    struct udev_enumerate** udev_enum_p_;
+   private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(UdevEnumerateCloser);
+  };
+
+  class UdevDeviceCloser {
+   public:
+    explicit UdevDeviceCloser(UdevInterface* udev_iface,
+                              struct udev_device** udev_dev_p)
+        : udev_iface_(udev_iface), udev_dev_p_(udev_dev_p) {
+      CHECK(udev_iface && udev_dev_p);
+    }
+    virtual ~UdevDeviceCloser() {
+      if (*udev_dev_p_) {
+        udev_iface_->DeviceUnref(*udev_dev_p_);
+        *udev_dev_p_ = NULL;
+      }
+    }
+   protected:
+    UdevInterface* udev_iface_;
+    struct udev_device** udev_dev_p_;
+   private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(UdevDeviceCloser);
+  };
+
+  virtual UdevCloser* NewUdevCloser(struct udev** udev_p) {
+    return new UdevCloser(this, udev_p);
+  }
+  virtual UdevEnumerateCloser* NewUdevEnumerateCloser(
+      struct udev_enumerate** udev_enum_p) {
+    return new UdevEnumerateCloser(this, udev_enum_p);
+  }
+  virtual UdevDeviceCloser* NewUdevDeviceCloser(
+      struct udev_device** udev_dev_p) {
+    return new UdevDeviceCloser(this, udev_dev_p);
+  }
+
+  // Lists.
+  virtual const char* ListEntryGetName(struct udev_list_entry* list_entry) = 0;
+  virtual udev_list_entry* ListEntryGetNext(
+      struct udev_list_entry* list_entry) = 0;
+
+  // Device methods.
+  virtual struct udev_device* DeviceNewFromSyspath(
+      struct udev* udev,
+      const char* syspath) = 0;
+  virtual const char* DeviceGetPropertyValue(struct udev_device* udev_device,
+                                             const char* key) = 0;
+  virtual const char* DeviceGetSyspath(
+      struct udev_device* udev_device) = 0;
+  virtual void DeviceUnref(struct udev_device* udev_device) = 0;
+
+  // Enumerate methods.
+  virtual struct udev_enumerate* EnumerateNew(struct udev* udev) = 0;
+  virtual int EnumerateAddMatchSubsystem(struct udev_enumerate* udev_enum,
+                                         const char* subsystem) = 0;
+  virtual int EnumerateAddMatchSysname(struct udev_enumerate* udev_enum,
+                                       const char* sysname) = 0;
+  virtual int EnumerateScanDevices(struct udev_enumerate* udev_enum) = 0;
+  virtual struct udev_list_entry* EnumerateGetListEntry(
+      struct udev_enumerate* udev_enum) = 0;
+  virtual void EnumerateUnref(struct udev_enumerate* udev_enum) = 0;
+
+  // Udev instance methods.
+  virtual struct udev* New() = 0;
+  virtual void Unref(struct udev* udev) = 0;
+};
+
+
+// Implementation of libudev interface using concrete udev calls.
+class StandardUdevInterface : public UdevInterface {
+ public:
+  // Concrete udev API wrappers utilizing the standard libudev calls.
+  virtual const char* ListEntryGetName(struct udev_list_entry* list_entry) {
+    return udev_list_entry_get_name(list_entry);
+  }
+  virtual struct udev_list_entry* ListEntryGetNext(
+      struct udev_list_entry* list_entry) {
+    return udev_list_entry_get_next(list_entry);
+  }
+
+  virtual struct udev_device* DeviceNewFromSyspath(struct udev* udev,
+                                                   const char* syspath) {
+    return udev_device_new_from_syspath(udev, syspath);
+  }
+  virtual const char* DeviceGetPropertyValue(struct udev_device* udev_device,
+                                             const char* key) {
+    return udev_device_get_property_value(udev_device, key);
+  }
+  virtual const char* DeviceGetSyspath(struct udev_device* udev_device) {
+    return udev_device_get_syspath(udev_device);
+  }
+  virtual void DeviceUnref(struct udev_device* udev_device) {
+    return udev_device_unref(udev_device);
+  }
+
+  virtual struct udev_enumerate* EnumerateNew(struct udev* udev) {
+    return udev_enumerate_new(udev);
+  }
+  virtual int EnumerateAddMatchSubsystem(struct udev_enumerate* udev_enum,
+                                         const char* subsystem) {
+    return udev_enumerate_add_match_subsystem(udev_enum, subsystem);
+  }
+  virtual int EnumerateAddMatchSysname(struct udev_enumerate* udev_enum,
+                                       const char* sysname) {
+    return udev_enumerate_add_match_sysname(udev_enum, sysname);
+  }
+  virtual int EnumerateScanDevices(struct udev_enumerate* udev_enum) {
+    return udev_enumerate_scan_devices(udev_enum);
+  }
+  virtual struct udev_list_entry* EnumerateGetListEntry(
+      struct udev_enumerate* udev_enum) {
+    return udev_enumerate_get_list_entry(udev_enum);
+  }
+  virtual void EnumerateUnref(struct udev_enumerate* udev_enum) {
+    return udev_enumerate_unref(udev_enum);
+  }
+
+  virtual struct udev* New() {
+    return udev_new();
+  }
+  virtual void Unref(struct udev* udev) {
+    return udev_unref(udev);
+  }
+};
+
+}  // namespace chromeos_update_engine
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UDEV_INTERFACE_H__
+