diff options
Diffstat (limited to 'boot_control_android.cc')
-rw-r--r-- | boot_control_android.cc | 315 |
1 files changed, 27 insertions, 288 deletions
diff --git a/boot_control_android.cc b/boot_control_android.cc index 8909cd90..dee5fa84 100644 --- a/boot_control_android.cc +++ b/boot_control_android.cc @@ -22,11 +22,8 @@ #include <base/bind.h> #include <base/logging.h> -#include <base/strings/string_util.h> #include <bootloader_message/bootloader_message.h> #include <brillo/message_loops/message_loop.h> -#include <fs_mgr.h> -#include <fs_mgr_overlayfs.h> #include "update_engine/common/utils.h" #include "update_engine/dynamic_partition_control_android.h" @@ -34,15 +31,12 @@ using std::string; using android::dm::DmDeviceState; -using android::fs_mgr::Partition; using android::hardware::hidl_string; using android::hardware::Return; using android::hardware::boot::V1_0::BoolResult; using android::hardware::boot::V1_0::CommandResult; using android::hardware::boot::V1_0::IBootControl; using Slot = chromeos_update_engine::BootControlInterface::Slot; -using PartitionMetadata = - chromeos_update_engine::BootControlInterface::PartitionMetadata; namespace { @@ -80,10 +74,6 @@ bool BootControlAndroid::Init() { return true; } -void BootControlAndroid::Cleanup() { - dynamic_control_->Cleanup(); -} - unsigned int BootControlAndroid::GetNumSlots() const { return module_->getNumberSlots(); } @@ -92,140 +82,24 @@ BootControlInterface::Slot BootControlAndroid::GetCurrentSlot() const { return module_->getCurrentSlot(); } -bool BootControlAndroid::GetSuffix(Slot slot, string* suffix) const { - auto store_suffix_cb = [&suffix](hidl_string cb_suffix) { - *suffix = cb_suffix.c_str(); - }; - Return<void> ret = module_->getSuffix(slot, store_suffix_cb); - - if (!ret.isOk()) { - LOG(ERROR) << "boot_control impl returned no suffix for slot " - << SlotName(slot); - return false; - } - return true; -} - -bool BootControlAndroid::IsSuperBlockDevice( - const base::FilePath& device_dir, - Slot slot, - const string& partition_name_suffix) const { - string source_device = - device_dir.Append(fs_mgr_get_super_partition_name(slot)).value(); - auto source_metadata = dynamic_control_->LoadMetadataBuilder( - source_device, slot, BootControlInterface::kInvalidSlot); - return source_metadata->HasBlockDevice(partition_name_suffix); -} - -BootControlAndroid::DynamicPartitionDeviceStatus -BootControlAndroid::GetDynamicPartitionDevice( - const base::FilePath& device_dir, - const string& partition_name_suffix, - Slot slot, - string* device) const { - string super_device = - device_dir.Append(fs_mgr_get_super_partition_name(slot)).value(); - - auto builder = dynamic_control_->LoadMetadataBuilder( - super_device, slot, BootControlInterface::kInvalidSlot); - - if (builder == nullptr) { - 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."; - - Slot current_slot = GetCurrentSlot(); - if (IsSuperBlockDevice(device_dir, current_slot, partition_name_suffix)) { - LOG(ERROR) << "The static partition " << partition_name_suffix - << " is a block device for current metadata (" - << fs_mgr_get_super_partition_name(current_slot) << ", slot " - << BootControlInterface::SlotName(current_slot) - << "). It cannot be used as a logical partition."; - return DynamicPartitionDeviceStatus::ERROR; - } - - return DynamicPartitionDeviceStatus::TRY_STATIC; - } - - DmDeviceState state = dynamic_control_->GetState(partition_name_suffix); - - // Device is mapped in the previous GetPartitionDevice() call. Just return - // the path. - 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; - } - - if (state == DmDeviceState::INVALID) { - bool force_writable = slot != GetCurrentSlot(); - if (dynamic_control_->MapPartitionOnDeviceMapper(super_device, - partition_name_suffix, - slot, - 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; +bool BootControlAndroid::GetPartitionDevice(const std::string& partition_name, + BootControlInterface::Slot slot, + bool not_in_payload, + std::string* device, + bool* is_dynamic) const { + return dynamic_control_->GetPartitionDevice(partition_name, + slot, + GetCurrentSlot(), + not_in_payload, + device, + is_dynamic); } bool BootControlAndroid::GetPartitionDevice(const string& partition_name, - Slot slot, + BootControlInterface::Slot slot, string* device) const { - string suffix; - if (!GetSuffix(slot, &suffix)) { - 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); - - // When looking up target partition devices, treat them as static if the - // current payload doesn't encode them as dynamic partitions. This may happen - // when applying a retrofit update on top of a dynamic-partitions-enabled - // build. - if (dynamic_control_->IsDynamicPartitionsEnabled() && - (slot == GetCurrentSlot() || is_target_dynamic_)) { - switch (GetDynamicPartitionDevice( - device_dir, 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; - } - - *device = path.value(); - return true; + return GetPartitionDevice( + partition_name, slot, false /* not_in_payload */, device, nullptr); } bool BootControlAndroid::IsSlotBootable(Slot slot) const { @@ -288,160 +162,25 @@ bool BootControlAndroid::MarkBootSuccessfulAsync( brillo::MessageLoop::kTaskIdNull; } -namespace { - -bool UpdatePartitionMetadata(DynamicPartitionControlInterface* dynamic_control, - Slot source_slot, - Slot target_slot, - const string& target_suffix, - const PartitionMetadata& partition_metadata) { - string device_dir_str; - if (!dynamic_control->GetDeviceDir(&device_dir_str)) { - return false; - } - base::FilePath device_dir(device_dir_str); - auto source_device = - device_dir.Append(fs_mgr_get_super_partition_name(source_slot)).value(); - - auto builder = dynamic_control->LoadMetadataBuilder( - source_device, source_slot, target_slot); - if (builder == nullptr) { - // TODO(elsk): allow reconstructing metadata from partition_metadata - // in recovery sideload. - LOG(ERROR) << "No metadata at " - << BootControlInterface::SlotName(source_slot); +bool BootControlAndroid::IsSlotMarkedSuccessful( + BootControlInterface::Slot slot) const { + Return<BoolResult> ret = module_->isSlotMarkedSuccessful(slot); + CommandResult result; + if (!ret.isOk()) { + LOG(ERROR) << "Unable to determine if slot " << SlotName(slot) + << " is marked successful: " << ret.description(); return false; } - - std::vector<string> groups = builder->ListGroups(); - for (const auto& group_name : groups) { - if (base::EndsWith( - group_name, target_suffix, base::CompareCase::SENSITIVE)) { - LOG(INFO) << "Removing group " << group_name; - builder->RemoveGroupAndPartitions(group_name); - } - } - - uint64_t total_size = 0; - for (const auto& group : partition_metadata.groups) { - total_size += group.size; - } - - string expr; - uint64_t allocatable_space = builder->AllocatableSpace(); - if (!dynamic_control->IsDynamicPartitionsRetrofit()) { - allocatable_space /= 2; - expr = "half of "; - } - if (total_size > allocatable_space) { - LOG(ERROR) << "The maximum size of all groups with suffix " << target_suffix - << " (" << total_size << ") has exceeded " << expr - << " allocatable space for dynamic partitions " - << allocatable_space << "."; + if (ret == BoolResult::INVALID_SLOT) { + LOG(ERROR) << "Invalid slot: " << SlotName(slot); return false; } - - for (const auto& group : partition_metadata.groups) { - auto group_name_suffix = group.name + target_suffix; - if (!builder->AddGroup(group_name_suffix, group.size)) { - LOG(ERROR) << "Cannot add group " << group_name_suffix << " with size " - << group.size; - return false; - } - LOG(INFO) << "Added group " << group_name_suffix << " with size " - << group.size; - - for (const auto& partition : group.partitions) { - auto partition_name_suffix = partition.name + target_suffix; - Partition* p = builder->AddPartition( - partition_name_suffix, group_name_suffix, LP_PARTITION_ATTR_READONLY); - if (!p) { - LOG(ERROR) << "Cannot add partition " << partition_name_suffix - << " to group " << group_name_suffix; - return false; - } - if (!builder->ResizePartition(p, partition.size)) { - LOG(ERROR) << "Cannot resize partition " << partition_name_suffix - << " to size " << partition.size << ". Not enough space?"; - return false; - } - LOG(INFO) << "Added partition " << partition_name_suffix << " to group " - << group_name_suffix << " with size " << partition.size; - } - } - - auto target_device = - device_dir.Append(fs_mgr_get_super_partition_name(target_slot)).value(); - return dynamic_control->StoreMetadata( - target_device, builder.get(), target_slot); -} - -bool UnmapTargetPartitions(DynamicPartitionControlInterface* dynamic_control, - const string& target_suffix, - const PartitionMetadata& partition_metadata) { - for (const auto& group : partition_metadata.groups) { - for (const auto& partition : group.partitions) { - if (!dynamic_control->UnmapPartitionOnDeviceMapper( - partition.name + target_suffix, true /* wait */)) { - return false; - } - } - } - return true; + return ret == BoolResult::TRUE; } -} // namespace - -bool BootControlAndroid::InitPartitionMetadata( - Slot target_slot, - const PartitionMetadata& partition_metadata, - bool update_metadata) { - if (fs_mgr_overlayfs_is_setup()) { - // Non DAP devices can use overlayfs as well. - LOG(WARNING) - << "overlayfs overrides are active and can interfere with our " - "resources.\n" - << "run adb enable-verity to deactivate if required and try again."; - } - if (!dynamic_control_->IsDynamicPartitionsEnabled()) { - return true; - } - - auto source_slot = GetCurrentSlot(); - if (target_slot == source_slot) { - LOG(ERROR) << "Cannot call InitPartitionMetadata on current slot."; - return false; - } - - // Although the current build supports dynamic partitions, the given payload - // doesn't use it for target partitions. This could happen when applying a - // retrofit update. Skip updating the partition metadata for the target slot. - is_target_dynamic_ = !partition_metadata.groups.empty(); - if (!is_target_dynamic_) { - return true; - } - - if (!update_metadata) { - return true; - } - - string target_suffix; - if (!GetSuffix(target_slot, &target_suffix)) { - return false; - } - - // Unmap all the target dynamic partitions because they would become - // inconsistent with the new metadata. - if (!UnmapTargetPartitions( - dynamic_control_.get(), target_suffix, partition_metadata)) { - return false; - } - - return UpdatePartitionMetadata(dynamic_control_.get(), - source_slot, - target_slot, - target_suffix, - partition_metadata); +DynamicPartitionControlInterface* +BootControlAndroid::GetDynamicPartitionControl() { + return dynamic_control_.get(); } } // namespace chromeos_update_engine |