Support sideload full update on VAB am: bae2784f42 am: f17f1c2856 am: ec5b496a1e
Change-Id: If3f500ec806fdf0a12b4336a4c2588e2f9765b2d
diff --git a/dynamic_partition_control_android.cc b/dynamic_partition_control_android.cc
index 881ff11..072a3ec 100644
--- a/dynamic_partition_control_android.cc
+++ b/dynamic_partition_control_android.cc
@@ -68,8 +68,14 @@
// needs to be mapped, this timeout is longer than |kMapTimeout|.
constexpr std::chrono::milliseconds kMapSnapshotTimeout{5000};
+#ifdef __ANDROID_RECOVERY__
+constexpr bool kIsRecovery = true;
+#else
+constexpr bool kIsRecovery = false;
+#endif
+
DynamicPartitionControlAndroid::~DynamicPartitionControlAndroid() {
- CleanupInternal();
+ Cleanup();
}
static FeatureFlag GetFeatureFlag(const char* enable_prop,
@@ -234,8 +240,7 @@
return true;
}
-void DynamicPartitionControlAndroid::CleanupInternal() {
- metadata_device_.reset();
+void DynamicPartitionControlAndroid::UnmapAllPartitions() {
if (mapped_devices_.empty()) {
return;
}
@@ -249,7 +254,8 @@
}
void DynamicPartitionControlAndroid::Cleanup() {
- CleanupInternal();
+ UnmapAllPartitions();
+ metadata_device_.reset();
}
bool DynamicPartitionControlAndroid::DeviceExists(const std::string& path) {
@@ -419,28 +425,53 @@
if (!update)
return true;
+ bool delete_source = false;
+
if (GetVirtualAbFeatureFlag().IsEnabled()) {
// On Virtual A/B device, either CancelUpdate() or BeginUpdate() must be
// called before calling UnmapUpdateSnapshot.
// - If target_supports_snapshot_, PrepareSnapshotPartitionsForUpdate()
// calls BeginUpdate() which resets update state
- // - If !target_supports_snapshot_, explicitly CancelUpdate().
+ // - If !target_supports_snapshot_ or PrepareSnapshotPartitionsForUpdate
+ // failed in recovery, explicitly CancelUpdate().
if (target_supports_snapshot_) {
- return PrepareSnapshotPartitionsForUpdate(
- source_slot, target_slot, manifest, required_size);
+ if (PrepareSnapshotPartitionsForUpdate(
+ source_slot, target_slot, manifest, required_size)) {
+ return true;
+ }
+
+ // Virtual A/B device doing Virtual A/B update in Android mode must use
+ // snapshots.
+ if (!IsRecovery()) {
+ LOG(ERROR) << "PrepareSnapshotPartitionsForUpdate failed in Android "
+ << "mode";
+ return false;
+ }
+
+ delete_source = true;
+ LOG(INFO) << "PrepareSnapshotPartitionsForUpdate failed in recovery. "
+ << "Attempt to overwrite existing partitions if possible";
+ } else {
+ // Downgrading to an non-Virtual A/B build or is secondary OTA.
+ LOG(INFO) << "Using regular A/B on Virtual A/B because package disabled "
+ << "snapshots.";
}
+
if (!snapshot_->CancelUpdate()) {
LOG(ERROR) << "Cannot cancel previous update.";
return false;
}
}
- return PrepareDynamicPartitionsForUpdate(source_slot, target_slot, manifest);
+
+ return PrepareDynamicPartitionsForUpdate(
+ source_slot, target_slot, manifest, delete_source);
}
bool DynamicPartitionControlAndroid::PrepareDynamicPartitionsForUpdate(
uint32_t source_slot,
uint32_t target_slot,
- const DeltaArchiveManifest& manifest) {
+ const DeltaArchiveManifest& manifest,
+ bool delete_source) {
const std::string target_suffix = SlotSuffixForSlotNumber(target_slot);
// Unmap all the target dynamic partitions because they would become
@@ -468,6 +499,11 @@
return false;
}
+ if (delete_source) {
+ TEST_AND_RETURN_FALSE(
+ DeleteSourcePartitions(builder.get(), source_slot, manifest));
+ }
+
if (!UpdatePartitionMetadata(builder.get(), target_slot, manifest)) {
return false;
}
@@ -585,7 +621,7 @@
}
bool DynamicPartitionControlAndroid::FinishUpdate() {
- if (GetVirtualAbFeatureFlag().IsEnabled() && target_supports_snapshot_) {
+ if (snapshot_->GetUpdateState() == UpdateState::Initiated) {
LOG(INFO) << "Snapshot writes are done.";
return snapshot_->FinishedSnapshotWrites();
}
@@ -713,4 +749,40 @@
return ErrorCode::kDeviceCorrupted;
}
+bool DynamicPartitionControlAndroid::IsRecovery() {
+ return kIsRecovery;
+}
+
+static bool IsIncrementalUpdate(const DeltaArchiveManifest& manifest) {
+ const auto& partitions = manifest.partitions();
+ return std::any_of(partitions.begin(), partitions.end(), [](const auto& p) {
+ return p.has_old_partition_info();
+ });
+}
+
+bool DynamicPartitionControlAndroid::DeleteSourcePartitions(
+ MetadataBuilder* builder,
+ uint32_t source_slot,
+ const DeltaArchiveManifest& manifest) {
+ TEST_AND_RETURN_FALSE(IsRecovery());
+
+ if (IsIncrementalUpdate(manifest)) {
+ LOG(ERROR) << "Cannot sideload incremental OTA because snapshots cannot "
+ << "be created.";
+ if (GetVirtualAbFeatureFlag().IsLaunch()) {
+ LOG(ERROR) << "Sideloading incremental updates on devices launches "
+ << " Virtual A/B is not supported.";
+ }
+ return false;
+ }
+
+ LOG(INFO) << "Will overwrite existing partitions. Slot "
+ << BootControlInterface::SlotName(source_slot)
+ << "may be unbootable until update finishes!";
+ const std::string source_suffix = SlotSuffixForSlotNumber(source_slot);
+ DeleteGroupsWithSuffix(builder, source_suffix);
+
+ return true;
+}
+
} // namespace chromeos_update_engine
diff --git a/dynamic_partition_control_android.h b/dynamic_partition_control_android.h
index ba23e7c..e7ae26b 100644
--- a/dynamic_partition_control_android.h
+++ b/dynamic_partition_control_android.h
@@ -127,10 +127,13 @@
virtual void set_fake_mapped_devices(const std::set<std::string>& fake);
+ // Allow mock objects to override this to test recovery mode.
+ virtual bool IsRecovery();
+
private:
friend class DynamicPartitionControlAndroidTest;
- void CleanupInternal();
+ void UnmapAllPartitions();
bool MapPartitionInternal(const std::string& super_device,
const std::string& target_partition_name,
uint32_t slot,
@@ -143,11 +146,14 @@
uint32_t target_slot,
const DeltaArchiveManifest& manifest);
- // Helper for PreparePartitionsForUpdate. Used for dynamic partitions without
- // Virtual A/B update.
+ // Helper for PreparePartitionsForUpdate. Used for devices with dynamic
+ // partitions updating without snapshots.
+ // If |delete_source| is set, source partitions are deleted before resizing
+ // target partitions (using DeleteSourcePartitions).
bool PrepareDynamicPartitionsForUpdate(uint32_t source_slot,
uint32_t target_slot,
- const DeltaArchiveManifest& manifest);
+ const DeltaArchiveManifest& manifest,
+ bool delete_source);
// Helper for PreparePartitionsForUpdate. Used for snapshotted partitions for
// Virtual A/B update.
@@ -179,6 +185,11 @@
uint32_t current_slot,
const std::string& partition_name_suffix);
+ // If sideloading a full OTA, delete source partitions from |builder|.
+ bool DeleteSourcePartitions(android::fs_mgr::MetadataBuilder* builder,
+ uint32_t source_slot,
+ const DeltaArchiveManifest& manifest);
+
std::set<std::string> mapped_devices_;
const FeatureFlag dynamic_partitions_;
const FeatureFlag virtual_ab_;