From 25eabc44f582b9e854119a05f85b3009f9edadcf Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Sun, 17 Mar 2024 23:45:21 -0700 Subject: [PATCH] libsnapshot: Prepare removal of legacy snapshot During OTA install, when vendor partition is on Android S, add a new flag in SnapshotUpdateStatus file to indicate that we need to support dm-snapshot based snapshot process. This will be used only during post OTA reboot. The primary change here is the OTA install path. Earlier, dm-snapshot based approach was used; with this change, since both "snapuserd" and "update-engine" resides on system partition, OTA installation will use the userspace snapshot approach. To maintain backward compatibility, the new flag "legacy_snapuserd" is used only after OTA reboot. This flag will make sure that update-engine will take the dm-snapshot based approach post reboot and for the entire duration of snapshot-merge. Additionally, during first-stage init if the vendor is on Android S, then "snapuserd" binary will continue to work based off dm-snapshot as none of this change will impact the mount process. Bug: 304829384 Test: OTA on Pixel th - OTA from Android S to TOT with vendor on S Change-Id: Idd9a60b09417cee141b2810e2d4b35e91c845a5c Signed-off-by: Akilesh Kailash --- .../android/snapshot/snapshot.proto | 3 + .../include/libsnapshot/snapshot.h | 4 + fs_mgr/libsnapshot/snapshot.cpp | 76 +++++++++++++++++-- fs_mgr/libsnapshot/utility.cpp | 17 +++-- fs_mgr/libsnapshot/utility.h | 1 + 5 files changed, 88 insertions(+), 13 deletions(-) diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto index f2f7fc1cd..076a918fe 100644 --- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto +++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto @@ -212,6 +212,9 @@ message SnapshotUpdateStatus { // io_uring support bool io_uring_enabled = 10; + + // legacy dm-snapshot based snapuserd + bool legacy_snapuserd = 11; } // Next: 10 diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index d10286312..3ccc3dbf4 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -829,6 +829,9 @@ class SnapshotManager final : public ISnapshotManager { // Set read-ahead size during OTA void SetReadAheadSize(const std::string& entry_block_device, off64_t size_kb); + // Returns true post OTA reboot if legacy snapuserd is required + bool IsLegacySnapuserdPostReboot(); + android::dm::IDeviceMapper& dm_; std::unique_ptr device_; std::string metadata_dir_; @@ -839,6 +842,7 @@ class SnapshotManager final : public ISnapshotManager { std::unique_ptr snapuserd_client_; std::unique_ptr old_partition_metadata_; std::optional is_snapshot_userspace_; + std::optional is_legacy_snapuserd_; }; } // namespace snapshot diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index e6c4de623..b4892b4a1 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -265,7 +265,6 @@ std::string SnapshotManager::ReadUpdateSourceSlotSuffix() { auto boot_file = GetSnapshotBootIndicatorPath(); std::string contents; if (!android::base::ReadFileToString(boot_file, &contents)) { - PLOG(WARNING) << "Cannot read " << boot_file; return {}; } return contents; @@ -2118,6 +2117,53 @@ bool SnapshotManager::UpdateUsesIouring(LockedFile* lock) { return update_status.io_uring_enabled(); } +/* + * Please see b/304829384 for more details. + * + * In Android S, we use dm-snapshot for mounting snapshots and snapshot-merge + * process. If the vendor partition continues to be on Android S, then + * "snapuserd" binary in first stage ramdisk will be from vendor partition. + * Thus, we need to maintain backward compatibility. + * + * Now, We take a two step approach to maintain the backward compatibility: + * + * 1: During OTA installation, we will continue to use "user-space" snapshots + * for OTA installation as both update-engine and snapuserd binary will be from system partition. + * However, during installation, we mark "legacy_snapuserd" in + * SnapshotUpdateStatus file to mark that this is a path to support backward compatibility. + * Thus, this function will return "false" during OTA installation. + * + * 2: Post OTA reboot, there are two key steps: + * a: During first stage init, "init" and "snapuserd" could be from vendor + * partition. This could be from Android S. Thus, the snapshot mount path + * will be based off dm-snapshot. + * + * b: Post selinux transition, "init" and "update-engine" will be "system" + * partition. Now, since the snapshots are mounted off dm-snapshot, + * update-engine interaction with "snapuserd" should work based off + * dm-snapshots. + * + * TL;DR: update-engine will use the "system" snapuserd for installing new + * updates (this is safe as there is no "vendor" snapuserd running during + * installation). Post reboot, update-engine will use the legacy path when + * communicating with "vendor" snapuserd that was started in first-stage + * init. Hence, this function checks: + * i: Are we in post OTA reboot + * ii: Is the Vendor from Android 12 + * iii: If both (i) and (ii) are true, then use the dm-snapshot based + * approach. + * + */ +bool SnapshotManager::IsLegacySnapuserdPostReboot() { + if (is_legacy_snapuserd_.has_value() && is_legacy_snapuserd_.value() == true) { + auto slot = GetCurrentSlot(); + if (slot == Slot::Target) { + return true; + } + } + return false; +} + bool SnapshotManager::UpdateUsesUserSnapshots() { // This and the following function is constantly // invoked during snapshot merge. We want to avoid @@ -2129,7 +2175,12 @@ bool SnapshotManager::UpdateUsesUserSnapshots() { // during merge phase. Hence, once we know that // the value is read from disk the very first time, // it is safe to read successive checks from memory. + if (is_snapshot_userspace_.has_value()) { + // Check if legacy snapuserd is running post OTA reboot + if (IsLegacySnapuserdPostReboot()) { + return false; + } return is_snapshot_userspace_.value(); } @@ -2140,13 +2191,16 @@ bool SnapshotManager::UpdateUsesUserSnapshots() { } bool SnapshotManager::UpdateUsesUserSnapshots(LockedFile* lock) { - // See UpdateUsesUserSnapshots() - if (is_snapshot_userspace_.has_value()) { - return is_snapshot_userspace_.value(); + if (!is_snapshot_userspace_.has_value()) { + SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock); + is_snapshot_userspace_ = update_status.userspace_snapshots(); + is_legacy_snapuserd_ = update_status.legacy_snapuserd(); + } + + if (IsLegacySnapuserdPostReboot()) { + return false; } - SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock); - is_snapshot_userspace_ = update_status.userspace_snapshots(); return is_snapshot_userspace_.value(); } @@ -3210,6 +3264,8 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife // Deduce supported features. bool userspace_snapshots = CanUseUserspaceSnapshots(); bool legacy_compression = GetLegacyCompressionEnabledProperty(); + bool is_legacy_snapuserd = IsVendorFromAndroid12(); + if (!vabc_disable_reason.empty()) { if (userspace_snapshots) { LOG(INFO) << "Userspace snapshots disabled: " << vabc_disable_reason; @@ -3219,6 +3275,7 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife } userspace_snapshots = false; legacy_compression = false; + is_legacy_snapuserd = false; } if (legacy_compression || userspace_snapshots) { @@ -3231,6 +3288,8 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife } } + LOG(INFO) << "userspace snapshots: " << userspace_snapshots + << " legacy_snapuserd: " << legacy_compression; const bool using_snapuserd = userspace_snapshots || legacy_compression; if (!using_snapuserd) { LOG(INFO) << "Using legacy Virtual A/B (dm-snapshot)"; @@ -3328,6 +3387,10 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife status.set_io_uring_enabled(true); LOG(INFO) << "io_uring for snapshots enabled"; } + + if (is_legacy_snapuserd) { + status.set_legacy_snapuserd(true); + } } else if (legacy_compression) { LOG(INFO) << "Virtual A/B using legacy snapuserd"; } else { @@ -3335,6 +3398,7 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife } is_snapshot_userspace_.emplace(userspace_snapshots); + is_legacy_snapuserd_.emplace(is_legacy_snapuserd); if (!device()->IsTestDevice() && using_snapuserd) { // Terminate stale daemon if any diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp index 1ffa89cba..fe2d95c64 100644 --- a/fs_mgr/libsnapshot/utility.cpp +++ b/fs_mgr/libsnapshot/utility.cpp @@ -230,11 +230,7 @@ bool GetUserspaceSnapshotsEnabledProperty() { return fetcher->GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false); } -bool CanUseUserspaceSnapshots() { - if (!GetUserspaceSnapshotsEnabledProperty()) { - return false; - } - +bool IsVendorFromAndroid12() { auto fetcher = IPropertyFetcher::GetInstance(); const std::string UNKNOWN = "unknown"; @@ -243,8 +239,15 @@ bool CanUseUserspaceSnapshots() { // No user-space snapshots if vendor partition is on Android 12 if (vendor_release.find("12") != std::string::npos) { - LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: " - << vendor_release; + return true; + } + + return false; +} + +bool CanUseUserspaceSnapshots() { + if (!GetUserspaceSnapshotsEnabledProperty()) { + LOG(INFO) << "Virtual A/B - Userspace snapshots disabled"; return false; } diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h index 370f3c4fc..f956a0544 100644 --- a/fs_mgr/libsnapshot/utility.h +++ b/fs_mgr/libsnapshot/utility.h @@ -136,6 +136,7 @@ bool GetXorCompressionEnabledProperty(); bool CanUseUserspaceSnapshots(); bool IsDmSnapshotTestingEnabled(); +bool IsVendorFromAndroid12(); // Swap the suffix of a partition name. std::string GetOtherPartitionName(const std::string& name);