summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp48
-rw-r--r--aosp/apex_handler_android.cc98
-rw-r--r--aosp/apex_handler_android.h48
-rw-r--r--aosp/apex_handler_android_unittest.cc109
-rw-r--r--aosp/apex_handler_interface.h36
-rw-r--r--aosp/cleanup_previous_update_action.cc6
-rw-r--r--aosp/cow_converter.cc131
-rw-r--r--aosp/daemon_state_android.cc9
-rw-r--r--aosp/dynamic_partition_control_android.cc14
-rw-r--r--aosp/dynamic_partition_control_android.h5
-rw-r--r--aosp/dynamic_partition_control_android_unittest.cc8
-rw-r--r--aosp/sideload_main.cc7
-rw-r--r--aosp/update_attempter_android.cc21
-rw-r--r--aosp/update_attempter_android.h6
-rw-r--r--aosp/update_attempter_android_unittest.cc2
-rw-r--r--common/cow_operation_convert.cc4
-rw-r--r--common/utils.cc26
-rw-r--r--common/utils.h5
-rw-r--r--payload_consumer/delta_performer.cc1
-rw-r--r--payload_consumer/delta_performer_integration_test.cc27
-rw-r--r--payload_consumer/payload_metadata.cc19
-rw-r--r--payload_consumer/payload_metadata.h7
-rw-r--r--payload_consumer/vabc_partition_writer.cc6
-rw-r--r--payload_generator/cow_size_estimator.cc93
-rw-r--r--payload_generator/cow_size_estimator.h17
-rw-r--r--payload_generator/delta_diff_generator.cc6
-rw-r--r--payload_generator/generate_delta_main.cc7
-rw-r--r--payload_generator/payload_file.cc3
-rw-r--r--payload_generator/payload_generation_config.cc9
-rw-r--r--payload_generator/payload_generation_config.h5
-rwxr-xr-xscripts/brillo_update_payload9
-rw-r--r--scripts/cow_converter.py87
-rwxr-xr-xscripts/update_device.py59
-rw-r--r--scripts/update_payload/update_metadata_pb2.py23
-rw-r--r--update_metadata.proto5
35 files changed, 892 insertions, 74 deletions
diff --git a/Android.bp b/Android.bp
index 4ec17f28..bc178bc5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -332,6 +332,7 @@ cc_defaults {
"PlatformProperties",
],
shared_libs: [
+ "apex_aidl_interface-cpp",
"libandroid_net",
"libbase",
"libbinder",
@@ -367,6 +368,7 @@ cc_library_static {
srcs: [
":libupdate_engine_aidl",
"common/system_state.cc",
+ "aosp/apex_handler_android.cc",
"aosp/binder_service_android.cc",
"aosp/binder_service_stable_android.cc",
"aosp/daemon_android.cc",
@@ -535,6 +537,7 @@ cc_defaults {
"libverity_tree",
"update_metadata-protos",
"libpayload_extent_utils",
+ "libcow_size_estimator",
],
shared_libs: [
"libbase",
@@ -558,6 +561,25 @@ cc_library_static {
}
cc_library_static {
+ name: "libcow_size_estimator",
+ defaults: [
+ "ue_defaults",
+ "update_metadata-protos_exports"
+ ],
+ host_supported: true,
+ recovery_available: true,
+ srcs: [
+ "payload_generator/cow_size_estimator.cc",
+ ],
+ static_libs: [
+ "update_metadata-protos",
+ "libbase",
+ "libsnapshot_cow",
+ "libcow_operation_convert",
+ ],
+}
+
+cc_library_static {
name: "libpayload_generator",
defaults: [
"ue_defaults",
@@ -574,7 +596,6 @@ cc_library_static {
"payload_generator/block_mapping.cc",
"payload_generator/boot_img_filesystem.cc",
"payload_generator/bzip.cc",
- "payload_generator/cow_size_estimator.cc",
"payload_generator/deflate_utils.cc",
"payload_generator/delta_diff_generator.cc",
"payload_generator/delta_diff_utils.cc",
@@ -740,6 +761,7 @@ cc_test {
test_suites: ["device-tests"],
srcs: [
+ "aosp/apex_handler_android_unittest.cc",
"aosp/dynamic_partition_control_android_unittest.cc",
"aosp/update_attempter_android_unittest.cc",
"certificate_checker_unittest.cc",
@@ -849,3 +871,27 @@ cc_library_headers {
},
}
}
+
+cc_binary_host {
+ name: "cow_converter",
+ defaults: [
+ "ue_defaults",
+ "libpayload_consumer_exports",
+ ],
+ srcs: [
+ "aosp/cow_converter.cc",
+ ],
+ static_libs: [
+ "liblog",
+ "libbrotli",
+ "libbase",
+ "libcow_operation_convert",
+ "libcow_size_estimator",
+ "libpayload_consumer",
+ "libpayload_extent_ranges",
+ "libpayload_extent_utils",
+ "libsnapshot_cow",
+ "libz",
+ "update_metadata-protos",
+ ],
+} \ No newline at end of file
diff --git a/aosp/apex_handler_android.cc b/aosp/apex_handler_android.cc
new file mode 100644
index 00000000..cdbc9834
--- /dev/null
+++ b/aosp/apex_handler_android.cc
@@ -0,0 +1,98 @@
+//
+// Copyright (C) 2021 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 <utility>
+
+#include <base/files/file_util.h>
+
+#include "update_engine/aosp/apex_handler_android.h"
+#include "update_engine/common/utils.h"
+
+namespace chromeos_update_engine {
+
+// Don't change this path... apexd relies on it.
+constexpr const char* kApexReserveSpaceDir = "/data/apex/ota_reserved";
+
+uint64_t ApexHandlerAndroid::CalculateSize(
+ const std::vector<ApexInfo>& apex_infos) const {
+ return CalculateSize(apex_infos, GetApexService());
+}
+
+uint64_t ApexHandlerAndroid::CalculateSize(
+ const std::vector<ApexInfo>& apex_infos,
+ android::sp<android::apex::IApexService> apex_service) const {
+ // The safest option is to allocate space for every compressed APEX
+ uint64_t size_required_default = 0;
+
+ // We might not need to decompress every APEX. Communicate with apexd to get
+ // accurate requirement.
+ int64_t size_from_apexd;
+ android::apex::CompressedApexInfoList compressed_apex_info_list;
+
+ for (const auto& apex_info : apex_infos) {
+ if (!apex_info.is_compressed()) {
+ continue;
+ }
+
+ size_required_default += apex_info.decompressed_size();
+
+ android::apex::CompressedApexInfo compressed_apex_info;
+ compressed_apex_info.moduleName = apex_info.package_name();
+ compressed_apex_info.versionCode = apex_info.version();
+ compressed_apex_info.decompressedSize = apex_info.decompressed_size();
+ compressed_apex_info_list.apexInfos.emplace_back(
+ std::move(compressed_apex_info));
+ }
+ if (size_required_default == 0 || apex_service == nullptr) {
+ return size_required_default;
+ }
+
+ auto result = apex_service->calculateSizeForCompressedApex(
+ compressed_apex_info_list, &size_from_apexd);
+ if (!result.isOk()) {
+ return size_required_default;
+ }
+ return size_from_apexd;
+}
+
+bool ApexHandlerAndroid::AllocateSpace(const uint64_t size_required) const {
+ return AllocateSpace(size_required, kApexReserveSpaceDir);
+}
+
+bool ApexHandlerAndroid::AllocateSpace(const uint64_t size_required,
+ const std::string& dir_path) const {
+ if (size_required == 0) {
+ return true;
+ }
+ base::FilePath path{dir_path};
+ // The filename is not important, it just needs to be under
+ // kApexReserveSpaceDir. We call it "full.tmp" because the current space
+ // estimation is simply adding up all decompressed sizes.
+ path = path.Append("full.tmp");
+ return utils::ReserveStorageSpace(path.value().c_str(), size_required);
+}
+
+android::sp<android::apex::IApexService> ApexHandlerAndroid::GetApexService()
+ const {
+ auto binder = android::defaultServiceManager()->waitForService(
+ android::String16("apexservice"));
+ if (binder == nullptr) {
+ return nullptr;
+ }
+ return android::interface_cast<android::apex::IApexService>(binder);
+}
+
+} // namespace chromeos_update_engine
diff --git a/aosp/apex_handler_android.h b/aosp/apex_handler_android.h
new file mode 100644
index 00000000..aac1cd9c
--- /dev/null
+++ b/aosp/apex_handler_android.h
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2021 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.
+//
+
+#ifndef SYSTEM_UPDATE_ENGINE_AOSP_APEX_HANDLER_ANDROID_H_
+#define SYSTEM_UPDATE_ENGINE_AOSP_APEX_HANDLER_ANDROID_H_
+
+#include <string>
+#include <vector>
+
+#include <android/apex/IApexService.h>
+#include <binder/IServiceManager.h>
+
+#include "update_engine/aosp/apex_handler_interface.h"
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+class ApexHandlerAndroid : virtual public ApexHandlerInterface {
+ public:
+ uint64_t CalculateSize(const std::vector<ApexInfo>& apex_infos) const;
+ bool AllocateSpace(const uint64_t size_required) const;
+
+ private:
+ friend class ApexHandlerAndroidTest;
+ android::sp<android::apex::IApexService> GetApexService() const;
+ uint64_t CalculateSize(
+ const std::vector<ApexInfo>& apex_infos,
+ android::sp<android::apex::IApexService> apex_service) const;
+ bool AllocateSpace(const uint64_t size_required,
+ const std::string& dir_path) const;
+};
+
+} // namespace chromeos_update_engine
+
+#endif // SYSTEM_UPDATE_ENGINE_AOSP_APEX_HANDLER_ANDROID_H_
diff --git a/aosp/apex_handler_android_unittest.cc b/aosp/apex_handler_android_unittest.cc
new file mode 100644
index 00000000..3a99f79b
--- /dev/null
+++ b/aosp/apex_handler_android_unittest.cc
@@ -0,0 +1,109 @@
+//
+// Copyright (C) 2021 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 <utility>
+#include <filesystem>
+
+#include "update_engine/aosp/apex_handler_android.h"
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <gtest/gtest.h>
+
+using android::base::EndsWith;
+
+namespace chromeos_update_engine {
+
+namespace fs = std::filesystem;
+
+class ApexHandlerAndroidTest : public ::testing::Test {
+ protected:
+ ApexHandlerAndroidTest() = default;
+
+ android::sp<android::apex::IApexService> GetApexService() const {
+ return apex_handler_.GetApexService();
+ }
+
+ uint64_t CalculateSize(
+ const std::vector<ApexInfo>& apex_infos,
+ android::sp<android::apex::IApexService> apex_service) const {
+ return apex_handler_.CalculateSize(apex_infos, apex_service);
+ }
+
+ bool AllocateSpace(const uint64_t size_required,
+ const std::string& dir_path) const {
+ return apex_handler_.AllocateSpace(size_required, dir_path);
+ }
+
+ ApexInfo CreateApexInfo(const std::string& package_name,
+ int version,
+ bool is_compressed,
+ int decompressed_size) {
+ ApexInfo result;
+ result.set_package_name(package_name);
+ result.set_version(version);
+ result.set_is_compressed(is_compressed);
+ result.set_decompressed_size(decompressed_size);
+ return std::move(result);
+ }
+
+ ApexHandlerAndroid apex_handler_;
+};
+
+// TODO(b/172911822): Once apexd has more optimized response for CalculateSize,
+// improve this test
+TEST_F(ApexHandlerAndroidTest, CalculateSize) {
+ std::vector<ApexInfo> apex_infos;
+ ApexInfo compressed_apex_1 = CreateApexInfo("sample1", 1, true, 10);
+ ApexInfo compressed_apex_2 = CreateApexInfo("sample2", 2, true, 20);
+ apex_infos.push_back(compressed_apex_1);
+ apex_infos.push_back(compressed_apex_2);
+ auto apex_service = GetApexService();
+ EXPECT_TRUE(apex_service != nullptr) << "Apexservice not found";
+ int required_size = CalculateSize(apex_infos, apex_service);
+ EXPECT_EQ(required_size, 30);
+}
+
+TEST_F(ApexHandlerAndroidTest, AllocateSpace) {
+ // Allocating 0 space should be a no op
+ TemporaryDir td;
+ EXPECT_TRUE(AllocateSpace(0, td.path));
+ EXPECT_TRUE(fs::is_empty(td.path));
+
+ // Allocating non-zero space should create a file with tmp suffix
+ EXPECT_TRUE(AllocateSpace(2 << 20, td.path));
+ EXPECT_FALSE(fs::is_empty(td.path));
+ int num_of_file = 0;
+ for (const auto& entry : fs::directory_iterator(td.path)) {
+ num_of_file++;
+ EXPECT_TRUE(EndsWith(entry.path().string(), ".tmp"));
+ EXPECT_EQ(fs::file_size(entry.path()), 2u << 20);
+ }
+ EXPECT_EQ(num_of_file, 1);
+
+ // AllocateSpace should be safe to call twice
+ EXPECT_TRUE(AllocateSpace(100, td.path));
+ EXPECT_FALSE(fs::is_empty(td.path));
+ num_of_file = 0;
+ for (const auto& entry : fs::directory_iterator(td.path)) {
+ num_of_file++;
+ EXPECT_TRUE(EndsWith(entry.path().string(), ".tmp"));
+ EXPECT_EQ(fs::file_size(entry.path()), 100u);
+ }
+ EXPECT_EQ(num_of_file, 1);
+}
+
+} // namespace chromeos_update_engine
diff --git a/aosp/apex_handler_interface.h b/aosp/apex_handler_interface.h
new file mode 100644
index 00000000..c3399b61
--- /dev/null
+++ b/aosp/apex_handler_interface.h
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2021 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.
+//
+
+#ifndef SYSTEM_UPDATE_ENGINE_AOSP_APEX_HANDLER_INTERFACE_H_
+#define SYSTEM_UPDATE_ENGINE_AOSP_APEX_HANDLER_INTERFACE_H_
+
+#include <vector>
+
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+class ApexHandlerInterface {
+ public:
+ virtual ~ApexHandlerInterface() = default;
+ virtual uint64_t CalculateSize(
+ const std::vector<ApexInfo>& apex_infos) const = 0;
+ virtual bool AllocateSpace(const uint64_t size_required) const = 0;
+};
+
+} // namespace chromeos_update_engine
+
+#endif // SYSTEM_UPDATE_ENGINE_AOSP_APEX_HANDLER_INTERFACE_H_
diff --git a/aosp/cleanup_previous_update_action.cc b/aosp/cleanup_previous_update_action.cc
index 55c5a735..6eaa35b2 100644
--- a/aosp/cleanup_previous_update_action.cc
+++ b/aosp/cleanup_previous_update_action.cc
@@ -395,9 +395,9 @@ void CleanupPreviousUpdateAction::InitiateMergeAndWait() {
return;
}
- uint64_t cow_file_size;
- if (snapshot_->InitiateMerge(&cow_file_size)) {
- merge_stats_->set_cow_file_size(cow_file_size);
+ snapshot_->UpdateCowStats(merge_stats_);
+
+ if (snapshot_->InitiateMerge()) {
WaitForMergeOrSchedule();
return;
}
diff --git a/aosp/cow_converter.cc b/aosp/cow_converter.cc
new file mode 100644
index 00000000..8c641b8d
--- /dev/null
+++ b/aosp/cow_converter.cc
@@ -0,0 +1,131 @@
+//
+// Copyright (C) 2021 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 <stdio.h>
+#include <string.h>
+
+#include <cstdint>
+#include <cstdio>
+#include <memory>
+
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <base/files/file_path.h>
+#include <libsnapshot/cow_writer.h>
+
+#include "update_engine/common/cow_operation_convert.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/payload_metadata.h"
+#include "update_engine/payload_generator/cow_size_estimator.h"
+#include "update_engine/update_metadata.pb.h"
+
+using android::snapshot::CowWriter;
+
+namespace chromeos_update_engine {
+
+bool ProcessPartition(const chromeos_update_engine::PartitionUpdate& partition,
+ const char* image_dir,
+ size_t block_size) {
+ base::FilePath img_dir{image_dir};
+ auto target_img = img_dir.Append(partition.partition_name() + ".img");
+ auto output_cow = img_dir.Append(partition.partition_name() + ".cow");
+ FileDescriptorPtr target_img_fd = std::make_shared<EintrSafeFileDescriptor>();
+ if (!target_img_fd->Open(target_img.value().c_str(), O_RDONLY)) {
+ PLOG(ERROR) << "Failed to open " << target_img.value();
+ return false;
+ }
+ android::base::unique_fd output_fd{
+ open(output_cow.value().c_str(), O_RDWR | O_CREAT, 0744)};
+ if (output_fd < 0) {
+ PLOG(ERROR) << "Failed to open " << output_cow.value();
+ return false;
+ }
+
+ android::snapshot::CowWriter cow_writer{
+ {.block_size = static_cast<uint32_t>(block_size), .compression = "gz"}};
+ TEST_AND_RETURN_FALSE(cow_writer.Initialize(output_fd));
+ TEST_AND_RETURN_FALSE(CowDryRun(target_img_fd,
+ partition.operations(),
+ partition.merge_operations(),
+ block_size,
+ &cow_writer));
+ TEST_AND_RETURN_FALSE(cow_writer.Finalize());
+ return true;
+}
+
+} // namespace chromeos_update_engine
+
+using chromeos_update_engine::MetadataParseResult;
+using chromeos_update_engine::PayloadMetadata;
+
+int main(int argc, const char* argv[]) {
+ if (argc != 3) {
+ printf("Usage: %s <payload.bin> <extracted target_file>\n", argv[0]);
+ return -1;
+ }
+ const char* payload_path = argv[1];
+ const char* images_dir = argv[2];
+ int payload_fd = open(payload_path, O_RDONLY);
+ if (payload_fd < 0) {
+ PLOG(ERROR) << "Failed to open payload file:";
+ return 1;
+ }
+ chromeos_update_engine::ScopedFdCloser closer{&payload_fd};
+ auto payload_size = chromeos_update_engine::utils::FileSize(payload_fd);
+ if (payload_size <= 0) {
+ PLOG(ERROR)
+ << "Couldn't determine size of payload file, or payload file is empty";
+ return 2;
+ }
+
+ PayloadMetadata payload_metadata;
+ auto payload = static_cast<unsigned char*>(
+ mmap(nullptr, payload_size, PROT_READ, MAP_PRIVATE, payload_fd, 0));
+
+ // C++ dark magic to ensure that |payload| is properly deallocated once the
+ // program exits.
+ auto munmap_deleter = [payload_size](auto payload) {
+ munmap(payload, payload_size);
+ };
+ std::unique_ptr<unsigned char, decltype(munmap_deleter)> munmapper{
+ payload, munmap_deleter};
+
+ if (payload == nullptr) {
+ PLOG(ERROR) << "Failed to mmap() payload file";
+ return 3;
+ }
+ if (payload_metadata.ParsePayloadHeader(payload, payload_size, nullptr) !=
+ chromeos_update_engine::MetadataParseResult::kSuccess) {
+ LOG(ERROR) << "Payload header parse failed!";
+ return 4;
+ }
+ chromeos_update_engine::DeltaArchiveManifest manifest;
+ if (!payload_metadata.GetManifest(payload, payload_size, &manifest)) {
+ LOG(ERROR) << "Failed to parse manifest!";
+ return 5;
+ }
+
+ for (const auto& partition : manifest.partitions()) {
+ LOG(INFO) << partition.partition_name();
+ if (!ProcessPartition(partition, images_dir, manifest.block_size())) {
+ return 6;
+ }
+ }
+ return 0;
+}
diff --git a/aosp/daemon_state_android.cc b/aosp/daemon_state_android.cc
index 9bdd1750..fc89d73e 100644
--- a/aosp/daemon_state_android.cc
+++ b/aosp/daemon_state_android.cc
@@ -18,6 +18,7 @@
#include <base/logging.h>
+#include "update_engine/aosp/apex_handler_android.h"
#include "update_engine/aosp/update_attempter_android.h"
#include "update_engine/common/boot_control.h"
#include "update_engine/common/boot_control_stub.h"
@@ -64,8 +65,12 @@ bool DaemonStateAndroid::Initialize() {
certificate_checker_->Init();
// Initialize the UpdateAttempter before the UpdateManager.
- update_attempter_.reset(new UpdateAttempterAndroid(
- this, prefs_.get(), boot_control_.get(), hardware_.get()));
+ update_attempter_.reset(
+ new UpdateAttempterAndroid(this,
+ prefs_.get(),
+ boot_control_.get(),
+ hardware_.get(),
+ std::make_unique<ApexHandlerAndroid>()));
return true;
}
diff --git a/aosp/dynamic_partition_control_android.cc b/aosp/dynamic_partition_control_android.cc
index 657eec9a..6bf896c5 100644
--- a/aosp/dynamic_partition_control_android.cc
+++ b/aosp/dynamic_partition_control_android.cc
@@ -939,6 +939,12 @@ bool DynamicPartitionControlAndroid::UpdatePartitionMetadata(
<< " to size " << partition_size << ". Not enough space?";
return false;
}
+ if (p->size() < partition_size) {
+ LOG(ERROR) << "Partition " << partition_name_suffix
+ << " was expected to have size " << partition_size
+ << ", but instead has size " << p->size();
+ return false;
+ }
LOG(INFO) << "Added partition " << partition_name_suffix << " to group "
<< group_name_suffix << " with size " << partition_size;
}
@@ -1015,9 +1021,11 @@ DynamicPartitionControlAndroid::GetPartitionDevice(
partition_name + SlotSuffixForSlotNumber(slot);
if (UpdateUsesSnapshotCompression() && IsDynamicPartition(partition_name) &&
slot != current_slot) {
- return {{.mountable_device_path =
- GetStaticDevicePath(device_dir, partition_name_suffix),
- .is_dynamic = true}};
+ return {
+ {.mountable_device_path = base::FilePath{std::string{VABC_DEVICE_DIR}}
+ .Append(partition_name_suffix)
+ .value(),
+ .is_dynamic = true}};
}
// When looking up target partition devices, treat them as static if the
diff --git a/aosp/dynamic_partition_control_android.h b/aosp/dynamic_partition_control_android.h
index d7c8781a..a23827b4 100644
--- a/aosp/dynamic_partition_control_android.h
+++ b/aosp/dynamic_partition_control_android.h
@@ -20,6 +20,7 @@
#include <memory>
#include <set>
#include <string>
+#include <string_view>
#include <vector>
#include <base/files/file_util.h>
@@ -33,6 +34,10 @@ namespace chromeos_update_engine {
class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface {
public:
+ // A directory where all partitions mapped by VABC is expected to be found.
+ // Per earlier discussion with VAB team, this directory is unlikely to change.
+ // So we declare it as a constant here.
+ static constexpr std::string_view VABC_DEVICE_DIR = "/dev/block/mapper/";
DynamicPartitionControlAndroid();
~DynamicPartitionControlAndroid();
diff --git a/aosp/dynamic_partition_control_android_unittest.cc b/aosp/dynamic_partition_control_android_unittest.cc
index 2f290d7c..4a12b830 100644
--- a/aosp/dynamic_partition_control_android_unittest.cc
+++ b/aosp/dynamic_partition_control_android_unittest.cc
@@ -472,7 +472,10 @@ TEST_P(DynamicPartitionControlAndroidTestP, GetMountableDevicePathVABC) {
auto device_info =
dynamicControl().GetPartitionDevice("system", target(), source(), false);
ASSERT_TRUE(device_info.has_value());
- ASSERT_EQ(device_info->mountable_device_path, GetDevice(T("system")));
+ base::FilePath vabc_device_dir{
+ std::string{DynamicPartitionControlAndroid::VABC_DEVICE_DIR}};
+ ASSERT_EQ(device_info->mountable_device_path,
+ vabc_device_dir.Append(T("system")).value());
}
TEST_P(DynamicPartitionControlAndroidTestP,
@@ -1102,7 +1105,8 @@ TEST_P(SnapshotPartitionTestP, RecoveryErrorShouldDeleteSource) {
SetMetadata(
source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}}, 0, super_size);
ExpectUnmap({T("system"), T("vendor")});
- // Expect that the source partitions aren't present in target super metadata.
+ // Expect that the source partitions aren't present in target super
+ // metadata.
ExpectStoreMetadata({{T("system"), 3_GiB}, {T("vendor"), 1_GiB}});
uint64_t required_size = 0;
diff --git a/aosp/sideload_main.cc b/aosp/sideload_main.cc
index 3cbc0c7f..bf015c94 100644
--- a/aosp/sideload_main.cc
+++ b/aosp/sideload_main.cc
@@ -154,8 +154,11 @@ bool ApplyUpdatePayload(const string& payload,
return false;
}
- UpdateAttempterAndroid update_attempter(
- &sideload_daemon_state, &prefs, boot_control.get(), hardware.get());
+ UpdateAttempterAndroid update_attempter(&sideload_daemon_state,
+ &prefs,
+ boot_control.get(),
+ hardware.get(),
+ nullptr);
update_attempter.Init();
TEST_AND_RETURN_FALSE(update_attempter.ApplyPayload(
diff --git a/aosp/update_attempter_android.cc b/aosp/update_attempter_android.cc
index 79840e8b..c685855f 100644
--- a/aosp/update_attempter_android.cc
+++ b/aosp/update_attempter_android.cc
@@ -133,11 +133,13 @@ UpdateAttempterAndroid::UpdateAttempterAndroid(
DaemonStateInterface* daemon_state,
PrefsInterface* prefs,
BootControlInterface* boot_control,
- HardwareInterface* hardware)
+ HardwareInterface* hardware,
+ std::unique_ptr<ApexHandlerInterface> apex_handler)
: daemon_state_(daemon_state),
prefs_(prefs),
boot_control_(boot_control),
hardware_(hardware),
+ apex_handler_android_(std::move(apex_handler)),
processor_(new ActionProcessor()),
clock_(new Clock()) {
metrics_reporter_ = metrics::CreateMetricsReporter(
@@ -977,6 +979,13 @@ uint64_t UpdateAttempterAndroid::AllocateSpaceForPayload(
return 0;
}
+ std::vector<ApexInfo> apex_infos(manifest.apex_info().begin(),
+ manifest.apex_info().end());
+ uint64_t apex_size_required = 0;
+ if (apex_handler_android_ != nullptr) {
+ apex_size_required = apex_handler_android_->CalculateSize(apex_infos);
+ }
+
string payload_id = GetPayloadId(headers);
uint64_t required_size = 0;
if (!DeltaPerformer::PreparePartitionsForUpdate(prefs_,
@@ -990,11 +999,19 @@ uint64_t UpdateAttempterAndroid::AllocateSpaceForPayload(
return 0;
} else {
LOG(ERROR) << "Insufficient space for payload: " << required_size
+ << " bytes, apex decompression: " << apex_size_required
<< " bytes";
- return required_size;
+ return required_size + apex_size_required;
}
}
+ if (apex_size_required > 0 && apex_handler_android_ != nullptr &&
+ !apex_handler_android_->AllocateSpace(apex_size_required)) {
+ LOG(ERROR) << "Insufficient space for apex decompression: "
+ << apex_size_required << " bytes";
+ return apex_size_required;
+ }
+
LOG(INFO) << "Successfully allocated space for payload.";
return 0;
}
diff --git a/aosp/update_attempter_android.h b/aosp/update_attempter_android.h
index 499f8f6b..70938bcd 100644
--- a/aosp/update_attempter_android.h
+++ b/aosp/update_attempter_android.h
@@ -26,6 +26,7 @@
#include <android-base/unique_fd.h>
#include <base/time/time.h>
+#include "update_engine/aosp/apex_handler_interface.h"
#include "update_engine/aosp/service_delegate_android_interface.h"
#include "update_engine/client_library/include/update_engine/update_status.h"
#include "update_engine/common/action_processor.h"
@@ -57,7 +58,8 @@ class UpdateAttempterAndroid
UpdateAttempterAndroid(DaemonStateInterface* daemon_state,
PrefsInterface* prefs,
BootControlInterface* boot_control_,
- HardwareInterface* hardware_);
+ HardwareInterface* hardware_,
+ std::unique_ptr<ApexHandlerInterface> apex_handler);
~UpdateAttempterAndroid() override;
// Further initialization to be done post construction.
@@ -205,6 +207,8 @@ class UpdateAttempterAndroid
BootControlInterface* boot_control_;
HardwareInterface* hardware_;
+ std::unique_ptr<ApexHandlerInterface> apex_handler_android_;
+
// Last status notification timestamp used for throttling. Use monotonic
// TimeTicks to ensure that notifications are sent even if the system clock is
// set back in the middle of an update.
diff --git a/aosp/update_attempter_android_unittest.cc b/aosp/update_attempter_android_unittest.cc
index 173e943d..f799df3e 100644
--- a/aosp/update_attempter_android_unittest.cc
+++ b/aosp/update_attempter_android_unittest.cc
@@ -69,7 +69,7 @@ class UpdateAttempterAndroidTest : public ::testing::Test {
FakeHardware hardware_;
UpdateAttempterAndroid update_attempter_android_{
- &daemon_state_, &prefs_, &boot_control_, &hardware_};
+ &daemon_state_, &prefs_, &boot_control_, &hardware_, nullptr};
FakeClock* clock_;
testing::NiceMock<MockMetricsReporter>* metrics_reporter_;
diff --git a/common/cow_operation_convert.cc b/common/cow_operation_convert.cc
index 4dc73a7c..2564abf0 100644
--- a/common/cow_operation_convert.cc
+++ b/common/cow_operation_convert.cc
@@ -20,6 +20,7 @@
#include "update_engine/payload_generator/extent_ranges.h"
#include "update_engine/payload_generator/extent_utils.h"
+#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
@@ -40,6 +41,9 @@ std::vector<CowOperation> ConvertToCowOperations(
// This loop handles CowCopy blocks within SOURCE_COPY, and the next loop
// converts the leftover blocks to CowReplace?
for (const auto& merge_op : merge_operations) {
+ if (merge_op.type() != CowMergeOperation::COW_COPY) {
+ continue;
+ }
merge_extents.AddExtent(merge_op.dst_extent());
const auto& src_extent = merge_op.src_extent();
const auto& dst_extent = merge_op.dst_extent();
diff --git a/common/utils.cc b/common/utils.cc
index 0f3b6c65..f5532ffe 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -28,6 +28,7 @@
#include <string.h>
#include <sys/mount.h>
#include <sys/resource.h>
+#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
@@ -547,6 +548,31 @@ bool SetBlockDeviceReadOnly(const string& device, bool read_only) {
return true;
}
+bool ReserveStorageSpace(const char* path, uint64_t size) {
+ int fd = HANDLE_EINTR(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600));
+
+ TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
+ ScopedFdCloser closer1{&fd};
+ if (ftruncate(fd, size) < 0) {
+ PLOG(WARNING) << "Failed to ftruncate " << path;
+ }
+ // 1MB buffer
+ std::vector<unsigned char> buffer(1 << 20);
+
+ while (size > 0) {
+ uint64_t bytes_to_write = std::min(size, (uint64_t)buffer.size());
+ if (!utils::WriteAll(fd, buffer.data(), bytes_to_write)) {
+ auto off = lseek64(fd, 0, SEEK_CUR);
+ PLOG(ERROR) << "Failed to write 0 to " << path << "offset: " << off
+ << " size: " << size;
+ unlink(path);
+ return false;
+ }
+ size -= bytes_to_write;
+ }
+ return true;
+}
+
bool MountFilesystem(const string& device,
const string& mountpoint,
unsigned long mountflags, // NOLINT(runtime/int)
diff --git a/common/utils.h b/common/utils.h
index 5f6e4757..9a278eb1 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <algorithm>
+#include <cstdint>
#include <limits>
#include <map>
#include <memory>
@@ -181,6 +182,10 @@ std::string MakePartitionName(const std::string& disk_name, int partition_num);
// in |read_only|. Return whether the operation succeeded.
bool SetBlockDeviceReadOnly(const std::string& device, bool read_only);
+// Reserve |size| bytes on space on |path| by creating a file at |path| and
+// write 0s into it. Return true iff both creation and writing succeed.
+[[nodiscard]] bool ReserveStorageSpace(const char* path, uint64_t size);
+
// Synchronously mount or unmount a filesystem. Return true on success.
// When mounting, it will attempt to mount the device as the passed filesystem
// type |type|, with the passed |flags| options. If |type| is empty, "ext2",
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index c6d63437..f26dd482 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -802,6 +802,7 @@ bool DeltaPerformer::PreparePartitionsForUpdate(
} else {
LOG(INFO) << "Preparing partitions for new update. last hash = "
<< last_hash << ", new hash = " << update_check_response_hash;
+ ResetUpdateProgress(prefs, false);
}
if (!boot_control->GetDynamicPartitionControl()->PreparePartitionsForUpdate(
diff --git a/payload_consumer/delta_performer_integration_test.cc b/payload_consumer/delta_performer_integration_test.cc
index e7ccff57..4fab9751 100644
--- a/payload_consumer/delta_performer_integration_test.cc
+++ b/payload_consumer/delta_performer_integration_test.cc
@@ -61,6 +61,9 @@ using test_utils::kRandomString;
using test_utils::ScopedLoopMounter;
using test_utils::System;
using testing::_;
+using testing::IsEmpty;
+using testing::NiceMock;
+using testing::Not;
using testing::Return;
extern const char* kUnittestPrivateKeyPath;
@@ -717,7 +720,24 @@ static void ApplyDeltaFile(bool full_kernel,
EXPECT_FALSE(rootfs_part.new_partition_info().hash().empty());
}
- MockPrefs prefs;
+ NiceMock<MockPrefs> prefs;
+ ON_CALL(prefs, SetInt64(kPrefsManifestMetadataSize, -1))
+ .WillByDefault(Return(true));
+ ON_CALL(prefs, SetInt64(kPrefsUpdateCheckResponseHash, -1))
+ .WillByDefault(Return(true));
+ ON_CALL(prefs, GetString(kPrefsUpdateCheckResponseHash, _))
+ .WillByDefault(Return(true));
+ ON_CALL(prefs, GetString(kPrefsDynamicPartitionMetadataUpdated, _))
+ .WillByDefault(Return(true));
+
+ // Set default expectation to ignore uninteresting calls to
+ // SetString/SetInt64. When starting an update delta_performer might reset
+ // update checkpoints, which results in a lot of calls with empty string or
+ // integer -1. Ignore these.
+ EXPECT_CALL(prefs, SetString(_, IsEmpty())).WillRepeatedly(Return(true));
+ EXPECT_CALL(prefs, SetInt64(_, -1)).WillRepeatedly(Return(true));
+ EXPECT_CALL(prefs, SetInt64(_, 0)).WillRepeatedly(Return(true));
+
EXPECT_CALL(prefs, SetInt64(kPrefsManifestMetadataSize, state->metadata_size))
.WillOnce(Return(true));
EXPECT_CALL(
@@ -744,8 +764,9 @@ static void ApplyDeltaFile(bool full_kernel,
state->metadata_size)))
.WillRepeatedly(Return(true));
if (op_hash_test == kValidOperationData && signature_test != kSignatureNone) {
- EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignatureBlob, _))
- .WillOnce(Return(true));
+ EXPECT_CALL(prefs,
+ SetString(kPrefsUpdateStateSignatureBlob, Not(IsEmpty())))
+ .WillRepeatedly(Return(true));
}
EXPECT_CALL(state->mock_delegate_, ShouldCancel(_))
diff --git a/payload_consumer/payload_metadata.cc b/payload_consumer/payload_metadata.cc
index 2cb73eb1..f797723c 100644
--- a/payload_consumer/payload_metadata.cc
+++ b/payload_consumer/payload_metadata.cc
@@ -50,12 +50,17 @@ uint64_t PayloadMetadata::GetManifestOffset() const {
MetadataParseResult PayloadMetadata::ParsePayloadHeader(
const brillo::Blob& payload, ErrorCode* error) {
+ return ParsePayloadHeader(payload.data(), payload.size(), error);
+}
+
+MetadataParseResult PayloadMetadata::ParsePayloadHeader(
+ const unsigned char* payload, size_t size, ErrorCode* error) {
// Ensure we have data to cover the major payload version.
- if (payload.size() < kDeltaManifestSizeOffset)
+ if (size < kDeltaManifestSizeOffset)
return MetadataParseResult::kInsufficientData;
// Validate the magic string.
- if (memcmp(payload.data(), kDeltaMagic, sizeof(kDeltaMagic)) != 0) {
+ if (memcmp(payload, kDeltaMagic, sizeof(kDeltaMagic)) != 0) {
LOG(ERROR) << "Bad payload format -- invalid delta magic: "
<< base::StringPrintf("%02x%02x%02x%02x",
payload[0],
@@ -74,7 +79,7 @@ MetadataParseResult PayloadMetadata::ParsePayloadHeader(
uint64_t manifest_offset = GetManifestOffset();
// Check again with the manifest offset.
- if (payload.size() < manifest_offset)
+ if (size < manifest_offset)
return MetadataParseResult::kInsufficientData;
// Extract the payload version from the metadata.
@@ -136,8 +141,14 @@ bool PayloadMetadata::ParsePayloadHeader(const brillo::Blob& payload) {
bool PayloadMetadata::GetManifest(const brillo::Blob& payload,
DeltaArchiveManifest* out_manifest) const {
+ return GetManifest(payload.data(), payload.size(), out_manifest);
+}
+
+bool PayloadMetadata::GetManifest(const unsigned char* payload,
+ size_t size,
+ DeltaArchiveManifest* out_manifest) const {
uint64_t manifest_offset = GetManifestOffset();
- CHECK_GE(payload.size(), manifest_offset + manifest_size_);
+ CHECK_GE(size, manifest_offset + manifest_size_);
return out_manifest->ParseFromArray(&payload[manifest_offset],
manifest_size_);
}
diff --git a/payload_consumer/payload_metadata.h b/payload_consumer/payload_metadata.h
index 8b36f533..f23b668f 100644
--- a/payload_consumer/payload_metadata.h
+++ b/payload_consumer/payload_metadata.h
@@ -56,6 +56,9 @@ class PayloadMetadata {
// the payload.
MetadataParseResult ParsePayloadHeader(const brillo::Blob& payload,
ErrorCode* error);
+ MetadataParseResult ParsePayloadHeader(const unsigned char* payload,
+ size_t size,
+ ErrorCode* error);
// Simpler version of the above, returns true on success.
bool ParsePayloadHeader(const brillo::Blob& payload);
@@ -88,6 +91,10 @@ class PayloadMetadata {
bool GetManifest(const brillo::Blob& payload,
DeltaArchiveManifest* out_manifest) const;
+ bool GetManifest(const unsigned char* payload,
+ size_t size,
+ DeltaArchiveManifest* out_manifest) const;
+
// Parses a payload file |payload_path| and prepares the metadata properties,
// manifest and metadata signatures. Can be used as an easy to use utility to
// get the payload information without manually the process.
diff --git a/payload_consumer/vabc_partition_writer.cc b/payload_consumer/vabc_partition_writer.cc
index aa8c3cef..0843fffb 100644
--- a/payload_consumer/vabc_partition_writer.cc
+++ b/payload_consumer/vabc_partition_writer.cc
@@ -102,11 +102,11 @@ bool VABCPartitionWriter::WriteAllCowOps(
std::vector<uint8_t> buffer(block_size);
for (const auto& cow_op : converted) {
- if (cow_op.src_block == cow_op.dst_block) {
- continue;
- }
switch (cow_op.op) {
case CowOperation::CowCopy:
+ if (cow_op.src_block == cow_op.dst_block) {
+ continue;
+ }
TEST_AND_RETURN_FALSE(
cow_writer->AddCopy(cow_op.dst_block, cow_op.src_block));
break;
diff --git a/payload_generator/cow_size_estimator.cc b/payload_generator/cow_size_estimator.cc
index 3eb0acac..01e99653 100644
--- a/payload_generator/cow_size_estimator.cc
+++ b/payload_generator/cow_size_estimator.cc
@@ -16,20 +16,22 @@
#include "update_engine/payload_generator/cow_size_estimator.h"
+#include <string>
#include <utility>
#include <vector>
+#include <android-base/unique_fd.h>
#include <libsnapshot/cow_writer.h>
-#include "android-base/unique_fd.h"
#include "update_engine/common/cow_operation_convert.h"
-#include "update_engine/payload_consumer/vabc_partition_writer.h"
+#include "update_engine/common/utils.h"
#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
using android::snapshot::CowWriter;
-void PerformReplaceOp(const InstallOperation& op,
+namespace {
+bool PerformReplaceOp(const InstallOperation& op,
CowWriter* writer,
FileDescriptorPtr target_fd,
size_t block_size) {
@@ -44,47 +46,101 @@ void PerformReplaceOp(const InstallOperation& op,
buffer.size(),
extent.start_block() * block_size,
&bytes_read);
- CHECK(success);
+ TEST_AND_RETURN_FALSE(success);
CHECK_EQ(static_cast<size_t>(bytes_read), buffer.size());
- writer->AddRawBlocks(extent.start_block(), buffer.data(), buffer.size());
+ TEST_AND_RETURN_FALSE(writer->AddRawBlocks(
+ extent.start_block(), buffer.data(), buffer.size()));
}
+ return true;
}
-void PerformZeroOp(const InstallOperation& op,
+bool PerformZeroOp(const InstallOperation& op,
CowWriter* writer,
size_t block_size) {
for (const auto& extent : op.dst_extents()) {
- writer->AddZeroBlocks(extent.start_block(), extent.num_blocks());
+ TEST_AND_RETURN_FALSE(
+ writer->AddZeroBlocks(extent.start_block(), extent.num_blocks()));
}
+ return true;
}
+bool WriteAllCowOps(size_t block_size,
+ const std::vector<CowOperation>& converted,
+ android::snapshot::ICowWriter* cow_writer,
+ FileDescriptorPtr target_fd) {
+ std::vector<uint8_t> buffer(block_size);
+
+ for (const auto& cow_op : converted) {
+ switch (cow_op.op) {
+ case CowOperation::CowCopy:
+ if (cow_op.src_block == cow_op.dst_block) {
+ continue;
+ }
+ TEST_AND_RETURN_FALSE(
+ cow_writer->AddCopy(cow_op.dst_block, cow_op.src_block));
+ break;
+ case CowOperation::CowReplace:
+ ssize_t bytes_read = 0;
+ TEST_AND_RETURN_FALSE(chromeos_update_engine::utils::ReadAll(
+ target_fd,
+ buffer.data(),
+ block_size,
+ cow_op.dst_block * block_size,
+ &bytes_read));
+ if (bytes_read <= 0 || static_cast<size_t>(bytes_read) != block_size) {
+ LOG(ERROR) << "source_fd->Read failed: " << bytes_read;
+ return false;
+ }
+ TEST_AND_RETURN_FALSE(cow_writer->AddRawBlocks(
+ cow_op.dst_block, buffer.data(), block_size));
+ break;
+ }
+ }
+
+ return true;
+}
+} // namespace
+
size_t EstimateCowSize(
- FileDescriptorPtr source_fd,
FileDescriptorPtr target_fd,
const google::protobuf::RepeatedPtrField<InstallOperation>& operations,
const google::protobuf::RepeatedPtrField<CowMergeOperation>&
merge_operations,
- size_t block_size) {
+ size_t block_size,
+ std::string compression) {
android::snapshot::CowWriter cow_writer{
- {.block_size = static_cast<uint32_t>(block_size), .compression = "gz"}};
+ {.block_size = static_cast<uint32_t>(block_size),
+ .compression = std::move(compression)}};
// CowWriter treats -1 as special value, will discard all the data but still
// reports Cow size. Good for estimation purposes
cow_writer.Initialize(android::base::borrowed_fd{-1});
+ CHECK(CowDryRun(
+ target_fd, operations, merge_operations, block_size, &cow_writer));
+ CHECK(cow_writer.Finalize());
+ return cow_writer.GetCowSize();
+}
+bool CowDryRun(
+ FileDescriptorPtr target_fd,
+ const google::protobuf::RepeatedPtrField<InstallOperation>& operations,
+ const google::protobuf::RepeatedPtrField<CowMergeOperation>&
+ merge_operations,
+ size_t block_size,
+ android::snapshot::CowWriter* cow_writer) {
const auto converted = ConvertToCowOperations(operations, merge_operations);
- VABCPartitionWriter::WriteAllCowOps(
- block_size, converted, &cow_writer, source_fd);
- cow_writer.AddLabel(0);
+ WriteAllCowOps(block_size, converted, cow_writer, target_fd);
+ cow_writer->AddLabel(0);
for (const auto& op : operations) {
switch (op.type()) {
case InstallOperation::REPLACE:
case InstallOperation::REPLACE_BZ:
case InstallOperation::REPLACE_XZ:
- PerformReplaceOp(op, &cow_writer, target_fd, block_size);
+ TEST_AND_RETURN_FALSE(
+ PerformReplaceOp(op, cow_writer, target_fd, block_size));
break;
case InstallOperation::ZERO:
case InstallOperation::DISCARD:
- PerformZeroOp(op, &cow_writer, block_size);
+ TEST_AND_RETURN_FALSE(PerformZeroOp(op, cow_writer, block_size));
break;
case InstallOperation::SOURCE_COPY:
case InstallOperation::MOVE:
@@ -96,15 +152,16 @@ size_t EstimateCowSize(
case InstallOperation::BSDIFF:
// We might do something special by adding CowBsdiff to CowWriter.
// For now proceed the same way as normal REPLACE operation.
- PerformReplaceOp(op, &cow_writer, target_fd, block_size);
+ TEST_AND_RETURN_FALSE(
+ PerformReplaceOp(op, cow_writer, target_fd, block_size));
break;
}
// Arbitrary label number, we won't be resuming use these labels here.
// They are emitted just to keep size estimates accurate. As update_engine
// emits 1 label for every op.
- cow_writer.AddLabel(2);
+ cow_writer->AddLabel(2);
}
// TODO(zhangkelvin) Take FEC extents into account once VABC stabilizes
- return cow_writer.GetCowSize();
+ return true;
}
} // namespace chromeos_update_engine
diff --git a/payload_generator/cow_size_estimator.h b/payload_generator/cow_size_estimator.h
index cba89b54..850c8909 100644
--- a/payload_generator/cow_size_estimator.h
+++ b/payload_generator/cow_size_estimator.h
@@ -14,23 +14,34 @@
// limitations under the License.
//
#include <cstddef>
+#include <string>
+#include <libsnapshot/cow_writer.h>
#include <update_engine/update_metadata.pb.h>
#include "update_engine/payload_consumer/file_descriptor.h"
namespace chromeos_update_engine {
-// Given file descriptor to the source image, target image, and list of
+// Given file descriptor to the target image, and list of
// operations, estimate the size of COW image if the operations are applied on
// Virtual AB Compression enabled device. This is intended to be used by update
// generators to put an estimate cow size in OTA payload. When installing an OTA
// update, libsnapshot will take this estimate as a hint to allocate spaces.
size_t EstimateCowSize(
- FileDescriptorPtr source_fd,
FileDescriptorPtr target_fd,
const google::protobuf::RepeatedPtrField<InstallOperation>& operations,
const google::protobuf::RepeatedPtrField<CowMergeOperation>&
merge_operations,
- size_t block_size);
+ size_t block_size,
+ std::string compression);
+
+// Convert InstallOps to CowOps and apply the converted cow op to |cow_writer|
+bool CowDryRun(
+ FileDescriptorPtr target_fd,
+ const google::protobuf::RepeatedPtrField<InstallOperation>& operations,
+ const google::protobuf::RepeatedPtrField<CowMergeOperation>&
+ merge_operations,
+ size_t block_size,
+ android::snapshot::CowWriter* cow_writer);
} // namespace chromeos_update_engine
diff --git a/payload_generator/delta_diff_generator.cc b/payload_generator/delta_diff_generator.cc
index 74014d91..a87dabf1 100644
--- a/payload_generator/delta_diff_generator.cc
+++ b/payload_generator/delta_diff_generator.cc
@@ -132,11 +132,11 @@ class PartitionProcessor : public base::DelegateSimpleThread::Delegate {
*operations.Add() = aop.op;
}
*cow_size_ = EstimateCowSize(
- source_fd,
std::move(target_fd),
- operations,
+ std::move(operations),
{cow_merge_sequence_->begin(), cow_merge_sequence_->end()},
- config_.block_size);
+ config_.block_size,
+ config_.target.dynamic_partition_metadata->vabc_compression_param());
LOG(INFO) << "Estimated COW size for partition: " << new_part_.name << " "
<< *cow_size_;
}
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index 7288ecaa..b04fec0b 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -599,7 +599,6 @@ int Main(int argc, char** argv) {
if (FLAGS_is_partial_update) {
payload_config.is_partial_update = true;
}
- payload_config.disable_vabc = FLAGS_disable_vabc;
if (!FLAGS_in_file.empty()) {
return ApplyPayload(FLAGS_in_file, payload_config) ? 0 : 1;
@@ -627,6 +626,12 @@ int Main(int argc, char** argv) {
CHECK(store.Load(base::FilePath(FLAGS_dynamic_partition_info_file)));
CHECK(payload_config.target.LoadDynamicPartitionMetadata(store));
CHECK(payload_config.target.ValidateDynamicPartitionMetadata());
+ if (FLAGS_disable_vabc) {
+ LOG(INFO) << "Disabling VABC";
+ payload_config.target.dynamic_partition_metadata->set_vabc_enabled(false);
+ payload_config.target.dynamic_partition_metadata
+ ->set_vabc_compression_param("");
+ }
}
CHECK(!FLAGS_out_file.empty());
diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
index 4334066d..6ec219ff 100644
--- a/payload_generator/payload_file.cc
+++ b/payload_generator/payload_file.cc
@@ -72,9 +72,6 @@ bool PayloadFile::Init(const PayloadGenerationConfig& config) {
*(manifest_.mutable_dynamic_partition_metadata()) =
*(config.target.dynamic_partition_metadata);
- if (config.disable_vabc) {
- manifest_.mutable_dynamic_partition_metadata()->set_vabc_enabled(false);
- }
if (config.is_partial_update) {
manifest_.set_partial_update(true);
}
diff --git a/payload_generator/payload_generation_config.cc b/payload_generator/payload_generation_config.cc
index f5a70626..d45de6a6 100644
--- a/payload_generator/payload_generation_config.cc
+++ b/payload_generator/payload_generation_config.cc
@@ -177,10 +177,15 @@ bool ImageConfig::LoadDynamicPartitionMetadata(
store.GetBoolean("virtual_ab", &snapshot_enabled);
metadata->set_snapshot_enabled(snapshot_enabled);
bool vabc_enabled = false;
- if (store.GetBoolean("virtual_ab_compression", &vabc_enabled)) {
+ if (store.GetBoolean("virtual_ab_compression", &vabc_enabled) &&
+ vabc_enabled) {
+ LOG(INFO) << "Target build supports VABC";
metadata->set_vabc_enabled(vabc_enabled);
}
-
+ // We use "gz" compression by default for VABC.
+ if (metadata->vabc_enabled()) {
+ metadata->set_vabc_compression_param("gz");
+ }
dynamic_partition_metadata = std::move(metadata);
return true;
}
diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
index f7d0b6b3..9c8c59f9 100644
--- a/payload_generator/payload_generation_config.h
+++ b/payload_generator/payload_generation_config.h
@@ -231,11 +231,6 @@ struct PayloadGenerationConfig {
// The maximum timestamp of the OS allowed to apply this payload.
int64_t max_timestamp = 0;
- // Permit use of VABC by default. Even if this is set to true, the device must
- // support VABC in order to use it. If this is set to false, device must not
- // use VABC regardless.
- bool disable_vabc = false;
-
// Path to apex_info.pb, extracted from target_file.zip
std::string apex_info_file;
};
diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
index 5b4f959f..746cefba 100755
--- a/scripts/brillo_update_payload
+++ b/scripts/brillo_update_payload
@@ -708,10 +708,11 @@ cmd_generate() {
GENERATOR_ARGS+=(
--disable_verity_computation="${FLAGS_disable_verity_computation}" )
fi
- if [[ -n "${FLAGS_disable_vabc}" ]]; then
- GENERATOR_ARGS+=(
- --disable_vabc="${FLAGS_disable_vabc}" )
- fi
+ fi
+
+ if [[ -n "${FLAGS_disable_vabc}" ]]; then
+ GENERATOR_ARGS+=(
+ --disable_vabc="${FLAGS_disable_vabc}" )
fi
# minor version is set only for delta or partial payload.
diff --git a/scripts/cow_converter.py b/scripts/cow_converter.py
new file mode 100644
index 00000000..14e016cb
--- /dev/null
+++ b/scripts/cow_converter.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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.
+#
+
+"""Command-line tool for converting OTA payloads to VABC style COW images."""
+
+import os
+import sys
+import tempfile
+import zipfile
+import subprocess
+
+
+def IsSparseImage(filepath):
+ """Determine if an image is a sparse image
+ Args:
+ filepath: str, a path to an .img file
+
+ Returns:
+ return true iff the filepath is a sparse image.
+
+ """
+ with open(filepath, 'rb') as fp:
+ # Magic for android sparse image format
+ # https://source.android.com/devices/bootloader/images
+ return fp.read(4) == b'\x3A\xFF\x26\xED'
+
+
+def ConvertCOW(ota_path, target_file_path, tmp_dir, output_dir):
+ """Convert ota payload to COW IMAGE
+ Args:
+ ota_path: str, path to ota.zip
+ target_file_path: str, path to target_file.zip,
+ must be the target build for OTA.
+ tmp_dir: A temp dir as scratch space
+ output_dir: A directory where all converted COW images will be written.
+ """
+ with zipfile.ZipFile(ota_path) as ota_zip:
+ payload_path = ota_zip.extract("payload.bin", output_dir)
+ with zipfile.ZipFile(target_file_path) as zfp:
+ for fileinfo in zfp.infolist():
+ img_name = os.path.basename(fileinfo.filename)
+ if not fileinfo.filename.endswith(".img"):
+ continue
+ if fileinfo.filename.startswith("IMAGES/") or \
+ fileinfo.filename.startswith("RADIO/"):
+ img_path = zfp.extract(fileinfo, tmp_dir)
+ target_img_path = os.path.join(output_dir, img_name)
+ if IsSparseImage(img_path):
+ subprocess.check_call(["simg2img", img_path, target_img_path])
+ else:
+ os.rename(img_path, target_img_path)
+ print("Extracted", fileinfo.filename, "size:", fileinfo.file_size)
+
+ subprocess.call(["cow_converter", payload_path,
+ output_dir])
+
+
+def main():
+ if len(sys.argv) != 4:
+ print(
+ "Usage:", sys.argv[0], "<your_ota.zip> <target_file.zip> <output dir>")
+ return 1
+ ota_path = sys.argv[1]
+ target_file_path = sys.argv[2]
+ output_dir = sys.argv[3]
+ os.makedirs(output_dir, exist_ok=True)
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ ConvertCOW(ota_path, target_file_path, tmp_dir, output_dir)
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/scripts/update_device.py b/scripts/update_device.py
index 354972b7..074b91d6 100755
--- a/scripts/update_device.py
+++ b/scripts/update_device.py
@@ -29,6 +29,7 @@ import socket
import subprocess
import sys
import struct
+import tempfile
import threading
import xml.etree.ElementTree
import zipfile
@@ -384,6 +385,28 @@ class AdbHost(object):
return subprocess.check_output(command, universal_newlines=True)
+def PushMetadata(dut, otafile, metadata_path):
+ payload = update_payload.Payload(otafile)
+ payload.Init()
+ with tempfile.TemporaryDirectory() as tmpdir:
+ with zipfile.ZipFile(otafile, "r") as zfp:
+ extracted_path = os.path.join(tmpdir, "payload.bin")
+ with zfp.open("payload.bin") as payload_fp, \
+ open(extracted_path, "wb") as output_fp:
+ # Only extract the first |data_offset| bytes from the payload.
+ # This is because allocateSpaceForPayload only needs to see
+ # the manifest, not the entire payload.
+ # Extracting the entire payload works, but is slow for full
+ # OTA.
+ output_fp.write(payload_fp.read(payload.data_offset))
+
+ return dut.adb([
+ "push",
+ extracted_path,
+ metadata_path
+ ]) == 0
+
+
def main():
parser = argparse.ArgumentParser(description='Android A/B OTA helper.')
parser.add_argument('otafile', metavar='PAYLOAD', type=str,
@@ -405,6 +428,13 @@ def main():
help='Update with the secondary payload in the package.')
parser.add_argument('--no-slot-switch', action='store_true',
help='Do not perform slot switch after the update.')
+ parser.add_argument('--allocate_only', action='store_true',
+ help='Allocate space for this OTA, instead of actually \
+ applying the OTA.')
+ parser.add_argument('--verify_only', action='store_true',
+ help='Verify metadata then exit, instead of applying the OTA.')
+ parser.add_argument('--no_care_map', action='store_true',
+ help='Do not push care_map.pb to device.')
args = parser.parse_args()
logging.basicConfig(
level=logging.WARNING if args.no_verbose else logging.INFO)
@@ -422,9 +452,38 @@ def main():
help_cmd = ['shell', 'su', '0', 'update_engine_client', '--help']
use_omaha = 'omaha' in dut.adb_output(help_cmd)
+ metadata_path = "/data/ota_package/metadata"
+ if args.allocate_only:
+ if PushMetadata(dut, args.otafile, metadata_path):
+ dut.adb([
+ "shell", "update_engine_client", "--allocate",
+ "--metadata={}".format(metadata_path)])
+ # Return 0, as we are executing ADB commands here, no work needed after
+ # this point
+ return 0
+ if args.verify_only:
+ if PushMetadata(dut, args.otafile, metadata_path):
+ dut.adb([
+ "shell", "update_engine_client", "--verify",
+ "--metadata={}".format(metadata_path)])
+ # Return 0, as we are executing ADB commands here, no work needed after
+ # this point
+ return 0
+
if args.no_slot_switch:
args.extra_headers += "\nSWITCH_SLOT_ON_REBOOT=0"
+ with zipfile.ZipFile(args.otafile) as zfp:
+ CARE_MAP_ENTRY_NAME = "care_map.pb"
+ if CARE_MAP_ENTRY_NAME in zfp.namelist() and not args.no_care_map:
+ # Need root permission to push to /data
+ dut.adb(["root"])
+ with tempfile.NamedTemporaryFile() as care_map_fp:
+ care_map_fp.write(zfp.read(CARE_MAP_ENTRY_NAME))
+ care_map_fp.flush()
+ dut.adb(["push", care_map_fp.name,
+ "/data/ota_package/" + CARE_MAP_ENTRY_NAME])
+
if args.file:
# Update via pushing a file to /data.
device_ota_file = os.path.join(OTA_PACKAGE_PATH, 'debug.zip')
diff --git a/scripts/update_payload/update_metadata_pb2.py b/scripts/update_payload/update_metadata_pb2.py
index 16412297..9aef9f2f 100644
--- a/scripts/update_payload/update_metadata_pb2.py
+++ b/scripts/update_payload/update_metadata_pb2.py
@@ -20,7 +20,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
package='chromeos_update_engine',
syntax='proto2',
serialized_options=_b('H\003'),
- serialized_pb=_b('\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"\x9f\x01\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1aO\n\tSignature\x12\x13\n\x07version\x18\x01 \x01(\rB\x02\x18\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x1f\n\x17unpadded_signature_size\x18\x03 \x01(\x07\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"\x8f\x01\n\tImageInfo\x12\x11\n\x05\x62oard\x18\x01 \x01(\tB\x02\x18\x01\x12\x0f\n\x03key\x18\x02 \x01(\tB\x02\x18\x01\x12\x13\n\x07\x63hannel\x18\x03 \x01(\tB\x02\x18\x01\x12\x13\n\x07version\x18\x04 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_channel\x18\x05 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_version\x18\x06 \x01(\tB\x02\x18\x01\"\xee\x03\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\x04\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\xad\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x0c\n\x04MOVE\x10\x02\x1a\x02\x08\x01\x12\x0e\n\x06\x42SDIFF\x10\x03\x1a\x02\x08\x01\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x11\n\rBROTLI_BSDIFF\x10\n\x12\x0c\n\x08PUFFDIFF\x10\t\"\xcf\x01\n\x11\x43owMergeOperation\x12<\n\x04type\x18\x01 \x01(\x0e\x32..chromeos_update_engine.CowMergeOperation.Type\x12\x32\n\nsrc_extent\x18\x02 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\ndst_extent\x18\x03 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\"\x14\n\x04Type\x12\x0c\n\x08\x43OW_COPY\x10\x00\"\xc8\x06\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\x12=\n\x15hash_tree_data_extent\x18\n \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x38\n\x10hash_tree_extent\x18\x0b \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x1b\n\x13hash_tree_algorithm\x18\x0c \x01(\t\x12\x16\n\x0ehash_tree_salt\x18\r \x01(\x0c\x12\x37\n\x0f\x66\x65\x63_data_extent\x18\x0e \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\nfec_extent\x18\x0f \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x14\n\tfec_roots\x18\x10 \x01(\r:\x01\x32\x12\x0f\n\x07version\x18\x11 \x01(\t\x12\x43\n\x10merge_operations\x18\x12 \x03(\x0b\x32).chromeos_update_engine.CowMergeOperation\x12\x19\n\x11\x65stimate_cow_size\x18\x13 \x01(\x04\"L\n\x15\x44ynamicPartitionGroup\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x01(\x04\x12\x17\n\x0fpartition_names\x18\x03 \x03(\t\"\x89\x01\n\x18\x44ynamicPartitionMetadata\x12=\n\x06groups\x18\x01 \x03(\x0b\x32-.chromeos_update_engine.DynamicPartitionGroup\x12\x18\n\x10snapshot_enabled\x18\x02 \x01(\x08\x12\x14\n\x0cvabc_enabled\x18\x03 \x01(\x08\"c\n\x08\x41pexInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x03\x12\x15\n\ris_compressed\x18\x03 \x01(\x08\x12\x19\n\x11\x64\x65\x63ompressed_size\x18\x04 \x01(\x03\"C\n\x0c\x41pexMetadata\x12\x33\n\tapex_info\x18\x01 \x03(\x0b\x32 .chromeos_update_engine.ApexInfo\"\x9e\x07\n\x14\x44\x65ltaArchiveManifest\x12H\n\x12install_operations\x18\x01 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12O\n\x19kernel_install_operations\x18\x02 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12\x42\n\x0fold_kernel_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_kernel_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fold_rootfs_info\x18\x08 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_rootfs_info\x18\t \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12=\n\x0eold_image_info\x18\n \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12=\n\x0enew_image_info\x18\x0b \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdate\x12\x15\n\rmax_timestamp\x18\x0e \x01(\x03\x12T\n\x1a\x64ynamic_partition_metadata\x18\x0f \x01(\x0b\x32\x30.chromeos_update_engine.DynamicPartitionMetadata\x12\x16\n\x0epartial_update\x18\x10 \x01(\x08\x12\x33\n\tapex_info\x18\x11 \x03(\x0b\x32 .chromeos_update_engine.ApexInfoB\x02H\x03')
+ serialized_pb=_b('\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"\x9f\x01\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1aO\n\tSignature\x12\x13\n\x07version\x18\x01 \x01(\rB\x02\x18\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x1f\n\x17unpadded_signature_size\x18\x03 \x01(\x07\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"\x8f\x01\n\tImageInfo\x12\x11\n\x05\x62oard\x18\x01 \x01(\tB\x02\x18\x01\x12\x0f\n\x03key\x18\x02 \x01(\tB\x02\x18\x01\x12\x13\n\x07\x63hannel\x18\x03 \x01(\tB\x02\x18\x01\x12\x13\n\x07version\x18\x04 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_channel\x18\x05 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_version\x18\x06 \x01(\tB\x02\x18\x01\"\xee\x03\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\x04\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\xad\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x0c\n\x04MOVE\x10\x02\x1a\x02\x08\x01\x12\x0e\n\x06\x42SDIFF\x10\x03\x1a\x02\x08\x01\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x11\n\rBROTLI_BSDIFF\x10\n\x12\x0c\n\x08PUFFDIFF\x10\t\"\xcf\x01\n\x11\x43owMergeOperation\x12<\n\x04type\x18\x01 \x01(\x0e\x32..chromeos_update_engine.CowMergeOperation.Type\x12\x32\n\nsrc_extent\x18\x02 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\ndst_extent\x18\x03 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\"\x14\n\x04Type\x12\x0c\n\x08\x43OW_COPY\x10\x00\"\xc8\x06\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\x12=\n\x15hash_tree_data_extent\x18\n \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x38\n\x10hash_tree_extent\x18\x0b \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x1b\n\x13hash_tree_algorithm\x18\x0c \x01(\t\x12\x16\n\x0ehash_tree_salt\x18\r \x01(\x0c\x12\x37\n\x0f\x66\x65\x63_data_extent\x18\x0e \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\nfec_extent\x18\x0f \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x14\n\tfec_roots\x18\x10 \x01(\r:\x01\x32\x12\x0f\n\x07version\x18\x11 \x01(\t\x12\x43\n\x10merge_operations\x18\x12 \x03(\x0b\x32).chromeos_update_engine.CowMergeOperation\x12\x19\n\x11\x65stimate_cow_size\x18\x13 \x01(\x04\"L\n\x15\x44ynamicPartitionGroup\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x01(\x04\x12\x17\n\x0fpartition_names\x18\x03 \x03(\t\"\xa9\x01\n\x18\x44ynamicPartitionMetadata\x12=\n\x06groups\x18\x01 \x03(\x0b\x32-.chromeos_update_engine.DynamicPartitionGroup\x12\x18\n\x10snapshot_enabled\x18\x02 \x01(\x08\x12\x14\n\x0cvabc_enabled\x18\x03 \x01(\x08\x12\x1e\n\x16vabc_compression_param\x18\x04 \x01(\t\"c\n\x08\x41pexInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x03\x12\x15\n\ris_compressed\x18\x03 \x01(\x08\x12\x19\n\x11\x64\x65\x63ompressed_size\x18\x04 \x01(\x03\"C\n\x0c\x41pexMetadata\x12\x33\n\tapex_info\x18\x01 \x03(\x0b\x32 .chromeos_update_engine.ApexInfo\"\x9e\x07\n\x14\x44\x65ltaArchiveManifest\x12H\n\x12install_operations\x18\x01 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12O\n\x19kernel_install_operations\x18\x02 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12\x42\n\x0fold_kernel_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_kernel_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fold_rootfs_info\x18\x08 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_rootfs_info\x18\t \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12=\n\x0eold_image_info\x18\n \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12=\n\x0enew_image_info\x18\x0b \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdate\x12\x15\n\rmax_timestamp\x18\x0e \x01(\x03\x12T\n\x1a\x64ynamic_partition_metadata\x18\x0f \x01(\x0b\x32\x30.chromeos_update_engine.DynamicPartitionMetadata\x12\x16\n\x0epartial_update\x18\x10 \x01(\x08\x12\x33\n\tapex_info\x18\x11 \x03(\x0b\x32 .chromeos_update_engine.ApexInfoB\x02H\x03')
)
@@ -683,6 +683,13 @@ _DYNAMICPARTITIONMETADATA = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='vabc_compression_param', full_name='chromeos_update_engine.DynamicPartitionMetadata.vabc_compression_param', index=3,
+ number=4, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
@@ -696,7 +703,7 @@ _DYNAMICPARTITIONMETADATA = _descriptor.Descriptor(
oneofs=[
],
serialized_start=2082,
- serialized_end=2219,
+ serialized_end=2251,
)
@@ -747,8 +754,8 @@ _APEXINFO = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
- serialized_start=2221,
- serialized_end=2320,
+ serialized_start=2253,
+ serialized_end=2352,
)
@@ -778,8 +785,8 @@ _APEXMETADATA = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
- serialized_start=2322,
- serialized_end=2389,
+ serialized_start=2354,
+ serialized_end=2421,
)
@@ -921,8 +928,8 @@ _DELTAARCHIVEMANIFEST = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
- serialized_start=2392,
- serialized_end=3318,
+ serialized_start=2424,
+ serialized_end=3350,
)
_SIGNATURES_SIGNATURE.containing_type = _SIGNATURES
diff --git a/update_metadata.proto b/update_metadata.proto
index a1f093c7..bc9e34ac 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -354,6 +354,11 @@ message DynamicPartitionMetadata {
// supports it, but not guaranteed.
// VABC stands for Virtual AB Compression
optional bool vabc_enabled = 3;
+
+ // The compression algorithm used by VABC. Available ones are "gz", "brotli".
+ // See system/core/fs_mgr/libsnapshot/cow_writer.cpp for available options,
+ // as this parameter is ultimated forwarded to libsnapshot's CowWriter
+ optional string vabc_compression_param = 4;
}
// Definition has been duplicated from