Add security patch level to update manifest

When installing a full OTA, the target build might have a newer
timestamp but older SPL. In these caess, update_engine will fail to
recognize the SPL downgrade and skip data wipe, causing /data decryption
to fail on next reboot. To fix this issue, add a SPL field to update
manifest. update_engine will check this field on OTA install and
schedule data wipe as needed.

Test: install OTA with newer timestamp but older SPL, make sure data wipe is scheduled
Bug: 242812845


Change-Id: I9d1dd73b46323939bbf990e29da5cc0ba79f86e2
diff --git a/payload_generator/delta_diff_utils.h b/payload_generator/delta_diff_utils.h
index dcb6867..bfbcdf7 100644
--- a/payload_generator/delta_diff_utils.h
+++ b/payload_generator/delta_diff_utils.h
@@ -25,8 +25,9 @@
 #include <brillo/secure_blob.h>
 #include <puffin/puffdiff.h>
 
-#include "payload_generator/deflate_utils.h"
+#include "update_engine/payload_consumer/payload_constants.h"
 #include "update_engine/payload_generator/annotated_operation.h"
+#include "update_engine/payload_generator/deflate_utils.h"
 #include "update_engine/payload_generator/extent_ranges.h"
 #include "update_engine/payload_generator/payload_generation_config.h"
 #include "update_engine/update_metadata.pb.h"
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index 49c1e9c..96883a8 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -394,6 +394,11 @@
                "The maximum timestamp of the OS allowed to apply this "
                "payload.");
   DEFINE_string(
+      security_patch_level,
+      "",
+      "The security patch level of this OTA. Devices with a newer SPL "
+      "will not be allowed to apply this payload");
+  DEFINE_string(
       partition_timestamps,
       "",
       "The per-partition maximum timestamps which the OS allowed to apply this "
@@ -719,6 +724,9 @@
   }
 
   payload_config.max_timestamp = FLAGS_max_timestamp;
+
+  payload_config.security_patch_level = FLAGS_security_patch_level;
+
   if (!FLAGS_partition_timestamps.empty()) {
     CHECK(ParsePerPartitionTimestamps(FLAGS_partition_timestamps,
                                       &payload_config));
diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
index 129377a..0ef747a 100644
--- a/payload_generator/payload_file.cc
+++ b/payload_generator/payload_file.cc
@@ -26,7 +26,6 @@
 
 #include "update_engine/common/hash_calculator.h"
 #include "update_engine/common/utils.h"
-#include "update_engine/payload_consumer/delta_performer.h"
 #include "update_engine/payload_consumer/file_writer.h"
 #include "update_engine/payload_consumer/payload_constants.h"
 #include "update_engine/payload_generator/annotated_operation.h"
@@ -67,6 +66,7 @@
   manifest_.set_minor_version(config.version.minor);
   manifest_.set_block_size(config.block_size);
   manifest_.set_max_timestamp(config.max_timestamp);
+  manifest_.set_security_patch_level(config.security_patch_level);
 
   if (config.target.dynamic_partition_metadata != nullptr)
     *(manifest_.mutable_dynamic_partition_metadata()) =
diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
index 1e8794b..fc56f56 100644
--- a/payload_generator/payload_generation_config.h
+++ b/payload_generator/payload_generation_config.h
@@ -27,7 +27,6 @@
 #include <brillo/secure_blob.h>
 
 #include "bsdiff/constants.h"
-#include "update_engine/payload_consumer/payload_constants.h"
 #include "update_engine/payload_generator/filesystem_interface.h"
 #include "update_engine/update_metadata.pb.h"
 
@@ -262,6 +261,8 @@
   // Whether to enable zucchini ops
   bool enable_zucchini = true;
 
+  std::string security_patch_level;
+
   std::vector<bsdiff::CompressorType> compressors{
       bsdiff::CompressorType::kBZ2, bsdiff::CompressorType::kBrotli};
 
diff --git a/payload_generator/payload_properties_unittest.cc b/payload_generator/payload_properties_unittest.cc
index 0ff364f..0d62681 100644
--- a/payload_generator/payload_properties_unittest.cc
+++ b/payload_generator/payload_properties_unittest.cc
@@ -104,9 +104,9 @@
       "{"
       R"("is_delta":true,)"
       R"("metadata_signature":"",)"
-      R"("metadata_size":165,)"
-      R"("sha256_hex":"cV7kfZBH3K0B6QJHxxykDh6b6x0WgVOmc63whPLOy7U=",)"
-      R"("size":211,)"
+      R"("metadata_size":168,)"
+      R"("sha256_hex":"6rXHDjFO8k8mNtIbLhimWOifecVI1Ts230Ia1DyNuPY=",)"
+      R"("size":214,)"
       R"("version":2)"
       "}";
   string json;
@@ -118,10 +118,10 @@
 // Validate the hash of file and metadata are within the output.
 TEST_F(PayloadPropertiesTest, GetPropertiesAsKeyValueTestHash) {
   constexpr char kKeyValueProperties[] =
-      "FILE_HASH=cV7kfZBH3K0B6QJHxxykDh6b6x0WgVOmc63whPLOy7U=\n"
-      "FILE_SIZE=211\n"
-      "METADATA_HASH=aEKYyzJt2E8Gz8fzB+gmekN5mriotZCSq6R+kDfdeV4=\n"
-      "METADATA_SIZE=165\n";
+      "FILE_HASH=6rXHDjFO8k8mNtIbLhimWOifecVI1Ts230Ia1DyNuPY=\n"
+      "FILE_SIZE=214\n"
+      "METADATA_HASH=wq2nRZ7o/aqEeVWcc2Z+bebLYEI8quPEnXHlyLtdW9Y=\n"
+      "METADATA_SIZE=168\n";
   string key_value;
   EXPECT_TRUE(PayloadProperties{payload_file_.path()}.GetPropertiesAsKeyValue(
       &key_value));