BootControlAndroid::GetPartitionDevice checks super metadata
... before checking device mapper. When sideloading, current (source) slot
partitions aren't mapped on device mapper in recovery. Hence, When
GetPartitionDevice is called:
- If device is already mapped, use it
- If device isn't mapped but is in metadata, this is a dynamic
partition and will be mapped (with force_writable = false, since
writable partitions should have been mapped with force_writable
in InitPartitionMetadata)
- If device isn't mapped and it is not in metadata, this is a static
partition.
Test: manual sideload incremental update with a device with dynamic partitions
Test: update_engine_unittests
Fixes: 117101719
Change-Id: I85b490e11cee689846d2bf899b6015f1b320bed9
diff --git a/boot_control_android.cc b/boot_control_android.cc
index 12296d7..4568fe4 100644
--- a/boot_control_android.cc
+++ b/boot_control_android.cc
@@ -105,6 +105,72 @@
return true;
}
+namespace {
+
+enum class DynamicPartitionDeviceStatus {
+ SUCCESS,
+ ERROR,
+ TRY_STATIC,
+};
+
+DynamicPartitionDeviceStatus GetDynamicPartitionDevice(
+ DynamicPartitionControlInterface* dynamic_control,
+ const string& super_device,
+ const string& partition_name_suffix,
+ Slot slot,
+ string* device) {
+ auto builder = dynamic_control->LoadMetadataBuilder(super_device, slot);
+
+ if (builder == nullptr) {
+ if (!dynamic_control->IsDynamicPartitionsEnabled()) {
+ return DynamicPartitionDeviceStatus::TRY_STATIC;
+ }
+ LOG(ERROR) << "No metadata in slot "
+ << BootControlInterface::SlotName(slot);
+ return DynamicPartitionDeviceStatus::ERROR;
+ }
+
+ if (builder->FindPartition(partition_name_suffix) == nullptr) {
+ LOG(INFO) << partition_name_suffix
+ << " is not in super partition metadata.";
+ return DynamicPartitionDeviceStatus::TRY_STATIC;
+ }
+
+ DmDeviceState state = dynamic_control->GetState(partition_name_suffix);
+
+ if (state == DmDeviceState::ACTIVE) {
+ if (dynamic_control->GetDmDevicePathByName(partition_name_suffix, device)) {
+ LOG(INFO) << partition_name_suffix
+ << " is mapped on device mapper: " << *device;
+ return DynamicPartitionDeviceStatus::SUCCESS;
+ }
+ LOG(ERROR) << partition_name_suffix << " is mapped but path is unknown.";
+ return DynamicPartitionDeviceStatus::ERROR;
+ }
+
+ // DeltaPerformer calls InitPartitionMetadata before calling
+ // InstallPlan::LoadPartitionsFromSlots. After InitPartitionMetadata,
+ // the target partition must be re-mapped with force_writable == true.
+ // Hence, if it is not mapped, we assume it is a source partition and
+ // map it without force_writable.
+ if (state == DmDeviceState::INVALID) {
+ if (dynamic_control->MapPartitionOnDeviceMapper(super_device,
+ partition_name_suffix,
+ slot,
+ false /* force_writable */,
+ device)) {
+ return DynamicPartitionDeviceStatus::SUCCESS;
+ }
+ return DynamicPartitionDeviceStatus::ERROR;
+ }
+
+ LOG(ERROR) << partition_name_suffix
+ << " is mapped on device mapper but state is unknown: "
+ << static_cast<std::underlying_type_t<DmDeviceState>>(state);
+ return DynamicPartitionDeviceStatus::ERROR;
+}
+} // namespace
+
bool BootControlAndroid::GetPartitionDevice(const string& partition_name,
Slot slot,
string* device) const {
@@ -112,45 +178,31 @@
if (!GetSuffix(slot, &suffix)) {
return false;
}
-
- const string target_partition_name = partition_name + suffix;
-
- // DeltaPerformer calls InitPartitionMetadata before calling
- // InstallPlan::LoadPartitionsFromSlots. After InitPartitionMetadata,
- // the partition must be re-mapped with force_writable == true. Hence,
- // we only need to check device mapper.
- if (dynamic_control_->IsDynamicPartitionsEnabled()) {
- switch (dynamic_control_->GetState(target_partition_name)) {
- case DmDeviceState::ACTIVE:
- if (dynamic_control_->GetDmDevicePathByName(target_partition_name,
- device)) {
- LOG(INFO) << target_partition_name
- << " is mapped on device mapper: " << *device;
- return true;
- }
- LOG(ERROR) << target_partition_name
- << " is mapped but path is unknown.";
- return false;
-
- case DmDeviceState::INVALID:
- // Try static partitions.
- break;
-
- case DmDeviceState::SUSPENDED: // fallthrough
- default:
- LOG(ERROR) << target_partition_name
- << " is mapped on device mapper but state is unknown";
- return false;
- }
- }
+ const string partition_name_suffix = partition_name + suffix;
string device_dir_str;
if (!dynamic_control_->GetDeviceDir(&device_dir_str)) {
return false;
}
+ base::FilePath device_dir(device_dir_str);
- base::FilePath path =
- base::FilePath(device_dir_str).Append(target_partition_name);
+ string super_device =
+ device_dir.Append(fs_mgr_get_super_partition_name()).value();
+ switch (GetDynamicPartitionDevice(dynamic_control_.get(),
+ super_device,
+ partition_name_suffix,
+ slot,
+ device)) {
+ case DynamicPartitionDeviceStatus::SUCCESS:
+ return true;
+ case DynamicPartitionDeviceStatus::TRY_STATIC:
+ break;
+ case DynamicPartitionDeviceStatus::ERROR: // fallthrough
+ default:
+ return false;
+ }
+
+ base::FilePath path = device_dir.Append(partition_name_suffix);
if (!dynamic_control_->DeviceExists(path.value())) {
LOG(ERROR) << "Device file " << path.value() << " does not exist.";
return false;