1 // 2 // Copyright (C) 2018 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "update_engine/dynamic_partition_control_android.h" 18 19 #include <chrono> // NOLINT(build/c++11) - using libsnapshot / liblp API 20 #include <map> 21 #include <memory> 22 #include <set> 23 #include <string> 24 #include <vector> 25 26 #include <android-base/properties.h> 27 #include <android-base/strings.h> 28 #include <base/files/file_util.h> 29 #include <base/logging.h> 30 #include <base/strings/string_util.h> 31 #include <bootloader_message/bootloader_message.h> 32 #include <fs_mgr.h> 33 #include <fs_mgr_dm_linear.h> 34 #include <fs_mgr_overlayfs.h> 35 #include <libavb/libavb.h> 36 #include <libdm/dm.h> 37 #include <libsnapshot/snapshot.h> 38 39 #include "update_engine/cleanup_previous_update_action.h" 40 #include "update_engine/common/boot_control_interface.h" 41 #include "update_engine/common/utils.h" 42 #include "update_engine/dynamic_partition_utils.h" 43 #include "update_engine/payload_consumer/delta_performer.h" 44 45 using android::base::GetBoolProperty; 46 using android::base::GetProperty; 47 using android::base::Join; 48 using android::dm::DeviceMapper; 49 using android::dm::DmDeviceState; 50 using android::fs_mgr::CreateLogicalPartition; 51 using android::fs_mgr::CreateLogicalPartitionParams; 52 using android::fs_mgr::DestroyLogicalPartition; 53 using android::fs_mgr::Fstab; 54 using android::fs_mgr::MetadataBuilder; 55 using android::fs_mgr::Partition; 56 using android::fs_mgr::PartitionOpener; 57 using android::fs_mgr::SlotSuffixForSlotNumber; 58 using android::snapshot::OptimizeSourceCopyOperation; 59 using android::snapshot::Return; 60 using android::snapshot::SnapshotManager; 61 using android::snapshot::UpdateState; 62 63 namespace chromeos_update_engine { 64 65 constexpr char kUseDynamicPartitions[] = "ro.boot.dynamic_partitions"; 66 constexpr char kRetrfoitDynamicPartitions[] = 67 "ro.boot.dynamic_partitions_retrofit"; 68 constexpr char kVirtualAbEnabled[] = "ro.virtual_ab.enabled"; 69 constexpr char kVirtualAbRetrofit[] = "ro.virtual_ab.retrofit"; 70 constexpr char kPostinstallFstabPrefix[] = "ro.postinstall.fstab.prefix"; 71 // Map timeout for dynamic partitions. 72 constexpr std::chrono::milliseconds kMapTimeout{1000}; 73 // Map timeout for dynamic partitions with snapshots. Since several devices 74 // needs to be mapped, this timeout is longer than |kMapTimeout|. 75 constexpr std::chrono::milliseconds kMapSnapshotTimeout{5000}; 76 77 #ifdef __ANDROID_RECOVERY__ 78 constexpr bool kIsRecovery = true; 79 #else 80 constexpr bool kIsRecovery = false; 81 #endif 82 83 DynamicPartitionControlAndroid::~DynamicPartitionControlAndroid() { 84 Cleanup(); 85 } 86 87 static FeatureFlag GetFeatureFlag(const char* enable_prop, 88 const char* retrofit_prop) { 89 bool retrofit = GetBoolProperty(retrofit_prop, false); 90 bool enabled = GetBoolProperty(enable_prop, false); 91 if (retrofit && !enabled) { 92 LOG(ERROR) << retrofit_prop << " is true but " << enable_prop 93 << " is not. These sysprops are inconsistent. Assume that " 94 << enable_prop << " is true from now on."; 95 } 96 if (retrofit) { 97 return FeatureFlag(FeatureFlag::Value::RETROFIT); 98 } 99 if (enabled) { 100 return FeatureFlag(FeatureFlag::Value::LAUNCH); 101 } 102 return FeatureFlag(FeatureFlag::Value::NONE); 103 } 104 105 DynamicPartitionControlAndroid::DynamicPartitionControlAndroid() 106 : dynamic_partitions_( 107 GetFeatureFlag(kUseDynamicPartitions, kRetrfoitDynamicPartitions)), 108 virtual_ab_(GetFeatureFlag(kVirtualAbEnabled, kVirtualAbRetrofit)) { 109 if (GetVirtualAbFeatureFlag().IsEnabled()) { 110 snapshot_ = SnapshotManager::New(); 111 CHECK(snapshot_ != nullptr) << "Cannot initialize SnapshotManager."; 112 } 113 } 114 115 FeatureFlag DynamicPartitionControlAndroid::GetDynamicPartitionsFeatureFlag() { 116 return dynamic_partitions_; 117 } 118 119 FeatureFlag DynamicPartitionControlAndroid::GetVirtualAbFeatureFlag() { 120 return virtual_ab_; 121 } 122 123 bool DynamicPartitionControlAndroid::OptimizeOperation( 124 const std::string& partition_name, 125 const InstallOperation& operation, 126 InstallOperation* optimized) { 127 switch (operation.type()) { 128 case InstallOperation::SOURCE_COPY: 129 return target_supports_snapshot_ && 130 GetVirtualAbFeatureFlag().IsEnabled() && 131 mapped_devices_.count(partition_name + 132 SlotSuffixForSlotNumber(target_slot_)) > 0 && 133 OptimizeSourceCopyOperation(operation, optimized); 134 break; 135 default: 136 break; 137 } 138 return false; 139 } 140 141 bool DynamicPartitionControlAndroid::MapPartitionInternal( 142 const std::string& super_device, 143 const std::string& target_partition_name, 144 uint32_t slot, 145 bool force_writable, 146 std::string* path) { 147 CreateLogicalPartitionParams params = { 148 .block_device = super_device, 149 .metadata_slot = slot, 150 .partition_name = target_partition_name, 151 .force_writable = force_writable, 152 }; 153 bool success = false; 154 if (GetVirtualAbFeatureFlag().IsEnabled() && target_supports_snapshot_ && 155 force_writable && ExpectMetadataMounted()) { 156 // Only target partitions are mapped with force_writable. On Virtual 157 // A/B devices, target partitions may overlap with source partitions, so 158 // they must be mapped with snapshot. 159 // One exception is when /metadata is not mounted. Fallback to 160 // CreateLogicalPartition as snapshots are not created in the first place. 161 params.timeout_ms = kMapSnapshotTimeout; 162 success = snapshot_->MapUpdateSnapshot(params, path); 163 } else { 164 params.timeout_ms = kMapTimeout; 165 success = CreateLogicalPartition(params, path); 166 } 167 168 if (!success) { 169 LOG(ERROR) << "Cannot map " << target_partition_name << " in " 170 << super_device << " on device mapper."; 171 return false; 172 } 173 LOG(INFO) << "Succesfully mapped " << target_partition_name 174 << " to device mapper (force_writable = " << force_writable 175 << "); device path at " << *path; 176 mapped_devices_.insert(target_partition_name); 177 return true; 178 } 179 180 bool DynamicPartitionControlAndroid::MapPartitionOnDeviceMapper( 181 const std::string& super_device, 182 const std::string& target_partition_name, 183 uint32_t slot, 184 bool force_writable, 185 std::string* path) { 186 DmDeviceState state = GetState(target_partition_name); 187 if (state == DmDeviceState::ACTIVE) { 188 if (mapped_devices_.find(target_partition_name) != mapped_devices_.end()) { 189 if (GetDmDevicePathByName(target_partition_name, path)) { 190 LOG(INFO) << target_partition_name 191 << " is mapped on device mapper: " << *path; 192 return true; 193 } 194 LOG(ERROR) << target_partition_name << " is mapped but path is unknown."; 195 return false; 196 } 197 // If target_partition_name is not in mapped_devices_ but state is ACTIVE, 198 // the device might be mapped incorrectly before. Attempt to unmap it. 199 // Note that for source partitions, if GetState() == ACTIVE, callers (e.g. 200 // BootControlAndroid) should not call MapPartitionOnDeviceMapper, but 201 // should directly call GetDmDevicePathByName. 202 if (!UnmapPartitionOnDeviceMapper(target_partition_name)) { 203 LOG(ERROR) << target_partition_name 204 << " is mapped before the update, and it cannot be unmapped."; 205 return false; 206 } 207 state = GetState(target_partition_name); 208 if (state != DmDeviceState::INVALID) { 209 LOG(ERROR) << target_partition_name << " is unmapped but state is " 210 << static_cast<std::underlying_type_t<DmDeviceState>>(state); 211 return false; 212 } 213 } 214 if (state == DmDeviceState::INVALID) { 215 return MapPartitionInternal( 216 super_device, target_partition_name, slot, force_writable, path); 217 } 218 219 LOG(ERROR) << target_partition_name 220 << " is mapped on device mapper but state is unknown: " 221 << static_cast<std::underlying_type_t<DmDeviceState>>(state); 222 return false; 223 } 224 225 bool DynamicPartitionControlAndroid::UnmapPartitionOnDeviceMapper( 226 const std::string& target_partition_name) { 227 if (DeviceMapper::Instance().GetState(target_partition_name) != 228 DmDeviceState::INVALID) { 229 // Partitions at target slot on non-Virtual A/B devices are mapped as 230 // dm-linear. Also, on Virtual A/B devices, system_other may be mapped for 231 // preopt apps as dm-linear. 232 // Call DestroyLogicalPartition to handle these cases. 233 bool success = DestroyLogicalPartition(target_partition_name); 234 235 // On a Virtual A/B device, |target_partition_name| may be a leftover from 236 // a paused update. Clean up any underlying devices. 237 if (ExpectMetadataMounted()) { 238 success &= snapshot_->UnmapUpdateSnapshot(target_partition_name); 239 } else { 240 LOG(INFO) << "Skip UnmapUpdateSnapshot(" << target_partition_name 241 << ") because metadata is not mounted"; 242 } 243 244 if (!success) { 245 LOG(ERROR) << "Cannot unmap " << target_partition_name 246 << " from device mapper."; 247 return false; 248 } 249 LOG(INFO) << "Successfully unmapped " << target_partition_name 250 << " from device mapper."; 251 } 252 mapped_devices_.erase(target_partition_name); 253 return true; 254 } 255 256 void DynamicPartitionControlAndroid::UnmapAllPartitions() { 257 if (mapped_devices_.empty()) { 258 return; 259 } 260 // UnmapPartitionOnDeviceMapper removes objects from mapped_devices_, hence 261 // a copy is needed for the loop. 262 std::set<std::string> mapped = mapped_devices_; 263 LOG(INFO) << "Destroying [" << Join(mapped, ", ") << "] from device mapper"; 264 for (const auto& partition_name : mapped) { 265 ignore_result(UnmapPartitionOnDeviceMapper(partition_name)); 266 } 267 } 268 269 void DynamicPartitionControlAndroid::Cleanup() { 270 UnmapAllPartitions(); 271 metadata_device_.reset(); 272 } 273 274 bool DynamicPartitionControlAndroid::DeviceExists(const std::string& path) { 275 return base::PathExists(base::FilePath(path)); 276 } 277 278 android::dm::DmDeviceState DynamicPartitionControlAndroid::GetState( 279 const std::string& name) { 280 return DeviceMapper::Instance().GetState(name); 281 } 282 283 bool DynamicPartitionControlAndroid::GetDmDevicePathByName( 284 const std::string& name, std::string* path) { 285 return DeviceMapper::Instance().GetDmDevicePathByName(name, path); 286 } 287 288 std::unique_ptr<MetadataBuilder> 289 DynamicPartitionControlAndroid::LoadMetadataBuilder( 290 const std::string& super_device, uint32_t source_slot) { 291 return LoadMetadataBuilder( 292 super_device, source_slot, BootControlInterface::kInvalidSlot); 293 } 294 295 std::unique_ptr<MetadataBuilder> 296 DynamicPartitionControlAndroid::LoadMetadataBuilder( 297 const std::string& super_device, 298 uint32_t source_slot, 299 uint32_t target_slot) { 300 std::unique_ptr<MetadataBuilder> builder; 301 if (target_slot == BootControlInterface::kInvalidSlot) { 302 builder = 303 MetadataBuilder::New(PartitionOpener(), super_device, source_slot); 304 } else { 305 bool always_keep_source_slot = !target_supports_snapshot_; 306 builder = MetadataBuilder::NewForUpdate(PartitionOpener(), 307 super_device, 308 source_slot, 309 target_slot, 310 always_keep_source_slot); 311 } 312 313 if (builder == nullptr) { 314 LOG(WARNING) << "No metadata slot " 315 << BootControlInterface::SlotName(source_slot) << " in " 316 << super_device; 317 return nullptr; 318 } 319 LOG(INFO) << "Loaded metadata from slot " 320 << BootControlInterface::SlotName(source_slot) << " in " 321 << super_device; 322 return builder; 323 } 324 325 bool DynamicPartitionControlAndroid::StoreMetadata( 326 const std::string& super_device, 327 MetadataBuilder* builder, 328 uint32_t target_slot) { 329 auto metadata = builder->Export(); 330 if (metadata == nullptr) { 331 LOG(ERROR) << "Cannot export metadata to slot " 332 << BootControlInterface::SlotName(target_slot) << " in " 333 << super_device; 334 return false; 335 } 336 337 if (GetDynamicPartitionsFeatureFlag().IsRetrofit()) { 338 if (!FlashPartitionTable(super_device, *metadata)) { 339 LOG(ERROR) << "Cannot write metadata to " << super_device; 340 return false; 341 } 342 LOG(INFO) << "Written metadata to " << super_device; 343 } else { 344 if (!UpdatePartitionTable(super_device, *metadata, target_slot)) { 345 LOG(ERROR) << "Cannot write metadata to slot " 346 << BootControlInterface::SlotName(target_slot) << " in " 347 << super_device; 348 return false; 349 } 350 LOG(INFO) << "Copied metadata to slot " 351 << BootControlInterface::SlotName(target_slot) << " in " 352 << super_device; 353 } 354 355 return true; 356 } 357 358 bool DynamicPartitionControlAndroid::GetDeviceDir(std::string* out) { 359 // We can't use fs_mgr to look up |partition_name| because fstab 360 // doesn't list every slot partition (it uses the slotselect option 361 // to mask the suffix). 362 // 363 // We can however assume that there's an entry for the /misc mount 364 // point and use that to get the device file for the misc 365 // partition. This helps us locate the disk that |partition_name| 366 // resides on. From there we'll assume that a by-name scheme is used 367 // so we can just replace the trailing "misc" by the given 368 // |partition_name| and suffix corresponding to |slot|, e.g. 369 // 370 // /dev/block/platform/soc.0/7824900.sdhci/by-name/misc -> 371 // /dev/block/platform/soc.0/7824900.sdhci/by-name/boot_a 372 // 373 // If needed, it's possible to relax the by-name assumption in the 374 // future by trawling /sys/block looking for the appropriate sibling 375 // of misc and then finding an entry in /dev matching the sysfs 376 // entry. 377 378 std::string err, misc_device = get_bootloader_message_blk_device(&err); 379 if (misc_device.empty()) { 380 LOG(ERROR) << "Unable to get misc block device: " << err; 381 return false; 382 } 383 384 if (!utils::IsSymlink(misc_device.c_str())) { 385 LOG(ERROR) << "Device file " << misc_device << " for /misc " 386 << "is not a symlink."; 387 return false; 388 } 389 *out = base::FilePath(misc_device).DirName().value(); 390 return true; 391 } 392 393 bool DynamicPartitionControlAndroid::PreparePartitionsForUpdate( 394 uint32_t source_slot, 395 uint32_t target_slot, 396 const DeltaArchiveManifest& manifest, 397 bool update, 398 uint64_t* required_size) { 399 source_slot_ = source_slot; 400 target_slot_ = target_slot; 401 if (required_size != nullptr) { 402 *required_size = 0; 403 } 404 405 if (fs_mgr_overlayfs_is_setup()) { 406 // Non DAP devices can use overlayfs as well. 407 LOG(WARNING) 408 << "overlayfs overrides are active and can interfere with our " 409 "resources.\n" 410 << "run adb enable-verity to deactivate if required and try again."; 411 } 412 413 // If metadata is erased but not formatted, it is possible to not mount 414 // it in recovery. It is acceptable to skip mounting and choose fallback path 415 // (PrepareDynamicPartitionsForUpdate) when sideloading full OTAs. 416 TEST_AND_RETURN_FALSE(EnsureMetadataMounted() || IsRecovery()); 417 418 if (update) { 419 TEST_AND_RETURN_FALSE(EraseSystemOtherAvbFooter(source_slot, target_slot)); 420 } 421 422 if (!GetDynamicPartitionsFeatureFlag().IsEnabled()) { 423 return true; 424 } 425 426 if (target_slot == source_slot) { 427 LOG(ERROR) << "Cannot call PreparePartitionsForUpdate on current slot."; 428 return false; 429 } 430 431 // Although the current build supports dynamic partitions, the given payload 432 // doesn't use it for target partitions. This could happen when applying a 433 // retrofit update. Skip updating the partition metadata for the target slot. 434 is_target_dynamic_ = !manifest.dynamic_partition_metadata().groups().empty(); 435 if (!is_target_dynamic_) { 436 return true; 437 } 438 439 target_supports_snapshot_ = 440 manifest.dynamic_partition_metadata().snapshot_enabled(); 441 442 if (!update) 443 return true; 444 445 bool delete_source = false; 446 447 if (GetVirtualAbFeatureFlag().IsEnabled()) { 448 // On Virtual A/B device, either CancelUpdate() or BeginUpdate() must be 449 // called before calling UnmapUpdateSnapshot. 450 // - If target_supports_snapshot_, PrepareSnapshotPartitionsForUpdate() 451 // calls BeginUpdate() which resets update state 452 // - If !target_supports_snapshot_ or PrepareSnapshotPartitionsForUpdate 453 // failed in recovery, explicitly CancelUpdate(). 454 if (target_supports_snapshot_) { 455 if (PrepareSnapshotPartitionsForUpdate( 456 source_slot, target_slot, manifest, required_size)) { 457 return true; 458 } 459 460 // Virtual A/B device doing Virtual A/B update in Android mode must use 461 // snapshots. 462 if (!IsRecovery()) { 463 LOG(ERROR) << "PrepareSnapshotPartitionsForUpdate failed in Android " 464 << "mode"; 465 return false; 466 } 467 468 delete_source = true; 469 LOG(INFO) << "PrepareSnapshotPartitionsForUpdate failed in recovery. " 470 << "Attempt to overwrite existing partitions if possible"; 471 } else { 472 // Downgrading to an non-Virtual A/B build or is secondary OTA. 473 LOG(INFO) << "Using regular A/B on Virtual A/B because package disabled " 474 << "snapshots."; 475 } 476 477 // In recovery, if /metadata is not mounted, it is likely that metadata 478 // partition is erased and not formatted yet. After sideloading, when 479 // rebooting into the new version, init will erase metadata partition, 480 // hence the failure of CancelUpdate() can be ignored here. 481 // However, if metadata is mounted and CancelUpdate fails, sideloading 482 // should not proceed because during next boot, snapshots will overlay on 483 // the devices incorrectly. 484 if (ExpectMetadataMounted()) { 485 TEST_AND_RETURN_FALSE(snapshot_->CancelUpdate()); 486 } else { 487 LOG(INFO) << "Skip canceling previous update because metadata is not " 488 << "mounted"; 489 } 490 } 491 492 return PrepareDynamicPartitionsForUpdate( 493 source_slot, target_slot, manifest, delete_source); 494 } 495 496 namespace { 497 // Try our best to erase AVB footer. 498 class AvbFooterEraser { 499 public: 500 explicit AvbFooterEraser(const std::string& path) : path_(path) {} 501 bool Erase() { 502 // Try to mark the block device read-only. Ignore any 503 // failure since this won't work when passing regular files. 504 ignore_result(utils::SetBlockDeviceReadOnly(path_, false /* readonly */)); 505 506 fd_.reset(new EintrSafeFileDescriptor()); 507 int flags = O_WRONLY | O_TRUNC | O_CLOEXEC | O_SYNC; 508 TEST_AND_RETURN_FALSE(fd_->Open(path_.c_str(), flags)); 509 510 // Need to write end-AVB_FOOTER_SIZE to end. 511 static_assert(AVB_FOOTER_SIZE > 0); 512 off64_t offset = fd_->Seek(-AVB_FOOTER_SIZE, SEEK_END); 513 TEST_AND_RETURN_FALSE_ERRNO(offset >= 0); 514 uint64_t write_size = AVB_FOOTER_SIZE; 515 LOG(INFO) << "Zeroing " << path_ << " @ [" << offset << ", " 516 << (offset + write_size) << "] (" << write_size << " bytes)"; 517 brillo::Blob zeros(write_size); 518 TEST_AND_RETURN_FALSE(utils::WriteAll(fd_, zeros.data(), zeros.size())); 519 return true; 520 } 521 ~AvbFooterEraser() { 522 TEST_AND_RETURN(fd_ != nullptr && fd_->IsOpen()); 523 if (!fd_->Close()) { 524 LOG(WARNING) << "Failed to close fd for " << path_; 525 } 526 } 527 528 private: 529 std::string path_; 530 FileDescriptorPtr fd_; 531 }; 532 533 } // namespace 534 535 std::optional<bool> 536 DynamicPartitionControlAndroid::IsAvbEnabledOnSystemOther() { 537 auto prefix = GetProperty(kPostinstallFstabPrefix, ""); 538 if (prefix.empty()) { 539 LOG(WARNING) << "Cannot get " << kPostinstallFstabPrefix; 540 return std::nullopt; 541 } 542 auto path = base::FilePath(prefix).Append("etc/fstab.postinstall").value(); 543 return IsAvbEnabledInFstab(path); 544 } 545 546 std::optional<bool> DynamicPartitionControlAndroid::IsAvbEnabledInFstab( 547 const std::string& path) { 548 Fstab fstab; 549 if (!ReadFstabFromFile(path, &fstab)) { 550 PLOG(WARNING) << "Cannot read fstab from " << path; 551 if (errno == ENOENT) { 552 return false; 553 } 554 return std::nullopt; 555 } 556 for (const auto& entry : fstab) { 557 if (!entry.avb_keys.empty()) { 558 return true; 559 } 560 } 561 return false; 562 } 563 564 bool DynamicPartitionControlAndroid::GetSystemOtherPath( 565 uint32_t source_slot, 566 uint32_t target_slot, 567 const std::string& partition_name_suffix, 568 std::string* path, 569 bool* should_unmap) { 570 path->clear(); 571 *should_unmap = false; 572 573 // Check that AVB is enabled on system_other before erasing. 574 auto has_avb = IsAvbEnabledOnSystemOther(); 575 TEST_AND_RETURN_FALSE(has_avb.has_value()); 576 if (!has_avb.value()) { 577 LOG(INFO) << "AVB is not enabled on system_other. Skip erasing."; 578 return true; 579 } 580 581 if (!IsRecovery()) { 582 // Found unexpected avb_keys for system_other on devices retrofitting 583 // dynamic partitions. Previous crash in update_engine may leave logical 584 // partitions mapped on physical system_other partition. It is difficult to 585 // handle these cases. Just fail. 586 if (GetDynamicPartitionsFeatureFlag().IsRetrofit()) { 587 LOG(ERROR) << "Cannot erase AVB footer on system_other on devices with " 588 << "retrofit dynamic partitions. They should not have AVB " 589 << "enabled on system_other."; 590 return false; 591 } 592 } 593 594 std::string device_dir_str; 595 TEST_AND_RETURN_FALSE(GetDeviceDir(&device_dir_str)); 596 base::FilePath device_dir(device_dir_str); 597 598 // On devices without dynamic partition, search for static partitions. 599 if (!GetDynamicPartitionsFeatureFlag().IsEnabled()) { 600 *path = device_dir.Append(partition_name_suffix).value(); 601 TEST_AND_RETURN_FALSE(DeviceExists(*path)); 602 return true; 603 } 604 605 auto source_super_device = 606 device_dir.Append(GetSuperPartitionName(source_slot)).value(); 607 608 auto builder = LoadMetadataBuilder(source_super_device, source_slot); 609 if (builder == nullptr) { 610 if (IsRecovery()) { 611 // It might be corrupted for some reason. It should still be able to 612 // sideload. 613 LOG(WARNING) << "Super partition metadata cannot be read from the source " 614 << "slot, skip erasing."; 615 return true; 616 } else { 617 // Device has booted into Android mode, indicating that the super 618 // partition metadata should be there. 619 LOG(ERROR) << "Super partition metadata cannot be read from the source " 620 << "slot. This is unexpected on devices with dynamic " 621 << "partitions enabled."; 622 return false; 623 } 624 } 625 auto p = builder->FindPartition(partition_name_suffix); 626 if (p == nullptr) { 627 // If the source slot is flashed without system_other, it does not exist 628 // in super partition metadata at source slot. It is safe to skip it. 629 LOG(INFO) << "Can't find " << partition_name_suffix 630 << " in metadata source slot, skip erasing."; 631 return true; 632 } 633 // System_other created by flashing tools should be erased. 634 // If partition is created by update_engine (via NewForUpdate), it is a 635 // left-over partition from the previous update and does not contain 636 // system_other, hence there is no need to erase. 637 // Note the reverse is not necessary true. If the flag is not set, we don't 638 // know if the partition is created by update_engine or by flashing tools 639 // because older versions of super partition metadata does not contain this 640 // flag. It is okay to erase the AVB footer anyways. 641 if (p->attributes() & LP_PARTITION_ATTR_UPDATED) { 642 LOG(INFO) << partition_name_suffix 643 << " does not contain system_other, skip erasing."; 644 return true; 645 } 646 647 if (p->size() < AVB_FOOTER_SIZE) { 648 LOG(INFO) << partition_name_suffix << " has length " << p->size() 649 << "( < AVB_FOOTER_SIZE " << AVB_FOOTER_SIZE 650 << "), skip erasing."; 651 return true; 652 } 653 654 // Delete any pre-existing device with name |partition_name_suffix| and 655 // also remove it from |mapped_devices_|. 656 // In recovery, metadata might not be mounted, and 657 // UnmapPartitionOnDeviceMapper might fail. However, 658 // it is unusual that system_other has already been mapped. Hence, just skip. 659 TEST_AND_RETURN_FALSE(UnmapPartitionOnDeviceMapper(partition_name_suffix)); 660 // Use CreateLogicalPartition directly to avoid mapping with existing 661 // snapshots. 662 CreateLogicalPartitionParams params = { 663 .block_device = source_super_device, 664 .metadata_slot = source_slot, 665 .partition_name = partition_name_suffix, 666 .force_writable = true, 667 .timeout_ms = kMapTimeout, 668 }; 669 TEST_AND_RETURN_FALSE(CreateLogicalPartition(params, path)); 670 *should_unmap = true; 671 return true; 672 } 673 674 bool DynamicPartitionControlAndroid::EraseSystemOtherAvbFooter( 675 uint32_t source_slot, uint32_t target_slot) { 676 LOG(INFO) << "Erasing AVB footer of system_other partition before update."; 677 678 const std::string target_suffix = SlotSuffixForSlotNumber(target_slot); 679 const std::string partition_name_suffix = "system" + target_suffix; 680 681 std::string path; 682 bool should_unmap = false; 683 684 TEST_AND_RETURN_FALSE(GetSystemOtherPath( 685 source_slot, target_slot, partition_name_suffix, &path, &should_unmap)); 686 687 if (path.empty()) { 688 return true; 689 } 690 691 bool ret = AvbFooterEraser(path).Erase(); 692 693 // Delete |partition_name_suffix| from device mapper and from 694 // |mapped_devices_| again so that it does not interfere with update process. 695 // In recovery, metadata might not be mounted, and 696 // UnmapPartitionOnDeviceMapper might fail. However, DestroyLogicalPartition 697 // should be called. If DestroyLogicalPartition does fail, it is still okay 698 // to skip the error here and let Prepare*() fail later. 699 if (should_unmap) { 700 TEST_AND_RETURN_FALSE(UnmapPartitionOnDeviceMapper(partition_name_suffix)); 701 } 702 703 return ret; 704 } 705 706 bool DynamicPartitionControlAndroid::PrepareDynamicPartitionsForUpdate( 707 uint32_t source_slot, 708 uint32_t target_slot, 709 const DeltaArchiveManifest& manifest, 710 bool delete_source) { 711 const std::string target_suffix = SlotSuffixForSlotNumber(target_slot); 712 713 // Unmap all the target dynamic partitions because they would become 714 // inconsistent with the new metadata. 715 for (const auto& group : manifest.dynamic_partition_metadata().groups()) { 716 for (const auto& partition_name : group.partition_names()) { 717 if (!UnmapPartitionOnDeviceMapper(partition_name + target_suffix)) { 718 return false; 719 } 720 } 721 } 722 723 std::string device_dir_str; 724 if (!GetDeviceDir(&device_dir_str)) { 725 return false; 726 } 727 base::FilePath device_dir(device_dir_str); 728 auto source_device = 729 device_dir.Append(GetSuperPartitionName(source_slot)).value(); 730 731 auto builder = LoadMetadataBuilder(source_device, source_slot, target_slot); 732 if (builder == nullptr) { 733 LOG(ERROR) << "No metadata at " 734 << BootControlInterface::SlotName(source_slot); 735 return false; 736 } 737 738 if (delete_source) { 739 TEST_AND_RETURN_FALSE( 740 DeleteSourcePartitions(builder.get(), source_slot, manifest)); 741 } 742 743 if (!UpdatePartitionMetadata(builder.get(), target_slot, manifest)) { 744 return false; 745 } 746 747 auto target_device = 748 device_dir.Append(GetSuperPartitionName(target_slot)).value(); 749 return StoreMetadata(target_device, builder.get(), target_slot); 750 } 751 752 bool DynamicPartitionControlAndroid::PrepareSnapshotPartitionsForUpdate( 753 uint32_t source_slot, 754 uint32_t target_slot, 755 const DeltaArchiveManifest& manifest, 756 uint64_t* required_size) { 757 TEST_AND_RETURN_FALSE(ExpectMetadataMounted()); 758 if (!snapshot_->BeginUpdate()) { 759 LOG(ERROR) << "Cannot begin new update."; 760 return false; 761 } 762 auto ret = snapshot_->CreateUpdateSnapshots(manifest); 763 if (!ret) { 764 LOG(ERROR) << "Cannot create update snapshots: " << ret.string(); 765 if (required_size != nullptr && 766 ret.error_code() == Return::ErrorCode::NO_SPACE) { 767 *required_size = ret.required_size(); 768 } 769 return false; 770 } 771 return true; 772 } 773 774 std::string DynamicPartitionControlAndroid::GetSuperPartitionName( 775 uint32_t slot) { 776 return fs_mgr_get_super_partition_name(slot); 777 } 778 779 bool DynamicPartitionControlAndroid::UpdatePartitionMetadata( 780 MetadataBuilder* builder, 781 uint32_t target_slot, 782 const DeltaArchiveManifest& manifest) { 783 // If applying downgrade from Virtual A/B to non-Virtual A/B, the left-over 784 // COW group needs to be deleted to ensure there are enough space to create 785 // target partitions. 786 builder->RemoveGroupAndPartitions(android::snapshot::kCowGroupName); 787 788 const std::string target_suffix = SlotSuffixForSlotNumber(target_slot); 789 DeleteGroupsWithSuffix(builder, target_suffix); 790 791 uint64_t total_size = 0; 792 for (const auto& group : manifest.dynamic_partition_metadata().groups()) { 793 total_size += group.size(); 794 } 795 796 std::string expr; 797 uint64_t allocatable_space = builder->AllocatableSpace(); 798 if (!GetDynamicPartitionsFeatureFlag().IsRetrofit()) { 799 allocatable_space /= 2; 800 expr = "half of "; 801 } 802 if (total_size > allocatable_space) { 803 LOG(ERROR) << "The maximum size of all groups with suffix " << target_suffix 804 << " (" << total_size << ") has exceeded " << expr 805 << "allocatable space for dynamic partitions " 806 << allocatable_space << "."; 807 return false; 808 } 809 810 // name of partition(e.g. "system") -> size in bytes 811 std::map<std::string, uint64_t> partition_sizes; 812 for (const auto& partition : manifest.partitions()) { 813 partition_sizes.emplace(partition.partition_name(), 814 partition.new_partition_info().size()); 815 } 816 817 for (const auto& group : manifest.dynamic_partition_metadata().groups()) { 818 auto group_name_suffix = group.name() + target_suffix; 819 if (!builder->AddGroup(group_name_suffix, group.size())) { 820 LOG(ERROR) << "Cannot add group " << group_name_suffix << " with size " 821 << group.size(); 822 return false; 823 } 824 LOG(INFO) << "Added group " << group_name_suffix << " with size " 825 << group.size(); 826 827 for (const auto& partition_name : group.partition_names()) { 828 auto partition_sizes_it = partition_sizes.find(partition_name); 829 if (partition_sizes_it == partition_sizes.end()) { 830 // TODO(tbao): Support auto-filling partition info for framework-only 831 // OTA. 832 LOG(ERROR) << "dynamic_partition_metadata contains partition " 833 << partition_name << " but it is not part of the manifest. " 834 << "This is not supported."; 835 return false; 836 } 837 uint64_t partition_size = partition_sizes_it->second; 838 839 auto partition_name_suffix = partition_name + target_suffix; 840 Partition* p = builder->AddPartition( 841 partition_name_suffix, group_name_suffix, LP_PARTITION_ATTR_READONLY); 842 if (!p) { 843 LOG(ERROR) << "Cannot add partition " << partition_name_suffix 844 << " to group " << group_name_suffix; 845 return false; 846 } 847 if (!builder->ResizePartition(p, partition_size)) { 848 LOG(ERROR) << "Cannot resize partition " << partition_name_suffix 849 << " to size " << partition_size << ". Not enough space?"; 850 return false; 851 } 852 LOG(INFO) << "Added partition " << partition_name_suffix << " to group " 853 << group_name_suffix << " with size " << partition_size; 854 } 855 } 856 857 return true; 858 } 859 860 bool DynamicPartitionControlAndroid::FinishUpdate(bool powerwash_required) { 861 if (ExpectMetadataMounted()) { 862 if (snapshot_->GetUpdateState() == UpdateState::Initiated) { 863 LOG(INFO) << "Snapshot writes are done."; 864 return snapshot_->FinishedSnapshotWrites(powerwash_required); 865 } 866 } else { 867 LOG(INFO) << "Skip FinishedSnapshotWrites() because /metadata is not " 868 << "mounted"; 869 } 870 return true; 871 } 872 873 bool DynamicPartitionControlAndroid::GetPartitionDevice( 874 const std::string& partition_name, 875 uint32_t slot, 876 uint32_t current_slot, 877 std::string* device) { 878 const auto& partition_name_suffix = 879 partition_name + SlotSuffixForSlotNumber(slot); 880 std::string device_dir_str; 881 TEST_AND_RETURN_FALSE(GetDeviceDir(&device_dir_str)); 882 base::FilePath device_dir(device_dir_str); 883 884 // When looking up target partition devices, treat them as static if the 885 // current payload doesn't encode them as dynamic partitions. This may happen 886 // when applying a retrofit update on top of a dynamic-partitions-enabled 887 // build. 888 if (GetDynamicPartitionsFeatureFlag().IsEnabled() && 889 (slot == current_slot || is_target_dynamic_)) { 890 switch (GetDynamicPartitionDevice( 891 device_dir, partition_name_suffix, slot, current_slot, device)) { 892 case DynamicPartitionDeviceStatus::SUCCESS: 893 return true; 894 case DynamicPartitionDeviceStatus::TRY_STATIC: 895 break; 896 case DynamicPartitionDeviceStatus::ERROR: // fallthrough 897 default: 898 return false; 899 } 900 } 901 base::FilePath path = device_dir.Append(partition_name_suffix); 902 if (!DeviceExists(path.value())) { 903 LOG(ERROR) << "Device file " << path.value() << " does not exist."; 904 return false; 905 } 906 907 *device = path.value(); 908 return true; 909 } 910 911 bool DynamicPartitionControlAndroid::IsSuperBlockDevice( 912 const base::FilePath& device_dir, 913 uint32_t current_slot, 914 const std::string& partition_name_suffix) { 915 std::string source_device = 916 device_dir.Append(GetSuperPartitionName(current_slot)).value(); 917 auto source_metadata = LoadMetadataBuilder(source_device, current_slot); 918 return source_metadata->HasBlockDevice(partition_name_suffix); 919 } 920 921 DynamicPartitionControlAndroid::DynamicPartitionDeviceStatus 922 DynamicPartitionControlAndroid::GetDynamicPartitionDevice( 923 const base::FilePath& device_dir, 924 const std::string& partition_name_suffix, 925 uint32_t slot, 926 uint32_t current_slot, 927 std::string* device) { 928 std::string super_device = 929 device_dir.Append(GetSuperPartitionName(slot)).value(); 930 931 auto builder = LoadMetadataBuilder(super_device, slot); 932 if (builder == nullptr) { 933 LOG(ERROR) << "No metadata in slot " 934 << BootControlInterface::SlotName(slot); 935 return DynamicPartitionDeviceStatus::ERROR; 936 } 937 if (builder->FindPartition(partition_name_suffix) == nullptr) { 938 LOG(INFO) << partition_name_suffix 939 << " is not in super partition metadata."; 940 941 if (IsSuperBlockDevice(device_dir, current_slot, partition_name_suffix)) { 942 LOG(ERROR) << "The static partition " << partition_name_suffix 943 << " is a block device for current metadata." 944 << "It cannot be used as a logical partition."; 945 return DynamicPartitionDeviceStatus::ERROR; 946 } 947 948 return DynamicPartitionDeviceStatus::TRY_STATIC; 949 } 950 951 if (slot == current_slot) { 952 if (GetState(partition_name_suffix) != DmDeviceState::ACTIVE) { 953 LOG(WARNING) << partition_name_suffix << " is at current slot but it is " 954 << "not mapped. Now try to map it."; 955 } else { 956 if (GetDmDevicePathByName(partition_name_suffix, device)) { 957 LOG(INFO) << partition_name_suffix 958 << " is mapped on device mapper: " << *device; 959 return DynamicPartitionDeviceStatus::SUCCESS; 960 } 961 LOG(ERROR) << partition_name_suffix << "is mapped but path is unknown."; 962 return DynamicPartitionDeviceStatus::ERROR; 963 } 964 } 965 966 bool force_writable = slot != current_slot; 967 if (MapPartitionOnDeviceMapper( 968 super_device, partition_name_suffix, slot, force_writable, device)) { 969 return DynamicPartitionDeviceStatus::SUCCESS; 970 } 971 return DynamicPartitionDeviceStatus::ERROR; 972 } 973 974 void DynamicPartitionControlAndroid::set_fake_mapped_devices( 975 const std::set<std::string>& fake) { 976 mapped_devices_ = fake; 977 } 978 979 bool DynamicPartitionControlAndroid::IsRecovery() { 980 return kIsRecovery; 981 } 982 983 static bool IsIncrementalUpdate(const DeltaArchiveManifest& manifest) { 984 const auto& partitions = manifest.partitions(); 985 return std::any_of(partitions.begin(), partitions.end(), [](const auto& p) { 986 return p.has_old_partition_info(); 987 }); 988 } 989 990 bool DynamicPartitionControlAndroid::DeleteSourcePartitions( 991 MetadataBuilder* builder, 992 uint32_t source_slot, 993 const DeltaArchiveManifest& manifest) { 994 TEST_AND_RETURN_FALSE(IsRecovery()); 995 996 if (IsIncrementalUpdate(manifest)) { 997 LOG(ERROR) << "Cannot sideload incremental OTA because snapshots cannot " 998 << "be created."; 999 if (GetVirtualAbFeatureFlag().IsLaunch()) { 1000 LOG(ERROR) << "Sideloading incremental updates on devices launches " 1001 << " Virtual A/B is not supported."; 1002 } 1003 return false; 1004 } 1005 1006 LOG(INFO) << "Will overwrite existing partitions. Slot " 1007 << BootControlInterface::SlotName(source_slot) 1008 << "may be unbootable until update finishes!"; 1009 const std::string source_suffix = SlotSuffixForSlotNumber(source_slot); 1010 DeleteGroupsWithSuffix(builder, source_suffix); 1011 1012 return true; 1013 } 1014 1015 std::unique_ptr<AbstractAction> 1016 DynamicPartitionControlAndroid::GetCleanupPreviousUpdateAction( 1017 BootControlInterface* boot_control, 1018 PrefsInterface* prefs, 1019 CleanupPreviousUpdateActionDelegateInterface* delegate) { 1020 if (!GetVirtualAbFeatureFlag().IsEnabled()) { 1021 return std::make_unique<NoOpAction>(); 1022 } 1023 return std::make_unique<CleanupPreviousUpdateAction>( 1024 prefs, boot_control, snapshot_.get(), delegate); 1025 } 1026 1027 bool DynamicPartitionControlAndroid::ResetUpdate(PrefsInterface* prefs) { 1028 if (!GetVirtualAbFeatureFlag().IsEnabled()) { 1029 return true; 1030 } 1031 1032 LOG(INFO) << __func__ << " resetting update state and deleting snapshots."; 1033 TEST_AND_RETURN_FALSE(prefs != nullptr); 1034 1035 // If the device has already booted into the target slot, 1036 // ResetUpdateProgress may pass but CancelUpdate fails. 1037 // This is expected. A scheduled CleanupPreviousUpdateAction should free 1038 // space when it is done. 1039 TEST_AND_RETURN_FALSE(DeltaPerformer::ResetUpdateProgress( 1040 prefs, false /* quick */, false /* skip dynamic partitions metadata */)); 1041 1042 if (ExpectMetadataMounted()) { 1043 TEST_AND_RETURN_FALSE(snapshot_->CancelUpdate()); 1044 } else { 1045 LOG(INFO) << "Skip cancelling update in ResetUpdate because /metadata is " 1046 << "not mounted"; 1047 } 1048 1049 return true; 1050 } 1051 1052 bool DynamicPartitionControlAndroid::ExpectMetadataMounted() { 1053 // No need to mount metadata for non-Virtual A/B devices. 1054 if (!GetVirtualAbFeatureFlag().IsEnabled()) { 1055 return false; 1056 } 1057 // Intentionally not checking |metadata_device_| in Android mode. 1058 // /metadata should always be mounted in Android mode. If it isn't, let caller 1059 // fails when calling into SnapshotManager. 1060 if (!IsRecovery()) { 1061 return true; 1062 } 1063 // In recovery mode, explicitly check |metadata_device_|. 1064 return metadata_device_ != nullptr; 1065 } 1066 1067 bool DynamicPartitionControlAndroid::EnsureMetadataMounted() { 1068 // No need to mount metadata for non-Virtual A/B devices. 1069 if (!GetVirtualAbFeatureFlag().IsEnabled()) { 1070 return true; 1071 } 1072 1073 if (metadata_device_ == nullptr) { 1074 metadata_device_ = snapshot_->EnsureMetadataMounted(); 1075 } 1076 return metadata_device_ != nullptr; 1077 } 1078 1079 } // namespace chromeos_update_engine 1080