| 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 | } |