DynamicPartitionControl: support retrofit devices
On retrofit devices:
* The retrofit update includes block devices at source
slot (for example, system_a, vendor_a, product_a).
This is done automatically because the retrofit update
does not look different from regular updates in OTA
client's perspective.
* The first update after the retrofit update includes
the rest of the block devices (in the above example,
system_b, vendor_b and product_b).
In order to do the second,
* use NewForUpdate() API from liblp to automatically
include block devices at the target slot when the metadata
is loaded.
* Use FlashPartitionTable() API to flash metadata to system_b
directly without reading existing metadata from it.
Test: manual OTA on retrofit devices
Bug: 118506262
Change-Id: Ib2c15b8a1a04271320bfef408813723a5b2a7bd7
diff --git a/dynamic_partition_control_android.cc b/dynamic_partition_control_android.cc
index 38c6759..93a0fae 100644
--- a/dynamic_partition_control_android.cc
+++ b/dynamic_partition_control_android.cc
@@ -37,10 +37,13 @@
using android::fs_mgr::CreateLogicalPartition;
using android::fs_mgr::DestroyLogicalPartition;
using android::fs_mgr::MetadataBuilder;
+using android::fs_mgr::PartitionOpener;
namespace chromeos_update_engine {
-constexpr char kUseDynamicPartitions[] = "ro.boot.logical_partitions";
+constexpr char kUseDynamicPartitions[] = "ro.boot.dynamic_partitions";
+constexpr char kRetrfoitDynamicPartitions[] =
+ "ro.boot.dynamic_partitions_retrofit";
constexpr uint64_t kMapTimeoutMillis = 1000;
DynamicPartitionControlAndroid::~DynamicPartitionControlAndroid() {
@@ -51,6 +54,10 @@
return GetBoolProperty(kUseDynamicPartitions, false);
}
+static bool IsDynamicPartitionsRetrofit() {
+ return GetBoolProperty(kRetrfoitDynamicPartitions, false);
+}
+
bool DynamicPartitionControlAndroid::MapPartitionOnDeviceMapper(
const std::string& super_device,
const std::string& target_partition_name,
@@ -122,8 +129,20 @@
std::unique_ptr<MetadataBuilder>
DynamicPartitionControlAndroid::LoadMetadataBuilder(
- const std::string& super_device, uint32_t source_slot) {
- auto builder = MetadataBuilder::New(super_device, source_slot);
+ const std::string& super_device,
+ uint32_t source_slot,
+ uint32_t target_slot) {
+ std::unique_ptr<MetadataBuilder> builder;
+
+ if (target_slot != BootControlInterface::kInvalidSlot &&
+ IsDynamicPartitionsRetrofit()) {
+ builder = MetadataBuilder::NewForUpdate(
+ PartitionOpener(), super_device, source_slot, target_slot);
+ } else {
+ builder =
+ MetadataBuilder::New(PartitionOpener(), super_device, source_slot);
+ }
+
if (builder == nullptr) {
LOG(WARNING) << "No metadata slot "
<< BootControlInterface::SlotName(source_slot) << " in "
@@ -148,16 +167,24 @@
return false;
}
- if (!UpdatePartitionTable(super_device, *metadata, target_slot)) {
- LOG(ERROR) << "Cannot write metadata to slot "
- << BootControlInterface::SlotName(target_slot) << " in "
- << super_device;
- return false;
+ if (IsDynamicPartitionsRetrofit()) {
+ if (!FlashPartitionTable(super_device, *metadata)) {
+ LOG(ERROR) << "Cannot write metadata to " << super_device;
+ return false;
+ }
+ LOG(INFO) << "Written metadata to " << super_device;
+ } else {
+ if (!UpdatePartitionTable(super_device, *metadata, target_slot)) {
+ LOG(ERROR) << "Cannot write metadata to slot "
+ << BootControlInterface::SlotName(target_slot) << " in "
+ << super_device;
+ return false;
+ }
+ LOG(INFO) << "Copied metadata to slot "
+ << BootControlInterface::SlotName(target_slot) << " in "
+ << super_device;
}
- LOG(INFO) << "Copied metadata to slot "
- << BootControlInterface::SlotName(target_slot) << " in "
- << super_device;
return true;
}