Loading fastboot/fastboot.cpp +186 −176 Original line number Diff line number Diff line Loading @@ -574,6 +574,7 @@ static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) { ZipEntry zip_entry; if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) { fprintf(stderr, "archive does not contain '%s'\n", entry_name); errno = ENOENT; return -1; } Loading Loading @@ -1033,14 +1034,6 @@ static void do_flash(const char* pname, const char* fname) { flash_buf(pname, &buf); } static void do_update_signature(ZipArchiveHandle zip, const char* filename) { int64_t sz; void* data = unzip_to_memory(zip, filename, &sz); if (data == nullptr) return; fb_queue_download("signature", data, sz); fb_queue_command("signature", "installing signature"); } // Sets slot_override as the active slot. If slot_override is blank, // set current slot as active instead. This clears slot-unbootable. static void set_active(const std::string& slot_override) { Loading Loading @@ -1080,133 +1073,182 @@ static bool if_partition_exists(const std::string& partition, const std::string& return fb_getvar("partition-size:" + partition_name, &partition_size); } static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) { queue_info_dump(); static bool is_logical(const std::string& partition) { std::string value; return fb_getvar("is-logical:" + partition, &value) && value == "yes"; } fb_queue_query_save("product", cur_product, sizeof(cur_product)); static void reboot_to_userspace_fastboot() { if (!fb_reboot_to_userspace()) { die("Must reboot to userspace fastboot to flash logical partitions"); } ZipArchiveHandle zip; int error = OpenArchive(filename, &zip); if (error != 0) { die("failed to open zip file '%s': %s", filename, ErrorCodeString(error)); // Give the current connection time to close. std::this_thread::sleep_for(std::chrono::milliseconds(1000)); fb_reinit(open_device()); } class ImageSource { public: virtual void* ReadFile(const std::string& name, int64_t* size) const = 0; virtual int OpenFile(const std::string& name) const = 0; }; class FlashAllTool { public: FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe); void Flash(); private: void CheckRequirements(); void DetermineSecondarySlot(); void CollectImages(); void FlashImages(const std::vector<std::pair<const Image*, std::string>>& images); void FlashImage(const Image& image, const std::string& slot, fastboot_buffer* buf); void UpdateSuperPartition(); const ImageSource& source_; std::string slot_override_; bool skip_secondary_; bool wipe_; std::string secondary_slot_; std::vector<std::pair<const Image*, std::string>> boot_images_; std::vector<std::pair<const Image*, std::string>> os_images_; }; FlashAllTool::FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe) : source_(source), slot_override_(slot_override), skip_secondary_(skip_secondary), wipe_(wipe) { } void FlashAllTool::Flash() { CheckRequirements(); DetermineSecondarySlot(); CollectImages(); // First flash boot partitions. We allow this to happen either in userspace // or in bootloader fastboot. FlashImages(boot_images_); // Sync the super partition. This will reboot to userspace fastboot if needed. UpdateSuperPartition(); // Resize any logical partition to 0, so each partition is reset to 0 // extents, and will achieve more optimal allocation. for (const auto& [image, slot] : os_images_) { auto resize_partition = [](const std::string& partition) -> void { if (is_logical(partition)) { fb_queue_resize_partition(partition, "0"); } }; do_for_partitions(image->part_name, slot, resize_partition, false); } // Flash OS images, resizing logical partitions as needed. FlashImages(os_images_); if (slot_override_ == "all") { set_active("a"); } else { set_active(slot_override_); } } void FlashAllTool::CheckRequirements() { int64_t sz; void* data = unzip_to_memory(zip, "android-info.txt", &sz); void* data = source_.ReadFile("android-info.txt", &sz); if (data == nullptr) { die("update package '%s' has no android-info.txt", filename); die("could not read android-info.txt"); } check_requirements(reinterpret_cast<char*>(data), sz); } std::string secondary; if (!skip_secondary) { if (slot_override != "") { secondary = get_other_slot(slot_override); void FlashAllTool::DetermineSecondarySlot() { if (skip_secondary_) { return; } if (slot_override_ != "") { secondary_slot_ = get_other_slot(slot_override_); } else { secondary = get_other_slot(); secondary_slot_ = get_other_slot(); } if (secondary == "") { if (secondary_slot_ == "") { if (supports_AB()) { fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n"); } skip_secondary = true; skip_secondary_ = true; } } void FlashAllTool::CollectImages() { for (size_t i = 0; i < arraysize(images); ++i) { const char* slot = slot_override.c_str(); std::string slot = slot_override_; if (images[i].IsSecondary()) { if (!skip_secondary) { slot = secondary.c_str(); } else { if (skip_secondary_) { continue; } slot = secondary_slot_; } if (images[i].type == ImageType::BootCritical) { boot_images_.emplace_back(&images[i], slot); } else if (images[i].type == ImageType::Normal) { os_images_.emplace_back(&images[i], slot); } int fd = unzip_to_file(zip, images[i].img_name); if (fd == -1) { if (images[i].optional_if_no_image) { continue; // An optional file is missing, so ignore it. } die("non-optional file %s missing", images[i].img_name); } void FlashAllTool::FlashImages(const std::vector<std::pair<const Image*, std::string>>& images) { for (const auto& [image, slot] : images) { fastboot_buffer buf; if (!load_buf_fd(fd, &buf)) { die("cannot load %s from flash: %s", images[i].img_name, strerror(errno)); int fd = source_.OpenFile(image->img_name); if (fd < 0 || !load_buf_fd(fd, &buf)) { if (image->optional_if_no_image) { continue; } auto update = [&](const std::string& partition) { do_update_signature(zip, images[i].sig_name); flash_buf(partition.c_str(), &buf); /* not closing the fd here since the sparse code keeps the fd around * but hasn't mmaped data yet. The temporary file will get cleaned up when the * program exits. */ }; do_for_partitions(images[i].part_name, slot, update, false); die("could not load '%s': %s", image->img_name, strerror(errno)); } if (slot_override == "all") { set_active("a"); } else { set_active(slot_override); FlashImage(*image, slot, &buf); } CloseArchive(zip); } static void do_send_signature(const std::string& fn) { std::size_t extension_loc = fn.find(".img"); if (extension_loc == std::string::npos) return; std::string fs_sig = fn.substr(0, extension_loc) + ".sig"; void FlashAllTool::FlashImage(const Image& image, const std::string& slot, fastboot_buffer* buf) { auto flash = [&, this](const std::string& partition_name) { int64_t sz; void* data = load_file(fs_sig.c_str(), &sz); if (data == nullptr) return; void* data = source_.ReadFile(image.sig_name, &sz); if (data) { fb_queue_download("signature", data, sz); fb_queue_command("signature", "installing signature"); } static bool is_logical(const std::string& partition) { std::string value; return fb_getvar("is-logical:" + partition, &value) && value == "yes"; if (is_logical(partition_name)) { fb_queue_resize_partition(partition_name, std::to_string(buf->image_size)); } static void reboot_to_userspace_fastboot() { if (!fb_reboot_to_userspace()) { die("Must reboot to userspace fastboot to flash logical partitions"); } // Give the current connection time to close. std::this_thread::sleep_for(std::chrono::milliseconds(1000)); fb_reinit(open_device()); flash_buf(partition_name.c_str(), buf); }; do_for_partitions(image.part_name, slot, flash, false); } static void update_super_partition(bool force_wipe) { void FlashAllTool::UpdateSuperPartition() { if (!if_partition_exists("super", "")) { return; } std::string image = find_item_given_name("super_empty.img"); if (access(image.c_str(), R_OK) < 0) { int fd = source_.OpenFile("super_empty.img"); if (fd < 0) { return; } if (!is_userspace_fastboot()) { reboot_to_userspace_fastboot(); } 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) { if (wipe_) { command += ":wipe"; } fb_queue_command(command, "Updating super partition"); Loading @@ -1216,100 +1258,68 @@ static void update_super_partition(bool force_wipe) { fb_execute_queue(); } static void flash_images(const std::vector<std::pair<const Image*, std::string>>& images) { // Flash each partition in the list if it has a corresponding image. for (const auto& [image, slot] : images) { auto fname = find_item_given_name(image->img_name); fastboot_buffer buf; if (!load_buf(fname.c_str(), &buf)) { if (image->optional_if_no_image) continue; die("could not load '%s': %s", image->img_name, strerror(errno)); } 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); class ZipImageSource final : public ImageSource { public: explicit ZipImageSource(ZipArchiveHandle zip) : zip_(zip) {} void* ReadFile(const std::string& name, int64_t* size) const override; int OpenFile(const std::string& name) const override; private: ZipArchiveHandle zip_; }; do_for_partitions(image->part_name, slot, flashall, false); void* ZipImageSource::ReadFile(const std::string& name, int64_t* size) const { return unzip_to_memory(zip_, name.c_str(), size); } int ZipImageSource::OpenFile(const std::string& name) const { return unzip_to_file(zip_, name.c_str()); } static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) { std::string fname; static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) { queue_info_dump(); fb_queue_query_save("product", cur_product, sizeof(cur_product)); fname = find_item_given_name("android-info.txt"); if (fname.empty()) die("cannot find android-info.txt"); int64_t sz; void* data = load_file(fname.c_str(), &sz); if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno)); ZipArchiveHandle zip; int error = OpenArchive(filename, &zip); if (error != 0) { die("failed to open zip file '%s': %s", filename, ErrorCodeString(error)); } check_requirements(reinterpret_cast<char*>(data), sz); FlashAllTool tool(ZipImageSource(zip), slot_override, skip_secondary, false); tool.Flash(); std::string secondary; if (!skip_secondary) { if (slot_override != "") { secondary = get_other_slot(slot_override); } else { secondary = get_other_slot(); } if (secondary == "") { if (supports_AB()) { fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n"); } skip_secondary = true; } CloseArchive(zip); } // List of partitions to flash and their slots. std::vector<std::pair<const Image*, std::string>> boot_images; std::vector<std::pair<const Image*, std::string>> os_images; for (size_t i = 0; i < arraysize(images); i++) { const char* slot = NULL; if (images[i].IsSecondary()) { if (!skip_secondary) slot = secondary.c_str(); } else { slot = slot_override.c_str(); } if (!slot) continue; if (images[i].type == ImageType::BootCritical) { boot_images.emplace_back(&images[i], slot); } else if (images[i].type == ImageType::Normal) { os_images.emplace_back(&images[i], slot); class LocalImageSource final : public ImageSource { public: void* ReadFile(const std::string& name, int64_t* size) const override; int OpenFile(const std::string& name) const override; }; void* LocalImageSource::ReadFile(const std::string& name, int64_t* size) const { auto path = find_item_given_name(name); if (path.empty()) { return nullptr; } return load_file(path.c_str(), size); } // First flash boot partitions. We allow this to happen either in userspace // or in bootloader fastboot. flash_images(boot_images); // Sync the super partition. This will reboot to userspace fastboot if needed. update_super_partition(wipe); // Resize any logical partition to 0, so each partition is reset to 0 // extents, and will achieve more optimal allocation. for (const auto& [image, slot] : os_images) { auto resize_partition = [](const std::string& partition) -> void { if (is_logical(partition)) { fb_queue_resize_partition(partition, "0"); } }; do_for_partitions(image->part_name, slot, resize_partition, false); int LocalImageSource::OpenFile(const std::string& name) const { auto path = find_item_given_name(name); return open(path.c_str(), O_RDONLY); } // Flash OS images, resizing logical partitions as needed. flash_images(os_images); static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) { std::string fname; queue_info_dump(); if (slot_override == "all") { set_active("a"); } else { set_active(slot_override); } fb_queue_query_save("product", cur_product, sizeof(cur_product)); FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe); tool.Flash(); } static std::string next_arg(std::vector<std::string>* args) { Loading Loading
fastboot/fastboot.cpp +186 −176 Original line number Diff line number Diff line Loading @@ -574,6 +574,7 @@ static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) { ZipEntry zip_entry; if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) { fprintf(stderr, "archive does not contain '%s'\n", entry_name); errno = ENOENT; return -1; } Loading Loading @@ -1033,14 +1034,6 @@ static void do_flash(const char* pname, const char* fname) { flash_buf(pname, &buf); } static void do_update_signature(ZipArchiveHandle zip, const char* filename) { int64_t sz; void* data = unzip_to_memory(zip, filename, &sz); if (data == nullptr) return; fb_queue_download("signature", data, sz); fb_queue_command("signature", "installing signature"); } // Sets slot_override as the active slot. If slot_override is blank, // set current slot as active instead. This clears slot-unbootable. static void set_active(const std::string& slot_override) { Loading Loading @@ -1080,133 +1073,182 @@ static bool if_partition_exists(const std::string& partition, const std::string& return fb_getvar("partition-size:" + partition_name, &partition_size); } static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) { queue_info_dump(); static bool is_logical(const std::string& partition) { std::string value; return fb_getvar("is-logical:" + partition, &value) && value == "yes"; } fb_queue_query_save("product", cur_product, sizeof(cur_product)); static void reboot_to_userspace_fastboot() { if (!fb_reboot_to_userspace()) { die("Must reboot to userspace fastboot to flash logical partitions"); } ZipArchiveHandle zip; int error = OpenArchive(filename, &zip); if (error != 0) { die("failed to open zip file '%s': %s", filename, ErrorCodeString(error)); // Give the current connection time to close. std::this_thread::sleep_for(std::chrono::milliseconds(1000)); fb_reinit(open_device()); } class ImageSource { public: virtual void* ReadFile(const std::string& name, int64_t* size) const = 0; virtual int OpenFile(const std::string& name) const = 0; }; class FlashAllTool { public: FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe); void Flash(); private: void CheckRequirements(); void DetermineSecondarySlot(); void CollectImages(); void FlashImages(const std::vector<std::pair<const Image*, std::string>>& images); void FlashImage(const Image& image, const std::string& slot, fastboot_buffer* buf); void UpdateSuperPartition(); const ImageSource& source_; std::string slot_override_; bool skip_secondary_; bool wipe_; std::string secondary_slot_; std::vector<std::pair<const Image*, std::string>> boot_images_; std::vector<std::pair<const Image*, std::string>> os_images_; }; FlashAllTool::FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe) : source_(source), slot_override_(slot_override), skip_secondary_(skip_secondary), wipe_(wipe) { } void FlashAllTool::Flash() { CheckRequirements(); DetermineSecondarySlot(); CollectImages(); // First flash boot partitions. We allow this to happen either in userspace // or in bootloader fastboot. FlashImages(boot_images_); // Sync the super partition. This will reboot to userspace fastboot if needed. UpdateSuperPartition(); // Resize any logical partition to 0, so each partition is reset to 0 // extents, and will achieve more optimal allocation. for (const auto& [image, slot] : os_images_) { auto resize_partition = [](const std::string& partition) -> void { if (is_logical(partition)) { fb_queue_resize_partition(partition, "0"); } }; do_for_partitions(image->part_name, slot, resize_partition, false); } // Flash OS images, resizing logical partitions as needed. FlashImages(os_images_); if (slot_override_ == "all") { set_active("a"); } else { set_active(slot_override_); } } void FlashAllTool::CheckRequirements() { int64_t sz; void* data = unzip_to_memory(zip, "android-info.txt", &sz); void* data = source_.ReadFile("android-info.txt", &sz); if (data == nullptr) { die("update package '%s' has no android-info.txt", filename); die("could not read android-info.txt"); } check_requirements(reinterpret_cast<char*>(data), sz); } std::string secondary; if (!skip_secondary) { if (slot_override != "") { secondary = get_other_slot(slot_override); void FlashAllTool::DetermineSecondarySlot() { if (skip_secondary_) { return; } if (slot_override_ != "") { secondary_slot_ = get_other_slot(slot_override_); } else { secondary = get_other_slot(); secondary_slot_ = get_other_slot(); } if (secondary == "") { if (secondary_slot_ == "") { if (supports_AB()) { fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n"); } skip_secondary = true; skip_secondary_ = true; } } void FlashAllTool::CollectImages() { for (size_t i = 0; i < arraysize(images); ++i) { const char* slot = slot_override.c_str(); std::string slot = slot_override_; if (images[i].IsSecondary()) { if (!skip_secondary) { slot = secondary.c_str(); } else { if (skip_secondary_) { continue; } slot = secondary_slot_; } if (images[i].type == ImageType::BootCritical) { boot_images_.emplace_back(&images[i], slot); } else if (images[i].type == ImageType::Normal) { os_images_.emplace_back(&images[i], slot); } int fd = unzip_to_file(zip, images[i].img_name); if (fd == -1) { if (images[i].optional_if_no_image) { continue; // An optional file is missing, so ignore it. } die("non-optional file %s missing", images[i].img_name); } void FlashAllTool::FlashImages(const std::vector<std::pair<const Image*, std::string>>& images) { for (const auto& [image, slot] : images) { fastboot_buffer buf; if (!load_buf_fd(fd, &buf)) { die("cannot load %s from flash: %s", images[i].img_name, strerror(errno)); int fd = source_.OpenFile(image->img_name); if (fd < 0 || !load_buf_fd(fd, &buf)) { if (image->optional_if_no_image) { continue; } auto update = [&](const std::string& partition) { do_update_signature(zip, images[i].sig_name); flash_buf(partition.c_str(), &buf); /* not closing the fd here since the sparse code keeps the fd around * but hasn't mmaped data yet. The temporary file will get cleaned up when the * program exits. */ }; do_for_partitions(images[i].part_name, slot, update, false); die("could not load '%s': %s", image->img_name, strerror(errno)); } if (slot_override == "all") { set_active("a"); } else { set_active(slot_override); FlashImage(*image, slot, &buf); } CloseArchive(zip); } static void do_send_signature(const std::string& fn) { std::size_t extension_loc = fn.find(".img"); if (extension_loc == std::string::npos) return; std::string fs_sig = fn.substr(0, extension_loc) + ".sig"; void FlashAllTool::FlashImage(const Image& image, const std::string& slot, fastboot_buffer* buf) { auto flash = [&, this](const std::string& partition_name) { int64_t sz; void* data = load_file(fs_sig.c_str(), &sz); if (data == nullptr) return; void* data = source_.ReadFile(image.sig_name, &sz); if (data) { fb_queue_download("signature", data, sz); fb_queue_command("signature", "installing signature"); } static bool is_logical(const std::string& partition) { std::string value; return fb_getvar("is-logical:" + partition, &value) && value == "yes"; if (is_logical(partition_name)) { fb_queue_resize_partition(partition_name, std::to_string(buf->image_size)); } static void reboot_to_userspace_fastboot() { if (!fb_reboot_to_userspace()) { die("Must reboot to userspace fastboot to flash logical partitions"); } // Give the current connection time to close. std::this_thread::sleep_for(std::chrono::milliseconds(1000)); fb_reinit(open_device()); flash_buf(partition_name.c_str(), buf); }; do_for_partitions(image.part_name, slot, flash, false); } static void update_super_partition(bool force_wipe) { void FlashAllTool::UpdateSuperPartition() { if (!if_partition_exists("super", "")) { return; } std::string image = find_item_given_name("super_empty.img"); if (access(image.c_str(), R_OK) < 0) { int fd = source_.OpenFile("super_empty.img"); if (fd < 0) { return; } if (!is_userspace_fastboot()) { reboot_to_userspace_fastboot(); } 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) { if (wipe_) { command += ":wipe"; } fb_queue_command(command, "Updating super partition"); Loading @@ -1216,100 +1258,68 @@ static void update_super_partition(bool force_wipe) { fb_execute_queue(); } static void flash_images(const std::vector<std::pair<const Image*, std::string>>& images) { // Flash each partition in the list if it has a corresponding image. for (const auto& [image, slot] : images) { auto fname = find_item_given_name(image->img_name); fastboot_buffer buf; if (!load_buf(fname.c_str(), &buf)) { if (image->optional_if_no_image) continue; die("could not load '%s': %s", image->img_name, strerror(errno)); } 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); class ZipImageSource final : public ImageSource { public: explicit ZipImageSource(ZipArchiveHandle zip) : zip_(zip) {} void* ReadFile(const std::string& name, int64_t* size) const override; int OpenFile(const std::string& name) const override; private: ZipArchiveHandle zip_; }; do_for_partitions(image->part_name, slot, flashall, false); void* ZipImageSource::ReadFile(const std::string& name, int64_t* size) const { return unzip_to_memory(zip_, name.c_str(), size); } int ZipImageSource::OpenFile(const std::string& name) const { return unzip_to_file(zip_, name.c_str()); } static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) { std::string fname; static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) { queue_info_dump(); fb_queue_query_save("product", cur_product, sizeof(cur_product)); fname = find_item_given_name("android-info.txt"); if (fname.empty()) die("cannot find android-info.txt"); int64_t sz; void* data = load_file(fname.c_str(), &sz); if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno)); ZipArchiveHandle zip; int error = OpenArchive(filename, &zip); if (error != 0) { die("failed to open zip file '%s': %s", filename, ErrorCodeString(error)); } check_requirements(reinterpret_cast<char*>(data), sz); FlashAllTool tool(ZipImageSource(zip), slot_override, skip_secondary, false); tool.Flash(); std::string secondary; if (!skip_secondary) { if (slot_override != "") { secondary = get_other_slot(slot_override); } else { secondary = get_other_slot(); } if (secondary == "") { if (supports_AB()) { fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n"); } skip_secondary = true; } CloseArchive(zip); } // List of partitions to flash and their slots. std::vector<std::pair<const Image*, std::string>> boot_images; std::vector<std::pair<const Image*, std::string>> os_images; for (size_t i = 0; i < arraysize(images); i++) { const char* slot = NULL; if (images[i].IsSecondary()) { if (!skip_secondary) slot = secondary.c_str(); } else { slot = slot_override.c_str(); } if (!slot) continue; if (images[i].type == ImageType::BootCritical) { boot_images.emplace_back(&images[i], slot); } else if (images[i].type == ImageType::Normal) { os_images.emplace_back(&images[i], slot); class LocalImageSource final : public ImageSource { public: void* ReadFile(const std::string& name, int64_t* size) const override; int OpenFile(const std::string& name) const override; }; void* LocalImageSource::ReadFile(const std::string& name, int64_t* size) const { auto path = find_item_given_name(name); if (path.empty()) { return nullptr; } return load_file(path.c_str(), size); } // First flash boot partitions. We allow this to happen either in userspace // or in bootloader fastboot. flash_images(boot_images); // Sync the super partition. This will reboot to userspace fastboot if needed. update_super_partition(wipe); // Resize any logical partition to 0, so each partition is reset to 0 // extents, and will achieve more optimal allocation. for (const auto& [image, slot] : os_images) { auto resize_partition = [](const std::string& partition) -> void { if (is_logical(partition)) { fb_queue_resize_partition(partition, "0"); } }; do_for_partitions(image->part_name, slot, resize_partition, false); int LocalImageSource::OpenFile(const std::string& name) const { auto path = find_item_given_name(name); return open(path.c_str(), O_RDONLY); } // Flash OS images, resizing logical partitions as needed. flash_images(os_images); static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) { std::string fname; queue_info_dump(); if (slot_override == "all") { set_active("a"); } else { set_active(slot_override); } fb_queue_query_save("product", cur_product, sizeof(cur_product)); FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe); tool.Flash(); } static std::string next_arg(std::vector<std::string>* args) { Loading