diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 430ff14bf..0e5f3fba1 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -982,7 +982,7 @@ static void DumpInfo() { fprintf(stderr, "--------------------------------------------\n"); } -static std::vector resparse_file(sparse_file* s, int64_t max_size) { +std::vector resparse_file(sparse_file* s, int64_t max_size) { if (max_size <= 0 || max_size > std::numeric_limits::max()) { die("invalid max size %" PRId64, max_size); } @@ -1027,7 +1027,7 @@ static uint64_t get_uint_var(const char* var_name) { return value; } -static int64_t get_sparse_limit(int64_t size) { +int64_t get_sparse_limit(int64_t size) { int64_t limit = sparse_limit; if (limit == 0) { // Unlimited, so see what the target device's limit is. @@ -1161,7 +1161,7 @@ static bool has_vbmeta_partition() { // Note: this only works in userspace fastboot. In the bootloader, use // should_flash_in_userspace(). -static bool is_logical(const std::string& partition) { +bool is_logical(const std::string& partition) { std::string value; return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes"; } @@ -1243,8 +1243,7 @@ static void copy_avb_footer(const std::string& partition, struct fastboot_buffer lseek(buf->fd.get(), 0, SEEK_SET); } -static void flash_partition_files(const std::string& partition, - const std::vector& files) { +void flash_partition_files(const std::string& partition, const std::vector& files) { for (size_t i = 0; i < files.size(); i++) { sparse_file* s = files[i].get(); int64_t sz = sparse_file_len(s, true, false); @@ -1303,7 +1302,7 @@ static int get_slot_count() { return count; } -static bool supports_AB() { +bool supports_AB() { return get_slot_count() >= 2; } @@ -1426,7 +1425,7 @@ void do_for_partitions(const std::string& part, const std::string& slot, } } -static bool is_retrofit_device() { +bool is_retrofit_device() { std::string value; if (fb->GetVar("super-partition-name", &value) != fastboot::SUCCESS) { return false; @@ -1562,6 +1561,20 @@ static void CancelSnapshotIfNeeded() { } } +std::string GetPartitionName(const ImageEntry& entry, std::string& current_slot) { + auto slot = entry.second; + if (slot.empty()) { + slot = current_slot; + } + if (slot.empty()) { + return entry.first->part_name; + } + if (slot == "all") { + LOG(FATAL) << "Cannot retrieve a singular name when using all slots"; + } + return entry.first->part_name + "_" + slot; +} + class FlashAllTool { public: FlashAllTool(FlashingPlan* fp); @@ -1575,15 +1588,12 @@ class FlashAllTool { void FlashImages(const std::vector>& images); void FlashImage(const Image& image, const std::string& slot, fastboot_buffer* buf); void UpdateSuperPartition(); - bool OptimizedFlashSuper(); // If the image uses the default slot, or the user specified "all", then // the paired string will be empty. If the image requests a specific slot // (for example, system_other) it is specified instead. using ImageEntry = std::pair; - std::string GetPartitionName(const ImageEntry& entry); - std::vector boot_images_; std::vector os_images_; FlashingPlan* fp_; @@ -1612,10 +1622,13 @@ void FlashAllTool::Flash() { // or in bootloader fastboot. FlashImages(boot_images_); - if (!OptimizedFlashSuper()) { + auto flash_super_task = FlashSuperLayoutTask::Initialize(fp_, os_images_); + + if (flash_super_task) { + flash_super_task->Run(); + } else { // 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_) { @@ -1627,77 +1640,9 @@ void FlashAllTool::Flash() { do_for_partitions(image->part_name, slot, resize_partition, false); } } - - // Flash OS images, resizing logical partitions as needed. FlashImages(os_images_); } -bool FlashAllTool::OptimizedFlashSuper() { - if (!supports_AB()) { - LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device"; - return false; - } - if (fp_->slot == "all") { - LOG(VERBOSE) << "Cannot optimize flashing super for all slots"; - return false; - } - - // Does this device use dynamic partitions at all? - unique_fd fd = fp_->source->OpenFile("super_empty.img"); - if (fd < 0) { - LOG(VERBOSE) << "could not open super_empty.img"; - return false; - } - - // Try to find whether there is a super partition. - std::string super_name; - if (fb->GetVar("super-partition-name", &super_name) != fastboot::SUCCESS) { - super_name = "super"; - } - std::string partition_size_str; - if (fb->GetVar("partition-size:" + super_name, &partition_size_str) != fastboot::SUCCESS) { - LOG(VERBOSE) << "Cannot optimize super flashing: could not determine super partition"; - return false; - } - - SuperFlashHelper helper(*fp_->source); - if (!helper.Open(fd)) { - return false; - } - - for (const auto& entry : os_images_) { - auto partition = GetPartitionName(entry); - auto image = entry.first; - - if (!helper.AddPartition(partition, image->img_name, image->optional_if_no_image)) { - return false; - } - } - - auto s = helper.GetSparseLayout(); - if (!s) { - return false; - } - - std::vector files; - if (int limit = get_sparse_limit(sparse_file_len(s.get(), false, false))) { - files = resparse_file(s.get(), limit); - } else { - files.emplace_back(std::move(s)); - } - - // Send the data to the device. - flash_partition_files(super_name, files); - - // Remove images that we already flashed, just in case we have non-dynamic OS images. - auto remove_if_callback = [&, this](const ImageEntry& entry) -> bool { - return helper.WillFlash(GetPartitionName(entry)); - }; - os_images_.erase(std::remove_if(os_images_.begin(), os_images_.end(), remove_if_callback), - os_images_.end()); - return true; -} - void FlashAllTool::CheckRequirements() { std::vector contents; if (!fp_->source->ReadFile("android-info.txt", &contents)) { @@ -1811,20 +1756,6 @@ void FlashAllTool::UpdateSuperPartition() { } } -std::string FlashAllTool::GetPartitionName(const ImageEntry& entry) { - auto slot = entry.second; - if (slot.empty()) { - slot = fp_->current_slot; - } - if (slot.empty()) { - return entry.first->part_name; - } - if (slot == "all") { - LOG(FATAL) << "Cannot retrieve a singular name when using all slots"; - } - return entry.first->part_name + "_" + slot; -} - class ZipImageSource final : public ImageSource { public: explicit ZipImageSource(ZipArchiveHandle zip) : zip_(zip) {} diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index 09666aaa9..2264ca343 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -29,6 +29,7 @@ #include #include "fastboot_driver.h" +#include "super_flash_helper.h" #include "util.h" #include @@ -82,7 +83,6 @@ struct FlashingPlan { std::string current_slot; std::string secondary_slot; fastboot::FastBootDriver* fb; - }; bool should_flash_in_userspace(const std::string& partition_name); @@ -100,4 +100,12 @@ struct NetworkSerial { int port; }; -Result ParseNetworkSerial(const std::string& serial); \ No newline at end of file +Result ParseNetworkSerial(const std::string& serial); +bool supports_AB(); +std::string GetPartitionName(const ImageEntry& entry, std::string& current_slot_); +void flash_partition_files(const std::string& partition, const std::vector& files); +int64_t get_sparse_limit(int64_t size); +std::vector resparse_file(sparse_file* s, int64_t max_size); + +bool is_retrofit_device(); +bool is_logical(const std::string& partition); diff --git a/fastboot/task.cpp b/fastboot/task.cpp index a4aa637ae..e77fa4a0b 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -14,11 +14,12 @@ // limitations under the License. // #include "task.h" +#include #include "fastboot.h" -#include "util.h" +#include "filesystem.h" +#include "super_flash_helper.h" -#include "fastboot.h" -#include "util.h" +using namespace std::string_literals; FlashTask::FlashTask(const std::string& _slot, const std::string& _pname) : pname_(_pname), fname_(find_item(_pname)), slot_(_slot) { @@ -66,3 +67,78 @@ void RebootTask::Run() { syntax_error("unknown reboot target %s", reboot_target_.c_str()); } } + +FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name, + std::unique_ptr helper, + SparsePtr sparse_layout) + : super_name_(super_name), + helper_(std::move(helper)), + sparse_layout_(std::move(sparse_layout)) {} + +void FlashSuperLayoutTask::Run() { + std::vector files; + if (int limit = get_sparse_limit(sparse_file_len(sparse_layout_.get(), false, false))) { + files = resparse_file(sparse_layout_.get(), limit); + } else { + files.emplace_back(std::move(sparse_layout_)); + } + + // Send the data to the device. + flash_partition_files(super_name_, files); +} + +std::unique_ptr FlashSuperLayoutTask::Initialize( + FlashingPlan* fp, std::vector& os_images) { + if (!supports_AB()) { + LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device"; + return nullptr; + } + if (fp->slot == "all") { + LOG(VERBOSE) << "Cannot optimize flashing super for all slots"; + return nullptr; + } + + // Does this device use dynamic partitions at all? + unique_fd fd = fp->source->OpenFile("super_empty.img"); + + if (fd < 0) { + LOG(VERBOSE) << "could not open super_empty.img"; + return nullptr; + } + + std::string super_name; + // Try to find whether there is a super partition. + if (fp->fb->GetVar("super-partition-name", &super_name) != fastboot::SUCCESS) { + super_name = "super"; + } + std::string partition_size_str; + + if (fp->fb->GetVar("partition-size:" + super_name, &partition_size_str) != fastboot::SUCCESS) { + LOG(VERBOSE) << "Cannot optimize super flashing: could not determine super partition"; + return nullptr; + } + std::unique_ptr helper = std::make_unique(*fp->source); + if (!helper->Open(fd)) { + return nullptr; + } + + for (const auto& entry : os_images) { + auto partition = GetPartitionName(entry, fp->current_slot); + auto image = entry.first; + + if (!helper->AddPartition(partition, image->img_name, image->optional_if_no_image)) { + return nullptr; + } + } + + auto s = helper->GetSparseLayout(); + if (!s) return nullptr; + + // Remove images that we already flashed, just in case we have non-dynamic OS images. + auto remove_if_callback = [&](const ImageEntry& entry) -> bool { + return helper->WillFlash(GetPartitionName(entry, fp->current_slot)); + }; + os_images.erase(std::remove_if(os_images.begin(), os_images.end(), remove_if_callback), + os_images.end()); + return std::make_unique(super_name, std::move(helper), std::move(s)); +} diff --git a/fastboot/task.h b/fastboot/task.h index d8b9e215f..7acb3d595 100644 --- a/fastboot/task.h +++ b/fastboot/task.h @@ -20,6 +20,8 @@ #include "fastboot.h" #include "fastboot_driver.h" +#include "super_flash_helper.h" +#include "util.h" class Task { public: @@ -52,4 +54,19 @@ class RebootTask : public Task { private: const std::string reboot_target_ = ""; FlashingPlan* fp_; -}; \ No newline at end of file +}; + +class FlashSuperLayoutTask : public Task { + public: + FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr helper, + SparsePtr sparse_layout); + static std::unique_ptr Initialize(FlashingPlan* fp, + std::vector& os_images); + using ImageEntry = std::pair; + void Run() override; + + private: + const std::string super_name_; + std::unique_ptr helper_; + SparsePtr sparse_layout_; +};