Add ability to check /etc/lsb-release for HWID

This is enabled by a compile-time option, only.

On certain boards HWID may not be available via normal means.
This functionality allows a compile-time choice to enable
behavior that will check /etc/lsb-release for an
HWID_OVERRIDE=<id> entry instead.

CQ-DEPEND=CL:186482
BUG=None
TEST=unit tests

Change-Id: I1279ea142a3b08dc4c50c527d8ee8f7b44c4a63f
Reviewed-on: https://chromium-review.googlesource.com/186483
Tested-by: Chris Masone <cmasone@chromium.org>
Reviewed-by: Chris Sosa <sosa@chromium.org>
Commit-Queue: Chris Masone <cmasone@chromium.org>
diff --git a/SConstruct b/SConstruct
index 9513526..0fe2bf9 100644
--- a/SConstruct
+++ b/SConstruct
@@ -269,6 +269,7 @@
                    hardware.cc
                    http_common.cc
                    http_fetcher.cc
+                   hwid_override.cc
                    install_plan.cc
                    libcurl_http_fetcher.cc
                    marshal.glibmarshal.c
@@ -320,6 +321,7 @@
                             gpio_mock_udev_interface.cc
                             graph_utils_unittest.cc
                             http_fetcher_unittest.cc
+                            hwid_override_unittest.cc
                             metadata_unittest.cc
                             mock_http_fetcher.cc
                             mock_system_state.cc
diff --git a/extent_writer_unittest.cc b/extent_writer_unittest.cc
index f0f5f7a..55cbff6 100644
--- a/extent_writer_unittest.cc
+++ b/extent_writer_unittest.cc
@@ -40,7 +40,7 @@
   }
   int fd() { return fd_; }
   const char* path() { return path_; }
-  
+
   // Writes data to an extent writer in 'chunk_size' chunks with
   // the first chunk of size first_chunk_size. It calculates what the
   // resultant file should look like and ensure that the extent writer
diff --git a/hardware.cc b/hardware.cc
index 6213739..26435cf 100644
--- a/hardware.cc
+++ b/hardware.cc
@@ -20,6 +20,7 @@
 const char* command = "";
 void (*uuid_generator)(uint8_t* buffer) = NULL;
 
+#include "update_engine/hwid_override.h"
 #include "update_engine/subprocess.h"
 #include "update_engine/utils.h"
 
@@ -28,6 +29,10 @@
 
 namespace chromeos_update_engine {
 
+Hardware::Hardware() {}
+
+Hardware::~Hardware() {}
+
 const string Hardware::BootKernelDevice() {
   return utils::KernelDeviceOfBootDevice(Hardware::BootDevice());
 }
@@ -128,6 +133,9 @@
 }
 
 string Hardware::GetHardwareClass() {
+  if (USE_HWID_OVERRIDE) {
+    return HwidOverride::Read(base::FilePath("/"));
+  }
   return ReadValueFromCrosSystem("hwid");
 }
 
diff --git a/hardware.h b/hardware.h
index 2693e3b..8168d9c 100644
--- a/hardware.h
+++ b/hardware.h
@@ -14,7 +14,8 @@
 // Implements the real interface with the hardware.
 class Hardware : public HardwareInterface {
  public:
-  Hardware() {}
+  Hardware();
+  virtual ~Hardware();
 
   // HardwareInterface methods.
   virtual const std::string BootKernelDevice();
diff --git a/hwid_override.cc b/hwid_override.cc
new file mode 100644
index 0000000..90e413b
--- /dev/null
+++ b/hwid_override.cc
@@ -0,0 +1,37 @@
+// 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.
+
+#include "update_engine/hwid_override.h"
+
+#include <map>
+#include <string>
+
+#include <base/basictypes.h>
+#include <base/file_path.h>
+#include <base/file_util.h>
+
+#include "update_engine/simple_key_value_store.h"
+
+using std::map;
+using std::string;
+
+namespace chromeos_update_engine {
+
+const char HwidOverride::kHwidOverrideKey[] = "HWID_OVERRIDE";
+
+HwidOverride::HwidOverride() {}
+
+HwidOverride::~HwidOverride() {}
+
+std::string HwidOverride::Read(const base::FilePath& root) {
+  base::FilePath kFile(root.value() + "/etc/lsb-release");
+  string file_data;
+  map<string, string> data;
+  if (file_util::ReadFileToString(kFile, &file_data)) {
+    data = simple_key_value_store::ParseString(file_data);
+  }
+  return data[kHwidOverrideKey];
+}
+
+}  // namespace chromeos_update_engine
diff --git a/hwid_override.h b/hwid_override.h
new file mode 100644
index 0000000..8f8dbc6
--- /dev/null
+++ b/hwid_override.h
@@ -0,0 +1,33 @@
+// 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_HWID_OVERRIDE_H__
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_HWID_OVERRIDE_H__
+
+#include <map>
+#include <string>
+
+#include <base/basictypes.h>
+#include <base/file_path.h>
+
+namespace chromeos_update_engine {
+
+// Class that allows HWID to be read from <root>/etc/lsb-release.
+class HwidOverride {
+ public:
+  HwidOverride();
+  ~HwidOverride();
+
+  // Read HWID from an /etc/lsb-release file under given root.
+  // An empty string is returned if there is any error.
+  static std::string Read(const base::FilePath& root);
+
+  static const char kHwidOverrideKey[];
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HwidOverride);
+};
+
+}  // namespace chromeos_update_engine
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_HWID_OVERRIDE_H__
diff --git a/hwid_override_unittest.cc b/hwid_override_unittest.cc
new file mode 100644
index 0000000..01c9fa0
--- /dev/null
+++ b/hwid_override_unittest.cc
@@ -0,0 +1,55 @@
+// 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.
+
+#include "update_engine/hwid_override.h"
+
+#include <string>
+
+#include <base/file_path.h>
+#include <base/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <gtest/gtest.h>
+
+namespace chromeos_update_engine {
+
+class HwidOverrideTest : public ::testing::Test {
+ public:
+  HwidOverrideTest() {}
+  virtual ~HwidOverrideTest() {}
+
+  virtual void SetUp() {
+    ASSERT_TRUE(tempdir_.CreateUniqueTempDir());
+    ASSERT_TRUE(file_util::CreateDirectory(tempdir_.path().Append("etc")));
+  }
+
+ protected:
+  base::ScopedTempDir tempdir_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HwidOverrideTest);
+};
+
+TEST_F(HwidOverrideTest, ReadGood) {
+  std::string expected_hwid("expected");
+  std::string keyval(HwidOverride::kHwidOverrideKey);
+  keyval += ("=" + expected_hwid);
+  ASSERT_EQ(file_util::WriteFile(tempdir_.path().Append("etc/lsb-release"),
+                                 keyval.c_str(), keyval.length()),
+            keyval.length());
+  EXPECT_EQ(expected_hwid, HwidOverride::Read(tempdir_.path()));
+}
+
+TEST_F(HwidOverrideTest, ReadNothing) {
+  std::string keyval("SOMETHING_ELSE=UNINTERESTING");
+  ASSERT_EQ(file_util::WriteFile(tempdir_.path().Append("etc/lsb-release"),
+                                 keyval.c_str(), keyval.length()),
+            keyval.length());
+  EXPECT_EQ(std::string(), HwidOverride::Read(tempdir_.path()));
+}
+
+TEST_F(HwidOverrideTest, ReadFailure) {
+  EXPECT_EQ(std::string(), HwidOverride::Read(tempdir_.path()));
+}
+
+}  // namespace chromeos_update_engine
diff --git a/simple_key_value_store.h b/simple_key_value_store.h
index 6453eee..24a1d75 100644
--- a/simple_key_value_store.h
+++ b/simple_key_value_store.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
 
@@ -14,8 +14,8 @@
 
 namespace chromeos_update_engine {
 namespace simple_key_value_store {
-  
-// Parses a string. 
+
+// Parses a string.
 std::map<std::string, std::string> ParseString(const std::string& str);
 
 std::string AssembleString(const std::map<std::string, std::string>& data);