Add a skeleton class for VABCPartitionWriter
Bug: 168554689
Test: treehugger
Change-Id: Ib73084b779620db47d2ff4fbb6d87f38047e9211
diff --git a/Android.bp b/Android.bp
index 9187e67..27ba172 100644
--- a/Android.bp
+++ b/Android.bp
@@ -124,6 +124,7 @@
"libfec_rs",
"libpuffpatch",
"libverity_tree",
+ "libsnapshot_cow",
],
shared_libs: [
"libbase",
@@ -179,6 +180,8 @@
"payload_consumer/payload_metadata.cc",
"payload_consumer/payload_verifier.cc",
"payload_consumer/partition_writer.cc",
+ "payload_consumer/partition_writer_factory_android.cc",
+ "payload_consumer/vabc_partition_writer.cc",
"payload_consumer/postinstall_runner_action.cc",
"payload_consumer/verity_writer_android.cc",
"payload_consumer/xz_extent_writer.cc",
diff --git a/BUILD.gn b/BUILD.gn
index b7de9fc..9575fab 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -160,6 +160,8 @@
"payload_consumer/install_plan.cc",
"payload_consumer/mount_history.cc",
"payload_consumer/partition_update_generator_stub.cc",
+ "payload_consumer/partition_writer_factory_chromeos.cc",
+ "payload_consumer/partition_writer.cc",
"payload_consumer/payload_constants.cc",
"payload_consumer/payload_metadata.cc",
"payload_consumer/payload_verifier.cc",
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 87fc4cf..9bf6d7e 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -241,13 +241,14 @@
install_plan_->partitions.size() - partitions_.size();
const InstallPlan::Partition& install_part =
install_plan_->partitions[num_previous_partitions + current_partition_];
- partition_writer_ = std::make_unique<PartitionWriter>(
+ auto dynamic_control = boot_control_->GetDynamicPartitionControl();
+ partition_writer_ = partition_writer::CreatePartitionWriter(
partition,
install_part,
- boot_control_->GetDynamicPartitionControl(),
+ dynamic_control,
block_size_,
- interactive_);
-
+ interactive_,
+ IsDynamicPartition(install_part.name));
// Open source fds if we have a delta payload, or for partitions in the
// partial update.
bool source_may_exist = manifest_.partial_update() ||
@@ -642,6 +643,11 @@
}
}
+ auto dynamic_control = boot_control_->GetDynamicPartitionControl();
+ CHECK_NE(dynamic_control, nullptr);
+ TEST_AND_RETURN_FALSE(dynamic_control->ListDynamicPartitionsForSlot(
+ install_plan_->target_slot, &dynamic_partitions_));
+
// Partitions in manifest are no longer needed after preparing partitions.
manifest_.clear_partitions();
// TODO(xunchang) TBD: allow partial update only on devices with dynamic
@@ -1503,4 +1509,10 @@
return true;
}
+bool DeltaPerformer::IsDynamicPartition(const std::string& part_name) {
+ return std::find(dynamic_partitions_.begin(),
+ dynamic_partitions_.end(),
+ part_name) != dynamic_partitions_.end();
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_consumer/delta_performer.h b/payload_consumer/delta_performer.h
index d44f6c2..96bc849 100644
--- a/payload_consumer/delta_performer.h
+++ b/payload_consumer/delta_performer.h
@@ -299,6 +299,8 @@
// a generic error on the device.
ErrorCode CheckTimestampError() const;
+ // Check if partition `part_name` is a dynamic partition.
+ bool IsDynamicPartition(const std::string& part_name);
// Update Engine preference store.
PrefsInterface* prefs_;
@@ -336,22 +338,22 @@
// otherwise 0.
size_t num_total_operations_{0};
- // The list of partitions to update as found in the manifest major version 2.
- // When parsing an older manifest format, the information is converted over to
- // this format instead.
+ // The list of partitions to update as found in the manifest major
+ // version 2. When parsing an older manifest format, the information is
+ // converted over to this format instead.
std::vector<PartitionUpdate> partitions_;
// Index in the list of partitions (|partitions_| member) of the current
// partition being processed.
size_t current_partition_{0};
- // Index of the next operation to perform in the manifest. The index is linear
- // on the total number of operation on the manifest.
+ // Index of the next operation to perform in the manifest. The index is
+ // linear on the total number of operation on the manifest.
size_t next_operation_num_{0};
// A buffer used for accumulating downloaded data. Initially, it stores the
- // payload metadata; once that's downloaded and parsed, it stores data for the
- // next update operation.
+ // payload metadata; once that's downloaded and parsed, it stores data for
+ // the next update operation.
brillo::Blob buffer_;
// Offset of buffer_ in the binary blobs section of the update.
uint64_t buffer_offset_{0};
@@ -393,8 +395,9 @@
// If |true|, the update is user initiated (vs. periodic update checks).
bool interactive_{false};
- // The timeout after which we should force emitting a progress log (constant),
- // and the actual point in time for the next forced log to be emitted.
+ // The timeout after which we should force emitting a progress log
+ // (constant), and the actual point in time for the next forced log to be
+ // emitted.
const base::TimeDelta forced_progress_log_wait_{
base::TimeDelta::FromSeconds(kProgressLogTimeoutSeconds)};
base::TimeTicks forced_progress_log_time_;
@@ -407,6 +410,8 @@
std::unique_ptr<PartitionWriter> partition_writer_;
+ // List of dynamic partitions on device.
+ std::vector<std::string> dynamic_partitions_;
DISALLOW_COPY_AND_ASSIGN(DeltaPerformer);
};
diff --git a/payload_consumer/partition_writer.cc b/payload_consumer/partition_writer.cc
index d47ebee..b4b869c 100644
--- a/payload_consumer/partition_writer.cc
+++ b/payload_consumer/partition_writer.cc
@@ -308,7 +308,7 @@
const void* data,
size_t count) {
// Setup the ExtentWriter stack based on the operation type.
- std::unique_ptr<ExtentWriter> writer = std::make_unique<DirectExtentWriter>();
+ std::unique_ptr<ExtentWriter> writer = CreateBaseExtentWriter();
if (operation.type() == InstallOperation::REPLACE_BZ) {
writer.reset(new BzipExtentWriter(std::move(writer)));
@@ -320,7 +320,7 @@
writer->Init(target_fd_, operation.dst_extents(), block_size_));
TEST_AND_RETURN_FALSE(writer->Write(data, operation.data_length()));
- return target_fd_->Flush();
+ return Flush();
}
bool PartitionWriter::PerformZeroOrDiscardOperation(
@@ -353,7 +353,7 @@
target_fd_, zeros.data(), chunk_length, start + offset));
}
}
- return target_fd_->Flush();
+ return Flush();
}
bool PartitionWriter::PerformSourceCopyOperation(
@@ -464,8 +464,9 @@
block_size_,
nullptr));
}
- return target_fd_->Flush();
+ return Flush();
}
+
bool PartitionWriter::PerformSourceBsdiffOperation(
const InstallOperation& operation,
ErrorCode* error,
@@ -481,7 +482,7 @@
std::move(reader),
utils::BlocksInExtents(operation.src_extents()) * block_size_);
- auto writer = std::make_unique<DirectExtentWriter>();
+ auto writer = CreateBaseExtentWriter();
TEST_AND_RETURN_FALSE(
writer->Init(target_fd_, operation.dst_extents(), block_size_));
auto dst_file = std::make_unique<BsdiffExtentFile>(
@@ -492,7 +493,7 @@
std::move(dst_file),
reinterpret_cast<const uint8_t*>(data),
count) == 0);
- return target_fd_->Flush();
+ return Flush();
}
bool PartitionWriter::PerformPuffDiffOperation(
@@ -510,7 +511,7 @@
std::move(reader),
utils::BlocksInExtents(operation.src_extents()) * block_size_));
- auto writer = std::make_unique<DirectExtentWriter>();
+ auto writer = CreateBaseExtentWriter();
TEST_AND_RETURN_FALSE(
writer->Init(target_fd_, operation.dst_extents(), block_size_));
puffin::UniqueStreamPtr dst_stream(new PuffinExtentStream(
@@ -524,7 +525,7 @@
reinterpret_cast<const uint8_t*>(data),
count,
kMaxCacheSize));
- return target_fd_->Flush();
+ return Flush();
}
FileDescriptorPtr PartitionWriter::ChooseSourceFD(
@@ -641,4 +642,13 @@
source_ecc_open_failure_ = false;
return -err;
}
+
+std::unique_ptr<ExtentWriter> PartitionWriter::CreateBaseExtentWriter() {
+ return std::make_unique<DirectExtentWriter>();
+}
+
+bool PartitionWriter::Flush() {
+ return target_fd_->Flush();
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_consumer/partition_writer.h b/payload_consumer/partition_writer.h
index 624a411..1acbddc 100644
--- a/payload_consumer/partition_writer.h
+++ b/payload_consumer/partition_writer.h
@@ -18,12 +18,14 @@
#define UPDATE_ENGINE_PARTITION_WRITER_H_
#include <cstdint>
+#include <memory>
#include <string>
#include <brillo/secure_blob.h>
#include <gtest/gtest_prod.h>
#include "update_engine/common/dynamic_partition_control_interface.h"
+#include "update_engine/payload_consumer/extent_writer.h"
#include "update_engine/payload_consumer/file_descriptor.h"
#include "update_engine/payload_consumer/install_plan.h"
#include "update_engine/update_metadata.pb.h"
@@ -35,7 +37,7 @@
DynamicPartitionControlInterface* dynamic_control,
size_t block_size,
bool is_interactive);
- ~PartitionWriter();
+ virtual ~PartitionWriter();
static bool ValidateSourceHash(const brillo::Blob& calculated_hash,
const InstallOperation& operation,
const FileDescriptorPtr source_fd,
@@ -43,33 +45,34 @@
// Perform necessary initialization work before InstallOperation can be
// applied to this partition
- [[nodiscard]] bool Init(const InstallPlan* install_plan,
- bool source_may_exist);
+ [[nodiscard]] virtual bool Init(const InstallPlan* install_plan,
+ bool source_may_exist);
int Close();
// These perform a specific type of operation and return true on success.
// |error| will be set if source hash mismatch, otherwise |error| might not be
// set even if it fails.
- [[nodiscard]] bool PerformReplaceOperation(const InstallOperation& operation,
- const void* data,
- size_t count);
- [[nodiscard]] bool PerformZeroOrDiscardOperation(
+ [[nodiscard]] virtual bool PerformReplaceOperation(
+ const InstallOperation& operation, const void* data, size_t count);
+ [[nodiscard]] virtual bool PerformZeroOrDiscardOperation(
const InstallOperation& operation);
- [[nodiscard]] bool PerformSourceCopyOperation(
+ [[nodiscard]] virtual bool PerformSourceCopyOperation(
const InstallOperation& operation, ErrorCode* error);
- [[nodiscard]] bool PerformSourceBsdiffOperation(
+ [[nodiscard]] virtual bool PerformSourceBsdiffOperation(
const InstallOperation& operation,
ErrorCode* error,
const void* data,
size_t count);
- [[nodiscard]] bool PerformPuffDiffOperation(const InstallOperation& operation,
- ErrorCode* error,
- const void* data,
- size_t count);
+ [[nodiscard]] virtual bool PerformPuffDiffOperation(
+ const InstallOperation& operation,
+ ErrorCode* error,
+ const void* data,
+ size_t count);
+ [[nodiscard]] virtual bool Flush();
- private:
+ protected:
friend class PartitionWriterTest;
FRIEND_TEST(PartitionWriterTest, ChooseSourceFDTest);
@@ -80,6 +83,7 @@
// the |error| accordingly.
FileDescriptorPtr ChooseSourceFD(const InstallOperation& operation,
ErrorCode* error);
+ [[nodiscard]] virtual std::unique_ptr<ExtentWriter> CreateBaseExtentWriter();
const PartitionUpdate& partition_update_;
const InstallPlan::Partition& install_part_;
@@ -108,6 +112,18 @@
// error corrected.
bool source_ecc_open_failure_{false};
};
+
+namespace partition_writer {
+// Return a PartitionWriter instance for perform InstallOps on this partition.
+// Uses VABCPartitionWriter for Virtual AB Compression
+std::unique_ptr<PartitionWriter> CreatePartitionWriter(
+ const PartitionUpdate& partition_update,
+ const InstallPlan::Partition& install_part,
+ DynamicPartitionControlInterface* dynamic_control,
+ size_t block_size,
+ bool is_interactive,
+ bool is_dynamic_partition);
+} // namespace partition_writer
} // namespace chromeos_update_engine
#endif
diff --git a/payload_consumer/partition_writer_factory_android.cc b/payload_consumer/partition_writer_factory_android.cc
new file mode 100644
index 0000000..0c9f7ea
--- /dev/null
+++ b/payload_consumer/partition_writer_factory_android.cc
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2020 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 <cstddef>
+#include <memory>
+
+#include <base/logging.h>
+
+#include "update_engine/payload_consumer/vabc_partition_writer.h"
+
+namespace chromeos_update_engine::partition_writer {
+
+std::unique_ptr<PartitionWriter> CreatePartitionWriter(
+ const PartitionUpdate& partition_update,
+ const InstallPlan::Partition& install_part,
+ DynamicPartitionControlInterface* dynamic_control,
+ size_t block_size,
+ bool is_interactive,
+ bool is_dynamic_partition) {
+ if (dynamic_control &&
+ dynamic_control->GetVirtualAbCompressionFeatureFlag().IsEnabled() &&
+ is_dynamic_partition) {
+ LOG(INFO)
+ << "Virtual AB Compression Enabled, using VABC Partition Writer for `"
+ << install_part.name << '`';
+ return std::make_unique<VABCPartitionWriter>(partition_update,
+ install_part,
+ dynamic_control,
+ block_size,
+ is_interactive);
+ } else {
+ LOG(INFO) << "Virtual AB Compression disabled, using Partition Writer for `"
+ << install_part.name << '`';
+ return std::make_unique<PartitionWriter>(partition_update,
+ install_part,
+ dynamic_control,
+ block_size,
+ is_interactive);
+ }
+}
+} // namespace chromeos_update_engine::partition_writer
diff --git a/payload_consumer/partition_writer_factory_chromeos.cc b/payload_consumer/partition_writer_factory_chromeos.cc
new file mode 100644
index 0000000..609f043
--- /dev/null
+++ b/payload_consumer/partition_writer_factory_chromeos.cc
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2020 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 <cstddef>
+#include <memory>
+
+#include <base/logging.h>
+
+#include "update_engine/payload_consumer/partition_writer.h"
+
+namespace chromeos_update_engine::partition_writer {
+std::unique_ptr<PartitionWriter> CreatePartitionWriter(
+ const PartitionUpdate& partition_update,
+ const InstallPlan::Partition& install_part,
+ DynamicPartitionControlInterface* dynamic_control,
+ size_t block_size,
+ bool is_interactive,
+ bool is_dynamic_partition) {
+ return std::make_unique<PartitionWriter>(partition_update,
+ install_part,
+ dynamic_control,
+ block_size,
+ is_interactive);
+}
+} // namespace chromeos_update_engine::partition_writer
diff --git a/payload_consumer/vabc_partition_writer.cc b/payload_consumer/vabc_partition_writer.cc
new file mode 100644
index 0000000..ab4897f
--- /dev/null
+++ b/payload_consumer/vabc_partition_writer.cc
@@ -0,0 +1,58 @@
+//
+// Copyright (C) 2020 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_consumer/vabc_partition_writer.h"
+
+#include <memory>
+
+#include <libsnapshot/cow_writer.h>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_consumer/install_plan.h"
+#include "update_engine/payload_consumer/partition_writer.h"
+
+namespace chromeos_update_engine {
+bool VABCPartitionWriter::Init(const InstallPlan* install_plan,
+ bool source_may_exist) {
+ TEST_AND_RETURN_FALSE(PartitionWriter::Init(install_plan, source_may_exist));
+
+ // TODO(zhangkelvin) Add code specific to VABC. E.x. Convert InstallOps to
+ // CowOps, perform all SOURCE_COPY upfront according to merge sequence.
+ return true;
+}
+
+std::unique_ptr<ExtentWriter> VABCPartitionWriter::CreateBaseExtentWriter() {
+ // TODO(zhangkelvin) Return a SnapshotExtentWriter
+ return std::make_unique<DirectExtentWriter>();
+}
+
+[[nodiscard]] bool VABCPartitionWriter::PerformZeroOrDiscardOperation(
+ const InstallOperation& operation) {
+ // TODO(zhangkelvin) Create a COW_ZERO operation and send it to CowWriter
+ return PartitionWriter::PerformZeroOrDiscardOperation(operation);
+}
+
+[[nodiscard]] bool VABCPartitionWriter::PerformSourceCopyOperation(
+ const InstallOperation& operation, ErrorCode* error) {
+ // TODO(zhangkelvin) Probably just ignore SOURCE_COPY? They should be taken
+ // care of during Init();
+ return true;
+}
+
+VABCPartitionWriter::~VABCPartitionWriter() = default;
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/vabc_partition_writer.h b/payload_consumer/vabc_partition_writer.h
new file mode 100644
index 0000000..034fb57
--- /dev/null
+++ b/payload_consumer/vabc_partition_writer.h
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2020 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 UPDATE_ENGINE_VABC_PARTITION_WRITER_H_
+#define UPDATE_ENGINE_VABC_PARTITION_WRITER_H_
+
+#include <memory>
+
+#include <libsnapshot/cow_writer.h>
+
+#include "update_engine/payload_consumer/install_plan.h"
+#include "update_engine/payload_consumer/partition_writer.h"
+
+namespace chromeos_update_engine {
+class VABCPartitionWriter final : public PartitionWriter {
+ public:
+ using PartitionWriter::PartitionWriter;
+ [[nodiscard]] bool Init(const InstallPlan* install_plan,
+ bool source_may_exist) override;
+ ~VABCPartitionWriter() override;
+
+ [[nodiscard]] std::unique_ptr<ExtentWriter> CreateBaseExtentWriter() override;
+
+ // Only ZERO and SOURCE_COPY InstallOperations are treated special by VABC
+ // Partition Writer. These operations correspond to COW_ZERO and COW_COPY. All
+ // other operations just get converted to COW_REPLACE.
+ [[nodiscard]] bool PerformZeroOrDiscardOperation(
+ const InstallOperation& operation) override;
+ [[nodiscard]] bool PerformSourceCopyOperation(
+ const InstallOperation& operation, ErrorCode* error) override;
+
+ private:
+ std::unique_ptr<android::snapshot::ICowWriter> cow_writer_;
+};
+
+} // namespace chromeos_update_engine
+
+#endif