update_engine: Detect supported minor version from conf file.

If the delta minor version is not given as a command line argument, the
payload generator will look for the minor version in
etc/update_engine.conf in the old image.

BUG=chromium:455493
TEST=`FEATURES=test emerge-link update_engine`
CQ-DEPEND=CL:249956

Change-Id: I0f8e3f3c05432169770f2e8e283e8f1fb363def3
Reviewed-on: https://chromium-review.googlesource.com/249955
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Allie Wood <alliewood@chromium.org>
Tested-by: Allie Wood <alliewood@chromium.org>
diff --git a/delta_performer_unittest.cc b/delta_performer_unittest.cc
index b32ffc9..4e39c0c 100644
--- a/delta_performer_unittest.cc
+++ b/delta_performer_unittest.cc
@@ -11,6 +11,7 @@
 #include <string>
 #include <vector>
 
+#include <base/files/file_path.h>
 #include <base/files/file_util.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
@@ -1339,4 +1340,13 @@
   EXPECT_TRUE(test_utils::RecursiveUnlinkDir(temp_dir));
 }
 
+TEST(DeltaPerformerTest, MinorVersionsMatch) {
+  // Test that the minor version in update_engine.conf that is installed to
+  // the image matches the supported delta minor version in the update engine.
+  uint32_t minor_version;
+  base::FilePath conf_path("update_engine.conf");
+  EXPECT_TRUE(utils::GetMinorVersion(conf_path, &minor_version));
+  ASSERT_EQ(DeltaPerformer::kSupportedMinorPayloadVersion, minor_version);
+}
+
 }  // namespace chromeos_update_engine
diff --git a/payload_generator/delta_diff_generator.cc b/payload_generator/delta_diff_generator.cc
index 0791f4d..f11b694 100644
--- a/payload_generator/delta_diff_generator.cc
+++ b/payload_generator/delta_diff_generator.cc
@@ -1574,7 +1574,7 @@
     const string& private_key_path,
     off_t chunk_size,
     size_t rootfs_partition_size,
-    uint64_t minor_version,
+    uint32_t minor_version,
     const ImageInfo* old_image_info,
     const ImageInfo* new_image_info,
     uint64_t* metadata_size) {
diff --git a/payload_generator/delta_diff_generator.h b/payload_generator/delta_diff_generator.h
index a6dfa6a..8fc84eb 100644
--- a/payload_generator/delta_diff_generator.h
+++ b/payload_generator/delta_diff_generator.h
@@ -81,7 +81,7 @@
                                       const std::string& private_key_path,
                                       off_t chunk_size,
                                       size_t rootfs_partition_size,
-                                      uint64_t minor_version,
+                                      uint32_t minor_version,
                                       const ImageInfo* old_image_info,
                                       const ImageInfo* new_image_info,
                                       uint64_t* metadata_size);
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index cbcbaf0..4832430 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -40,7 +40,8 @@
 
 namespace {
 
-const uint64_t kInPlaceMinorPayloadVersion = 1;
+// The minor version used by the in-place delta generator algorithm.
+const uint32_t kInPlaceMinorPayloadVersion = 1;
 
 void ParseSignatureSizes(const string& signature_sizes_flag,
                          vector<int>* signature_sizes) {
@@ -255,7 +256,7 @@
   DEFINE_int64(rootfs_partition_size,
                chromeos_update_engine::kRootFSPartitionSize,
                "RootFS partition size for the image once installed");
-  DEFINE_int64(minor_version, 0,
+  DEFINE_int32(minor_version, 0,
                "The minor version of the payload being generated");
 
   DEFINE_string(old_channel, "",
@@ -378,17 +379,28 @@
     LOG(INFO) << "Generating full update";
   }
 
+  // Look for the minor version in the old image if it was not given as an
+  // argument.
   if (!CommandLine::ForCurrentProcess()->HasSwitch("minor_version")) {
-    if (is_delta) {
-      FLAGS_minor_version = DeltaPerformer::kSupportedMinorPayloadVersion;
+    uint32_t minor_version;
+    base::FilePath image_path(FLAGS_old_dir);
+    base::FilePath conf_loc("etc/update_engine.conf");
+    base::FilePath conf_path = image_path.Append(conf_loc);
+    if (utils::GetMinorVersion(conf_path, &minor_version)) {
+      FLAGS_minor_version = minor_version;
     } else {
-      FLAGS_minor_version = DeltaPerformer::kFullPayloadMinorVersion;
+      if (is_delta) {
+        FLAGS_minor_version = DeltaPerformer::kSupportedMinorPayloadVersion;
+      } else {
+        FLAGS_minor_version = DeltaPerformer::kFullPayloadMinorVersion;
+      }
     }
   }
 
-  if (FLAGS_minor_version == kInPlaceMinorPayloadVersion ||
-      static_cast<uint64_t>(FLAGS_minor_version) ==
-          DeltaPerformer::kFullPayloadMinorVersion) {
+  if (static_cast<uint32_t>(FLAGS_minor_version) ==
+      kInPlaceMinorPayloadVersion ||
+      static_cast<uint32_t>(FLAGS_minor_version) ==
+      DeltaPerformer::kFullPayloadMinorVersion) {
     uint64_t metadata_size;
     if (!DeltaDiffGenerator::GenerateDeltaUpdateFile(
         FLAGS_old_dir,
diff --git a/update_engine.conf b/update_engine.conf
new file mode 100644
index 0000000..ff69eb8
--- /dev/null
+++ b/update_engine.conf
@@ -0,0 +1 @@
+PAYLOAD_MINOR_VERSION=1
diff --git a/utils.cc b/utils.cc
index 77e5a35..c512414 100644
--- a/utils.cc
+++ b/utils.cc
@@ -37,6 +37,7 @@
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
 #include <chromeos/data_encoding.h>
+#include <chromeos/key_value_store.h>
 #include <glib.h>
 
 #include "update_engine/clock_interface.h"
@@ -1574,6 +1575,17 @@
   return ret;
 }
 
+bool GetMinorVersion(base::FilePath path, uint32_t* minor_version) {
+  chromeos::KeyValueStore store;
+  std::string result;
+  if (base::PathExists(path) && store.Load(path) &&
+      store.GetString("PAYLOAD_MINOR_VERSION", &result)) {
+    *minor_version = atoi(result.c_str());
+    return true;
+  }
+  return false;
+}
+
 }  // namespace utils
 
 }  // namespace chromeos_update_engine
diff --git a/utils.h b/utils.h
index 661a260..8e168f1 100644
--- a/utils.h
+++ b/utils.h
@@ -437,6 +437,14 @@
                              int64_t* storage,
                              base::TimeDelta* out_duration);
 
+// This function looks for a configuration file at |path|. If it finds that
+// file, it will try get the PAYLOAD_MINOR_VERSION value from it and set
+// |minor_version| to that value.
+//
+// The function will return |true| if it succeeds at finding the file and
+// value and setting it, and |false| otherwise.
+bool GetMinorVersion(base::FilePath path, uint32_t* minor_version);
+
 }  // namespace utils
 
 
diff --git a/utils_unittest.cc b/utils_unittest.cc
index ce65c50..2ac95cb 100644
--- a/utils_unittest.cc
+++ b/utils_unittest.cc
@@ -15,6 +15,7 @@
 
 #include <base/files/file_path.h>
 #include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
 #include <gtest/gtest.h>
@@ -771,6 +772,23 @@
                                      NetworkTethering::kUnknown));
 }
 
+TEST(UtilsTest, GetMinorVersion) {
+  // Test GetMinorVersion by verifying that it parses the conf file and returns
+  // the correct value.
+  string contents = "PAYLOAD_MINOR_VERSION=1\n";
+  uint32_t minor_version;
+
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  base::FilePath temp_file("update_engine.conf");
+  base::FilePath filepath = temp_dir.path().Append(temp_file);
+
+  ASSERT_TRUE(test_utils::WriteFileString(filepath.value(), contents.c_str()));
+  ASSERT_TRUE(utils::GetMinorVersion(filepath, &minor_version));
+  ASSERT_EQ(minor_version, 1);
+}
+
 static bool BoolMacroTestHelper() {
   int i = 1;
   unsigned int ui = 1;