summaryrefslogtreecommitdiff
path: root/fastboot/device/commands.cpp
diff options
context:
space:
mode:
authorDavid Anderson <dvander@google.com>2019-11-19 00:49:44 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2019-11-19 00:49:44 +0000
commitbf55a76fd9ce15b288d8cfa5425fb889bd069d51 (patch)
treee0d004d0184c2839c9f7b7bb65a5a7d09e9c322d /fastboot/device/commands.cpp
parent7d16aedc47552bbb67563ef6754a77c88b5821ea (diff)
parent220ddb1f0fb9d0e47f7c812c93da174ea3a8c037 (diff)
Merge "fastbootd: Disallow certain operations during snapshot updates."
Diffstat (limited to 'fastboot/device/commands.cpp')
-rw-r--r--fastboot/device/commands.cpp102
1 files changed, 87 insertions, 15 deletions
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index a2c95d636..1a745ab46 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -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");
}
+ if (args[1] == "cancel") {
+ switch (status) {
+ case MergeStatus::SNAPSHOTTED:
+ case MergeStatus::MERGING:
+ 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");
+ }
- MergeStatus status = hal11->getSnapshotMergeStatus();
- switch (status) {
- case MergeStatus::SNAPSHOTTED:
- case MergeStatus::MERGING:
- hal11->setSnapshotMergeStatus(MergeStatus::CANCELLED);
- break;
- default:
- break;
+ 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");
}