Round partition sizes to multiple of 4K in delta_generator
In the past, brillo_update_payload has been rounding partition sizes
before calling delta_generator. Since we plan to remove
brillo_update_payload, move such logic to delta_generator. This CL does
not change behavior of OTA generation.
Bug: 227848550
Test: th
Change-Id: Icba1fb61ce21a65334a9c29a14c939d205fcd878
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index 3a8d91a..5a901d3 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -14,6 +14,7 @@
// limitations under the License.
//
+#include <cstring>
#include <map>
#include <string>
#include <vector>
@@ -28,6 +29,7 @@
#include <base/strings/string_util.h>
#include <brillo/key_value_store.h>
#include <brillo/message_loops/base_message_loop.h>
+#include <unistd.h>
#include <xz.h>
#include <gflags/gflags.h>
@@ -304,156 +306,186 @@
return true;
}
- DEFINE_string(old_image, "", "Path to the old rootfs");
- DEFINE_string(new_image, "", "Path to the new rootfs");
- DEFINE_string(old_kernel, "", "Path to the old kernel partition image");
- DEFINE_string(new_kernel, "", "Path to the new kernel partition image");
- DEFINE_string(old_partitions,
- "",
- "Path to the old partitions. To pass multiple partitions, use "
- "a single argument with a colon between paths, e.g. "
- "/path/to/part:/path/to/part2::/path/to/last_part . Path can "
- "be empty, but it has to match the order of partition_names.");
- DEFINE_string(new_partitions,
- "",
- "Path to the new partitions. To pass multiple partitions, use "
- "a single argument with a colon between paths, e.g. "
- "/path/to/part:/path/to/part2:/path/to/last_part . Path has "
- "to match the order of partition_names.");
- DEFINE_string(old_mapfiles,
- "",
- "Path to the .map files associated with the partition files "
- "in the old partition. The .map file is normally generated "
- "when creating the image in Android builds. Only recommended "
- "for unsupported filesystem. Pass multiple files separated by "
- "a colon as with -old_partitions.");
- DEFINE_string(new_mapfiles,
- "",
- "Path to the .map files associated with the partition files "
- "in the new partition, similar to the -old_mapfiles flag.");
- DEFINE_string(partition_names,
- string(kPartitionNameRoot) + ":" + kPartitionNameKernel,
- "Names of the partitions. To pass multiple names, use a single "
- "argument with a colon between names, e.g. "
- "name:name2:name3:last_name . Name can not be empty, and it "
- "has to match the order of partitions.");
- DEFINE_string(in_file,
- "",
- "Path to input delta payload file used to hash/sign payloads "
- "and apply delta over old_image (for debugging)");
- DEFINE_string(out_file, "", "Path to output delta payload file");
- DEFINE_string(out_hash_file, "", "Path to output hash file");
- DEFINE_string(
- out_metadata_hash_file, "", "Path to output metadata hash file");
- DEFINE_string(
- out_metadata_size_file, "", "Path to output metadata size file");
- DEFINE_string(private_key, "", "Path to private key in .pem format");
- DEFINE_string(public_key, "", "Path to public key in .pem format");
- DEFINE_int32(
- public_key_version, -1, "DEPRECATED. Key-check version # of client");
- DEFINE_string(signature_size,
- "",
- "Raw signature size used for hash calculation. "
- "You may pass in multiple sizes by colon separating them. E.g. "
- "2048:2048:4096 will assume 3 signatures, the first two with "
- "2048 size and the last 4096.");
- DEFINE_string(payload_signature_file,
- "",
- "Raw signature file to sign payload with. To pass multiple "
- "signatures, use a single argument with a colon between paths, "
- "e.g. /path/to/sig:/path/to/next:/path/to/last_sig . Each "
- "signature will be assigned a client version, starting from "
- "kSignatureOriginalVersion.");
- DEFINE_string(metadata_signature_file,
- "",
- "Raw signature file with the signature of the metadata hash. "
- "To pass multiple signatures, use a single argument with a "
- "colon between paths, "
- "e.g. /path/to/sig:/path/to/next:/path/to/last_sig .");
- DEFINE_int32(
- chunk_size, 200 * 1024 * 1024, "Payload chunk size (-1 for whole files)");
- DEFINE_uint64(rootfs_partition_size,
- chromeos_update_engine::kRootFSPartitionSize,
- "RootFS partition size for the image once installed");
- DEFINE_uint64(
- major_version, 2, "The major version of the payload being generated.");
- DEFINE_int32(minor_version,
- -1,
- "The minor version of the payload being generated "
- "(-1 means autodetect).");
- DEFINE_string(properties_file,
- "",
- "If passed, dumps the payload properties of the payload passed "
- "in --in_file and exits. Look at --properties_format.");
- DEFINE_string(properties_format,
- kPayloadPropertiesFormatKeyValue,
- "Defines the format of the --properties_file. The acceptable "
- "values are: key-value (default) and json");
- DEFINE_int64(max_timestamp,
- 0,
- "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 "
- "payload. Passed in comma separated pairs, e.x. system:1234,vendor:5678");
+DEFINE_string(old_image, "", "Path to the old rootfs");
+DEFINE_string(new_image, "", "Path to the new rootfs");
+DEFINE_string(old_kernel, "", "Path to the old kernel partition image");
+DEFINE_string(new_kernel, "", "Path to the new kernel partition image");
+DEFINE_string(old_partitions,
+ "",
+ "Path to the old partitions. To pass multiple partitions, use "
+ "a single argument with a colon between paths, e.g. "
+ "/path/to/part:/path/to/part2::/path/to/last_part . Path can "
+ "be empty, but it has to match the order of partition_names.");
+DEFINE_string(new_partitions,
+ "",
+ "Path to the new partitions. To pass multiple partitions, use "
+ "a single argument with a colon between paths, e.g. "
+ "/path/to/part:/path/to/part2:/path/to/last_part . Path has "
+ "to match the order of partition_names.");
+DEFINE_string(old_mapfiles,
+ "",
+ "Path to the .map files associated with the partition files "
+ "in the old partition. The .map file is normally generated "
+ "when creating the image in Android builds. Only recommended "
+ "for unsupported filesystem. Pass multiple files separated by "
+ "a colon as with -old_partitions.");
+DEFINE_string(new_mapfiles,
+ "",
+ "Path to the .map files associated with the partition files "
+ "in the new partition, similar to the -old_mapfiles flag.");
+DEFINE_string(partition_names,
+ string(kPartitionNameRoot) + ":" + kPartitionNameKernel,
+ "Names of the partitions. To pass multiple names, use a single "
+ "argument with a colon between names, e.g. "
+ "name:name2:name3:last_name . Name can not be empty, and it "
+ "has to match the order of partitions.");
+DEFINE_string(in_file,
+ "",
+ "Path to input delta payload file used to hash/sign payloads "
+ "and apply delta over old_image (for debugging)");
+DEFINE_string(out_file, "", "Path to output delta payload file");
+DEFINE_string(out_hash_file, "", "Path to output hash file");
+DEFINE_string(out_metadata_hash_file, "", "Path to output metadata hash file");
+DEFINE_string(out_metadata_size_file, "", "Path to output metadata size file");
+DEFINE_string(private_key, "", "Path to private key in .pem format");
+DEFINE_string(public_key, "", "Path to public key in .pem format");
+DEFINE_int32(public_key_version,
+ -1,
+ "DEPRECATED. Key-check version # of client");
+DEFINE_string(signature_size,
+ "",
+ "Raw signature size used for hash calculation. "
+ "You may pass in multiple sizes by colon separating them. E.g. "
+ "2048:2048:4096 will assume 3 signatures, the first two with "
+ "2048 size and the last 4096.");
+DEFINE_string(payload_signature_file,
+ "",
+ "Raw signature file to sign payload with. To pass multiple "
+ "signatures, use a single argument with a colon between paths, "
+ "e.g. /path/to/sig:/path/to/next:/path/to/last_sig . Each "
+ "signature will be assigned a client version, starting from "
+ "kSignatureOriginalVersion.");
+DEFINE_string(metadata_signature_file,
+ "",
+ "Raw signature file with the signature of the metadata hash. "
+ "To pass multiple signatures, use a single argument with a "
+ "colon between paths, "
+ "e.g. /path/to/sig:/path/to/next:/path/to/last_sig .");
+DEFINE_int32(chunk_size,
+ 200 * 1024 * 1024,
+ "Payload chunk size (-1 for whole files)");
+DEFINE_uint64(rootfs_partition_size,
+ chromeos_update_engine::kRootFSPartitionSize,
+ "RootFS partition size for the image once installed");
+DEFINE_uint64(major_version,
+ 2,
+ "The major version of the payload being generated.");
+DEFINE_int32(minor_version,
+ -1,
+ "The minor version of the payload being generated "
+ "(-1 means autodetect).");
+DEFINE_string(properties_file,
+ "",
+ "If passed, dumps the payload properties of the payload passed "
+ "in --in_file and exits. Look at --properties_format.");
+DEFINE_string(properties_format,
+ kPayloadPropertiesFormatKeyValue,
+ "Defines the format of the --properties_file. The acceptable "
+ "values are: key-value (default) and json");
+DEFINE_int64(max_timestamp,
+ 0,
+ "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 "
+ "payload. Passed in comma separated pairs, e.x. system:1234,vendor:5678");
- DEFINE_string(new_postinstall_config_file,
- "",
- "A config file specifying postinstall related metadata. "
- "Only allowed in major version 2 or newer.");
- DEFINE_string(dynamic_partition_info_file,
- "",
- "An info file specifying dynamic partition metadata. "
- "Only allowed in major version 2 or newer.");
- DEFINE_bool(disable_fec_computation,
- false,
- "Disables the fec data computation on device.");
- DEFINE_bool(disable_verity_computation,
- false,
- "Disables the verity data computation on device.");
- DEFINE_string(
- out_maximum_signature_size_file,
- "",
- "Path to the output maximum signature size given a private key.");
- DEFINE_bool(is_partial_update,
- false,
- "The payload only targets a subset of partitions on the device,"
- "e.g. generic kernel image update.");
- DEFINE_bool(
- disable_vabc,
- false,
- "Whether to disable Virtual AB Compression when installing the OTA");
- DEFINE_bool(enable_vabc_xor,
- false,
- "Whether to use Virtual AB Compression XOR feature");
- DEFINE_string(
- apex_info_file, "", "Path to META/apex_info.pb found in target build");
- DEFINE_string(compressor_types,
- "bz2:brotli",
- "Colon ':' separated list of compressors. Allowed valures are "
- "bz2 and brotli.");
- DEFINE_bool(
- enable_lz4diff,
- false,
- "Whether to enable LZ4diff feature when processing EROFS images.");
+DEFINE_string(new_postinstall_config_file,
+ "",
+ "A config file specifying postinstall related metadata. "
+ "Only allowed in major version 2 or newer.");
+DEFINE_string(dynamic_partition_info_file,
+ "",
+ "An info file specifying dynamic partition metadata. "
+ "Only allowed in major version 2 or newer.");
+DEFINE_bool(disable_fec_computation,
+ false,
+ "Disables the fec data computation on device.");
+DEFINE_bool(disable_verity_computation,
+ false,
+ "Disables the verity data computation on device.");
+DEFINE_string(out_maximum_signature_size_file,
+ "",
+ "Path to the output maximum signature size given a private key.");
+DEFINE_bool(is_partial_update,
+ false,
+ "The payload only targets a subset of partitions on the device,"
+ "e.g. generic kernel image update.");
+DEFINE_bool(
+ disable_vabc,
+ false,
+ "Whether to disable Virtual AB Compression when installing the OTA");
+DEFINE_bool(enable_vabc_xor,
+ false,
+ "Whether to use Virtual AB Compression XOR feature");
+DEFINE_string(apex_info_file,
+ "",
+ "Path to META/apex_info.pb found in target build");
+DEFINE_string(compressor_types,
+ "bz2:brotli",
+ "Colon ':' separated list of compressors. Allowed valures are "
+ "bz2 and brotli.");
+DEFINE_bool(enable_lz4diff,
+ false,
+ "Whether to enable LZ4diff feature when processing EROFS images.");
- DEFINE_bool(
- enable_zucchini,
- true,
- "Whether to enable zucchini feature when processing executable files.");
+DEFINE_bool(
+ enable_zucchini,
+ true,
+ "Whether to enable zucchini feature when processing executable files.");
- DEFINE_string(erofs_compression_param,
- "",
- "Compression parameter passed to mkfs.erofs's -z option. "
- "Example: lz4 lz4hc,9");
- int Main(int argc, char** argv) {
+DEFINE_string(erofs_compression_param,
+ "",
+ "Compression parameter passed to mkfs.erofs's -z option. "
+ "Example: lz4 lz4hc,9");
+
+void RoundDownPartitions(const ImageConfig& config) {
+ for (const auto& part : config.partitions) {
+ if (part.path.empty()) {
+ continue;
+ }
+ const auto size = utils::FileSize(part.path);
+ if (size % kBlockSize != 0) {
+ const auto err =
+ truncate(part.path.c_str(), size / kBlockSize * kBlockSize);
+ CHECK_EQ(err, 0) << "Failed to truncate " << part.path << ", error "
+ << strerror(errno);
+ }
+ }
+}
+
+void RoundUpPartitions(const ImageConfig& config) {
+ for (const auto& part : config.partitions) {
+ if (part.path.empty()) {
+ continue;
+ }
+ const auto size = utils::FileSize(part.path);
+ if (size % kBlockSize != 0) {
+ const auto err = truncate(
+ part.path.c_str(), (size + kBlockSize - 1) / kBlockSize * kBlockSize);
+ CHECK_EQ(err, 0) << "Failed to truncate " << part.path << ", error "
+ << strerror(errno);
+ }
+ }
+}
+
+int Main(int argc, char** argv) {
gflags::SetUsageMessage(
"Generates a payload to provide to ChromeOS' update_engine.\n\n"
"This tool can create full payloads and also delta payloads if the src\n"
@@ -656,8 +688,10 @@
// The partition size is never passed to the delta_generator, so we
// need to detect those from the provided files.
if (payload_config.is_delta) {
+ RoundDownPartitions(payload_config.source);
CHECK(payload_config.source.LoadImageSize());
}
+ RoundUpPartitions(payload_config.target);
CHECK(payload_config.target.LoadImageSize());
if (!FLAGS_dynamic_partition_info_file.empty()) {
@@ -773,7 +807,7 @@
metadata_size_string.size()));
}
return 0;
- }
+}
} // namespace