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/boot_control_android.cc b/boot_control_android.cc
index 4568fe4..1d13139 100644
--- a/boot_control_android.cc
+++ b/boot_control_android.cc
@@ -119,7 +119,8 @@
const string& partition_name_suffix,
Slot slot,
string* device) {
- auto builder = dynamic_control->LoadMetadataBuilder(super_device, slot);
+ auto builder = dynamic_control->LoadMetadataBuilder(
+ super_device, slot, BootControlInterface::kInvalidSlot);
if (builder == nullptr) {
if (!dynamic_control->IsDynamicPartitionsEnabled()) {
@@ -284,8 +285,8 @@
Slot target_slot,
const string& target_suffix,
const PartitionMetadata& partition_metadata) {
- auto builder =
- dynamic_control->LoadMetadataBuilder(super_device, source_slot);
+ auto builder = dynamic_control->LoadMetadataBuilder(
+ super_device, source_slot, target_slot);
if (builder == nullptr) {
// TODO(elsk): allow reconstructing metadata from partition_metadata
// in recovery sideload.
diff --git a/boot_control_android_unittest.cc b/boot_control_android_unittest.cc
index e98d2f4..6460ffe 100644
--- a/boot_control_android_unittest.cc
+++ b/boot_control_android_unittest.cc
@@ -298,10 +298,12 @@
}
void SetMetadata(uint32_t slot, const PartitionMetadata& metadata) {
- EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(), slot))
+ EXPECT_CALL(dynamicControl(),
+ LoadMetadataBuilder(GetSuperDevice(), slot, _))
.Times(AnyNumber())
- .WillRepeatedly(Invoke(
- [metadata](auto, auto) { return NewFakeMetadata(metadata); }));
+ .WillRepeatedly(Invoke([metadata](auto, auto, auto) {
+ return NewFakeMetadata(metadata);
+ }));
}
// Expect that MapPartitionOnDeviceMapper is called on target() metadata slot
@@ -394,7 +396,7 @@
.Times(0);
// Should not load metadata from target slot.
EXPECT_CALL(dynamicControl(),
- LoadMetadataBuilder(GetSuperDevice(), target()))
+ LoadMetadataBuilder(GetSuperDevice(), target(), _))
.Times(0);
}
@@ -512,8 +514,9 @@
// Test corrupt source metadata case.
TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) {
- EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(), source()))
- .WillOnce(Invoke([](auto, auto) { return nullptr; }));
+ EXPECT_CALL(dynamicControl(),
+ LoadMetadataBuilder(GetSuperDevice(), source(), _))
+ .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
EXPECT_FALSE(InitPartitionMetadata(target(), {{"system", 1_GiB}}))
<< "Should not be able to continue with corrupt source metadata";
}
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;
}
diff --git a/dynamic_partition_control_android.h b/dynamic_partition_control_android.h
index 91c9f87..52d4f5b 100644
--- a/dynamic_partition_control_android.h
+++ b/dynamic_partition_control_android.h
@@ -43,7 +43,9 @@
bool GetDmDevicePathByName(const std::string& name,
std::string* path) override;
std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder(
- const std::string& super_device, uint32_t source_slot) override;
+ const std::string& super_device,
+ uint32_t source_slot,
+ uint32_t target_slot) override;
bool StoreMetadata(const std::string& super_device,
android::fs_mgr::MetadataBuilder* builder,
uint32_t target_slot) override;
diff --git a/dynamic_partition_control_interface.h b/dynamic_partition_control_interface.h
index 95b01a1..b92d88a 100644
--- a/dynamic_partition_control_interface.h
+++ b/dynamic_partition_control_interface.h
@@ -74,8 +74,12 @@
std::string* path) = 0;
// Retrieve metadata from |super_device| at slot |source_slot|.
+ // On retrofit devices, if |target_slot| != kInvalidSlot, the returned
+ // metadata automatically includes block devices at |target_slot|.
virtual std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder(
- const std::string& super_device, uint32_t source_slot) = 0;
+ const std::string& super_device,
+ uint32_t source_slot,
+ uint32_t target_slot) = 0;
// Write metadata |builder| to |super_device| at slot |target_slot|.
virtual bool StoreMetadata(const std::string& super_device,
diff --git a/mock_dynamic_partition_control.h b/mock_dynamic_partition_control.h
index 6b233b3..7b37581 100644
--- a/mock_dynamic_partition_control.h
+++ b/mock_dynamic_partition_control.h
@@ -38,9 +38,9 @@
MOCK_METHOD1(DeviceExists, bool(const std::string&));
MOCK_METHOD1(GetState, ::android::dm::DmDeviceState(const std::string&));
MOCK_METHOD2(GetDmDevicePathByName, bool(const std::string&, std::string*));
- MOCK_METHOD2(LoadMetadataBuilder,
+ MOCK_METHOD3(LoadMetadataBuilder,
std::unique_ptr<::android::fs_mgr::MetadataBuilder>(
- const std::string&, uint32_t));
+ const std::string&, uint32_t, uint32_t));
MOCK_METHOD3(StoreMetadata,
bool(const std::string&,
android::fs_mgr::MetadataBuilder*,