Send an UMA metric when failed to boot into the new partition.

When a payload is successfully applied, the /other/ partition
is marked as valid and a reboot is needed, the reboot into this
new partition can fail due to several reasons. If than happens,
the firmware can rollback to the previous partition.

When this happens, this fix sends a new UMA metric with the
attempt number of this failing payload.

In order to test this functionality we need to fake the
utils::BootDevice() to emulate a reboot into the same or
a different partition. To achieve this, this function is
moved to a new "HardwareInterface" that can be faked
using the FakeHardware class that can hold similar hardware
related functions. Implementations and unittest were
refactored as needed.

BUG=chromium:243572
TEST=unittests

Change-Id: I1a4242df0bd61e2718ab881ead603b1d3705b877
Reviewed-on: https://gerrit.chromium.org/gerrit/61815
Commit-Queue: Alex Deymo <deymo@chromium.org>
Reviewed-by: Alex Deymo <deymo@chromium.org>
Tested-by: Alex Deymo <deymo@chromium.org>
diff --git a/hardware_interface.h b/hardware_interface.h
new file mode 100644
index 0000000..98773d9
--- /dev/null
+++ b/hardware_interface.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2013 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_HARDWARE_INTERFACE_H__
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_HARDWARE_INTERFACE_H__
+
+#include <string>
+
+namespace chromeos_update_engine {
+
+// The hardware interface allows access to the following parts of the system,
+// closely related to the hardware:
+//  * crossystem exposed properties: firmware, hwid, etc.
+//  * Physical disk: partition booted from and partition name conversions.
+// These stateless functions are tied together in this interface to facilitate
+// unit testing.
+class HardwareInterface {
+ public:
+  // Returns the currently booted device. "/dev/sda3", for example.
+  // This will not interpret LABEL= or UUID=. You'll need to use findfs
+  // or something with equivalent funcionality to interpret those.
+  virtual const std::string BootDevice() = 0;
+
+  // Returns the kernel device associated with the given boot device,
+  // for example, this function returns "/dev/sda2" if |boot_device| is
+  // "/dev/sda3".
+  // To obtain the current booted kernel device, the suggested calling
+  // convention is KernelDeviceOfBootDevice(BootDevice()).
+  // This function works by doing string modification on |boot_device|.
+  // Returns empty string on failure.
+  virtual const std::string KernelDeviceOfBootDevice(
+      const std::string& boot_device) = 0;
+
+  // TODO(deymo): Move other hardware-dependant functions to this interface:
+  // GetECVersion, GetFirmwareVersion, GetHardwareClass, IsNormalBootMode and
+  // IsOfficialBuild.
+
+  virtual ~HardwareInterface() {}
+};
+
+}  // namespace chromeos_update_engine
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_HARDWARE_INTERFACE_H__