Skip to content

Commit

Permalink
fastbootd: Add commands for logical partitions.
Browse files Browse the repository at this point in the history
This patch adds the following new commands to fastbootd:

    getvar is_logical:<partition>
    create-logical-logical-partition <partition> <size>
    delete-logical-partition <partition>
    resize-logicallogical-partition <partition> <size>

All of these commands operate on logical partitions only, and require a
properly configured "super" partition to operate.

Bug: 78793464
Test: fastboot create-logical-partition example 4096
      fastboot create-logical-partition example 4096 returns error
      fastboot getvar is-logical:example returns "yes"
      fastboot getvar partition-size:example returns "1000"
      fastboot resize-logicalpartition example 8000
      fastboot getvar partition-size:example returns "2000"
      fastboot delete-logical-partition example
      fastboot getvar is-logical:example returns error
      fastboot getvar is-logical:system_a returns "no"

Change-Id: Iff323eabcf5c559fa04c7c92574650b01803eb1f
  • Loading branch information
dvandercorp committed Aug 9, 2018
1 parent 3cf9f9b commit 0d4277d
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 1 deletion.
1 change: 1 addition & 0 deletions fastboot/Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ cc_binary {
"libbase",
"libbootloader_message",
"libcutils",
"libext2_uuid",
"libext4_utils",
"libfs_mgr",
"libhidlbase",
Expand Down
4 changes: 4 additions & 0 deletions fastboot/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
#define FB_CMD_REBOOT_RECOVERY "reboot-recovery"
#define FB_CMD_REBOOT_FASTBOOT "reboot-fastboot"
#define FB_CMD_POWERDOWN "powerdown"
#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 RESPONSE_OKAY "OKAY"
#define RESPONSE_FAIL "FAIL"
Expand All @@ -53,3 +56,4 @@
#define FB_VAR_PARTITION_SIZE "partition-size"
#define FB_VAR_SLOT_SUCCESSFUL "slot-successful"
#define FB_VAR_SLOT_UNBOOTABLE "slot-unbootable"
#define FB_VAR_IS_LOGICAL "is-logical"
128 changes: 127 additions & 1 deletion fastboot/device/commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
#include <android-base/unique_fd.h>
#include <cutils/android_reboot.h>
#include <ext4_utils/wipe.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
#include <uuid/uuid.h>

#include "constants.h"
#include "fastboot_device.h"
Expand All @@ -37,6 +40,7 @@ using ::android::hardware::hidl_string;
using ::android::hardware::boot::V1_0::BoolResult;
using ::android::hardware::boot::V1_0::CommandResult;
using ::android::hardware::boot::V1_0::Slot;
using namespace android::fs_mgr;

bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args) {
using VariableHandler = std::function<bool(FastbootDevice*, const std::vector<std::string>&)>;
Expand All @@ -54,7 +58,8 @@ bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args)
{FB_VAR_HAS_SLOT, GetHasSlot},
{FB_VAR_SLOT_SUCCESSFUL, GetSlotSuccessful},
{FB_VAR_SLOT_UNBOOTABLE, GetSlotUnbootable},
{FB_VAR_PARTITION_SIZE, GetPartitionSize}};
{FB_VAR_PARTITION_SIZE, GetPartitionSize},
{FB_VAR_IS_LOGICAL, GetPartitionIsLogical}};

// args[0] is command name, args[1] is variable.
auto found_variable = kVariableMap.find(args[1]);
Expand Down Expand Up @@ -209,3 +214,124 @@ bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string
TEMP_FAILURE_RETRY(pause());
return status;
}

// Helper class for opening a handle to a MetadataBuilder and writing the new
// partition table to the same place it was read.
class PartitionBuilder {
public:
explicit PartitionBuilder(FastbootDevice* device);

bool Write();
bool Valid() const { return !!builder_; }
MetadataBuilder* operator->() const { return builder_.get(); }

private:
std::string super_device_;
uint32_t slot_number_;
std::unique_ptr<MetadataBuilder> builder_;
};

PartitionBuilder::PartitionBuilder(FastbootDevice* device) {
auto super_device = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
if (!super_device) {
return;
}
super_device_ = *super_device;

std::string slot = device->GetCurrentSlot();
slot_number_ = SlotNumberForSlotSuffix(slot);
builder_ = MetadataBuilder::New(super_device_, slot_number_);
}

bool PartitionBuilder::Write() {
std::unique_ptr<LpMetadata> metadata = builder_->Export();
if (!metadata) {
return false;
}
return UpdatePartitionTable(super_device_, *metadata.get(), slot_number_);
}

bool CreatePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
if (args.size() < 3) {
return device->WriteFail("Invalid partition name and size");
}

uint64_t partition_size;
std::string partition_name = args[1];
if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
return device->WriteFail("Invalid partition size");
}

PartitionBuilder builder(device);
if (!builder.Valid()) {
return device->WriteFail("Could not open super partition");
}
// TODO(112433293) Disallow if the name is in the physical table as well.
if (builder->FindPartition(partition_name)) {
return device->WriteFail("Partition already exists");
}

// Make a random UUID, since they're not currently used.
uuid_t uuid;
char uuid_str[37];
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);

Partition* partition = builder->AddPartition(partition_name, uuid_str, 0);
if (!partition) {
return device->WriteFail("Failed to add partition");
}
if (!builder->ResizePartition(partition, partition_size)) {
builder->RemovePartition(partition_name);
return device->WriteFail("Not enough space for partition");
}
if (!builder.Write()) {
return device->WriteFail("Failed to write partition table");
}
return device->WriteOkay("Partition created");
}

bool DeletePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
if (args.size() < 2) {
return device->WriteFail("Invalid partition name and size");
}

PartitionBuilder builder(device);
if (!builder.Valid()) {
return device->WriteFail("Could not open super partition");
}
builder->RemovePartition(args[1]);
if (!builder.Write()) {
return device->WriteFail("Failed to write partition table");
}
return device->WriteOkay("Partition deleted");
}

bool ResizePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
if (args.size() < 3) {
return device->WriteFail("Invalid partition name and size");
}

uint64_t partition_size;
std::string partition_name = args[1];
if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
return device->WriteFail("Invalid partition size");
}

PartitionBuilder builder(device);
if (!builder.Valid()) {
return device->WriteFail("Could not open super partition");
}

Partition* partition = builder->FindPartition(partition_name);
if (!partition) {
return device->WriteFail("Partition does not exist");
}
if (!builder->ResizePartition(partition, partition_size)) {
return device->WriteFail("Not enough space to resize partition");
}
if (!builder.Write()) {
return device->WriteFail("Failed to write partition table");
}
return device->WriteOkay("Partition resized");
}
3 changes: 3 additions & 0 deletions fastboot/device/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@ bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string
bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args);
bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args);
bool FlashHandler(FastbootDevice* device, const std::vector<std::string>& args);
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);
3 changes: 3 additions & 0 deletions fastboot/device/fastboot_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ FastbootDevice::FastbootDevice()
{FB_CMD_REBOOT_RECOVERY, RebootRecoveryHandler},
{FB_CMD_ERASE, EraseHandler},
{FB_CMD_FLASH, FlashHandler},
{FB_CMD_CREATE_PARTITION, CreatePartitionHandler},
{FB_CMD_DELETE_PARTITION, DeletePartitionHandler},
{FB_CMD_RESIZE_PARTITION, ResizePartitionHandler},
}),
transport_(std::make_unique<ClientUsbTransport>()),
boot_control_hal_(IBootControl::getService()) {}
Expand Down
17 changes: 17 additions & 0 deletions fastboot/device/variables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,20 @@ bool GetPartitionSize(FastbootDevice* device, const std::vector<std::string>& ar
uint64_t size = get_block_device_size(handle.fd());
return device->WriteOkay(android::base::StringPrintf("%" PRIX64, size));
}

bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string>& args) {
if (args.size() < 1) {
return device->WriteFail("Missing argument");
}
// Note: if a partition name is in both the GPT and the super partition, we
// return "true", to be consistent with prefering to flash logical partitions
// over physical ones.
std::string partition_name = args[0];
if (LogicalPartitionExists(partition_name, device->GetCurrentSlot())) {
return device->WriteOkay("yes");
}
if (FindPhysicalPartition(partition_name)) {
return device->WriteOkay("no");
}
return device->WriteFail("Partition not found");
}
1 change: 1 addition & 0 deletions fastboot/device/variables.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ bool GetMaxDownloadSize(FastbootDevice* device, const std::vector<std::string>&
bool GetUnlocked(FastbootDevice* device, const std::vector<std::string>& args);
bool GetHasSlot(FastbootDevice* device, const std::vector<std::string>& args);
bool GetPartitionSize(FastbootDevice* device, const std::vector<std::string>& args);
bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string>& args);
15 changes: 15 additions & 0 deletions fastboot/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,21 @@ void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s,
total);
}

void fb_queue_create_partition(const std::string& partition, const std::string& size) {
Action& a = queue_action(OP_COMMAND, FB_CMD_CREATE_PARTITION ":" + partition + ":" + size);
a.msg = "Creating '" + partition + "'";
}

void fb_queue_delete_partition(const std::string& partition) {
Action& a = queue_action(OP_COMMAND, FB_CMD_DELETE_PARTITION ":" + partition);
a.msg = "Deleting '" + partition + "'";
}

void fb_queue_resize_partition(const std::string& partition, const std::string& size) {
Action& a = queue_action(OP_COMMAND, FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size);
a.msg = "Resizing '" + partition + "'";
}

static int match(const char* str, const char** value, unsigned count) {
unsigned n;

Expand Down
3 changes: 3 additions & 0 deletions fastboot/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ void fb_queue_download_fd(const std::string& name, int fd, uint32_t sz);
void fb_queue_upload(const std::string& outfile);
void fb_queue_notice(const std::string& notice);
void fb_queue_wait_for_disconnect(void);
void fb_queue_create_partition(const std::string& partition, const std::string& size);
void fb_queue_delete_partition(const std::string& partition);
void fb_queue_resize_partition(const std::string& partition, const std::string& size);
int64_t fb_execute_queue();
void fb_set_active(const std::string& slot);

Expand Down
11 changes: 11 additions & 0 deletions fastboot/fastboot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1691,6 +1691,17 @@ int FastBootTool::Main(int argc, char* argv[]) {
} else {
syntax_error("unknown 'flashing' command %s", args[0].c_str());
}
} else if (command == "create-logical-partition") {
std::string partition = next_arg(&args);
std::string size = next_arg(&args);
fb_queue_create_partition(partition, size);
} else if (command == "delete-logical-partition") {
std::string partition = next_arg(&args);
fb_queue_delete_partition(partition);
} else if (command == "resize-logical-partition") {
std::string partition = next_arg(&args);
std::string size = next_arg(&args);
fb_queue_resize_partition(partition, size);
} else {
syntax_error("unknown command %s", command.c_str());
}
Expand Down

0 comments on commit 0d4277d

Please sign in to comment.