Add PartitionUpdateGenerator am: d3865d1bc4
Original change: https://android-review.googlesource.com/c/platform/system/update_engine/+/1326712
Change-Id: I9b02a17fe1b0146771f8277b1a1ccb7c507f261d
diff --git a/Android.bp b/Android.bp
index 3287b7b..59d698d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -184,6 +184,7 @@
"payload_consumer/verity_writer_android.cc",
"payload_consumer/xz_extent_writer.cc",
"payload_consumer/fec_file_descriptor.cc",
+ "payload_consumer/partition_update_generator_android.cc",
],
}
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 4c4ff04..d1de9f4 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -23,6 +23,7 @@
#include <cstring>
#include <map>
#include <memory>
+#include <set>
#include <string>
#include <utility>
#include <vector>
@@ -50,6 +51,7 @@
#include "update_engine/payload_consumer/download_action.h"
#include "update_engine/payload_consumer/extent_reader.h"
#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_consumer/partition_update_generator_interface.h"
#if USE_FEC
#include "update_engine/payload_consumer/fec_file_descriptor.h"
#endif // USE_FEC
@@ -357,12 +359,15 @@
install_plan_->partitions.size() - partitions_.size();
const InstallPlan::Partition& install_part =
install_plan_->partitions[num_previous_partitions + current_partition_];
- // Open source fds if we have a delta payload with minor version >= 2.
- if (payload_->type == InstallPayloadType::kDelta &&
- GetMinorVersion() != kInPlaceMinorPayloadVersion &&
- // With dynamic partitions we could create a new partition in a
- // delta payload, and we shouldn't open source partition in that case.
- install_part.source_size > 0) {
+ // Open source fds if we have a delta payload with minor version >= 2, or for
+ // partitions in the partial update.
+ bool source_may_exist = manifest_.partial_update() ||
+ (payload_->type == InstallPayloadType::kDelta &&
+ GetMinorVersion() != kInPlaceMinorPayloadVersion);
+ // We shouldn't open the source partition in certain cases, e.g. some dynamic
+ // partitions in delta payload, partitions included in the full payload for
+ // partial updates. Use the source size as the indicator.
+ if (source_may_exist && install_part.source_size > 0) {
source_path_ = install_part.source_path;
int err;
source_fd_ = OpenFile(source_path_.c_str(), O_RDONLY, false, &err);
@@ -851,6 +856,41 @@
partitions_.push_back(std::move(kern_part));
}
+ // For VAB and partial updates, the partition preparation will copy the
+ // dynamic partitions metadata to the target metadata slot, and rename the
+ // slot suffix of the partitions in the metadata.
+ if (install_plan_->target_slot != BootControlInterface::kInvalidSlot) {
+ uint64_t required_size = 0;
+ if (!PreparePartitionsForUpdate(&required_size)) {
+ if (required_size > 0) {
+ *error = ErrorCode::kNotEnoughSpace;
+ } else {
+ *error = ErrorCode::kInstallDeviceOpenError;
+ }
+ return false;
+ }
+ }
+
+ // TODO(xunchang) TBD: allow partial update only on devices with dynamic
+ // partition.
+ if (manifest_.partial_update()) {
+ std::set<std::string> touched_partitions;
+ for (const auto& partition_update : partitions_) {
+ touched_partitions.insert(partition_update.partition_name());
+ }
+
+ auto generator = partition_update_generator::Create(boot_control_);
+ std::vector<PartitionUpdate> other_partitions;
+ TEST_AND_RETURN_FALSE(
+ generator->GenerateOperationsForPartitionsNotInPayload(
+ install_plan_->source_slot,
+ install_plan_->target_slot,
+ touched_partitions,
+ &other_partitions));
+ partitions_.insert(
+ partitions_.end(), other_partitions.begin(), other_partitions.end());
+ }
+
// Fill in the InstallPlan::partitions based on the partitions from the
// payload.
for (const auto& partition : partitions_) {
@@ -924,22 +964,13 @@
install_plan_->partitions.push_back(install_part);
}
- if (install_plan_->target_slot != BootControlInterface::kInvalidSlot) {
- uint64_t required_size = 0;
- if (!PreparePartitionsForUpdate(&required_size)) {
- if (required_size > 0) {
- *error = ErrorCode::kNotEnoughSpace;
- } else {
- *error = ErrorCode::kInstallDeviceOpenError;
- }
- return false;
- }
- }
-
if (major_payload_version_ == kBrilloMajorPayloadVersion) {
manifest_.clear_partitions();
}
+ // TODO(xunchang) only need to load the partitions for those in payload.
+ // Because we have already loaded the other once when generating SOURCE_COPY
+ // operations.
if (!install_plan_->LoadPartitionsFromSlots(boot_control_)) {
LOG(ERROR) << "Unable to determine all the partition devices.";
*error = ErrorCode::kInstallDeviceOpenError;
@@ -1712,7 +1743,6 @@
ErrorCode DeltaPerformer::ValidateManifest() {
// Perform assorted checks to sanity check the manifest, make sure it
// matches data from other sources, and that it is a supported version.
-
bool has_old_fields =
(manifest_.has_old_kernel_info() || manifest_.has_old_rootfs_info());
for (const PartitionUpdate& partition : manifest_.partitions()) {
@@ -1737,8 +1767,8 @@
<< "' payload.";
return ErrorCode::kPayloadMismatchedType;
}
-
// Check that the minor version is compatible.
+ // TODO(xunchang) increment minor version & add check for partial update
if (actual_payload_type == InstallPayloadType::kFull) {
if (manifest_.minor_version() != kFullPayloadMinorVersion) {
LOG(ERROR) << "Manifest contains minor version "
diff --git a/payload_consumer/partition_update_generator_android.cc b/payload_consumer/partition_update_generator_android.cc
new file mode 100644
index 0000000..fcacc86
--- /dev/null
+++ b/payload_consumer/partition_update_generator_android.cc
@@ -0,0 +1,41 @@
+//
+// 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/partition_update_generator_android.h"
+
+#include <memory>
+
+namespace chromeos_update_engine {
+
+bool PartitionUpdateGeneratorAndroid::
+ GenerateOperationsForPartitionsNotInPayload(
+ BootControlInterface::Slot source_slot,
+ BootControlInterface::Slot target_slot,
+ const std::set<std::string>& partitions_in_payload,
+ std::vector<PartitionUpdate>* update_list) {
+ // TODO(xunchang) implement the function
+ CHECK(boot_control_);
+ return true;
+}
+
+namespace partition_update_generator {
+std::unique_ptr<PartitionUpdateGeneratorInterface> Create(
+ BootControlInterface* boot_control) {
+ return std::make_unique<PartitionUpdateGeneratorAndroid>(boot_control);
+}
+} // namespace partition_update_generator
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/partition_update_generator_android.h b/payload_consumer/partition_update_generator_android.h
new file mode 100644
index 0000000..bb50133
--- /dev/null
+++ b/payload_consumer/partition_update_generator_android.h
@@ -0,0 +1,46 @@
+//
+// 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_PAYLOAD_CONSUMER_PARTITION_UPDATE_GENERATOR_ANDROID_H_
+#define UPDATE_ENGINE_PAYLOAD_CONSUMER_PARTITION_UPDATE_GENERATOR_ANDROID_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "update_engine/common/boot_control_interface.h"
+#include "update_engine/payload_consumer/partition_update_generator_interface.h"
+
+namespace chromeos_update_engine {
+class PartitionUpdateGeneratorAndroid
+ : public PartitionUpdateGeneratorInterface {
+ public:
+ explicit PartitionUpdateGeneratorAndroid(BootControlInterface* boot_control)
+ : boot_control_(boot_control) {}
+
+ bool GenerateOperationsForPartitionsNotInPayload(
+ BootControlInterface::Slot source_slot,
+ BootControlInterface::Slot target_slot,
+ const std::set<std::string>& partitions_in_payload,
+ std::vector<PartitionUpdate>* update_list) override;
+
+ private:
+ BootControlInterface* boot_control_;
+};
+
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/payload_consumer/partition_update_generator_interface.h b/payload_consumer/partition_update_generator_interface.h
new file mode 100644
index 0000000..0341d40
--- /dev/null
+++ b/payload_consumer/partition_update_generator_interface.h
@@ -0,0 +1,55 @@
+//
+// 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_PAYLOAD_CONSUMER_PARTITION_UPDATE_GENERATOR_INTERFACE_H_
+#define UPDATE_ENGINE_PAYLOAD_CONSUMER_PARTITION_UPDATE_GENERATOR_INTERFACE_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "update_engine/common/boot_control_interface.h"
+
+namespace chromeos_update_engine {
+class PartitionUpdate;
+
+// This class parses the partitions that are not included in the payload of a
+// partial A/B update. And it generates additional operations for these
+// partitions to make the update complete.
+class PartitionUpdateGeneratorInterface {
+ public:
+ virtual ~PartitionUpdateGeneratorInterface() = default;
+
+ // Adds PartitionUpdate for partitions not included in the payload. For static
+ // partitions, it generates SOURCE_COPY operations to copy the bytes from the
+ // source slot to target slot. For dynamic partitions, it only calculates the
+ // partition hash for the filesystem verification later.
+ virtual bool GenerateOperationsForPartitionsNotInPayload(
+ BootControlInterface::Slot source_slot,
+ BootControlInterface::Slot target_slot,
+ const std::set<std::string>& partitions_in_payload,
+ std::vector<PartitionUpdate>* update_list) = 0;
+};
+
+namespace partition_update_generator {
+std::unique_ptr<PartitionUpdateGeneratorInterface> Create(
+ BootControlInterface* boot_control);
+}
+
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/payload_consumer/partition_update_generator_stub.cc b/payload_consumer/partition_update_generator_stub.cc
new file mode 100644
index 0000000..e2b64ec
--- /dev/null
+++ b/payload_consumer/partition_update_generator_stub.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 "update_engine/payload_consumer/partition_update_generator_stub.h"
+
+#include <memory>
+
+namespace chromeos_update_engine {
+
+bool PartitionUpdateGeneratorStub::GenerateOperationsForPartitionsNotInPayload(
+ chromeos_update_engine::BootControlInterface::Slot source_slot,
+ chromeos_update_engine::BootControlInterface::Slot target_slot,
+ const std::set<std::string>& partitions_in_payload,
+ std::vector<PartitionUpdate>* update_list) {
+ return true;
+}
+
+namespace partition_update_generator {
+std::unique_ptr<PartitionUpdateGeneratorInterface> Create(
+ BootControlInterface* boot_control) {
+ return std::make_unique<PartitionUpdateGeneratorStub>();
+}
+} // namespace partition_update_generator
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/partition_update_generator_stub.h b/payload_consumer/partition_update_generator_stub.h
new file mode 100644
index 0000000..282875e
--- /dev/null
+++ b/payload_consumer/partition_update_generator_stub.h
@@ -0,0 +1,40 @@
+//
+// 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_PAYLOAD_CONSUMER_PARTITION_UPDATE_GENERATOR_STUB_H_
+#define UPDATE_ENGINE_PAYLOAD_CONSUMER_PARTITION_UPDATE_GENERATOR_STUB_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "update_engine/common/boot_control_interface.h"
+#include "update_engine/payload_consumer/partition_update_generator_interface.h"
+
+namespace chromeos_update_engine {
+class PartitionUpdateGeneratorStub : public PartitionUpdateGeneratorInterface {
+ public:
+ PartitionUpdateGeneratorStub() = default;
+ bool GenerateOperationsForPartitionsNotInPayload(
+ BootControlInterface::Slot source_slot,
+ BootControlInterface::Slot target_slot,
+ const std::set<std::string>& partitions_in_payload,
+ std::vector<PartitionUpdate>* update_list) override;
+};
+
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/update_metadata.proto b/update_metadata.proto
index 9bc0d8a..4b4c327 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -367,4 +367,7 @@
// Metadata related to all dynamic partitions.
optional DynamicPartitionMetadata dynamic_partition_metadata = 15;
+
+ // If the payload only updates a subset of partitions on the device.
+ optional bool partial_update = 16;
}