Merge "fastbootd: Add an update-super command to sync the super partition."
diff --git a/fastboot/README.md b/fastboot/README.md
index ec7dcb4..15b5965 100644
--- a/fastboot/README.md
+++ b/fastboot/README.md
@@ -186,10 +186,45 @@
bootloader requiring a signature before
it will install or boot images.
+ is-userspace If the value is "yes", the device is running
+ fastbootd. Otherwise, it is running fastboot
+ in the bootloader.
+
Names starting with a lowercase character are reserved by this
specification. OEM-specific names should not start with lowercase
characters.
+## Logical Partitions
+
+There are a number of commands to interact with logical partitions:
+
+ update-super:%s:%s Write the previously downloaded image to a super
+ partition. Unlike the "flash" command, this has
+ special rules. The image must have been created by
+ the lpmake command, and must not be a sparse image.
+ If the last argument is "wipe", then all existing
+ logical partitions are deleted. If no final argument
+ is specified, the partition tables are merged. Any
+ partition in the new image that does not exist in the
+ old image is created with a zero size.
+
+ In all cases, this will cause the temporary "scratch"
+ partition to be deleted if it exists.
+
+ create-logical-partition:%s:%d
+ Create a logical partition with the given name and
+ size, in the super partition.
+
+ delete-logical-partition:%s
+ Delete a logical partition with the given name.
+
+ resize-logical-partition:%s:%d
+ Change the size of the named logical partition.
+
+In addition, there is a variable to test whether a partition is logical:
+
+ is-logical:%s If the value is "yes", the partition is logical.
+ Otherwise the partition is physical.
## TCP Protocol v1
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 43daab0..6542b83 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -33,6 +33,7 @@
#define FB_CMD_CREATE_PARTITION "create-logical-partition"
#define FB_CMD_DELETE_PARTITION "delete-logical-partition"
#define FB_CMD_RESIZE_PARTITION "resize-logical-partition"
+#define FB_CMD_UPDATE_SUPER "update-super"
#define RESPONSE_OKAY "OKAY"
#define RESPONSE_FAIL "FAIL"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 690bfa8..1e853bf 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -336,3 +336,11 @@
}
return device->WriteOkay("Partition resized");
}
+
+bool UpdateSuperHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 2) {
+ return device->WriteFail("Invalid arguments");
+ }
+ bool wipe = (args.size() >= 3 && args[2] == "wipe");
+ return UpdateSuper(device, args[1], wipe);
+}
diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h
index f67df91..4778d23 100644
--- a/fastboot/device/commands.h
+++ b/fastboot/device/commands.h
@@ -44,3 +44,4 @@
bool CreatePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args);
bool DeletePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args);
bool ResizePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool UpdateSuperHandler(FastbootDevice* device, const std::vector<std::string>& args);
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index c306e67..6ed6d32 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -46,6 +46,7 @@
{FB_CMD_CREATE_PARTITION, CreatePartitionHandler},
{FB_CMD_DELETE_PARTITION, DeletePartitionHandler},
{FB_CMD_RESIZE_PARTITION, ResizePartitionHandler},
+ {FB_CMD_UPDATE_SUPER, UpdateSuperHandler},
}),
transport_(std::make_unique<ClientUsbTransport>()),
boot_control_hal_(IBootControl::getService()) {}
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index b5ed170..e3efbcb 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -25,6 +25,8 @@
#include <android-base/logging.h>
#include <android-base/strings.h>
#include <ext4_utils/ext4_utils.h>
+#include <liblp/builder.h>
+#include <liblp/liblp.h>
#include <sparse/sparse.h>
#include "fastboot_device.h"
@@ -36,6 +38,8 @@
} // namespace
+using namespace android::fs_mgr;
+
int FlashRawDataChunk(int fd, const char* data, size_t len) {
size_t ret = 0;
while (ret < len) {
@@ -99,3 +103,74 @@
}
return FlashBlockDevice(handle.fd(), data);
}
+
+bool UpdateSuper(FastbootDevice* device, const std::string& partition_name, bool wipe) {
+ std::optional<std::string> super = FindPhysicalPartition(partition_name);
+ if (!super) {
+ return device->WriteFail("Could not find partition: " + partition_name);
+ }
+
+ std::vector<char> data = std::move(device->download_data());
+ if (data.empty()) {
+ return device->WriteFail("No data available");
+ }
+
+ std::unique_ptr<LpMetadata> new_metadata = ReadFromImageBlob(data.data(), data.size());
+ if (!new_metadata) {
+ return device->WriteFail("Data is not a valid logical partition metadata image");
+ }
+
+ // If we are unable to read the existing metadata, then the super partition
+ // is corrupt. In this case we reflash the whole thing using the provided
+ // image.
+ std::string slot_suffix = device->GetCurrentSlot();
+ uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
+ std::unique_ptr<LpMetadata> metadata = ReadMetadata(super->c_str(), slot_number);
+ if (!metadata || wipe) {
+ if (!FlashPartitionTable(super.value(), *new_metadata.get())) {
+ return device->WriteFail("Unable to flash new partition table");
+ }
+ return device->WriteOkay("Successfully flashed partition table");
+ }
+
+ // There's a working super partition, and we don't want to wipe it - it may
+ // may contain partitions created for the user. Instead, we create a zero-
+ // sized partition for each entry in the new partition table. It is then
+ // the host's responsibility to size it correctly via resize-logical-partition.
+ std::unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(*metadata.get());
+ if (!builder) {
+ return device->WriteFail("Unable to create a metadata builder");
+ }
+ for (const auto& partition : new_metadata->partitions) {
+ std::string name = GetPartitionName(partition);
+ if (builder->FindPartition(name)) {
+ continue;
+ }
+ std::string guid = GetPartitionGuid(partition);
+ if (!builder->AddPartition(name, guid, partition.attributes)) {
+ return device->WriteFail("Unable to add partition: " + name);
+ }
+ }
+
+ // The scratch partition may exist as temporary storage, created for
+ // use by adb remount for overlayfs. If we're performing a flashall
+ // operation then we want to start over with a clean slate, so we
+ // remove the scratch partition until it is requested again.
+ builder->RemovePartition("scratch");
+
+ new_metadata = builder->Export();
+ if (!new_metadata) {
+ return device->WriteFail("Unable to export new partition table");
+ }
+
+ // Write the new table to every metadata slot.
+ bool ok = true;
+ for (size_t i = 0; i < new_metadata->geometry.metadata_slot_count; i++) {
+ ok &= UpdatePartitionTable(super.value(), *new_metadata.get(), i);
+ }
+
+ if (!ok) {
+ return device->WriteFail("Unable to write new partition table");
+ }
+ return device->WriteOkay("Successfully updated partition table");
+}
diff --git a/fastboot/device/flashing.h b/fastboot/device/flashing.h
index 206a407..89e20fc 100644
--- a/fastboot/device/flashing.h
+++ b/fastboot/device/flashing.h
@@ -22,3 +22,4 @@
class FastbootDevice;
int Flash(FastbootDevice* device, const std::string& partition_name);
+bool UpdateSuper(FastbootDevice* device, const std::string& partition_name, bool wipe);