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

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

libsnapshot: Add a helper for handling data wipes in recovery.

This patch also fixes a bug where the Initiated state resulted in
a SNAPSHOTTED state, despite not relevant to recovery or the
bootloader. SNAPSHOTTED implies the current slot will run off a
snapshot.

Bug: 139156011
Test: manual test
Change-Id: I30dbb0e79906550f08d4cd71194b1361fd5315c0
parent 50e102c5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ filegroup {
    name: "libsnapshot_sources",
    srcs: [
        "android/snapshot/snapshot.proto",
        "device_info.cpp",
        "snapshot.cpp",
        "snapshot_metadata_updater.cpp",
        "partition_cow_creator.cpp",
+123 −0
Original line number Diff line number Diff line
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "device_info.h"

#include <android-base/logging.h>
#include <fs_mgr.h>
#include <fs_mgr_overlayfs.h>

namespace android {
namespace snapshot {

#ifdef LIBSNAPSHOT_USE_HAL
using android::hardware::boot::V1_0::CommandResult;
#endif

using namespace std::string_literals;

#ifdef __ANDROID_RECOVERY__
constexpr bool kIsRecovery = true;
#else
constexpr bool kIsRecovery = false;
#endif

std::string DeviceInfo::GetGsidDir() const {
    return "ota"s;
}

std::string DeviceInfo::GetMetadataDir() const {
    return "/metadata/ota"s;
}

std::string DeviceInfo::GetSlotSuffix() const {
    return fs_mgr_get_slot_suffix();
}

std::string DeviceInfo::GetOtherSlotSuffix() const {
    return fs_mgr_get_other_slot_suffix();
}

const android::fs_mgr::IPartitionOpener& DeviceInfo::GetPartitionOpener() const {
    return opener_;
}

std::string DeviceInfo::GetSuperDevice(uint32_t slot) const {
    return fs_mgr_get_super_partition_name(slot);
}

bool DeviceInfo::IsOverlayfsSetup() const {
    return fs_mgr_overlayfs_is_setup();
}

#ifdef LIBSNAPSHOT_USE_HAL
bool DeviceInfo::EnsureBootHal() {
    if (!boot_control_) {
        auto hal = android::hardware::boot::V1_0::IBootControl::getService();
        if (!hal) {
            LOG(ERROR) << "Could not find IBootControl HAL";
            return false;
        }
        boot_control_ = android::hardware::boot::V1_1::IBootControl::castFrom(hal);
        if (!boot_control_) {
            LOG(ERROR) << "Could not find IBootControl 1.1 HAL";
            return false;
        }
    }
    return true;
}
#endif

bool DeviceInfo::SetBootControlMergeStatus([[maybe_unused]] MergeStatus status) {
#ifdef LIBSNAPSHOT_USE_HAL
    if (!EnsureBootHal()) {
        return false;
    }
    if (!boot_control_->setSnapshotMergeStatus(status)) {
        LOG(ERROR) << "Unable to set the snapshot merge status";
        return false;
    }
    return true;
#else
    LOG(ERROR) << "HAL support not enabled.";
    return false;
#endif
}

bool DeviceInfo::IsRecovery() const {
    return kIsRecovery;
}

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

    CommandResult result = {};
    auto cb = [&](CommandResult r) -> void { result = r; };
    boot_control_->setSlotAsUnbootable(slot, cb);
    if (!result.success) {
        LOG(ERROR) << "Error setting slot " << slot << " unbootable: " << result.errMsg;
        return false;
    }
    return true;
#else
    LOG(ERROR) << "HAL support not enabled.";
    return false;
#endif
}

}  // namespace snapshot
}  // namespace android
+53 −0
Original line number Diff line number Diff line
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <string>

#ifdef LIBSNAPSHOT_USE_HAL
#include <android/hardware/boot/1.1/IBootControl.h>
#endif
#include <liblp/partition_opener.h>
#include <libsnapshot/snapshot.h>

namespace android {
namespace snapshot {

class DeviceInfo final : public SnapshotManager::IDeviceInfo {
    using MergeStatus = android::hardware::boot::V1_1::MergeStatus;

  public:
    std::string GetGsidDir() const override;
    std::string GetMetadataDir() const override;
    std::string GetSlotSuffix() const override;
    std::string GetOtherSlotSuffix() const override;
    const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const override;
    std::string GetSuperDevice(uint32_t slot) const override;
    bool IsOverlayfsSetup() const override;
    bool SetBootControlMergeStatus(MergeStatus status) override;
    bool SetSlotAsUnbootable(unsigned int slot) override;
    bool IsRecovery() const override;

  private:
    bool EnsureBootHal();

    android::fs_mgr::PartitionOpener opener_;
#ifdef LIBSNAPSHOT_USE_HAL
    android::sp<android::hardware::boot::V1_1::IBootControl> boot_control_;
#endif
};

}  // namespace snapshot
}  // namespace android
+2 −0
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ struct AutoDevice {
    virtual ~AutoDevice(){};
    void Release();

    bool HasDevice() const { return !name_.empty(); }

  protected:
    AutoDevice(const std::string& name) : name_(name) {}
    std::string name_;
+26 −3
Original line number Diff line number Diff line
@@ -122,6 +122,7 @@ class SnapshotManager final {
        virtual const IPartitionOpener& GetPartitionOpener() const = 0;
        virtual bool IsOverlayfsSetup() const = 0;
        virtual bool SetBootControlMergeStatus(MergeStatus status) = 0;
        virtual bool SetSlotAsUnbootable(unsigned int slot) = 0;
        virtual bool IsRecovery() const = 0;
    };

@@ -133,7 +134,7 @@ class SnapshotManager final {
    static std::unique_ptr<SnapshotManager> New(IDeviceInfo* device = nullptr);

    // This is similar to New(), except designed specifically for first-stage
    // init.
    // init or recovery.
    static std::unique_ptr<SnapshotManager> NewForFirstStageMount(IDeviceInfo* device = nullptr);

    // Helper function for first-stage init to check whether a SnapshotManager
@@ -180,7 +181,10 @@ class SnapshotManager final {
    //
    //   MergeCompleted indicates that the update has fully completed.
    //   GetUpdateState will return None, and a new update can begin.
    UpdateState ProcessUpdateState();
    //
    // The optional callback allows the caller to periodically check the
    // progress with GetUpdateState().
    UpdateState ProcessUpdateState(const std::function<void()>& callback = {});

  public:
    // Initiate the merge if necessary, then wait for the merge to finish.
@@ -219,6 +223,18 @@ class SnapshotManager final {
    // call to CreateLogicalPartitions when snapshots are present.
    bool CreateLogicalAndSnapshotPartitions(const std::string& super_device);

    // This method should be called preceding any wipe or flash of metadata or
    // userdata. It is only valid in recovery.
    //
    // When userdata will be wiped or flashed, it is necessary to clean up any
    // snapshot state. If a merge is in progress, the merge must be finished.
    // If a snapshot is present but not yet merged, the slot must be marked as
    // unbootable.
    //
    // Returns true on success (or nothing to do), false on failure. The
    // optional callback fires periodically to query progress via GetUpdateState.
    bool HandleImminentDataWipe(const std::function<void()>& callback = {});

    // Dump debug information.
    bool Dump(std::ostream& os);

@@ -231,7 +247,7 @@ class SnapshotManager final {
    // is not found in fstab.
    // Note: if this function is called the second time before the AutoDevice returned from the
    // first call is destroyed, the device will be unmounted when any of these AutoDevices is
    // destroyed. FOr example:
    // destroyed. For example:
    //   auto a = mgr->EnsureMetadataMounted(); // mounts
    //   auto b = mgr->EnsureMetadataMounted(); // does nothing
    //   b.reset() // unmounts
@@ -250,7 +266,10 @@ class SnapshotManager final {
    FRIEND_TEST(SnapshotTest, Merge);
    FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot);
    FRIEND_TEST(SnapshotTest, UpdateBootControlHal);
    FRIEND_TEST(SnapshotUpdateTest, DataWipeAfterRollback);
    FRIEND_TEST(SnapshotUpdateTest, DataWipeRollbackInRecovery);
    FRIEND_TEST(SnapshotUpdateTest, MergeCannotRemoveCow);
    FRIEND_TEST(SnapshotUpdateTest, MergeInRecovery);
    FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow);
    friend class SnapshotTest;
    friend class SnapshotUpdateTest;
@@ -464,6 +483,10 @@ class SnapshotManager final {
            const LpMetadata* exported_target_metadata, const std::string& target_suffix,
            const std::map<std::string, SnapshotStatus>& all_snapshot_status);

    // Unmap all partitions that were mapped by CreateLogicalAndSnapshotPartitions.
    // This should only be called in recovery.
    bool UnmapAllPartitions();

    std::string gsid_dir_;
    std::string metadata_dir_;
    std::unique_ptr<IDeviceInfo> device_;
Loading