delta_generator: Include postinstall calls in the payload major version 2.
Added a new flag --new_postinstall_config_file which takes a path to a key
value store config file and saves this information to the PartitionUpdate
field.
The config file looks like this:
RUN_POSTINSTALL_root=true
POSTINSTALL_PATH_root=postinstall
FILESYSTEM_TYPE_root=ext4
"root" can be changed to any partition name.
Bug: 24537566
TEST=Generated a payload v2 with postinstall.
TEST=Added unittest.
Change-Id: Ied3c7bc2cfb54f4bcc69207f1e5bd473f72024fe
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index dbb15bc..2ea2f5e 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -28,6 +28,7 @@
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_split.h>
#include <brillo/flag_helper.h>
+#include <brillo/key_value_store.h>
#include "update_engine/common/prefs.h"
#include "update_engine/common/terminator.h"
@@ -327,6 +328,9 @@
"'npo-channel'. Ignored, except during delta generation.");
DEFINE_string(new_build_version, "",
"The version of the build containing the new image.");
+ DEFINE_string(new_postinstall_config_file, "",
+ "A config file specifying postinstall related metadata. "
+ "Only allowed in major version 2 or newer.");
brillo::FlagHelper::Init(argc, argv,
"Generates a payload to provide to ChromeOS' update_engine.\n\n"
@@ -430,6 +434,14 @@
}
}
+ if (!FLAGS_new_postinstall_config_file.empty()) {
+ LOG_IF(FATAL, FLAGS_major_version == kChromeOSMajorPayloadVersion)
+ << "Postinstall config is only allowed in major version 2 or newer.";
+ brillo::KeyValueStore store;
+ CHECK(store.Load(base::FilePath(FLAGS_new_postinstall_config_file)));
+ CHECK(payload_config.target.LoadPostInstallConfig(store));
+ }
+
// Use the default soft_chunk_size defined in the config.
payload_config.hard_chunk_size = FLAGS_chunk_size;
payload_config.block_size = kBlockSize;
diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
index 8b3efa6..d268ab8 100644
--- a/payload_generator/payload_file.cc
+++ b/payload_generator/payload_file.cc
@@ -87,6 +87,7 @@
Partition part;
part.name = new_conf.name;
part.aops = aops;
+ part.postinstall = new_conf.postinstall;
// Initialize the PartitionInfo objects if present.
if (!old_conf.path.empty())
TEST_AND_RETURN_FALSE(diff_utils::InitializePartitionInfo(old_conf,
@@ -132,6 +133,13 @@
if (major_version_ == kBrilloMajorPayloadVersion) {
PartitionUpdate* partition = manifest_.add_partitions();
partition->set_partition_name(part.name);
+ if (part.postinstall.run) {
+ partition->set_run_postinstall(true);
+ if (!part.postinstall.path.empty())
+ partition->set_postinstall_path(part.postinstall.path);
+ if (!part.postinstall.filesystem_type.empty())
+ partition->set_filesystem_type(part.postinstall.filesystem_type);
+ }
for (const AnnotatedOperation& aop : part.aops) {
*partition->add_operations() = aop.op;
}
diff --git a/payload_generator/payload_file.h b/payload_generator/payload_file.h
index 51584d6..7cc792a 100644
--- a/payload_generator/payload_file.h
+++ b/payload_generator/payload_file.h
@@ -93,6 +93,8 @@
PartitionInfo old_info;
PartitionInfo new_info;
+
+ PostInstallConfig postinstall;
};
std::vector<Partition> part_vec_;
diff --git a/payload_generator/payload_generation_config.cc b/payload_generator/payload_generation_config.cc
index 63d1884..813e33c 100644
--- a/payload_generator/payload_generation_config.cc
+++ b/payload_generator/payload_generation_config.cc
@@ -26,6 +26,10 @@
namespace chromeos_update_engine {
+bool PostInstallConfig::IsEmpty() const {
+ return run == false && path.empty() && filesystem_type.empty();
+}
+
bool PartitionConfig::ValidateExists() const {
TEST_AND_RETURN_FALSE(!path.empty());
TEST_AND_RETURN_FALSE(utils::FileExists(path.c_str()));
@@ -79,6 +83,26 @@
return true;
}
+bool ImageConfig::LoadPostInstallConfig(const brillo::KeyValueStore& store) {
+ bool found_postinstall = false;
+ for (PartitionConfig& part : partitions) {
+ bool run_postinstall;
+ if (!store.GetBoolean("RUN_POSTINSTALL_" + part.name, &run_postinstall) ||
+ !run_postinstall)
+ continue;
+ found_postinstall = true;
+ part.postinstall.run = true;
+ store.GetString("POSTINSTALL_PATH_" + part.name, &part.postinstall.path);
+ store.GetString("FILESYSTEM_TYPE_" + part.name,
+ &part.postinstall.filesystem_type);
+ }
+ if (!found_postinstall) {
+ LOG(ERROR) << "No valid postinstall config found.";
+ return false;
+ }
+ return true;
+}
+
bool ImageConfig::ImageInfoIsEmpty() const {
return image_info.board().empty()
&& image_info.key().empty()
@@ -95,6 +119,8 @@
TEST_AND_RETURN_FALSE(part.ValidateExists());
TEST_AND_RETURN_FALSE(part.size % block_size == 0);
}
+ // Source partition should not have postinstall.
+ TEST_AND_RETURN_FALSE(part.postinstall.IsEmpty());
}
// Check for the supported minor_version values.
@@ -118,6 +144,8 @@
if (minor_version == kInPlaceMinorPayloadVersion &&
part.name == kLegacyPartitionNameRoot)
TEST_AND_RETURN_FALSE(rootfs_partition_size >= part.size);
+ if (major_version == kChromeOSMajorPayloadVersion)
+ TEST_AND_RETURN_FALSE(part.postinstall.IsEmpty());
}
TEST_AND_RETURN_FALSE(hard_chunk_size == -1 ||
diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
index 8723680..21bb89b 100644
--- a/payload_generator/payload_generation_config.h
+++ b/payload_generator/payload_generation_config.h
@@ -23,12 +23,31 @@
#include <string>
#include <vector>
+#include <brillo/key_value_store.h>
+
#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_generator/filesystem_interface.h"
#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
+struct PostInstallConfig {
+ // Whether the postinstall config is empty.
+ bool IsEmpty() const;
+
+ // Whether this partition carries a filesystem with post-install program that
+ // must be run to finalize the update process.
+ bool run = false;
+
+ // The path to the post-install program relative to the root of this
+ // filesystem.
+ std::string path;
+
+ // The filesystem type used to mount the partition in order to run the
+ // post-install program.
+ std::string filesystem_type;
+};
+
struct PartitionConfig {
explicit PartitionConfig(std::string name) : name(name) {}
@@ -57,6 +76,8 @@
std::unique_ptr<FilesystemInterface> fs_interface;
std::string name;
+
+ PostInstallConfig postinstall;
};
// The ImageConfig struct describes a pair of binaries kernel and rootfs and the
@@ -72,6 +93,9 @@
// Returns whether the image size was properly detected.
bool LoadImageSize();
+ // Load postinstall config from a key value store.
+ bool LoadPostInstallConfig(const brillo::KeyValueStore& store);
+
// Returns whether the |image_info| field is empty.
bool ImageInfoIsEmpty() const;
diff --git a/payload_generator/payload_generation_config_unittest.cc b/payload_generator/payload_generation_config_unittest.cc
new file mode 100644
index 0000000..122d94a
--- /dev/null
+++ b/payload_generator/payload_generation_config_unittest.cc
@@ -0,0 +1,52 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/payload_generator/payload_generation_config.h"
+
+#include <gtest/gtest.h>
+
+namespace chromeos_update_engine {
+
+class PayloadGenerationConfigTest : public ::testing::Test {};
+
+TEST_F(PayloadGenerationConfigTest, SimpleLoadPostInstallConfigTest) {
+ ImageConfig image_config;
+ image_config.partitions.emplace_back("root");
+ brillo::KeyValueStore store;
+ EXPECT_TRUE(
+ store.LoadFromString("RUN_POSTINSTALL_root=true\n"
+ "POSTINSTALL_PATH_root=postinstall\n"
+ "FILESYSTEM_TYPE_root=ext4"));
+ EXPECT_TRUE(image_config.LoadPostInstallConfig(store));
+ EXPECT_FALSE(image_config.partitions[0].postinstall.IsEmpty());
+ EXPECT_EQ(true, image_config.partitions[0].postinstall.run);
+ EXPECT_EQ("postinstall", image_config.partitions[0].postinstall.path);
+ EXPECT_EQ("ext4", image_config.partitions[0].postinstall.filesystem_type);
+}
+
+TEST_F(PayloadGenerationConfigTest, LoadPostInstallConfigNameMismatchTest) {
+ ImageConfig image_config;
+ image_config.partitions.emplace_back("system");
+ brillo::KeyValueStore store;
+ EXPECT_TRUE(
+ store.LoadFromString("RUN_POSTINSTALL_root=true\n"
+ "POSTINSTALL_PATH_root=postinstall\n"
+ "FILESYSTEM_TYPE_root=ext4"));
+ EXPECT_FALSE(image_config.LoadPostInstallConfig(store));
+ EXPECT_TRUE(image_config.partitions[0].postinstall.IsEmpty());
+}
+
+} // namespace chromeos_update_engine
diff --git a/update_engine.gyp b/update_engine.gyp
index 4254e9a..47727c8 100644
--- a/update_engine.gyp
+++ b/update_engine.gyp
@@ -486,6 +486,7 @@
'payload_generator/graph_utils_unittest.cc',
'payload_generator/inplace_generator_unittest.cc',
'payload_generator/payload_file_unittest.cc',
+ 'payload_generator/payload_generation_config_unittest.cc',
'payload_generator/payload_signer_unittest.cc',
'payload_generator/tarjan_unittest.cc',
'payload_generator/topological_sort_unittest.cc',