avbtool: make_vbmeta_image: Add --padding_size option.

This can be used to ensure the size of vbmeta.img is a multiple of
e.g. 4096 bytes.

Bug: 38454093
Test: New unit test and all unit tests pass.
Change-Id: I260003ce4ae127eb89ce0b547d5c5920dbe6b6e5
diff --git a/avbtool b/avbtool
index eea7664..17b8a0d 100755
--- a/avbtool
+++ b/avbtool
@@ -2353,7 +2353,8 @@
                         signing_helper_with_files,
                         release_string,
                         append_to_release_string,
-                        print_required_libavb_version):
+                        print_required_libavb_version,
+                        padding_size):
     """Implements the 'make_vbmeta_image' command.
 
     Arguments:
@@ -2374,6 +2375,7 @@
       release_string: None or avbtool release string to use instead of default.
       append_to_release_string: None or string to append.
       print_required_libavb_version: True to only print required libavb version.
+      padding_size: If not 0, pads output so size is a multiple of the number.
 
     Raises:
       AvbError: If a chained partition is malformed.
@@ -2403,6 +2405,11 @@
     output.seek(0)
     output.write(vbmeta_blob)
 
+    if padding_size > 0:
+      padded_size = round_to_multiple(len(vbmeta_blob), padding_size)
+      padding_needed = padded_size - len(vbmeta_blob)
+      output.write('\0' * padding_needed)
+
   def _generate_vbmeta_blob(self, algorithm_name, key_path,
                             public_key_metadata_path, descriptors,
                             chain_partitions,
@@ -3532,6 +3539,12 @@
     sub_parser.add_argument('--output',
                             help='Output file name',
                             type=argparse.FileType('wb'))
+    sub_parser.add_argument('--padding_size',
+                            metavar='NUMBER',
+                            help='If non-zero, pads output with NUL bytes so '
+                                 'its size is a multiple of NUMBER (default: 0)',
+                            type=parse_number,
+                            default=0)
     self._add_common_args(sub_parser)
     sub_parser.set_defaults(func=self.make_vbmeta_image)
 
@@ -3808,7 +3821,8 @@
                                args.signing_helper_with_files,
                                args.internal_release_string,
                                args.append_to_release_string,
-                               args.print_required_libavb_version)
+                               args.print_required_libavb_version,
+                               args.padding_size)
 
   def append_vbmeta_image(self, args):
     """Implements the 'append_vbmeta_image' sub-command."""
diff --git a/test/avbtool_unittest.cc b/test/avbtool_unittest.cc
index 19c0e37..fbfa4dd 100644
--- a/test/avbtool_unittest.cc
+++ b/test/avbtool_unittest.cc
@@ -263,6 +263,35 @@
   EXPECT_EQ('\n', s[20]);
 }
 
+TEST_F(AvbToolTest, Padding) {
+  GenerateVBMetaImage("vbmeta.img",
+                      "SHA256_RSA2048",
+                      0,
+                      base::FilePath("test/data/testkey_rsa2048.pem"),
+                      "--internal_release_string \"\"");
+
+  GenerateVBMetaImage("vbmeta_padded.img",
+                      "SHA256_RSA2048",
+                      0,
+                      base::FilePath("test/data/testkey_rsa2048.pem"),
+                      "--internal_release_string \"\" --padding_size 4096");
+
+  base::FilePath vbmeta_path = testdir_.Append("vbmeta.img");
+  base::FilePath vbmeta_padded_path = testdir_.Append("vbmeta_padded.img");
+  int64_t vbmeta_size, vbmeta_padded_size;
+  ASSERT_TRUE(base::GetFileSize(vbmeta_path, &vbmeta_size));
+  ASSERT_TRUE(base::GetFileSize(vbmeta_padded_path, &vbmeta_padded_size));
+
+  EXPECT_NE(vbmeta_size, vbmeta_padded_size);
+
+  // The padded size should be a multiple of 4096.
+  EXPECT_EQ(vbmeta_padded_size % 4096, 0);
+
+  // When rounded up the unpadded size should equal the padded size.
+  int64_t vbmeta_size_rounded_up = ((vbmeta_size + 4095) / 4096) * 4096;
+  EXPECT_EQ(vbmeta_size_rounded_up, vbmeta_padded_size);
+}
+
 TEST_F(AvbToolTest, CheckRollbackIndex) {
   uint64_t rollback_index = 42;
   GenerateVBMetaImage("vbmeta.img",