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/gpio_mock_udev_interface.h b/gpio_mock_udev_interface.h
new file mode 100644
index 0000000..724a0f4
--- /dev/null
+++ b/gpio_mock_udev_interface.h
@@ -0,0 +1,134 @@
+// 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_GPIO_MOCK_UDEV_INTERFACE_H__
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_GPIO_MOCK_UDEV_INTERFACE_H__
+
+#include "update_engine/gpio_handler.h"
+#include "update_engine/udev_interface.h"
+
+// A set of mock udev interfaces for unit testing of GPIO handler.
+
+// Constant defining number of allowable mock udev objects.
+#define MAX_UDEV_OBJECTS      1
+#define MAX_UDEV_ENUM_OBJECTS 3
+
+namespace chromeos_update_engine {
+
+// An abstract class providing some diagnostic methods for testing.
+class GpioMockUdevInterface : public UdevInterface {
+ public:
+  // Asserts that all resources have been properly deallocated.
+  virtual void ExpectAllResourcesDeallocated() const = 0;
+  // Asserts the the udev client has successfully discovered the syspath of the
+  // GPIO signals.
+  virtual void ExpectDiscoverySuccess() const = 0;
+  // Asserts the opposite.
+  virtual void ExpectDiscoveryFail() const = 0;
+};
+
+class StandardGpioMockUdevInterface : public GpioMockUdevInterface {
+ public:
+  // Default constructor.
+  StandardGpioMockUdevInterface();
+
+  // Inherited interface methods.
+  virtual const char* ListEntryGetName(struct udev_list_entry* list_entry);
+  virtual udev_list_entry* ListEntryGetNext(struct udev_list_entry* list_entry);
+
+  virtual struct udev_device* DeviceNewFromSyspath(struct udev* udev,
+                                                   const char* syspath);
+  virtual const char* DeviceGetPropertyValue(struct udev_device* udev_device,
+                                             const char* key);
+  virtual const char* DeviceGetSyspath(struct udev_device* udev_device);
+  virtual void DeviceUnref(struct udev_device* udev_device);
+
+  virtual struct udev_enumerate* EnumerateNew(struct udev* udev);
+  virtual int EnumerateAddMatchSubsystem(struct udev_enumerate* udev_enum,
+                                         const char* subsystem);
+  virtual int EnumerateAddMatchSysname(struct udev_enumerate* udev_enum,
+                                       const char* sysname);
+  virtual int EnumerateScanDevices(struct udev_enumerate* udev_enum);
+  virtual struct udev_list_entry* EnumerateGetListEntry(
+      struct udev_enumerate* udev_enum);
+  virtual void EnumerateUnref(struct udev_enumerate* udev_enum);
+
+  virtual struct udev* New();
+  virtual void Unref(struct udev* udev);
+
+  virtual void ExpectAllResourcesDeallocated() const;
+  virtual void ExpectDiscoverySuccess() const;
+  virtual void ExpectDiscoveryFail() const;
+
+ protected:
+  // Some constants.
+  static const char* kUdevGpioSubsystem;
+  static const char* kUdevGpioChipSysname;
+  static const char* kMockGpioSysfsRoot;
+
+  // GPIO descriptor lookup.
+  struct GpioDescriptor {
+    const char* property;
+    const char* value;
+  };
+  static const GpioDescriptor gpio_descriptors_[];
+
+  // Numeric identifiers for new udev and enumerate objects.
+  size_t udev_id_;
+  size_t udev_enum_id_;
+
+  // Null-terminated lists of devices returned by various enumerations.
+  static const char* enum_gpio_chip_dev_list_[];
+  static const char* enum_dutflaga_gpio_dev_list_[];
+  static const char* enum_dutflagb_gpio_dev_list_[];
+
+  // Mock devices to be used during GPIO discovery.  These contain the syspath
+  // and a set of properties that the device may contain.
+  struct MockDevice {
+    const char* syspath;
+    const GpioDescriptor* properties;
+    size_t num_properties;
+    bool is_gpio;
+    bool is_used;
+  };
+  MockDevice gpio_chip_dev_;
+  MockDevice dutflaga_gpio_dev_;
+  MockDevice dutflagb_gpio_dev_;
+
+  // Tracking active mock object handles.
+  bool used_udev_ids_[MAX_UDEV_OBJECTS];
+  bool used_udev_enum_ids_[MAX_UDEV_ENUM_OBJECTS];
+
+  // Track discovery progress of GPIO signals.
+  unsigned num_discovered_;
+
+  // Convert mock udev handles into internal handles, with sanity checks.
+  MockDevice* UdevDeviceToMock(struct udev_device* udev_dev) const;
+  size_t UdevEnumToId(struct udev_enumerate* udev_enum) const;
+  size_t UdevToId(struct udev* udev) const;
+};
+
+class MultiChipGpioMockUdevInterface : public StandardGpioMockUdevInterface {
+ public:
+  // Default constructor.
+  MultiChipGpioMockUdevInterface();
+
+ protected:
+  virtual struct udev_device* DeviceNewFromSyspath(struct udev* udev,
+                                                   const char* syspath);
+  virtual struct udev_list_entry* EnumerateGetListEntry(
+      struct udev_enumerate* udev_enum);
+
+  // Null-terminated lists of devices returned by various enumerations.
+  static const char* enum_gpio_chip_dev_list_[];
+
+  // Mock devices to be used during GPIO discovery.  These contain the syspath
+  // and a set of properties that the device may contain.
+  MockDevice gpio_chip1_dev_;
+  MockDevice gpio_chip2_dev_;
+};
+
+}  // namespace chromeos_update_engine
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_GPIO_MOCK_UDEV_INTERFACE_H__