Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c85af559 authored by David Anderson's avatar David Anderson
Browse files

libsnapshot: Simplify wipe handling in recovery.

This refactors HandleImminentDataWipe to address some shortcomings
discovered through testing. Previously, it always called
CreateSnapshotsAndLogicalPartitions, which meant trying to use snapuserd
even if completely unnecessary.

Instead we now peek at the update state and eliminate the "easy" cases
ahead of time. These are "none", "initiated", and "unverified" when
either a rollback happens or there is no forward merge indicator. In
this case we simply return early and allow the wipe to continue
(disabling the current slot if necessary).

The hard case, when a merge is needed, is still handled within
ProcessUpdateStateOnDataWipe. However it's no longer recursive, and it
can assume a merge is about to initiated or already in progress.

In all cases except a merge failure, we change the update state to None
to clear any roadblocks update_engine or the bootloader might encounter.
A merge failure, however, still blocks a data wipe. The way to recover
from this is adb sideload.

Bug: 350613336
Test: vts_libsnapshot_test
      wipe in INITIATED state, no merge
      wipe in UNVERIFIED state, no merge
      wipe in UNVERIFIED + rollback state, no merge
      wipe in MERGING state, merge
Change-Id: I387aabcfa6304118be88ddbb85842111d5c2ef6a
parent 9da55b8c
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -104,6 +104,24 @@ bool DeviceInfo::IsFirstStageInit() const {
    return first_stage_init_;
}

bool DeviceInfo::SetActiveBootSlot([[maybe_unused]] unsigned int slot) {
#ifdef LIBSNAPSHOT_USE_HAL
    if (!EnsureBootHal()) {
        return false;
    }

    CommandResult result = boot_control_->SetActiveBootSlot(slot);
    if (!result.success) {
        LOG(ERROR) << "Error setting slot " << slot << " active: " << result.errMsg;
        return false;
    }
    return true;
#else
    LOG(ERROR) << "HAL support not enabled.";
    return false;
#endif
}

bool DeviceInfo::SetSlotAsUnbootable([[maybe_unused]] unsigned int slot) {
#ifdef LIBSNAPSHOT_USE_HAL
    if (!EnsureBootHal()) {
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ class DeviceInfo final : public SnapshotManager::IDeviceInfo {
    std::string GetSuperDevice(uint32_t slot) const override;
    bool IsOverlayfsSetup() const override;
    bool SetBootControlMergeStatus(MergeStatus status) override;
    bool SetActiveBootSlot(unsigned int slot) override;
    bool SetSlotAsUnbootable(unsigned int slot) override;
    bool IsRecovery() const override;
    std::unique_ptr<IImageManager> OpenImageManager() const override;
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ class MockDeviceInfo : public SnapshotManager::IDeviceInfo {
    MOCK_METHOD(const android::fs_mgr::IPartitionOpener&, GetPartitionOpener, (), (const));
    MOCK_METHOD(bool, IsOverlayfsSetup, (), (const, override));
    MOCK_METHOD(bool, SetBootControlMergeStatus, (MergeStatus status), (override));
    MOCK_METHOD(bool, SetActiveBootSlot, (unsigned int slot), (override));
    MOCK_METHOD(bool, SetSlotAsUnbootable, (unsigned int slot), (override));
    MOCK_METHOD(bool, IsRecovery, (), (const, override));
    MOCK_METHOD(bool, IsFirstStageInit, (), (const, override));
+5 −6
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ class ISnapshotManager {
        virtual const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const = 0;
        virtual bool IsOverlayfsSetup() const = 0;
        virtual bool SetBootControlMergeStatus(MergeStatus status) = 0;
        virtual bool SetActiveBootSlot(unsigned int slot) = 0;
        virtual bool SetSlotAsUnbootable(unsigned int slot) = 0;
        virtual bool IsRecovery() const = 0;
        virtual bool IsTestDevice() const { return false; }
@@ -675,6 +676,8 @@ class SnapshotManager final : public ISnapshotManager {
    std::string GetBootSnapshotsWithoutSlotSwitchPath();
    std::string GetSnapuserdFromSystemPath();

    bool HasForwardMergeIndicator();

    const LpMetadata* ReadOldPartitionMetadata(LockedFile* lock);

    bool MapAllPartitions(LockedFile* lock, const std::string& super_device, uint32_t slot,
@@ -785,11 +788,8 @@ class SnapshotManager final : public ISnapshotManager {
    bool UpdateForwardMergeIndicator(bool wipe);

    // Helper for HandleImminentDataWipe.
    // Call ProcessUpdateState and handle states with special rules before data wipe. Specifically,
    // if |allow_forward_merge| and allow-forward-merge indicator exists, initiate merge if
    // necessary.
    UpdateState ProcessUpdateStateOnDataWipe(bool allow_forward_merge,
                                             const std::function<bool()>& callback);
    // Call ProcessUpdateState and handle states with special rules before data wipe.
    UpdateState ProcessUpdateStateOnDataWipe(const std::function<bool()>& callback);

    // Return device string of a mapped image, or if it is not available, the mapped image path.
    bool GetMappedImageDeviceStringOrPath(const std::string& device_name,
@@ -848,7 +848,6 @@ class SnapshotManager final : public ISnapshotManager {
    std::string metadata_dir_;
    std::unique_ptr<IImageManager> images_;
    bool use_first_stage_snapuserd_ = false;
    bool in_factory_data_reset_ = false;
    std::function<bool(const std::string&)> uevent_regen_callback_;
    std::unique_ptr<SnapuserdClient> snapuserd_client_;
    std::unique_ptr<LpMetadata> old_partition_metadata_;
+1 −0
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
    }
    bool IsOverlayfsSetup() const override { return false; }
    bool IsRecovery() const override { return recovery_; }
    bool SetActiveBootSlot([[maybe_unused]] unsigned int slot) override { return true; }
    bool SetSlotAsUnbootable(unsigned int slot) override {
        unbootable_slots_.insert(slot);
        return true;
Loading