| Daniel Zheng | 0d30718 | 2023-01-31 21:07:53 +0000 | [diff] [blame] | 1 | // | 
|  | 2 | // Copyright (C) 2023 The Android Open Source Project | 
|  | 3 | // | 
|  | 4 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | // you may not use this file except in compliance with the License. | 
|  | 6 | // You may obtain a copy of the License at | 
|  | 7 | // | 
|  | 8 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | // | 
|  | 10 | // Unless required by applicable law or agreed to in writing, software | 
|  | 11 | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | // See the License for the specific language governing permissions and | 
|  | 14 | // limitations under the License. | 
|  | 15 | // | 
|  | 16 | #include "task.h" | 
| Daniel Zheng | 47d70a5 | 2023-02-14 17:44:40 +0000 | [diff] [blame] | 17 | #include <iostream> | 
| Daniel Zheng | 71b3b43 | 2023-01-30 17:43:00 +0000 | [diff] [blame] | 18 | #include "fastboot.h" | 
| Daniel Zheng | 47d70a5 | 2023-02-14 17:44:40 +0000 | [diff] [blame] | 19 | #include "filesystem.h" | 
|  | 20 | #include "super_flash_helper.h" | 
| Daniel Zheng | 0d30718 | 2023-01-31 21:07:53 +0000 | [diff] [blame] | 21 |  | 
| Daniel Zheng | 47d70a5 | 2023-02-14 17:44:40 +0000 | [diff] [blame] | 22 | using namespace std::string_literals; | 
| Daniel Zheng | 0d30718 | 2023-01-31 21:07:53 +0000 | [diff] [blame] | 23 |  | 
| Daniel Zheng | 403657d | 2023-03-10 07:37:25 +0000 | [diff] [blame] | 24 | FlashTask::FlashTask(const std::string& slot, const std::string& pname, const bool apply_vbmeta) | 
|  | 25 | : pname_(pname), fname_(find_item(pname)), slot_(slot), apply_vbmeta_(apply_vbmeta) { | 
| Daniel Zheng | 0d30718 | 2023-01-31 21:07:53 +0000 | [diff] [blame] | 26 | if (fname_.empty()) die("cannot determine image filename for '%s'", pname_.c_str()); | 
|  | 27 | } | 
| Daniel Zheng | 403657d | 2023-03-10 07:37:25 +0000 | [diff] [blame] | 28 | FlashTask::FlashTask(const std::string& _slot, const std::string& _pname, const std::string& _fname, | 
|  | 29 | const bool apply_vbmeta) | 
|  | 30 | : pname_(_pname), fname_(_fname), slot_(_slot), apply_vbmeta_(apply_vbmeta) {} | 
| Daniel Zheng | 0d30718 | 2023-01-31 21:07:53 +0000 | [diff] [blame] | 31 |  | 
|  | 32 | void FlashTask::Run() { | 
|  | 33 | auto flash = [&](const std::string& partition) { | 
| Daniel Zheng | bc01da5 | 2023-02-23 03:25:52 +0000 | [diff] [blame] | 34 | if (should_flash_in_userspace(partition) && !is_userspace_fastboot()) { | 
| Daniel Zheng | 0d30718 | 2023-01-31 21:07:53 +0000 | [diff] [blame] | 35 | die("The partition you are trying to flash is dynamic, and " | 
|  | 36 | "should be flashed via fastbootd. Please run:\n" | 
|  | 37 | "\n" | 
|  | 38 | "    fastboot reboot fastboot\n" | 
|  | 39 | "\n" | 
|  | 40 | "And try again. If you are intentionally trying to " | 
|  | 41 | "overwrite a fixed partition, use --force."); | 
|  | 42 | } | 
| Daniel Zheng | 403657d | 2023-03-10 07:37:25 +0000 | [diff] [blame] | 43 | do_flash(partition.c_str(), fname_.c_str(), apply_vbmeta_); | 
| Daniel Zheng | 0d30718 | 2023-01-31 21:07:53 +0000 | [diff] [blame] | 44 | }; | 
|  | 45 | do_for_partitions(pname_, slot_, flash, true); | 
|  | 46 | } | 
| Daniel Zheng | 71b3b43 | 2023-01-30 17:43:00 +0000 | [diff] [blame] | 47 |  | 
| Daniel Zheng | 43987c9 | 2023-03-07 18:20:53 +0000 | [diff] [blame] | 48 | RebootTask::RebootTask(FlashingPlan* fp) : fp_(fp){}; | 
|  | 49 | RebootTask::RebootTask(FlashingPlan* fp, const std::string& reboot_target) | 
|  | 50 | : reboot_target_(reboot_target), fp_(fp){}; | 
| Daniel Zheng | 71b3b43 | 2023-01-30 17:43:00 +0000 | [diff] [blame] | 51 |  | 
|  | 52 | void RebootTask::Run() { | 
|  | 53 | if ((reboot_target_ == "userspace" || reboot_target_ == "fastboot")) { | 
|  | 54 | if (!is_userspace_fastboot()) { | 
|  | 55 | reboot_to_userspace_fastboot(); | 
| Daniel Zheng | bc01da5 | 2023-02-23 03:25:52 +0000 | [diff] [blame] | 56 | fp_->fb->WaitForDisconnect(); | 
| Daniel Zheng | 71b3b43 | 2023-01-30 17:43:00 +0000 | [diff] [blame] | 57 | } | 
|  | 58 | } else if (reboot_target_ == "recovery") { | 
| Daniel Zheng | bc01da5 | 2023-02-23 03:25:52 +0000 | [diff] [blame] | 59 | fp_->fb->RebootTo("recovery"); | 
|  | 60 | fp_->fb->WaitForDisconnect(); | 
| Daniel Zheng | 71b3b43 | 2023-01-30 17:43:00 +0000 | [diff] [blame] | 61 | } else if (reboot_target_ == "bootloader") { | 
| Daniel Zheng | bc01da5 | 2023-02-23 03:25:52 +0000 | [diff] [blame] | 62 | fp_->fb->RebootTo("bootloader"); | 
|  | 63 | fp_->fb->WaitForDisconnect(); | 
| Daniel Zheng | 71b3b43 | 2023-01-30 17:43:00 +0000 | [diff] [blame] | 64 | } else if (reboot_target_ == "") { | 
| Daniel Zheng | bc01da5 | 2023-02-23 03:25:52 +0000 | [diff] [blame] | 65 | fp_->fb->Reboot(); | 
|  | 66 | fp_->fb->WaitForDisconnect(); | 
| Daniel Zheng | 71b3b43 | 2023-01-30 17:43:00 +0000 | [diff] [blame] | 67 | } else { | 
|  | 68 | syntax_error("unknown reboot target %s", reboot_target_.c_str()); | 
|  | 69 | } | 
|  | 70 | } | 
| Daniel Zheng | 47d70a5 | 2023-02-14 17:44:40 +0000 | [diff] [blame] | 71 |  | 
|  | 72 | FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name, | 
|  | 73 | std::unique_ptr<SuperFlashHelper> helper, | 
|  | 74 | SparsePtr sparse_layout) | 
|  | 75 | : super_name_(super_name), | 
|  | 76 | helper_(std::move(helper)), | 
|  | 77 | sparse_layout_(std::move(sparse_layout)) {} | 
|  | 78 |  | 
|  | 79 | void FlashSuperLayoutTask::Run() { | 
|  | 80 | std::vector<SparsePtr> files; | 
|  | 81 | if (int limit = get_sparse_limit(sparse_file_len(sparse_layout_.get(), false, false))) { | 
|  | 82 | files = resparse_file(sparse_layout_.get(), limit); | 
|  | 83 | } else { | 
|  | 84 | files.emplace_back(std::move(sparse_layout_)); | 
|  | 85 | } | 
|  | 86 |  | 
|  | 87 | // Send the data to the device. | 
|  | 88 | flash_partition_files(super_name_, files); | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize( | 
|  | 92 | FlashingPlan* fp, std::vector<ImageEntry>& os_images) { | 
|  | 93 | if (!supports_AB()) { | 
|  | 94 | LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device"; | 
|  | 95 | return nullptr; | 
|  | 96 | } | 
|  | 97 | if (fp->slot == "all") { | 
|  | 98 | LOG(VERBOSE) << "Cannot optimize flashing super for all slots"; | 
|  | 99 | return nullptr; | 
|  | 100 | } | 
|  | 101 |  | 
|  | 102 | // Does this device use dynamic partitions at all? | 
|  | 103 | unique_fd fd = fp->source->OpenFile("super_empty.img"); | 
|  | 104 |  | 
|  | 105 | if (fd < 0) { | 
|  | 106 | LOG(VERBOSE) << "could not open super_empty.img"; | 
|  | 107 | return nullptr; | 
|  | 108 | } | 
|  | 109 |  | 
|  | 110 | std::string super_name; | 
|  | 111 | // Try to find whether there is a super partition. | 
|  | 112 | if (fp->fb->GetVar("super-partition-name", &super_name) != fastboot::SUCCESS) { | 
|  | 113 | super_name = "super"; | 
|  | 114 | } | 
|  | 115 | std::string partition_size_str; | 
|  | 116 |  | 
|  | 117 | if (fp->fb->GetVar("partition-size:" + super_name, &partition_size_str) != fastboot::SUCCESS) { | 
|  | 118 | LOG(VERBOSE) << "Cannot optimize super flashing: could not determine super partition"; | 
|  | 119 | return nullptr; | 
|  | 120 | } | 
|  | 121 | std::unique_ptr<SuperFlashHelper> helper = std::make_unique<SuperFlashHelper>(*fp->source); | 
|  | 122 | if (!helper->Open(fd)) { | 
|  | 123 | return nullptr; | 
|  | 124 | } | 
|  | 125 |  | 
|  | 126 | for (const auto& entry : os_images) { | 
|  | 127 | auto partition = GetPartitionName(entry, fp->current_slot); | 
|  | 128 | auto image = entry.first; | 
|  | 129 |  | 
|  | 130 | if (!helper->AddPartition(partition, image->img_name, image->optional_if_no_image)) { | 
|  | 131 | return nullptr; | 
|  | 132 | } | 
|  | 133 | } | 
|  | 134 |  | 
|  | 135 | auto s = helper->GetSparseLayout(); | 
|  | 136 | if (!s) return nullptr; | 
|  | 137 |  | 
|  | 138 | // Remove images that we already flashed, just in case we have non-dynamic OS images. | 
|  | 139 | auto remove_if_callback = [&](const ImageEntry& entry) -> bool { | 
|  | 140 | return helper->WillFlash(GetPartitionName(entry, fp->current_slot)); | 
|  | 141 | }; | 
|  | 142 | os_images.erase(std::remove_if(os_images.begin(), os_images.end(), remove_if_callback), | 
|  | 143 | os_images.end()); | 
|  | 144 | return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s)); | 
|  | 145 | } | 
| Daniel Zheng | 6bb8baa | 2023-03-03 07:14:23 +0000 | [diff] [blame] | 146 |  | 
| Daniel Zheng | 15e7783 | 2023-03-13 17:09:43 +0000 | [diff] [blame] | 147 | UpdateSuperTask::UpdateSuperTask(FlashingPlan* fp) : fp_(fp) {} | 
| Daniel Zheng | 6bb8baa | 2023-03-03 07:14:23 +0000 | [diff] [blame] | 148 |  | 
|  | 149 | void UpdateSuperTask::Run() { | 
|  | 150 | unique_fd fd = fp_->source->OpenFile("super_empty.img"); | 
|  | 151 | if (fd < 0) { | 
|  | 152 | return; | 
|  | 153 | } | 
|  | 154 | if (!is_userspace_fastboot()) { | 
|  | 155 | reboot_to_userspace_fastboot(); | 
|  | 156 | } | 
|  | 157 |  | 
|  | 158 | std::string super_name; | 
|  | 159 | if (fp_->fb->GetVar("super-partition-name", &super_name) != fastboot::RetCode::SUCCESS) { | 
|  | 160 | super_name = "super"; | 
|  | 161 | } | 
|  | 162 | fp_->fb->Download(super_name, fd, get_file_size(fd)); | 
|  | 163 |  | 
|  | 164 | std::string command = "update-super:" + super_name; | 
|  | 165 | if (fp_->wants_wipe) { | 
|  | 166 | command += ":wipe"; | 
|  | 167 | } | 
|  | 168 | fp_->fb->RawCommand(command, "Updating super partition"); | 
|  | 169 | } | 
| Daniel Zheng | 9f7bf7e | 2023-03-03 07:16:46 +0000 | [diff] [blame] | 170 |  | 
|  | 171 | ResizeTask::ResizeTask(FlashingPlan* fp, const std::string& pname, const std::string& size, | 
|  | 172 | const std::string& slot) | 
|  | 173 | : fp_(fp), pname_(pname), size_(size), slot_(slot) {} | 
|  | 174 |  | 
|  | 175 | void ResizeTask::Run() { | 
|  | 176 | auto resize_partition = [this](const std::string& partition) -> void { | 
|  | 177 | if (is_logical(partition)) { | 
|  | 178 | fp_->fb->ResizePartition(partition, size_); | 
|  | 179 | } | 
|  | 180 | }; | 
|  | 181 | do_for_partitions(pname_, slot_, resize_partition, false); | 
|  | 182 | } | 
| Daniel Zheng | aa70f4c | 2023-03-07 18:59:51 +0000 | [diff] [blame] | 183 |  | 
|  | 184 | DeleteTask::DeleteTask(FlashingPlan* fp, const std::string& pname) : fp_(fp), pname_(pname){}; | 
|  | 185 |  | 
|  | 186 | void DeleteTask::Run() { | 
|  | 187 | fp_->fb->DeletePartition(pname_); | 
| Daniel Zheng | 15e7783 | 2023-03-13 17:09:43 +0000 | [diff] [blame] | 188 | } | 
|  | 189 |  | 
|  | 190 | WipeTask::WipeTask(FlashingPlan* fp, const std::string& pname) : fp_(fp), pname_(pname){}; | 
|  | 191 |  | 
|  | 192 | void WipeTask::Run() { | 
|  | 193 | std::string partition_type; | 
|  | 194 | if (fp_->fb->GetVar("partition-type:" + pname_, &partition_type) != fastboot::SUCCESS) { | 
|  | 195 | return; | 
|  | 196 | } | 
|  | 197 | if (partition_type.empty()) return; | 
|  | 198 | fp_->fb->Erase(pname_); | 
|  | 199 | fb_perform_format(pname_, 1, partition_type, "", fp_->fs_options); | 
|  | 200 | } |