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

Commit bf55a76f authored by David Anderson's avatar David Anderson Committed by Gerrit Code Review
Browse files

Merge "fastbootd: Disallow certain operations during snapshot updates."

parents 7d16aedc 220ddb1f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -137,12 +137,14 @@ cc_binary {
        "libhidlbase",
        "liblog",
        "liblp",
        "libprotobuf-cpp-lite",
        "libsparse",
        "libutils",
    ],

    static_libs: [
        "libhealthhalutils",
        "libsnapshot_nobinder",
    ],

    header_libs: [
+87 −15
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
#include <sys/socket.h>
#include <sys/un.h>

#include <unordered_set>

#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
@@ -33,6 +35,7 @@
#include <libgsi/libgsi.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
#include <libsnapshot/snapshot.h>
#include <uuid/uuid.h>

#include "constants.h"
@@ -48,6 +51,7 @@ using ::android::hardware::boot::V1_0::Slot;
using ::android::hardware::boot::V1_1::MergeStatus;
using ::android::hardware::fastboot::V1_0::Result;
using ::android::hardware::fastboot::V1_0::Status;
using android::snapshot::SnapshotManager;
using IBootControl1_1 = ::android::hardware::boot::V1_1::IBootControl;

struct VariableHandlers {
@@ -57,6 +61,24 @@ struct VariableHandlers {
    std::function<std::vector<std::vector<std::string>>(FastbootDevice*)> get_all_args;
};

static bool IsSnapshotUpdateInProgress(FastbootDevice* device) {
    auto hal = device->boot1_1();
    if (!hal) {
        return false;
    }
    auto merge_status = hal->getSnapshotMergeStatus();
    return merge_status == MergeStatus::SNAPSHOTTED || merge_status == MergeStatus::MERGING;
}

static bool IsProtectedPartitionDuringMerge(FastbootDevice* device, const std::string& name) {
    static const std::unordered_set<std::string> ProtectedPartitionsDuringMerge = {
            "userdata", "metadata", "misc"};
    if (ProtectedPartitionsDuringMerge.count(name) == 0) {
        return false;
    }
    return IsSnapshotUpdateInProgress(device);
}

static void GetAllVars(FastbootDevice* device, const std::string& name,
                       const VariableHandlers& handlers) {
    if (!handlers.get_all_args) {
@@ -143,8 +165,14 @@ bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args)
        return device->WriteStatus(FastbootResult::FAIL, "Erase is not allowed on locked devices");
    }

    const auto& partition_name = args[1];
    if (IsProtectedPartitionDuringMerge(device, partition_name)) {
        auto message = "Cannot erase " + partition_name + " while a snapshot update is in progress";
        return device->WriteFail(message);
    }

    PartitionHandle handle;
    if (!OpenPartition(device, args[1], &handle)) {
    if (!OpenPartition(device, partition_name, &handle)) {
        return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
    }
    if (wipe_block_device(handle.fd(), get_block_device_size(handle.fd())) == 0) {
@@ -209,9 +237,9 @@ bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& ar
                                   "set_active command is not allowed on locked devices");
    }

    // Slot suffix needs to be between 'a' and 'z'.
    Slot slot;
    if (!GetSlotNumber(args[1], &slot)) {
        // Slot suffix needs to be between 'a' and 'z'.
        return device->WriteStatus(FastbootResult::FAIL, "Bad slot suffix");
    }

@@ -224,6 +252,32 @@ bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& ar
    if (slot >= boot_control_hal->getNumberSlots()) {
        return device->WriteStatus(FastbootResult::FAIL, "Slot out of range");
    }

    // If the slot is not changing, do nothing.
    if (slot == boot_control_hal->getCurrentSlot()) {
        return device->WriteOkay("");
    }

    // Check how to handle the current snapshot state.
    if (auto hal11 = device->boot1_1()) {
        auto merge_status = hal11->getSnapshotMergeStatus();
        if (merge_status == MergeStatus::MERGING) {
            return device->WriteFail("Cannot change slots while a snapshot update is in progress");
        }
        // Note: we allow the slot change if the state is SNAPSHOTTED. First-
        // stage init does not have access to the HAL, and uses the slot number
        // and /metadata OTA state to determine whether a slot change occurred.
        // Booting into the old slot would erase the OTA, and switching A->B->A
        // would simply resume it if no boots occur in between. Re-flashing
        // partitions implicitly cancels the OTA, so leaving the state as-is is
        // safe.
        if (merge_status == MergeStatus::SNAPSHOTTED) {
            device->WriteInfo(
                    "Changing the active slot with a snapshot applied may cancel the"
                    " update.");
        }
    }

    CommandResult ret;
    auto cb = [&ret](CommandResult result) { ret = result; };
    auto result = boot_control_hal->setActiveBootSlot(slot, cb);
@@ -467,6 +521,11 @@ bool FlashHandler(FastbootDevice* device, const std::vector<std::string>& args)
    }

    const auto& partition_name = args[1];
    if (IsProtectedPartitionDuringMerge(device, partition_name)) {
        auto message = "Cannot flash " + partition_name + " while a snapshot update is in progress";
        return device->WriteFail(message);
    }

    if (LogicalPartitionExists(device, partition_name)) {
        CancelPartitionSnapshot(device, partition_name);
    }
@@ -556,12 +615,9 @@ bool GsiHandler(FastbootDevice* device, const std::vector<std::string>& args) {
bool SnapshotUpdateHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    // Note that we use the HAL rather than mounting /metadata, since we want
    // our results to match the bootloader.
    auto hal = device->boot_control_hal();
    auto hal = device->boot1_1();
    if (!hal) return device->WriteFail("Not supported");

    android::sp<IBootControl1_1> hal11 = IBootControl1_1::castFrom(hal);
    if (!hal11) return device->WriteFail("Not supported");

    // If no arguments, return the same thing as a getvar. Note that we get the
    // HAL first so we can return "not supported" before we return the less
    // specific error message below.
@@ -574,18 +630,34 @@ bool SnapshotUpdateHandler(FastbootDevice* device, const std::vector<std::string
        return device->WriteOkay("");
    }

    if (args.size() != 2 || args[1] != "cancel") {
    MergeStatus status = hal->getSnapshotMergeStatus();

    if (args.size() != 2) {
        return device->WriteFail("Invalid arguments");
    }

    MergeStatus status = hal11->getSnapshotMergeStatus();
    if (args[1] == "cancel") {
        switch (status) {
            case MergeStatus::SNAPSHOTTED:
            case MergeStatus::MERGING:
            hal11->setSnapshotMergeStatus(MergeStatus::CANCELLED);
                hal->setSnapshotMergeStatus(MergeStatus::CANCELLED);
                break;
            default:
                break;
        }
    } else if (args[1] == "merge") {
        if (status != MergeStatus::MERGING) {
            return device->WriteFail("No snapshot merge is in progress");
        }

        auto sm = SnapshotManager::NewForFirstStageMount();
        if (!sm) {
            return device->WriteFail("Unable to create SnapshotManager");
        }
        if (!sm->HandleImminentDataWipe()) {
            return device->WriteFail("Unable to finish snapshot merge");
        }
    } else {
        return device->WriteFail("Invalid parameter to snapshot-update");
    }
    return device->WriteStatus(FastbootResult::OKAY, "Success");
}
+5 −1
Original line number Diff line number Diff line
@@ -60,7 +60,11 @@ FastbootDevice::FastbootDevice()
      boot_control_hal_(IBootControl::getService()),
      health_hal_(get_health_service()),
      fastboot_hal_(IFastboot::getService()),
      active_slot_("") {}
      active_slot_("") {
    if (boot_control_hal_) {
        boot1_1_ = android::hardware::boot::V1_1::IBootControl::castFrom(boot_control_hal_);
    }
}

FastbootDevice::~FastbootDevice() {
    CloseDevice();
+3 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <vector>

#include <android/hardware/boot/1.0/IBootControl.h>
#include <android/hardware/boot/1.1/IBootControl.h>
#include <android/hardware/fastboot/1.0/IFastboot.h>
#include <android/hardware/health/2.0/IHealth.h>

@@ -51,6 +52,7 @@ class FastbootDevice {
    android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal() {
        return boot_control_hal_;
    }
    android::sp<android::hardware::boot::V1_1::IBootControl> boot1_1() { return boot1_1_; }
    android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal() {
        return fastboot_hal_;
    }
@@ -63,6 +65,7 @@ class FastbootDevice {

    std::unique_ptr<Transport> transport_;
    android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal_;
    android::sp<android::hardware::boot::V1_1::IBootControl> boot1_1_;
    android::sp<android::hardware::health::V2_0::IHealth> health_hal_;
    android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal_;
    std::vector<char> download_data_;
+2 −8
Original line number Diff line number Diff line
@@ -432,19 +432,13 @@ bool GetSnapshotUpdateStatus(FastbootDevice* device, const std::vector<std::stri
                             std::string* message) {
    // Note that we use the HAL rather than mounting /metadata, since we want
    // our results to match the bootloader.
    auto hal = device->boot_control_hal();
    auto hal = device->boot1_1();
    if (!hal) {
        *message = "not supported";
        return false;
    }

    android::sp<IBootControl1_1> hal11 = IBootControl1_1::castFrom(hal);
    if (!hal11) {
        *message = "not supported";
        return false;
    }

    MergeStatus status = hal11->getSnapshotMergeStatus();
    MergeStatus status = hal->getSnapshotMergeStatus();
    switch (status) {
        case MergeStatus::SNAPSHOTTED:
            *message = "snapshotted";
Loading