Add human friendly payload information to the manifest.
This adds new strings to the payload manifest that describe what images
the payload updates from/to. These strings are passed in when delta_generator
is invoked, and are trusted implicitly.
BUG=chromium:226310
TEST=Built/Updated.
Change-Id: I278137c97cf8376d4e2fd8e82402cbb7d4f1a104
Reviewed-on: https://gerrit.chromium.org/gerrit/47347
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Tested-by: Don Garrett <dgarrett@chromium.org>
Commit-Queue: Don Garrett <dgarrett@chromium.org>
diff --git a/delta_diff_generator.cc b/delta_diff_generator.cc
index ee16454..9448c63 100644
--- a/delta_diff_generator.cc
+++ b/delta_diff_generator.cc
@@ -1387,6 +1387,8 @@
const string& private_key_path,
off_t chunk_size,
size_t rootfs_partition_size,
+ const ImageInfo* old_image_info,
+ const ImageInfo* new_image_info,
uint64_t* metadata_size) {
TEST_AND_RETURN_FALSE(chunk_size == -1 || chunk_size % kBlockSize == 0);
int old_image_block_count = 0, old_image_block_size = 0;
@@ -1401,6 +1403,12 @@
TEST_AND_RETURN_FALSE(old_image_block_size == new_image_block_size);
LOG_IF(WARNING, old_image_block_count != new_image_block_count)
<< "Old and new images have different block counts.";
+
+ // If new_image_info is present, old_image_info must but be present.
+ TEST_AND_RETURN_FALSE((bool)old_image_info == (bool)new_image_info);
+ } else {
+ // old_image_info must not be present for a full update.
+ TEST_AND_RETURN_FALSE(!old_image_info);
}
// Sanity checks for the partition size.
@@ -1521,6 +1529,13 @@
// Convert to protobuf Manifest object
DeltaArchiveManifest manifest;
+
+ if (old_image_info)
+ *(manifest.mutable_old_image_info()) = *old_image_info;
+
+ if (new_image_info)
+ *(manifest.mutable_new_image_info()) = *new_image_info;
+
OperationNameMap op_name_map;
CheckGraph(graph);
InstallOperationsToManifest(graph,
diff --git a/delta_diff_generator.h b/delta_diff_generator.h
index c258a58..aec403a 100644
--- a/delta_diff_generator.h
+++ b/delta_diff_generator.h
@@ -76,6 +76,8 @@
const std::string& private_key_path,
off_t chunk_size,
size_t rootfs_partition_size,
+ const ImageInfo* old_image_info,
+ const ImageInfo* new_image_info,
uint64_t* metadata_size);
// These functions are public so that the unit tests can access them:
diff --git a/delta_performer_unittest.cc b/delta_performer_unittest.cc
index 8964a3c..410fceb 100644
--- a/delta_performer_unittest.cc
+++ b/delta_performer_unittest.cc
@@ -269,6 +269,26 @@
state->image_size + 1024 * 1024 - 1)));
EXPECT_EQ(state->image_size + 1024 * 1024, utils::FileSize(state->a_img));
+ // Create ImageInfo A & B
+ ImageInfo old_image_info;
+ ImageInfo new_image_info;
+
+ if (!full_rootfs) {
+ old_image_info.set_channel("src-channel");
+ old_image_info.set_board("src-board");
+ old_image_info.set_version("src-version");
+ old_image_info.set_key("src-key");
+ old_image_info.set_build_channel("src-build-channel");
+ old_image_info.set_build_version("src-build-version");
+ }
+
+ new_image_info.set_channel("test-channel");
+ new_image_info.set_board("test-board");
+ new_image_info.set_version("test-version");
+ new_image_info.set_key("test-key");
+ new_image_info.set_build_channel("test-build-channel");
+ new_image_info.set_build_version("test-build-version");
+
// Make some changes to the A image.
{
string a_mnt;
@@ -311,6 +331,7 @@
if (noop) {
EXPECT_TRUE(file_util::CopyFile(FilePath(state->a_img),
FilePath(state->b_img)));
+ old_image_info = new_image_info;
} else {
CreateExtImageAtPath(state->b_img, NULL);
EXPECT_EQ(0, System(base::StringPrintf(
@@ -424,6 +445,8 @@
private_key,
chunk_size,
kRootFSPartitionSize,
+ full_rootfs ? NULL : &old_image_info,
+ &new_image_info,
&state->metadata_size));
}
@@ -454,6 +477,8 @@
&state->metadata_size));
LOG(INFO) << "Metadata size: " << state->metadata_size;
+
+
if (signature_test == kSignatureNone) {
EXPECT_FALSE(manifest.has_signatures_offset());
EXPECT_FALSE(manifest.has_signatures_size());
@@ -498,8 +523,41 @@
EXPECT_FALSE(manifest.old_kernel_info().hash().empty());
}
+ EXPECT_EQ(manifest.new_image_info().channel(), "test-channel");
+ EXPECT_EQ(manifest.new_image_info().board(), "test-board");
+ EXPECT_EQ(manifest.new_image_info().version(), "test-version");
+ EXPECT_EQ(manifest.new_image_info().key(), "test-key");
+ EXPECT_EQ(manifest.new_image_info().build_channel(), "test-build-channel");
+ EXPECT_EQ(manifest.new_image_info().build_version(), "test-build-version");
+
+ if (!full_rootfs) {
+
+ if (noop) {
+ EXPECT_EQ(manifest.old_image_info().channel(), "test-channel");
+ EXPECT_EQ(manifest.old_image_info().board(), "test-board");
+ EXPECT_EQ(manifest.old_image_info().version(), "test-version");
+ EXPECT_EQ(manifest.old_image_info().key(), "test-key");
+ EXPECT_EQ(manifest.old_image_info().build_channel(),
+ "test-build-channel");
+ EXPECT_EQ(manifest.old_image_info().build_version(),
+ "test-build-version");
+ } else {
+ EXPECT_EQ(manifest.old_image_info().channel(), "src-channel");
+ EXPECT_EQ(manifest.old_image_info().board(), "src-board");
+ EXPECT_EQ(manifest.old_image_info().version(), "src-version");
+ EXPECT_EQ(manifest.old_image_info().key(), "src-key");
+ EXPECT_EQ(manifest.old_image_info().build_channel(),
+ "src-build-channel");
+ EXPECT_EQ(manifest.old_image_info().build_version(),
+ "src-build-version");
+ }
+ }
+
+
if (full_rootfs) {
EXPECT_FALSE(manifest.has_old_rootfs_info());
+ EXPECT_FALSE(manifest.has_old_image_info());
+ EXPECT_TRUE(manifest.has_new_image_info());
} else {
EXPECT_EQ(state->image_size, manifest.old_rootfs_info().size());
EXPECT_FALSE(manifest.old_rootfs_info().hash().empty());
@@ -653,9 +711,9 @@
uint64_t new_rootfs_size;
vector<char> new_rootfs_hash;
EXPECT_TRUE(performer->GetNewPartitionInfo(&new_kernel_size,
- &new_kernel_hash,
- &new_rootfs_size,
- &new_rootfs_hash));
+ &new_kernel_hash,
+ &new_rootfs_size,
+ &new_rootfs_hash));
EXPECT_EQ(kDefaultKernelSize, new_kernel_size);
vector<char> expected_new_kernel_hash;
EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(state->new_kernel_data,
@@ -695,6 +753,7 @@
DeltaPerformer *performer;
GenerateDeltaFile(full_kernel, full_rootfs, noop, chunk_size,
signature_test, &state);
+
ScopedPathUnlinker a_img_unlinker(state.a_img);
ScopedPathUnlinker b_img_unlinker(state.b_img);
ScopedPathUnlinker delta_unlinker(state.delta_path);
diff --git a/generate_delta_main.cc b/generate_delta_main.cc
index 7c8b54b..1f49c42 100644
--- a/generate_delta_main.cc
+++ b/generate_delta_main.cc
@@ -65,6 +65,42 @@
chromeos_update_engine::kRootFSPartitionSize,
"RootFS partition size for the image once installed");
+DEFINE_string(old_channel, "",
+ "The channel for the old image. 'dev-channel', 'npo-channel', "
+ "etc. Ignored, except during delta generation.");
+DEFINE_string(old_board, "",
+ "The board for the old image. 'x86-mario', 'lumpy', "
+ "etc. Ignored, except during delta generation.");
+DEFINE_string(old_version, "",
+ "The build version of the old image. 1.2.3, etc.");
+DEFINE_string(old_key, "",
+ "The key used to sign the old image. 'premp', 'mp', 'mp-v3',"
+ " etc");
+DEFINE_string(old_build_channel, "",
+ "The channel for the build of the old image. 'dev-channel', "
+ "etc, but will never contain special channels such as "
+ "'npo-channel'. Ignored, except during delta generation.");
+DEFINE_string(old_build_version, "",
+ "The version of the build containing the old image.");
+
+DEFINE_string(new_channel, "",
+ "The channel for the new image. 'dev-channel', 'npo-channel', "
+ "etc. Ignored, except during delta generation.");
+DEFINE_string(new_board, "",
+ "The board for the new image. 'x86-mario', 'lumpy', "
+ "etc. Ignored, except during delta generation.");
+DEFINE_string(new_version, "",
+ "The build version of the new image. 1.2.3, etc.");
+DEFINE_string(new_key, "",
+ "The key used to sign the new image. 'premp', 'mp', 'mp-v3',"
+ " etc");
+DEFINE_string(new_build_channel, "",
+ "The channel for the build of the new image. 'dev-channel', "
+ "etc, but will never contain special channels such as "
+ "'npo-channel'. Ignored, except during delta generation.");
+DEFINE_string(new_build_version, "",
+ "The version of the build containing the new image.");
+
// This file contains a simple program that takes an old path, a new path,
// and an output file as arguments and the path to an output file and
// generates a delta that can be sent to Chrome OS clients.
@@ -99,6 +135,40 @@
}
+bool ParseImageInfo(const string& channel,
+ const string& board,
+ const string& version,
+ const string& key,
+ const string& build_channel,
+ const string& build_version,
+ ImageInfo* image_info) {
+
+ // All of these arguments should be present or missing.
+ bool empty = channel.empty();
+
+ CHECK_EQ(channel.empty(), empty);
+ CHECK_EQ(board.empty(), empty);
+ CHECK_EQ(version.empty(), empty);
+ CHECK_EQ(key.empty(), empty);
+
+ if (empty)
+ return false;
+
+ image_info->set_channel(channel);
+ image_info->set_board(board);
+ image_info->set_version(version);
+ image_info->set_key(key);
+
+ image_info->set_build_channel(
+ build_channel.empty() ? channel : build_channel);
+
+ image_info->set_build_version(
+ build_version.empty() ? version : build_version);
+
+ return true;
+}
+
+
void CalculatePayloadHashForSigning() {
LOG(INFO) << "Calculating payload hash for signing.";
LOG_IF(FATAL, FLAGS_in_file.empty())
@@ -257,28 +327,56 @@
CHECK(!FLAGS_new_image.empty());
CHECK(!FLAGS_out_file.empty());
CHECK(!FLAGS_new_kernel.empty());
- if (FLAGS_old_image.empty()) {
- LOG(INFO) << "Generating full update";
- } else {
+
+ bool is_delta = !FLAGS_old_image.empty();
+
+ ImageInfo old_image_info;
+ ImageInfo new_image_info;
+
+ // TODO(dgarrett) Check the result is True when these args are required.
+ ParseImageInfo(FLAGS_new_channel,
+ FLAGS_new_board,
+ FLAGS_new_version,
+ FLAGS_new_key,
+ FLAGS_new_build_channel,
+ FLAGS_new_build_version,
+ &new_image_info);
+
+ CHECK(is_delta || !ParseImageInfo(FLAGS_old_channel,
+ FLAGS_old_board,
+ FLAGS_old_version,
+ FLAGS_old_key,
+ FLAGS_old_build_channel,
+ FLAGS_old_build_version,
+ &old_image_info));
+
+
+ if (is_delta) {
LOG(INFO) << "Generating delta update";
CHECK(!FLAGS_old_dir.empty());
CHECK(!FLAGS_new_dir.empty());
if ((!IsDir(FLAGS_old_dir.c_str())) || (!IsDir(FLAGS_new_dir.c_str()))) {
LOG(FATAL) << "old_dir or new_dir not directory";
}
+ } else {
+ 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,
- &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 : NULL,
+ &new_image_info,
+ &metadata_size)) {
return 1;
}
return 0;
diff --git a/update_metadata.proto b/update_metadata.proto
index b9c061b..28ed0c6 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -90,6 +90,25 @@
optional bytes hash = 2;
}
+// Describe an image we are based on in a human friendly way.
+// Examples:
+// dev-channel, x86-alex, 1.2.3, mp-v3
+// nplusone-channel, x86-alex, 1.2.4, mp-v3, dev-channel, 1.2.3
+//
+// All fields will be set, if this message is present.
+message ImageInfo {
+ optional string board = 1;
+ optional string key = 2;
+ optional string channel = 3;
+ optional string version = 4;
+
+ // If these values aren't present, they should be assumed to match
+ // the equivalent value above. They are normally only different for
+ // special image types such as nplusone images.
+ optional string build_channel = 5;
+ optional string build_version = 6;
+}
+
message DeltaArchiveManifest {
message InstallOperation {
enum Type {
@@ -144,4 +163,9 @@
optional PartitionInfo new_kernel_info = 7;
optional PartitionInfo old_rootfs_info = 8;
optional PartitionInfo new_rootfs_info = 9;
+
+ // old_image_info will only be present for delta images.
+ optional ImageInfo old_image_info = 10;
+
+ optional ImageInfo new_image_info = 11;
}