Loading fastboot/fastboot.cpp +262 −30 Original line number Diff line number Diff line Loading @@ -1284,7 +1284,7 @@ static void flash_buf(const std::string& partition, struct fastboot_buffer* buf, } } static std::string get_current_slot() { std::string get_current_slot() { std::string current_slot; if (fb->GetVar("current-slot", ¤t_slot) != fastboot::SUCCESS) return ""; if (current_slot[0] == '_') current_slot.erase(0, 1); Loading Loading @@ -1560,7 +1560,7 @@ static void CancelSnapshotIfNeeded() { } } std::string GetPartitionName(const ImageEntry& entry, std::string& current_slot) { std::string GetPartitionName(const ImageEntry& entry, const std::string& current_slot) { auto slot = entry.second; if (slot.empty()) { slot = current_slot; Loading @@ -1574,6 +1574,216 @@ std::string GetPartitionName(const ImageEntry& entry, std::string& current_slot) return entry.first->part_name + "_" + slot; } std::unique_ptr<FlashTask> ParseFlashCommand(const FlashingPlan* fp, const std::vector<std::string>& parts) { bool apply_vbmeta = false; std::string slot = fp->slot_override; std::string partition; std::string img_name; for (auto& part : parts) { if (part == "--apply-vbmeta") { apply_vbmeta = true; } else if (part == "--slot-other") { slot = fp->secondary_slot; } else if (partition.empty()) { partition = part; } else if (img_name.empty()) { img_name = part; } else { LOG(ERROR) << "unknown argument" << part << " in fastboot-info.txt. parts: " << android::base::Join(parts, " "); return nullptr; } } if (partition.empty()) { LOG(ERROR) << "partition name not found when parsing fastboot-info.txt. parts: " << android::base::Join(parts, " "); return nullptr; } if (img_name.empty()) { img_name = partition + ".img"; } return std::make_unique<FlashTask>(slot, partition, img_name, apply_vbmeta); } std::unique_ptr<RebootTask> ParseRebootCommand(const FlashingPlan* fp, const std::vector<std::string>& parts) { if (parts.empty()) return std::make_unique<RebootTask>(fp); if (parts.size() > 1) { LOG(ERROR) << "unknown arguments in reboot {target} in fastboot-info.txt: " << android::base::Join(parts, " "); return nullptr; } return std::make_unique<RebootTask>(fp, parts[0]); } std::unique_ptr<WipeTask> ParseWipeCommand(const FlashingPlan* fp, const std::vector<std::string>& parts) { if (parts.size() != 1) { LOG(ERROR) << "unknown arguments in erase {partition} in fastboot-info.txt: " << android::base::Join(parts, " "); return nullptr; } return std::make_unique<WipeTask>(fp, parts[0]); } std::unique_ptr<Task> ParseFastbootInfoLine(const FlashingPlan* fp, const std::vector<std::string>& command) { if (command.size() == 0) { return nullptr; } std::unique_ptr<Task> task; if (command[0] == "flash") { task = ParseFlashCommand(fp, std::vector<std::string>{command.begin() + 1, command.end()}); } else if (command[0] == "reboot") { task = ParseRebootCommand(fp, std::vector<std::string>{command.begin() + 1, command.end()}); } else if (command[0] == "update-super" && command.size() == 1) { task = std::make_unique<UpdateSuperTask>(fp); } else if (command[0] == "erase" && command.size() == 2) { task = ParseWipeCommand(fp, std::vector<std::string>{command.begin() + 1, command.end()}); } if (!task) { LOG(ERROR) << "unknown command parsing fastboot-info.txt line: " << android::base::Join(command, " "); } return task; } void AddResizeTasks(const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>* tasks) { // expands "resize-partitions" into individual commands : resize {os_partition_1}, resize // {os_partition_2}, etc. std::vector<std::unique_ptr<Task>> resize_tasks; std::optional<size_t> loc; for (size_t i = 0; i < tasks->size(); i++) { if (auto flash_task = tasks->at(i)->AsFlashTask()) { if (should_flash_in_userspace(flash_task->GetPartitionAndSlot())) { if (!loc) { loc = i; } resize_tasks.emplace_back(std::make_unique<ResizeTask>( fp, flash_task->GetPartition(), "0", fp->slot_override)); } } } // if no logical partitions (although should never happen since system will always need to be // flashed) if (!loc) { return; } tasks->insert(tasks->begin() + loc.value(), std::make_move_iterator(resize_tasks.begin()), std::make_move_iterator(resize_tasks.end())); return; } static bool IsNumber(const std::string& s) { bool period = false; for (size_t i = 0; i < s.length(); i++) { if (!isdigit(s[i])) { if (!period && s[i] == '.' && i != 0 && i != s.length() - 1) { period = true; } else { return false; } } } return true; } static bool IsIgnore(const std::vector<std::string>& command) { if (command[0][0] == '#') { return true; } return false; } bool CheckFastbootInfoRequirements(const std::vector<std::string>& command) { if (command.size() != 2) { LOG(ERROR) << "unknown characters in version info in fastboot-info.txt -> " << android::base::Join(command, " "); return false; } if (command[0] != "version") { LOG(ERROR) << "unknown characters in version info in fastboot-info.txt -> " << android::base::Join(command, " "); return false; } if (!IsNumber(command[1])) { LOG(ERROR) << "version number contains non-numeric values in fastboot-info.txt -> " << android::base::Join(command, " "); return false; } LOG(VERBOSE) << "Checking 'fastboot-info.txt version'"; if (command[1] < PLATFORM_TOOLS_VERSION) { return true; } LOG(ERROR) << "fasboot-info.txt version: " << command[1] << " not compatible with host tool version --> " << PLATFORM_TOOLS_VERSION; return false; } std::vector<std::unique_ptr<Task>> ParseFastbootInfo(const FlashingPlan* fp, const std::vector<std::string>& file) { std::vector<std::unique_ptr<Task>> tasks; // Get os_partitions that need to be resized for (auto& text : file) { std::vector<std::string> command = android::base::Tokenize(text, " "); if (IsIgnore(command)) { continue; } if (command.size() > 1 && command[0] == "version") { if (!CheckFastbootInfoRequirements(command)) { return {}; } continue; } else if (command.size() >= 2 && command[0] == "if-wipe") { if (!fp->wants_wipe) { continue; } command.erase(command.begin()); } auto task = ParseFastbootInfoLine(fp, command); if (!task) { LOG(ERROR) << "Error when parsing fastboot-info.txt, falling back on Hardcoded list: " << text; return {}; } tasks.emplace_back(std::move(task)); } if (auto flash_super_task = FlashSuperLayoutTask::InitializeFromTasks(fp, tasks)) { auto it = tasks.begin(); for (size_t i = 0; i < tasks.size(); i++) { if (auto flash_task = tasks[i]->AsFlashTask()) { if (should_flash_in_userspace(flash_task->GetPartitionAndSlot())) { break; } } if (auto wipe_task = tasks[i]->AsWipeTask()) { break; } it++; } tasks.insert(it, std::move(flash_super_task)); } else { AddResizeTasks(fp, &tasks); } return tasks; } std::vector<std::unique_ptr<Task>> ParseFastbootInfo(const FlashingPlan* fp, std::ifstream& fs) { if (!fs || fs.eof()) return {}; std::string text; std::vector<std::string> file; // Get os_partitions that need to be resized while (std::getline(fs, text)) { file.emplace_back(text); } return ParseFastbootInfo(fp, file); } class FlashAllTool { public: FlashAllTool(FlashingPlan* fp); Loading @@ -1586,6 +1796,7 @@ class FlashAllTool { 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 HardcodedFlash(); std::vector<ImageEntry> boot_images_; std::vector<ImageEntry> os_images_; Loading @@ -1611,38 +1822,23 @@ void FlashAllTool::Flash() { CancelSnapshotIfNeeded(); // First flash boot partitions. We allow this to happen either in userspace // or in bootloader fastboot. FlashImages(boot_images_); std::vector<std::unique_ptr<Task>> tasks; if (auto flash_super_task = FlashSuperLayoutTask::Initialize(fp_, os_images_)) { tasks.emplace_back(std::move(flash_super_task)); } else { // Sync the super partition. This will reboot to userspace fastboot if needed. tasks.emplace_back(std::make_unique<UpdateSuperTask>(fp_)); // 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_) { // Retrofit devices have two super partitions, named super_a and super_b. // On these devices, secondary slots must be flashed as physical // partitions (otherwise they would not mount on first boot). To enforce // this, we delete any logical partitions for the "other" slot. if (is_retrofit_device()) { std::string partition_name = image->part_name + "_"s + slot; if (image->IsSecondary() && is_logical(partition_name)) { fp_->fb->DeletePartition(partition_name); } tasks.emplace_back(std::make_unique<DeleteTask>(fp_, partition_name)); } tasks.emplace_back(std::make_unique<ResizeTask>(fp_, image->part_name, "0", slot)); } std::string path = find_item_given_name("fastboot-info.txt"); std::ifstream stream(path); std::vector<std::unique_ptr<Task>> tasks = ParseFastbootInfo(fp_, stream); if (tasks.empty()) { LOG(VERBOSE) << "Flashing from hardcoded images. fastboot-info.txt is empty or does not " "exist"; HardcodedFlash(); return; } LOG(VERBOSE) << "Flashing from fastboot-info.txt"; for (auto& task : tasks) { task->Run(); } FlashImages(os_images_); if (fp_->wants_wipe) { // avoid adding duplicate wipe tasks in fastboot main code. fp_->wants_wipe = false; } } void FlashAllTool::CheckRequirements() { Loading Loading @@ -1693,6 +1889,42 @@ void FlashAllTool::CollectImages() { } } void FlashAllTool::HardcodedFlash() { CollectImages(); // First flash boot partitions. We allow this to happen either in userspace // or in bootloader fastboot. FlashImages(boot_images_); std::vector<std::unique_ptr<Task>> tasks; if (auto flash_super_task = FlashSuperLayoutTask::Initialize(fp_, os_images_)) { tasks.emplace_back(std::move(flash_super_task)); } else { // Sync the super partition. This will reboot to userspace fastboot if needed. tasks.emplace_back(std::make_unique<UpdateSuperTask>(fp_)); // 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_) { // Retrofit devices have two super partitions, named super_a and super_b. // On these devices, secondary slots must be flashed as physical // partitions (otherwise they would not mount on first boot). To enforce // this, we delete any logical partitions for the "other" slot. if (is_retrofit_device()) { std::string partition_name = image->part_name + "_"s + slot; if (image->IsSecondary() && should_flash_in_userspace(partition_name)) { fp_->fb->DeletePartition(partition_name); } tasks.emplace_back(std::make_unique<DeleteTask>(fp_, partition_name)); } tasks.emplace_back(std::make_unique<ResizeTask>(fp_, image->part_name, "0", slot)); } } for (auto& i : tasks) { i->Run(); } FlashImages(os_images_); } void FlashAllTool::FlashImages(const std::vector<std::pair<const Image*, std::string>>& images) { for (const auto& [image, slot] : images) { fastboot_buffer buf; Loading fastboot/fastboot.h +3 −1 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ struct FlashingPlan { std::string slot_override; std::string current_slot; std::string secondary_slot; fastboot::FastBootDriver* fb; }; Loading @@ -94,6 +95,7 @@ void do_for_partitions(const std::string& part, const std::string& slot, std::string find_item(const std::string& item); void reboot_to_userspace_fastboot(); void syntax_error(const char* fmt, ...); std::string get_current_slot(); struct NetworkSerial { Socket::Protocol protocol; Loading @@ -103,7 +105,7 @@ struct NetworkSerial { Result<NetworkSerial, FastbootError> ParseNetworkSerial(const std::string& serial); bool supports_AB(); std::string GetPartitionName(const ImageEntry& entry, std::string& current_slot_); std::string GetPartitionName(const ImageEntry& entry, const std::string& current_slot_); void flash_partition_files(const std::string& partition, const std::vector<SparsePtr>& files); int64_t get_sparse_limit(int64_t size); std::vector<SparsePtr> resparse_file(sparse_file* s, int64_t max_size); Loading fastboot/task.cpp +87 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include "fastboot.h" #include "filesystem.h" #include "super_flash_helper.h" #include "util.h" using namespace std::string_literals; FlashTask::FlashTask(const std::string& _slot, const std::string& _pname, const std::string& _fname, Loading @@ -45,6 +46,20 @@ void FlashTask::Run() { do_for_partitions(pname_, slot_, flash, true); } std::string FlashTask::GetPartitionAndSlot() { auto slot = slot_; if (slot.empty()) { slot = get_current_slot(); } if (slot.empty()) { return pname_; } if (slot == "all") { LOG(FATAL) << "Cannot retrieve a singular name when using all slots"; } return pname_ + "_" + slot; } RebootTask::RebootTask(const FlashingPlan* fp) : fp_(fp){}; RebootTask::RebootTask(const FlashingPlan* fp, const std::string& reboot_target) : reboot_target_(reboot_target), fp_(fp){}; Loading Loading @@ -93,7 +108,7 @@ void FlashSuperLayoutTask::Run() { } std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize( FlashingPlan* fp, std::vector<ImageEntry>& os_images) { const FlashingPlan* fp, std::vector<ImageEntry>& os_images) { if (!supports_AB()) { LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device"; return nullptr; Loading Loading @@ -156,6 +171,77 @@ std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize( partition_size); } std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::InitializeFromTasks( const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>& tasks) { if (!supports_AB()) { LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device"; return nullptr; } if (fp->slot_override == "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"; } uint64_t partition_size; 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; } partition_size_str = fb_fix_numeric_var(partition_size_str); if (!android::base::ParseUint(partition_size_str, &partition_size)) { LOG(VERBOSE) << "Could not parse " << super_name << " size: " << partition_size_str; return nullptr; } std::unique_ptr<SuperFlashHelper> helper = std::make_unique<SuperFlashHelper>(*fp->source); if (!helper->Open(fd)) { return nullptr; } for (const auto& task : tasks) { if (auto flash_task = task->AsFlashTask()) { if (should_flash_in_userspace(flash_task->GetPartitionAndSlot())) { auto partition = flash_task->GetPartitionAndSlot(); if (!helper->AddPartition(partition, flash_task->GetImageName(), false)) { 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 auto& task) -> bool { if (auto flash_task = task->AsFlashTask()) { return helper->WillFlash(flash_task->GetPartitionAndSlot()); } else if (auto update_super_task = task->AsUpdateSuperTask()) { return true; } else if (auto reboot_task = task->AsRebootTask()) { return true; } return false; }; tasks.erase(std::remove_if(tasks.begin(), tasks.end(), remove_if_callback), tasks.end()); return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s), partition_size); } UpdateSuperTask::UpdateSuperTask(const FlashingPlan* fp) : fp_(fp) {} void UpdateSuperTask::Run() { Loading fastboot/task.h +23 −1 Original line number Diff line number Diff line Loading @@ -26,10 +26,20 @@ struct FlashingPlan; struct Image; using ImageEntry = std::pair<const Image*, std::string>; class FlashTask; class RebootTask; class UpdateSuperTask; class WipeTask; class Task { public: Task() = default; virtual void Run() = 0; virtual FlashTask* AsFlashTask() { return nullptr; } virtual RebootTask* AsRebootTask() { return nullptr; } virtual UpdateSuperTask* AsUpdateSuperTask() { return nullptr; } virtual WipeTask* AsWipeTask() { return nullptr; } virtual ~Task() = default; }; Loading @@ -37,7 +47,12 @@ class FlashTask : public Task { public: FlashTask(const std::string& slot, const std::string& pname, const std::string& fname, const bool apply_vbmeta); virtual FlashTask* AsFlashTask() override { return this; } std::string GetPartition() { return pname_; } std::string GetImageName() { return fname_; } std::string GetPartitionAndSlot(); std::string GetSlot() { return slot_; } void Run() override; private: Loading @@ -51,6 +66,7 @@ class RebootTask : public Task { public: RebootTask(const FlashingPlan* fp); RebootTask(const FlashingPlan* fp, const std::string& reboot_target); virtual RebootTask* AsRebootTask() override { return this; } void Run() override; private: Loading @@ -62,8 +78,10 @@ class FlashSuperLayoutTask : public Task { public: FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr<SuperFlashHelper> helper, SparsePtr sparse_layout, uint64_t super_size); static std::unique_ptr<FlashSuperLayoutTask> Initialize(FlashingPlan* fp, static std::unique_ptr<FlashSuperLayoutTask> Initialize(const FlashingPlan* fp, std::vector<ImageEntry>& os_images); static std::unique_ptr<FlashSuperLayoutTask> InitializeFromTasks( const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>& tasks); using ImageEntry = std::pair<const Image*, std::string>; void Run() override; Loading @@ -77,6 +95,8 @@ class FlashSuperLayoutTask : public Task { class UpdateSuperTask : public Task { public: UpdateSuperTask(const FlashingPlan* fp); virtual UpdateSuperTask* AsUpdateSuperTask() override { return this; } void Run() override; private: Loading Loading @@ -109,6 +129,8 @@ class DeleteTask : public Task { class WipeTask : public Task { public: WipeTask(const FlashingPlan* fp, const std::string& pname); virtual WipeTask* AsWipeTask() override { return this; } void Run() override; private: Loading Loading
fastboot/fastboot.cpp +262 −30 Original line number Diff line number Diff line Loading @@ -1284,7 +1284,7 @@ static void flash_buf(const std::string& partition, struct fastboot_buffer* buf, } } static std::string get_current_slot() { std::string get_current_slot() { std::string current_slot; if (fb->GetVar("current-slot", ¤t_slot) != fastboot::SUCCESS) return ""; if (current_slot[0] == '_') current_slot.erase(0, 1); Loading Loading @@ -1560,7 +1560,7 @@ static void CancelSnapshotIfNeeded() { } } std::string GetPartitionName(const ImageEntry& entry, std::string& current_slot) { std::string GetPartitionName(const ImageEntry& entry, const std::string& current_slot) { auto slot = entry.second; if (slot.empty()) { slot = current_slot; Loading @@ -1574,6 +1574,216 @@ std::string GetPartitionName(const ImageEntry& entry, std::string& current_slot) return entry.first->part_name + "_" + slot; } std::unique_ptr<FlashTask> ParseFlashCommand(const FlashingPlan* fp, const std::vector<std::string>& parts) { bool apply_vbmeta = false; std::string slot = fp->slot_override; std::string partition; std::string img_name; for (auto& part : parts) { if (part == "--apply-vbmeta") { apply_vbmeta = true; } else if (part == "--slot-other") { slot = fp->secondary_slot; } else if (partition.empty()) { partition = part; } else if (img_name.empty()) { img_name = part; } else { LOG(ERROR) << "unknown argument" << part << " in fastboot-info.txt. parts: " << android::base::Join(parts, " "); return nullptr; } } if (partition.empty()) { LOG(ERROR) << "partition name not found when parsing fastboot-info.txt. parts: " << android::base::Join(parts, " "); return nullptr; } if (img_name.empty()) { img_name = partition + ".img"; } return std::make_unique<FlashTask>(slot, partition, img_name, apply_vbmeta); } std::unique_ptr<RebootTask> ParseRebootCommand(const FlashingPlan* fp, const std::vector<std::string>& parts) { if (parts.empty()) return std::make_unique<RebootTask>(fp); if (parts.size() > 1) { LOG(ERROR) << "unknown arguments in reboot {target} in fastboot-info.txt: " << android::base::Join(parts, " "); return nullptr; } return std::make_unique<RebootTask>(fp, parts[0]); } std::unique_ptr<WipeTask> ParseWipeCommand(const FlashingPlan* fp, const std::vector<std::string>& parts) { if (parts.size() != 1) { LOG(ERROR) << "unknown arguments in erase {partition} in fastboot-info.txt: " << android::base::Join(parts, " "); return nullptr; } return std::make_unique<WipeTask>(fp, parts[0]); } std::unique_ptr<Task> ParseFastbootInfoLine(const FlashingPlan* fp, const std::vector<std::string>& command) { if (command.size() == 0) { return nullptr; } std::unique_ptr<Task> task; if (command[0] == "flash") { task = ParseFlashCommand(fp, std::vector<std::string>{command.begin() + 1, command.end()}); } else if (command[0] == "reboot") { task = ParseRebootCommand(fp, std::vector<std::string>{command.begin() + 1, command.end()}); } else if (command[0] == "update-super" && command.size() == 1) { task = std::make_unique<UpdateSuperTask>(fp); } else if (command[0] == "erase" && command.size() == 2) { task = ParseWipeCommand(fp, std::vector<std::string>{command.begin() + 1, command.end()}); } if (!task) { LOG(ERROR) << "unknown command parsing fastboot-info.txt line: " << android::base::Join(command, " "); } return task; } void AddResizeTasks(const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>* tasks) { // expands "resize-partitions" into individual commands : resize {os_partition_1}, resize // {os_partition_2}, etc. std::vector<std::unique_ptr<Task>> resize_tasks; std::optional<size_t> loc; for (size_t i = 0; i < tasks->size(); i++) { if (auto flash_task = tasks->at(i)->AsFlashTask()) { if (should_flash_in_userspace(flash_task->GetPartitionAndSlot())) { if (!loc) { loc = i; } resize_tasks.emplace_back(std::make_unique<ResizeTask>( fp, flash_task->GetPartition(), "0", fp->slot_override)); } } } // if no logical partitions (although should never happen since system will always need to be // flashed) if (!loc) { return; } tasks->insert(tasks->begin() + loc.value(), std::make_move_iterator(resize_tasks.begin()), std::make_move_iterator(resize_tasks.end())); return; } static bool IsNumber(const std::string& s) { bool period = false; for (size_t i = 0; i < s.length(); i++) { if (!isdigit(s[i])) { if (!period && s[i] == '.' && i != 0 && i != s.length() - 1) { period = true; } else { return false; } } } return true; } static bool IsIgnore(const std::vector<std::string>& command) { if (command[0][0] == '#') { return true; } return false; } bool CheckFastbootInfoRequirements(const std::vector<std::string>& command) { if (command.size() != 2) { LOG(ERROR) << "unknown characters in version info in fastboot-info.txt -> " << android::base::Join(command, " "); return false; } if (command[0] != "version") { LOG(ERROR) << "unknown characters in version info in fastboot-info.txt -> " << android::base::Join(command, " "); return false; } if (!IsNumber(command[1])) { LOG(ERROR) << "version number contains non-numeric values in fastboot-info.txt -> " << android::base::Join(command, " "); return false; } LOG(VERBOSE) << "Checking 'fastboot-info.txt version'"; if (command[1] < PLATFORM_TOOLS_VERSION) { return true; } LOG(ERROR) << "fasboot-info.txt version: " << command[1] << " not compatible with host tool version --> " << PLATFORM_TOOLS_VERSION; return false; } std::vector<std::unique_ptr<Task>> ParseFastbootInfo(const FlashingPlan* fp, const std::vector<std::string>& file) { std::vector<std::unique_ptr<Task>> tasks; // Get os_partitions that need to be resized for (auto& text : file) { std::vector<std::string> command = android::base::Tokenize(text, " "); if (IsIgnore(command)) { continue; } if (command.size() > 1 && command[0] == "version") { if (!CheckFastbootInfoRequirements(command)) { return {}; } continue; } else if (command.size() >= 2 && command[0] == "if-wipe") { if (!fp->wants_wipe) { continue; } command.erase(command.begin()); } auto task = ParseFastbootInfoLine(fp, command); if (!task) { LOG(ERROR) << "Error when parsing fastboot-info.txt, falling back on Hardcoded list: " << text; return {}; } tasks.emplace_back(std::move(task)); } if (auto flash_super_task = FlashSuperLayoutTask::InitializeFromTasks(fp, tasks)) { auto it = tasks.begin(); for (size_t i = 0; i < tasks.size(); i++) { if (auto flash_task = tasks[i]->AsFlashTask()) { if (should_flash_in_userspace(flash_task->GetPartitionAndSlot())) { break; } } if (auto wipe_task = tasks[i]->AsWipeTask()) { break; } it++; } tasks.insert(it, std::move(flash_super_task)); } else { AddResizeTasks(fp, &tasks); } return tasks; } std::vector<std::unique_ptr<Task>> ParseFastbootInfo(const FlashingPlan* fp, std::ifstream& fs) { if (!fs || fs.eof()) return {}; std::string text; std::vector<std::string> file; // Get os_partitions that need to be resized while (std::getline(fs, text)) { file.emplace_back(text); } return ParseFastbootInfo(fp, file); } class FlashAllTool { public: FlashAllTool(FlashingPlan* fp); Loading @@ -1586,6 +1796,7 @@ class FlashAllTool { 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 HardcodedFlash(); std::vector<ImageEntry> boot_images_; std::vector<ImageEntry> os_images_; Loading @@ -1611,38 +1822,23 @@ void FlashAllTool::Flash() { CancelSnapshotIfNeeded(); // First flash boot partitions. We allow this to happen either in userspace // or in bootloader fastboot. FlashImages(boot_images_); std::vector<std::unique_ptr<Task>> tasks; if (auto flash_super_task = FlashSuperLayoutTask::Initialize(fp_, os_images_)) { tasks.emplace_back(std::move(flash_super_task)); } else { // Sync the super partition. This will reboot to userspace fastboot if needed. tasks.emplace_back(std::make_unique<UpdateSuperTask>(fp_)); // 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_) { // Retrofit devices have two super partitions, named super_a and super_b. // On these devices, secondary slots must be flashed as physical // partitions (otherwise they would not mount on first boot). To enforce // this, we delete any logical partitions for the "other" slot. if (is_retrofit_device()) { std::string partition_name = image->part_name + "_"s + slot; if (image->IsSecondary() && is_logical(partition_name)) { fp_->fb->DeletePartition(partition_name); } tasks.emplace_back(std::make_unique<DeleteTask>(fp_, partition_name)); } tasks.emplace_back(std::make_unique<ResizeTask>(fp_, image->part_name, "0", slot)); } std::string path = find_item_given_name("fastboot-info.txt"); std::ifstream stream(path); std::vector<std::unique_ptr<Task>> tasks = ParseFastbootInfo(fp_, stream); if (tasks.empty()) { LOG(VERBOSE) << "Flashing from hardcoded images. fastboot-info.txt is empty or does not " "exist"; HardcodedFlash(); return; } LOG(VERBOSE) << "Flashing from fastboot-info.txt"; for (auto& task : tasks) { task->Run(); } FlashImages(os_images_); if (fp_->wants_wipe) { // avoid adding duplicate wipe tasks in fastboot main code. fp_->wants_wipe = false; } } void FlashAllTool::CheckRequirements() { Loading Loading @@ -1693,6 +1889,42 @@ void FlashAllTool::CollectImages() { } } void FlashAllTool::HardcodedFlash() { CollectImages(); // First flash boot partitions. We allow this to happen either in userspace // or in bootloader fastboot. FlashImages(boot_images_); std::vector<std::unique_ptr<Task>> tasks; if (auto flash_super_task = FlashSuperLayoutTask::Initialize(fp_, os_images_)) { tasks.emplace_back(std::move(flash_super_task)); } else { // Sync the super partition. This will reboot to userspace fastboot if needed. tasks.emplace_back(std::make_unique<UpdateSuperTask>(fp_)); // 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_) { // Retrofit devices have two super partitions, named super_a and super_b. // On these devices, secondary slots must be flashed as physical // partitions (otherwise they would not mount on first boot). To enforce // this, we delete any logical partitions for the "other" slot. if (is_retrofit_device()) { std::string partition_name = image->part_name + "_"s + slot; if (image->IsSecondary() && should_flash_in_userspace(partition_name)) { fp_->fb->DeletePartition(partition_name); } tasks.emplace_back(std::make_unique<DeleteTask>(fp_, partition_name)); } tasks.emplace_back(std::make_unique<ResizeTask>(fp_, image->part_name, "0", slot)); } } for (auto& i : tasks) { i->Run(); } FlashImages(os_images_); } void FlashAllTool::FlashImages(const std::vector<std::pair<const Image*, std::string>>& images) { for (const auto& [image, slot] : images) { fastboot_buffer buf; Loading
fastboot/fastboot.h +3 −1 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ struct FlashingPlan { std::string slot_override; std::string current_slot; std::string secondary_slot; fastboot::FastBootDriver* fb; }; Loading @@ -94,6 +95,7 @@ void do_for_partitions(const std::string& part, const std::string& slot, std::string find_item(const std::string& item); void reboot_to_userspace_fastboot(); void syntax_error(const char* fmt, ...); std::string get_current_slot(); struct NetworkSerial { Socket::Protocol protocol; Loading @@ -103,7 +105,7 @@ struct NetworkSerial { Result<NetworkSerial, FastbootError> ParseNetworkSerial(const std::string& serial); bool supports_AB(); std::string GetPartitionName(const ImageEntry& entry, std::string& current_slot_); std::string GetPartitionName(const ImageEntry& entry, const std::string& current_slot_); void flash_partition_files(const std::string& partition, const std::vector<SparsePtr>& files); int64_t get_sparse_limit(int64_t size); std::vector<SparsePtr> resparse_file(sparse_file* s, int64_t max_size); Loading
fastboot/task.cpp +87 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include "fastboot.h" #include "filesystem.h" #include "super_flash_helper.h" #include "util.h" using namespace std::string_literals; FlashTask::FlashTask(const std::string& _slot, const std::string& _pname, const std::string& _fname, Loading @@ -45,6 +46,20 @@ void FlashTask::Run() { do_for_partitions(pname_, slot_, flash, true); } std::string FlashTask::GetPartitionAndSlot() { auto slot = slot_; if (slot.empty()) { slot = get_current_slot(); } if (slot.empty()) { return pname_; } if (slot == "all") { LOG(FATAL) << "Cannot retrieve a singular name when using all slots"; } return pname_ + "_" + slot; } RebootTask::RebootTask(const FlashingPlan* fp) : fp_(fp){}; RebootTask::RebootTask(const FlashingPlan* fp, const std::string& reboot_target) : reboot_target_(reboot_target), fp_(fp){}; Loading Loading @@ -93,7 +108,7 @@ void FlashSuperLayoutTask::Run() { } std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize( FlashingPlan* fp, std::vector<ImageEntry>& os_images) { const FlashingPlan* fp, std::vector<ImageEntry>& os_images) { if (!supports_AB()) { LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device"; return nullptr; Loading Loading @@ -156,6 +171,77 @@ std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize( partition_size); } std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::InitializeFromTasks( const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>& tasks) { if (!supports_AB()) { LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device"; return nullptr; } if (fp->slot_override == "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"; } uint64_t partition_size; 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; } partition_size_str = fb_fix_numeric_var(partition_size_str); if (!android::base::ParseUint(partition_size_str, &partition_size)) { LOG(VERBOSE) << "Could not parse " << super_name << " size: " << partition_size_str; return nullptr; } std::unique_ptr<SuperFlashHelper> helper = std::make_unique<SuperFlashHelper>(*fp->source); if (!helper->Open(fd)) { return nullptr; } for (const auto& task : tasks) { if (auto flash_task = task->AsFlashTask()) { if (should_flash_in_userspace(flash_task->GetPartitionAndSlot())) { auto partition = flash_task->GetPartitionAndSlot(); if (!helper->AddPartition(partition, flash_task->GetImageName(), false)) { 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 auto& task) -> bool { if (auto flash_task = task->AsFlashTask()) { return helper->WillFlash(flash_task->GetPartitionAndSlot()); } else if (auto update_super_task = task->AsUpdateSuperTask()) { return true; } else if (auto reboot_task = task->AsRebootTask()) { return true; } return false; }; tasks.erase(std::remove_if(tasks.begin(), tasks.end(), remove_if_callback), tasks.end()); return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s), partition_size); } UpdateSuperTask::UpdateSuperTask(const FlashingPlan* fp) : fp_(fp) {} void UpdateSuperTask::Run() { Loading
fastboot/task.h +23 −1 Original line number Diff line number Diff line Loading @@ -26,10 +26,20 @@ struct FlashingPlan; struct Image; using ImageEntry = std::pair<const Image*, std::string>; class FlashTask; class RebootTask; class UpdateSuperTask; class WipeTask; class Task { public: Task() = default; virtual void Run() = 0; virtual FlashTask* AsFlashTask() { return nullptr; } virtual RebootTask* AsRebootTask() { return nullptr; } virtual UpdateSuperTask* AsUpdateSuperTask() { return nullptr; } virtual WipeTask* AsWipeTask() { return nullptr; } virtual ~Task() = default; }; Loading @@ -37,7 +47,12 @@ class FlashTask : public Task { public: FlashTask(const std::string& slot, const std::string& pname, const std::string& fname, const bool apply_vbmeta); virtual FlashTask* AsFlashTask() override { return this; } std::string GetPartition() { return pname_; } std::string GetImageName() { return fname_; } std::string GetPartitionAndSlot(); std::string GetSlot() { return slot_; } void Run() override; private: Loading @@ -51,6 +66,7 @@ class RebootTask : public Task { public: RebootTask(const FlashingPlan* fp); RebootTask(const FlashingPlan* fp, const std::string& reboot_target); virtual RebootTask* AsRebootTask() override { return this; } void Run() override; private: Loading @@ -62,8 +78,10 @@ class FlashSuperLayoutTask : public Task { public: FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr<SuperFlashHelper> helper, SparsePtr sparse_layout, uint64_t super_size); static std::unique_ptr<FlashSuperLayoutTask> Initialize(FlashingPlan* fp, static std::unique_ptr<FlashSuperLayoutTask> Initialize(const FlashingPlan* fp, std::vector<ImageEntry>& os_images); static std::unique_ptr<FlashSuperLayoutTask> InitializeFromTasks( const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>& tasks); using ImageEntry = std::pair<const Image*, std::string>; void Run() override; Loading @@ -77,6 +95,8 @@ class FlashSuperLayoutTask : public Task { class UpdateSuperTask : public Task { public: UpdateSuperTask(const FlashingPlan* fp); virtual UpdateSuperTask* AsUpdateSuperTask() override { return this; } void Run() override; private: Loading Loading @@ -109,6 +129,8 @@ class DeleteTask : public Task { class WipeTask : public Task { public: WipeTask(const FlashingPlan* fp, const std::string& pname); virtual WipeTask* AsWipeTask() override { return this; } void Run() override; private: Loading