update_engine: Add command line option for payload minor version.

Adds minor_version option to delta_generator for delta updates. This
defaults to kSupportedMinorPayloadVersion when the value is not given.
Stores the value in the DeltaArchiveManifest protobuf. Checks
that the specified version is supported, and fails if it is not.

BUG=chromium:455489
TEST=delta_diff_generator unit tests and manual testing.

Change-Id: I95fb5576d8f33fe8be738488c5ea85d8a46e917b
Reviewed-on: https://chromium-review.googlesource.com/247802
Reviewed-by: Alex Deymo <[email protected]>
Commit-Queue: Allie Wood <[email protected]>
Trybot-Ready: Allie Wood <[email protected]>
Tested-by: Allie Wood <[email protected]>
diff --git a/delta_performer_unittest.cc b/delta_performer_unittest.cc
index b8aad44..af257df 100644
--- a/delta_performer_unittest.cc
+++ b/delta_performer_unittest.cc
@@ -479,6 +479,7 @@
             private_key,
             chunk_size,
             kRootFSPartitionSize,
+            DeltaPerformer::kSupportedMinorPayloadVersion,
             full_rootfs ? nullptr : &old_image_info,
             &new_image_info,
             &state->metadata_size));
diff --git a/payload_generator/delta_diff_generator.cc b/payload_generator/delta_diff_generator.cc
index fae43d3..3a5e1eb 100644
--- a/payload_generator/delta_diff_generator.cc
+++ b/payload_generator/delta_diff_generator.cc
@@ -1574,6 +1574,7 @@
     const string& private_key_path,
     off_t chunk_size,
     size_t rootfs_partition_size,
+    uint64_t minor_version,
     const ImageInfo* old_image_info,
     const ImageInfo* new_image_info,
     uint64_t* metadata_size) {
@@ -1643,6 +1644,10 @@
     if (!old_image.empty()) {
       // Delta update
 
+      // Set the minor version for this payload.
+      LOG(INFO) << "Adding Delta Minor Version.";
+      manifest.set_minor_version(minor_version);
+
       TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph,
                                            &blocks,
                                            old_root,
@@ -1705,10 +1710,6 @@
                                               &data_file_size,
                                               &final_order,
                                               scratch_vertex));
-
-      // Set the minor version for this payload.
-      LOG(INFO) << "Adding Delta Minor Version.";
-      manifest.set_minor_version(DeltaPerformer::kSupportedMinorPayloadVersion);
     } else {
       // Full update
       off_t new_image_size =
diff --git a/payload_generator/delta_diff_generator.h b/payload_generator/delta_diff_generator.h
index ee5a409..109004e 100644
--- a/payload_generator/delta_diff_generator.h
+++ b/payload_generator/delta_diff_generator.h
@@ -67,6 +67,7 @@
   // If |chunk_size| is not -1, the delta payload is generated based on
   // |chunk_size| chunks rather than whole files.
   // This method computes scratch space based on |rootfs_partition_size|.
+  // |minor_version| indicates the payload minor version for a delta update.
   // Returns true on success. Also writes the size of the metadata into
   // |metadata_size|.
   static bool GenerateDeltaUpdateFile(const std::string& old_root,
@@ -79,6 +80,7 @@
                                       const std::string& private_key_path,
                                       off_t chunk_size,
                                       size_t rootfs_partition_size,
+                                      uint64_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 bcd8738..c0dfe18 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -40,6 +40,8 @@
 
 namespace {
 
+const uint64_t kInPlaceMinorPayloadVersion = 1;
+
 void ParseSignatureSizes(const string& signature_sizes_flag,
                          vector<int>* signature_sizes) {
   signature_sizes->clear();
@@ -253,6 +255,8 @@
   DEFINE_int64(rootfs_partition_size,
                chromeos_update_engine::kRootFSPartitionSize,
                "RootFS partition size for the image once installed");
+  DEFINE_int64(minor_version, 0,
+               "The minor version of the payload being generated");
 
   DEFINE_string(old_channel, "",
                 "The channel for the old image. 'dev-channel', 'npo-channel', "
@@ -374,23 +378,39 @@
     LOG(INFO) << "Generating full update";
   }
 
-  uint64_t metadata_size;
-  if (!DeltaDiffGenerator::GenerateDeltaUpdateFile(
-      FLAGS_old_dir,
-      FLAGS_old_image,
-      FLAGS_new_dir,
-      FLAGS_new_image,
-      FLAGS_old_kernel,
-      FLAGS_new_kernel,
-      FLAGS_out_file,
-      FLAGS_private_key,
-      FLAGS_chunk_size,
-      FLAGS_rootfs_partition_size,
-      is_delta ? &old_image_info : nullptr,
-      &new_image_info,
-      &metadata_size)) {
-    return 1;
+  if (!CommandLine::ForCurrentProcess()->HasSwitch("minor_version")) {
+    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) {
+    uint64_t metadata_size;
+    if (!DeltaDiffGenerator::GenerateDeltaUpdateFile(
+        FLAGS_old_dir,
+        FLAGS_old_image,
+        FLAGS_new_dir,
+        FLAGS_new_image,
+        FLAGS_old_kernel,
+        FLAGS_new_kernel,
+        FLAGS_out_file,
+        FLAGS_private_key,
+        FLAGS_chunk_size,
+        FLAGS_rootfs_partition_size,
+        FLAGS_minor_version,
+        is_delta ? &old_image_info : nullptr,
+        &new_image_info,
+        &metadata_size)) {
+      return 1;
+    }
+  } else {
+    LOG(FATAL) << "Unsupported minor payload version: " << FLAGS_minor_version;
+  }
+
   return 0;
 }