Loading fs_mgr/fs_mgr_dm_linear.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -212,6 +212,17 @@ bool CreateLogicalPartition(const CreateLogicalPartitionParams& params, std::str return true; } std::string CreateLogicalPartitionParams::GetDeviceName() const { if (!device_name.empty()) return device_name; return GetPartitionName(); } std::string CreateLogicalPartitionParams::GetPartitionName() const { if (!partition_name.empty()) return partition_name; if (partition) return android::fs_mgr::GetPartitionName(*partition); return "<unknown partition>"; } bool UnmapDevice(const std::string& name) { DeviceMapper& dm = DeviceMapper::Instance(); if (!dm.DeleteDevice(name)) { Loading fs_mgr/include/fs_mgr_dm_linear.h +4 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,10 @@ struct CreateLogicalPartitionParams { // If non-null, this will use the specified IPartitionOpener rather than // the default one. const IPartitionOpener* partition_opener = nullptr; // Helpers for determining the effective partition and device name. std::string GetPartitionName() const; std::string GetDeviceName() const; }; bool CreateLogicalPartition(const CreateLogicalPartitionParams& params, std::string* path); Loading fs_mgr/libsnapshot/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ cc_defaults { ], static_libs: [ "libdm", "libfs_mgr", "liblp", ], whole_static_libs: [ "libext2_uuid", Loading fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +37 −3 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <android-base/unique_fd.h> #include <libdm/dm.h> #include <libfiemap/image_manager.h> #include <liblp/liblp.h> #ifndef FRIEND_TEST #define FRIEND_TEST(test_set_name, individual_test) \ Loading @@ -37,6 +38,11 @@ namespace fiemap { class IImageManager; } // namespace fiemap namespace fs_mgr { struct CreateLogicalPartitionParams; class IPartitionOpener; } // namespace fs_mgr namespace snapshot { enum class UpdateState : unsigned int { Loading Loading @@ -64,6 +70,10 @@ enum class UpdateState : unsigned int { }; class SnapshotManager final { using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams; using LpMetadata = android::fs_mgr::LpMetadata; using IPartitionOpener = android::fs_mgr::IPartitionOpener; public: // Dependency injection for testing. class IDeviceInfo { Loading @@ -72,6 +82,7 @@ class SnapshotManager final { virtual std::string GetGsidDir() const = 0; virtual std::string GetMetadataDir() const = 0; virtual std::string GetSlotSuffix() const = 0; virtual const IPartitionOpener& GetPartitionOpener() const = 0; }; ~SnapshotManager(); Loading @@ -81,6 +92,14 @@ class SnapshotManager final { // instance will be created. static std::unique_ptr<SnapshotManager> New(IDeviceInfo* device = nullptr); // This is similar to New(), except designed specifically for first-stage // init. static std::unique_ptr<SnapshotManager> NewForFirstStageMount(IDeviceInfo* device = nullptr); // Helper function for first-stage init to check whether a SnapshotManager // might be needed to perform first-stage mounts. static bool IsSnapshotManagerNeeded(); // Begin an update. This must be called before creating any snapshots. It // will fail if GetUpdateState() != None. bool BeginUpdate(); Loading Loading @@ -126,13 +145,24 @@ class SnapshotManager final { // Other: 0 UpdateState GetUpdateState(double* progress = nullptr); // If this returns true, first-stage mount must call // CreateLogicalAndSnapshotPartitions rather than CreateLogicalPartitions. bool NeedSnapshotsInFirstStageMount(); // Perform first-stage mapping of snapshot targets. This replaces init's // call to CreateLogicalPartitions when snapshots are present. bool CreateLogicalAndSnapshotPartitions(const std::string& super_device); private: FRIEND_TEST(SnapshotTest, CleanFirstStageMount); FRIEND_TEST(SnapshotTest, CreateSnapshot); FRIEND_TEST(SnapshotTest, MapSnapshot); FRIEND_TEST(SnapshotTest, FirstStageMountAfterRollback); FRIEND_TEST(SnapshotTest, FirstStageMountAndMerge); FRIEND_TEST(SnapshotTest, MapPartialSnapshot); FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot); FRIEND_TEST(SnapshotTest, MapSnapshot); FRIEND_TEST(SnapshotTest, Merge); FRIEND_TEST(SnapshotTest, MergeCannotRemoveCow); FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot); friend class SnapshotTest; using DmTargetSnapshot = android::dm::DmTargetSnapshot; Loading @@ -141,9 +171,12 @@ class SnapshotManager final { explicit SnapshotManager(IDeviceInfo* info); // This is created lazily since it connects via binder. // This is created lazily since it can connect via binder. bool EnsureImageManager(); // Helper for first-stage init. bool ForceLocalImageManager(); // Helper function for tests. IImageManager* image_manager() const { return images_.get(); } Loading Loading @@ -278,6 +311,7 @@ class SnapshotManager final { std::string metadata_dir_; std::unique_ptr<IDeviceInfo> device_; std::unique_ptr<IImageManager> images_; bool has_local_image_manager_ = false; }; } // namespace snapshot Loading fs_mgr/libsnapshot/snapshot.cpp +169 −7 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <sys/unistd.h> #include <thread> #include <unordered_set> #include <android-base/file.h> #include <android-base/logging.h> Loading @@ -27,9 +28,11 @@ #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <ext4_utils/ext4_utils.h> #include <fs_mgr_dm_linear.h> #include <fstab/fstab.h> #include <libdm/dm.h> #include <libfiemap/image_manager.h> #include <liblp/liblp.h> namespace android { namespace snapshot { Loading @@ -43,22 +46,30 @@ using android::dm::DmTargetSnapshot; using android::dm::kSectorSize; using android::dm::SnapshotStorageMode; using android::fiemap::IImageManager; using android::fs_mgr::CreateLogicalPartition; using android::fs_mgr::CreateLogicalPartitionParams; using android::fs_mgr::GetPartitionName; using android::fs_mgr::LpMetadata; using android::fs_mgr::SlotNumberForSlotSuffix; using namespace std::chrono_literals; using namespace std::string_literals; // Unit is sectors, this is a 4K chunk. static constexpr uint32_t kSnapshotChunkSize = 8; static constexpr char kSnapshotBootIndicatorFile[] = "snapshot-boot"; static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot"; class DeviceInfo final : public SnapshotManager::IDeviceInfo { public: std::string GetGsidDir() const override { return "ota"s; } std::string GetMetadataDir() const override { return "/metadata/ota"s; } std::string GetSlotSuffix() const override { return fs_mgr_get_slot_suffix(); } const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const { return opener_; } private: android::fs_mgr::PartitionOpener opener_; }; // Note: IIMageManager is an incomplete type in the header, so the default // Note: IImageManager is an incomplete type in the header, so the default // destructor doesn't work. SnapshotManager::~SnapshotManager() {} Loading @@ -69,6 +80,14 @@ std::unique_ptr<SnapshotManager> SnapshotManager::New(IDeviceInfo* info) { return std::unique_ptr<SnapshotManager>(new SnapshotManager(info)); } std::unique_ptr<SnapshotManager> SnapshotManager::NewForFirstStageMount(IDeviceInfo* info) { auto sm = New(info); if (!sm || !sm->ForceLocalImageManager()) { return nullptr; } return sm; } SnapshotManager::SnapshotManager(IDeviceInfo* device) : device_(device) { gsid_dir_ = device_->GetGsidDir(); metadata_dir_ = device_->GetMetadataDir(); Loading @@ -78,6 +97,10 @@ static std::string GetCowName(const std::string& snapshot_name) { return snapshot_name + "-cow"; } static std::string GetBaseDeviceName(const std::string& partition_name) { return partition_name + "-base"; } bool SnapshotManager::BeginUpdate() { auto file = LockExclusive(); if (!file) return false; Loading Loading @@ -197,8 +220,8 @@ bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name, } // Validate the block device size, as well as the requested snapshot size. // During this we also compute the linear sector region if any. { // Note that during first-stage init, we don't have the device paths. if (android::base::StartsWith(base_device, "/")) { unique_fd fd(open(base_device.c_str(), O_RDONLY | O_CLOEXEC)); if (fd < 0) { PLOG(ERROR) << "open failed: " << base_device; Loading Loading @@ -228,8 +251,17 @@ bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name, auto cow_name = GetCowName(name); bool ok; std::string cow_dev; if (!images_->MapImageDevice(cow_name, timeout_ms, &cow_dev)) { if (has_local_image_manager_) { // If we forced a local image manager, it means we don't have binder, // which means first-stage init. We must use device-mapper. const auto& opener = device_->GetPartitionOpener(); ok = images_->MapImageWithDeviceMapper(opener, cow_name, &cow_dev); } else { ok = images_->MapImageDevice(cow_name, timeout_ms, &cow_dev); } if (!ok) { LOG(ERROR) << "Could not map image device: " << cow_name; return false; } Loading Loading @@ -705,7 +737,7 @@ UpdateState SnapshotManager::CheckTargetMergeState(LockedFile* lock, const std:: } std::string SnapshotManager::GetSnapshotBootIndicatorPath() { return metadata_dir_ + "/" + kSnapshotBootIndicatorFile; return metadata_dir_ + "/" + android::base::Basename(kBootIndicatorPath); } void SnapshotManager::RemoveSnapshotBootIndicator() { Loading Loading @@ -931,6 +963,126 @@ bool SnapshotManager::ListSnapshots(LockedFile* lock, std::vector<std::string>* return true; } bool SnapshotManager::IsSnapshotManagerNeeded() { return access(kBootIndicatorPath, F_OK) == 0; } bool SnapshotManager::NeedSnapshotsInFirstStageMount() { // If we fail to read, we'll wind up using CreateLogicalPartitions, which // will create devices that look like the old slot, except with extra // content at the end of each device. This will confuse dm-verity, and // ultimately we'll fail to boot. Why not make it a fatal error and have // the reason be clearer? Because the indicator file still exists, and // if this was FATAL, reverting to the old slot would be broken. std::string old_slot; auto boot_file = GetSnapshotBootIndicatorPath(); if (!android::base::ReadFileToString(boot_file, &old_slot)) { PLOG(ERROR) << "Unable to read the snapshot indicator file: " << boot_file; return false; } if (device_->GetSlotSuffix() == old_slot) { LOG(INFO) << "Detected slot rollback, will not mount snapshots."; return false; } // If we can't read the update state, it's unlikely anything else will // succeed, so this is a fatal error. We'll eventually exhaust boot // attempts and revert to the old slot. auto lock = LockShared(); if (!lock) { LOG(FATAL) << "Could not read update state to determine snapshot status"; return false; } switch (ReadUpdateState(lock.get())) { case UpdateState::Unverified: case UpdateState::Merging: case UpdateState::MergeFailed: return true; default: return false; } } bool SnapshotManager::CreateLogicalAndSnapshotPartitions(const std::string& super_device) { LOG(INFO) << "Creating logical partitions with snapshots as needed"; auto lock = LockExclusive(); if (!lock) return false; std::vector<std::string> snapshot_list; if (!ListSnapshots(lock.get(), &snapshot_list)) { return false; } std::unordered_set<std::string> live_snapshots; for (const auto& snapshot : snapshot_list) { SnapshotStatus status; if (!ReadSnapshotStatus(lock.get(), snapshot, &status)) { return false; } if (status.state != SnapshotState::MergeCompleted) { live_snapshots.emplace(snapshot); } } const auto& opener = device_->GetPartitionOpener(); uint32_t slot = SlotNumberForSlotSuffix(device_->GetSlotSuffix()); auto metadata = android::fs_mgr::ReadMetadata(opener, super_device, slot); if (!metadata) { LOG(ERROR) << "Could not read dynamic partition metadata for device: " << super_device; return false; } // Map logical partitions. auto& dm = DeviceMapper::Instance(); for (const auto& partition : metadata->partitions) { auto partition_name = GetPartitionName(partition); if (!partition.num_extents) { LOG(INFO) << "Skipping zero-length logical partition: " << partition_name; continue; } CreateLogicalPartitionParams params = { .block_device = super_device, .metadata = metadata.get(), .partition = &partition, .partition_opener = &opener, }; if (auto iter = live_snapshots.find(partition_name); iter != live_snapshots.end()) { // If the device has a snapshot, it'll need to be writable, and // we'll need to create the logical partition with a marked-up name // (since the snapshot will use the partition name). params.force_writable = true; params.device_name = GetBaseDeviceName(partition_name); } std::string ignore_path; if (!CreateLogicalPartition(params, &ignore_path)) { LOG(ERROR) << "Could not create logical partition " << partition_name << " as device " << params.GetDeviceName(); return false; } if (!params.force_writable) { // No snapshot. continue; } // We don't have ueventd in first-stage init, so use device major:minor // strings instead. std::string base_device; if (!dm.GetDeviceString(params.GetDeviceName(), &base_device)) { LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName(); return false; } if (!MapSnapshot(lock.get(), partition_name, base_device, {}, &ignore_path)) { LOG(ERROR) << "Could not map snapshot for partition: " << partition_name; return false; } } return true; } auto SnapshotManager::OpenFile(const std::string& file, int open_flags, int lock_flags) -> std::unique_ptr<LockedFile> { unique_fd fd(open(file.c_str(), open_flags | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0660)); Loading Loading @@ -1173,5 +1325,15 @@ bool SnapshotManager::EnsureImageManager() { return true; } bool SnapshotManager::ForceLocalImageManager() { images_ = android::fiemap::ImageManager::Open(gsid_dir_); if (!images_) { LOG(ERROR) << "Could not open ImageManager"; return false; } has_local_image_manager_ = true; return true; } } // namespace snapshot } // namespace android Loading
fs_mgr/fs_mgr_dm_linear.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -212,6 +212,17 @@ bool CreateLogicalPartition(const CreateLogicalPartitionParams& params, std::str return true; } std::string CreateLogicalPartitionParams::GetDeviceName() const { if (!device_name.empty()) return device_name; return GetPartitionName(); } std::string CreateLogicalPartitionParams::GetPartitionName() const { if (!partition_name.empty()) return partition_name; if (partition) return android::fs_mgr::GetPartitionName(*partition); return "<unknown partition>"; } bool UnmapDevice(const std::string& name) { DeviceMapper& dm = DeviceMapper::Instance(); if (!dm.DeleteDevice(name)) { Loading
fs_mgr/include/fs_mgr_dm_linear.h +4 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,10 @@ struct CreateLogicalPartitionParams { // If non-null, this will use the specified IPartitionOpener rather than // the default one. const IPartitionOpener* partition_opener = nullptr; // Helpers for determining the effective partition and device name. std::string GetPartitionName() const; std::string GetDeviceName() const; }; bool CreateLogicalPartition(const CreateLogicalPartitionParams& params, std::string* path); Loading
fs_mgr/libsnapshot/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ cc_defaults { ], static_libs: [ "libdm", "libfs_mgr", "liblp", ], whole_static_libs: [ "libext2_uuid", Loading
fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +37 −3 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <android-base/unique_fd.h> #include <libdm/dm.h> #include <libfiemap/image_manager.h> #include <liblp/liblp.h> #ifndef FRIEND_TEST #define FRIEND_TEST(test_set_name, individual_test) \ Loading @@ -37,6 +38,11 @@ namespace fiemap { class IImageManager; } // namespace fiemap namespace fs_mgr { struct CreateLogicalPartitionParams; class IPartitionOpener; } // namespace fs_mgr namespace snapshot { enum class UpdateState : unsigned int { Loading Loading @@ -64,6 +70,10 @@ enum class UpdateState : unsigned int { }; class SnapshotManager final { using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams; using LpMetadata = android::fs_mgr::LpMetadata; using IPartitionOpener = android::fs_mgr::IPartitionOpener; public: // Dependency injection for testing. class IDeviceInfo { Loading @@ -72,6 +82,7 @@ class SnapshotManager final { virtual std::string GetGsidDir() const = 0; virtual std::string GetMetadataDir() const = 0; virtual std::string GetSlotSuffix() const = 0; virtual const IPartitionOpener& GetPartitionOpener() const = 0; }; ~SnapshotManager(); Loading @@ -81,6 +92,14 @@ class SnapshotManager final { // instance will be created. static std::unique_ptr<SnapshotManager> New(IDeviceInfo* device = nullptr); // This is similar to New(), except designed specifically for first-stage // init. static std::unique_ptr<SnapshotManager> NewForFirstStageMount(IDeviceInfo* device = nullptr); // Helper function for first-stage init to check whether a SnapshotManager // might be needed to perform first-stage mounts. static bool IsSnapshotManagerNeeded(); // Begin an update. This must be called before creating any snapshots. It // will fail if GetUpdateState() != None. bool BeginUpdate(); Loading Loading @@ -126,13 +145,24 @@ class SnapshotManager final { // Other: 0 UpdateState GetUpdateState(double* progress = nullptr); // If this returns true, first-stage mount must call // CreateLogicalAndSnapshotPartitions rather than CreateLogicalPartitions. bool NeedSnapshotsInFirstStageMount(); // Perform first-stage mapping of snapshot targets. This replaces init's // call to CreateLogicalPartitions when snapshots are present. bool CreateLogicalAndSnapshotPartitions(const std::string& super_device); private: FRIEND_TEST(SnapshotTest, CleanFirstStageMount); FRIEND_TEST(SnapshotTest, CreateSnapshot); FRIEND_TEST(SnapshotTest, MapSnapshot); FRIEND_TEST(SnapshotTest, FirstStageMountAfterRollback); FRIEND_TEST(SnapshotTest, FirstStageMountAndMerge); FRIEND_TEST(SnapshotTest, MapPartialSnapshot); FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot); FRIEND_TEST(SnapshotTest, MapSnapshot); FRIEND_TEST(SnapshotTest, Merge); FRIEND_TEST(SnapshotTest, MergeCannotRemoveCow); FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot); friend class SnapshotTest; using DmTargetSnapshot = android::dm::DmTargetSnapshot; Loading @@ -141,9 +171,12 @@ class SnapshotManager final { explicit SnapshotManager(IDeviceInfo* info); // This is created lazily since it connects via binder. // This is created lazily since it can connect via binder. bool EnsureImageManager(); // Helper for first-stage init. bool ForceLocalImageManager(); // Helper function for tests. IImageManager* image_manager() const { return images_.get(); } Loading Loading @@ -278,6 +311,7 @@ class SnapshotManager final { std::string metadata_dir_; std::unique_ptr<IDeviceInfo> device_; std::unique_ptr<IImageManager> images_; bool has_local_image_manager_ = false; }; } // namespace snapshot Loading
fs_mgr/libsnapshot/snapshot.cpp +169 −7 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <sys/unistd.h> #include <thread> #include <unordered_set> #include <android-base/file.h> #include <android-base/logging.h> Loading @@ -27,9 +28,11 @@ #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <ext4_utils/ext4_utils.h> #include <fs_mgr_dm_linear.h> #include <fstab/fstab.h> #include <libdm/dm.h> #include <libfiemap/image_manager.h> #include <liblp/liblp.h> namespace android { namespace snapshot { Loading @@ -43,22 +46,30 @@ using android::dm::DmTargetSnapshot; using android::dm::kSectorSize; using android::dm::SnapshotStorageMode; using android::fiemap::IImageManager; using android::fs_mgr::CreateLogicalPartition; using android::fs_mgr::CreateLogicalPartitionParams; using android::fs_mgr::GetPartitionName; using android::fs_mgr::LpMetadata; using android::fs_mgr::SlotNumberForSlotSuffix; using namespace std::chrono_literals; using namespace std::string_literals; // Unit is sectors, this is a 4K chunk. static constexpr uint32_t kSnapshotChunkSize = 8; static constexpr char kSnapshotBootIndicatorFile[] = "snapshot-boot"; static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot"; class DeviceInfo final : public SnapshotManager::IDeviceInfo { public: std::string GetGsidDir() const override { return "ota"s; } std::string GetMetadataDir() const override { return "/metadata/ota"s; } std::string GetSlotSuffix() const override { return fs_mgr_get_slot_suffix(); } const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const { return opener_; } private: android::fs_mgr::PartitionOpener opener_; }; // Note: IIMageManager is an incomplete type in the header, so the default // Note: IImageManager is an incomplete type in the header, so the default // destructor doesn't work. SnapshotManager::~SnapshotManager() {} Loading @@ -69,6 +80,14 @@ std::unique_ptr<SnapshotManager> SnapshotManager::New(IDeviceInfo* info) { return std::unique_ptr<SnapshotManager>(new SnapshotManager(info)); } std::unique_ptr<SnapshotManager> SnapshotManager::NewForFirstStageMount(IDeviceInfo* info) { auto sm = New(info); if (!sm || !sm->ForceLocalImageManager()) { return nullptr; } return sm; } SnapshotManager::SnapshotManager(IDeviceInfo* device) : device_(device) { gsid_dir_ = device_->GetGsidDir(); metadata_dir_ = device_->GetMetadataDir(); Loading @@ -78,6 +97,10 @@ static std::string GetCowName(const std::string& snapshot_name) { return snapshot_name + "-cow"; } static std::string GetBaseDeviceName(const std::string& partition_name) { return partition_name + "-base"; } bool SnapshotManager::BeginUpdate() { auto file = LockExclusive(); if (!file) return false; Loading Loading @@ -197,8 +220,8 @@ bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name, } // Validate the block device size, as well as the requested snapshot size. // During this we also compute the linear sector region if any. { // Note that during first-stage init, we don't have the device paths. if (android::base::StartsWith(base_device, "/")) { unique_fd fd(open(base_device.c_str(), O_RDONLY | O_CLOEXEC)); if (fd < 0) { PLOG(ERROR) << "open failed: " << base_device; Loading Loading @@ -228,8 +251,17 @@ bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name, auto cow_name = GetCowName(name); bool ok; std::string cow_dev; if (!images_->MapImageDevice(cow_name, timeout_ms, &cow_dev)) { if (has_local_image_manager_) { // If we forced a local image manager, it means we don't have binder, // which means first-stage init. We must use device-mapper. const auto& opener = device_->GetPartitionOpener(); ok = images_->MapImageWithDeviceMapper(opener, cow_name, &cow_dev); } else { ok = images_->MapImageDevice(cow_name, timeout_ms, &cow_dev); } if (!ok) { LOG(ERROR) << "Could not map image device: " << cow_name; return false; } Loading Loading @@ -705,7 +737,7 @@ UpdateState SnapshotManager::CheckTargetMergeState(LockedFile* lock, const std:: } std::string SnapshotManager::GetSnapshotBootIndicatorPath() { return metadata_dir_ + "/" + kSnapshotBootIndicatorFile; return metadata_dir_ + "/" + android::base::Basename(kBootIndicatorPath); } void SnapshotManager::RemoveSnapshotBootIndicator() { Loading Loading @@ -931,6 +963,126 @@ bool SnapshotManager::ListSnapshots(LockedFile* lock, std::vector<std::string>* return true; } bool SnapshotManager::IsSnapshotManagerNeeded() { return access(kBootIndicatorPath, F_OK) == 0; } bool SnapshotManager::NeedSnapshotsInFirstStageMount() { // If we fail to read, we'll wind up using CreateLogicalPartitions, which // will create devices that look like the old slot, except with extra // content at the end of each device. This will confuse dm-verity, and // ultimately we'll fail to boot. Why not make it a fatal error and have // the reason be clearer? Because the indicator file still exists, and // if this was FATAL, reverting to the old slot would be broken. std::string old_slot; auto boot_file = GetSnapshotBootIndicatorPath(); if (!android::base::ReadFileToString(boot_file, &old_slot)) { PLOG(ERROR) << "Unable to read the snapshot indicator file: " << boot_file; return false; } if (device_->GetSlotSuffix() == old_slot) { LOG(INFO) << "Detected slot rollback, will not mount snapshots."; return false; } // If we can't read the update state, it's unlikely anything else will // succeed, so this is a fatal error. We'll eventually exhaust boot // attempts and revert to the old slot. auto lock = LockShared(); if (!lock) { LOG(FATAL) << "Could not read update state to determine snapshot status"; return false; } switch (ReadUpdateState(lock.get())) { case UpdateState::Unverified: case UpdateState::Merging: case UpdateState::MergeFailed: return true; default: return false; } } bool SnapshotManager::CreateLogicalAndSnapshotPartitions(const std::string& super_device) { LOG(INFO) << "Creating logical partitions with snapshots as needed"; auto lock = LockExclusive(); if (!lock) return false; std::vector<std::string> snapshot_list; if (!ListSnapshots(lock.get(), &snapshot_list)) { return false; } std::unordered_set<std::string> live_snapshots; for (const auto& snapshot : snapshot_list) { SnapshotStatus status; if (!ReadSnapshotStatus(lock.get(), snapshot, &status)) { return false; } if (status.state != SnapshotState::MergeCompleted) { live_snapshots.emplace(snapshot); } } const auto& opener = device_->GetPartitionOpener(); uint32_t slot = SlotNumberForSlotSuffix(device_->GetSlotSuffix()); auto metadata = android::fs_mgr::ReadMetadata(opener, super_device, slot); if (!metadata) { LOG(ERROR) << "Could not read dynamic partition metadata for device: " << super_device; return false; } // Map logical partitions. auto& dm = DeviceMapper::Instance(); for (const auto& partition : metadata->partitions) { auto partition_name = GetPartitionName(partition); if (!partition.num_extents) { LOG(INFO) << "Skipping zero-length logical partition: " << partition_name; continue; } CreateLogicalPartitionParams params = { .block_device = super_device, .metadata = metadata.get(), .partition = &partition, .partition_opener = &opener, }; if (auto iter = live_snapshots.find(partition_name); iter != live_snapshots.end()) { // If the device has a snapshot, it'll need to be writable, and // we'll need to create the logical partition with a marked-up name // (since the snapshot will use the partition name). params.force_writable = true; params.device_name = GetBaseDeviceName(partition_name); } std::string ignore_path; if (!CreateLogicalPartition(params, &ignore_path)) { LOG(ERROR) << "Could not create logical partition " << partition_name << " as device " << params.GetDeviceName(); return false; } if (!params.force_writable) { // No snapshot. continue; } // We don't have ueventd in first-stage init, so use device major:minor // strings instead. std::string base_device; if (!dm.GetDeviceString(params.GetDeviceName(), &base_device)) { LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName(); return false; } if (!MapSnapshot(lock.get(), partition_name, base_device, {}, &ignore_path)) { LOG(ERROR) << "Could not map snapshot for partition: " << partition_name; return false; } } return true; } auto SnapshotManager::OpenFile(const std::string& file, int open_flags, int lock_flags) -> std::unique_ptr<LockedFile> { unique_fd fd(open(file.c_str(), open_flags | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0660)); Loading Loading @@ -1173,5 +1325,15 @@ bool SnapshotManager::EnsureImageManager() { return true; } bool SnapshotManager::ForceLocalImageManager() { images_ = android::fiemap::ImageManager::Open(gsid_dir_); if (!images_) { LOG(ERROR) << "Could not open ImageManager"; return false; } has_local_image_manager_ = true; return true; } } // namespace snapshot } // namespace android