diff options
Diffstat (limited to 'fastboot/fastboot.cpp')
-rw-r--r-- | fastboot/fastboot.cpp | 94 |
1 files changed, 82 insertions, 12 deletions
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index db6d5d657..20c33591d 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -104,9 +104,10 @@ struct fastboot_buffer { void* data; int64_t sz; int fd; + int64_t image_size; }; -static struct { +struct Image { const char* nickname; const char* img_name; const char* sig_name; @@ -114,7 +115,9 @@ static struct { bool optional_if_no_image; bool optional_if_no_partition; bool IsSecondary() const { return nickname == nullptr; } -} images[] = { +}; + +static Image images[] = { // clang-format off { "boot", "boot.img", "boot.sig", "boot", false, false }, { nullptr, "boot_other.img", "boot.sig", "boot", true, false }, @@ -128,7 +131,6 @@ static struct { "product_services", true, true }, { "recovery", "recovery.img", "recovery.sig", "recovery", true, false }, - { "super", "super.img", "super.sig", "super", true, true }, { "system", "system.img", "system.sig", "system", false, true }, { nullptr, "system_other.img", "system.sig", "system", true, false }, { "vbmeta", "vbmeta.img", "vbmeta.sig", "vbmeta", true, false }, @@ -773,6 +775,13 @@ static bool load_buf_fd(int fd, struct fastboot_buffer* buf) { return false; } + if (sparse_file* s = sparse_file_import_auto(fd, false, false)) { + buf->image_size = sparse_file_len(s, false, false); + sparse_file_destroy(s); + } else { + buf->image_size = sz; + } + lseek64(fd, 0, SEEK_SET); int64_t limit = get_sparse_limit(sz); if (limit) { @@ -1044,6 +1053,11 @@ static void set_active(const std::string& slot_override) { } } +static bool is_userspace_fastboot() { + std::string value; + return fb_getvar("is-userspace", &value) && value == "yes"; +} + static bool if_partition_exists(const std::string& partition, const std::string& slot) { std::string has_slot; std::string partition_name = partition; @@ -1158,7 +1172,42 @@ static void do_send_signature(const std::string& fn) { fb_queue_command("signature", "installing signature"); } -static void do_flashall(const std::string& slot_override, bool skip_secondary) { +static bool is_logical(const std::string& partition) { + std::string value; + return fb_getvar("is-logical:" + partition, &value) && value == "yes"; +} + +static void update_super_partition(bool force_wipe) { + if (!if_partition_exists("super", "")) { + return; + } + std::string image = find_item_given_name("super_empty.img"); + if (access(image.c_str(), R_OK) < 0) { + return; + } + + if (!is_userspace_fastboot()) { + die("Must have userspace fastboot to flash logical partitions"); + } + + int fd = open(image.c_str(), O_RDONLY); + if (fd < 0) { + die("could not open '%s': %s", image.c_str(), strerror(errno)); + } + fb_queue_download_fd("super", fd, get_file_size(fd)); + + std::string command = "update-super:super"; + if (force_wipe) { + command += ":wipe"; + } + fb_queue_command(command, "Updating super partition"); + + // We need these commands to have finished before proceeding, since + // otherwise "getvar is-logical" may not return a correct answer below. + fb_execute_queue(); +} + +static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) { std::string fname; queue_info_dump(); @@ -1188,6 +1237,10 @@ static void do_flashall(const std::string& slot_override, bool skip_secondary) { } } + update_super_partition(wipe); + + // List of partitions to flash and their slots. + std::vector<std::pair<const Image*, std::string>> entries; for (size_t i = 0; i < arraysize(images); i++) { const char* slot = NULL; if (images[i].IsSecondary()) { @@ -1196,21 +1249,38 @@ static void do_flashall(const std::string& slot_override, bool skip_secondary) { slot = slot_override.c_str(); } if (!slot) continue; - fname = find_item_given_name(images[i].img_name); + entries.emplace_back(&images[i], slot); + + // Resize any logical partition to 0, so each partition is reset to 0 + // extents, and will achieve more optimal allocation. + auto resize_partition = [](const std::string& partition) -> void { + if (is_logical(partition)) { + fb_queue_resize_partition(partition, "0"); + } + }; + do_for_partitions(images[i].part_name, slot, resize_partition, false); + } + + // Flash each partition in the list if it has a corresponding image. + for (const auto& [image, slot] : entries) { + fname = find_item_given_name(image->img_name); fastboot_buffer buf; if (!load_buf(fname.c_str(), &buf)) { - if (images[i].optional_if_no_image) continue; - die("could not load '%s': %s", images[i].img_name, strerror(errno)); + if (image->optional_if_no_image) continue; + die("could not load '%s': %s", image->img_name, strerror(errno)); } - if (images[i].optional_if_no_partition && - !if_partition_exists(images[i].part_name, slot)) { + if (image->optional_if_no_partition && + !if_partition_exists(image->part_name, slot)) { continue; } auto flashall = [&](const std::string &partition) { do_send_signature(fname.c_str()); + if (is_logical(partition)) { + fb_queue_resize_partition(partition, std::to_string(buf.image_size)); + } flash_buf(partition.c_str(), &buf); }; - do_for_partitions(images[i].part_name, slot, flashall, false); + do_for_partitions(image->part_name, slot, flashall, false); } if (slot_override == "all") { @@ -1648,9 +1718,9 @@ int FastBootTool::Main(int argc, char* argv[]) { } else if (command == "flashall") { if (slot_override == "all") { fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n"); - do_flashall(slot_override, true); + do_flashall(slot_override, true, wants_wipe); } else { - do_flashall(slot_override, skip_secondary); + do_flashall(slot_override, skip_secondary, wants_wipe); } wants_reboot = true; } else if (command == "update") { |