blob: d6f8ed791bce529a185ab436eca090f575597d70 [file] [log] [blame]
bigbiffad58e1b2020-07-06 20:24:34 -04001/*
2 Copyright 2013 to 2020 TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include <string>
20
21#include "data.hpp"
22#include "partitions.hpp"
23#include "twrp-functions.hpp"
24#include "twrpRepacker.hpp"
25#include "twcommon.h"
26#include "variables.h"
27#include "gui/gui.hpp"
28
29bool twrpRepacker::Prepare_Empty_Folder(const std::string& Folder) {
30 if (TWFunc::Path_Exists(Folder))
31 TWFunc::removeDir(Folder, false);
32 return TWFunc::Recursive_Mkdir(Folder);
33}
34
35bool twrpRepacker::Backup_Image_For_Repack(TWPartition* Part, const std::string& Temp_Folder_Destination,
36 const bool Create_Backup, const std::string& Backup_Name) {
37 if (!Part) {
38 LOGERR("Partition was null!\n");
39 return false;
40 }
41 if (!Prepare_Empty_Folder(Temp_Folder_Destination))
42 return false;
43 std::string target_image = Temp_Folder_Destination + "boot.img";
44 PartitionSettings part_settings;
45 part_settings.Part = Part;
46 if (Create_Backup) {
47 if (PartitionManager.Check_Backup_Name(Backup_Name, true, false) != 0)
48 return false;
49 DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, part_settings.Backup_Folder);
50 part_settings.Backup_Folder = part_settings.Backup_Folder + "/" + TWFunc::Get_Current_Date() + " " + Backup_Name + "/";
51 if (!TWFunc::Recursive_Mkdir(part_settings.Backup_Folder))
52 return false;
53 } else
54 part_settings.Backup_Folder = Temp_Folder_Destination;
55 part_settings.adbbackup = false;
56 part_settings.generate_digest = false;
57 part_settings.generate_md5 = false;
58 part_settings.PM_Method = PM_BACKUP;
59 part_settings.progress = NULL;
60 pid_t not_a_pid = 0;
61 if (!Part->Backup(&part_settings, &not_a_pid))
62 return false;
63 std::string backed_up_image = part_settings.Backup_Folder;
64 backed_up_image += Part->Get_Backup_FileName();
65 target_image = Temp_Folder_Destination + "boot.img";
66 if (Create_Backup) {
67 std::string source = part_settings.Backup_Folder + Part->Get_Backup_FileName();
68 if (TWFunc::copy_file(source, target_image, 0644) != 0) {
69 LOGERR("Failed to copy backup file '%s' to temp folder target '%s'\n", source.c_str(), target_image.c_str());
70 return false;
71 }
72 } else {
73 if (rename(backed_up_image.c_str(), target_image.c_str()) != 0) {
74 LOGERR("Failed to rename '%s' to '%s'\n", backed_up_image.c_str(), target_image.c_str());
75 return false;
76 }
77 }
78 original_ramdisk_format = Unpack_Image(target_image, Temp_Folder_Destination, false, false);
79 return !original_ramdisk_format.empty();
80}
81
82std::string twrpRepacker::Unpack_Image(const std::string& Source_Path, const std::string& Temp_Folder_Destination,
83 const bool Copy_Source, const bool Create_Destination) {
84 std::string txt_to_find = "RAMDISK_FMT";
85 if (Create_Destination) {
86 if (!Prepare_Empty_Folder(Temp_Folder_Destination))
87 return std::string();
88 }
89 if (Copy_Source) {
90 std::string destination = Temp_Folder_Destination + "/boot.img";
91 if (TWFunc::copy_file(Source_Path, destination, 0644))
92 return std::string();
93 }
nebrassyafb12ee2021-09-02 09:27:54 -040094 std::string command = "cd " + Temp_Folder_Destination + " && /system/bin/magiskboot unpack -h -n ";
bigbiffad58e1b2020-07-06 20:24:34 -040095 command = command + "'" + Source_Path +"'";
96
97 std::string magisk_unpack_output;
98 int ret;
99 if ((ret = TWFunc::Exec_Cmd(command, magisk_unpack_output, true)) != 0) {
100 LOGINFO("Error unpacking %s, ret: %d!\n", Source_Path.c_str(), ret);
101 gui_msg(Msg(msg::kError, "unpack_error=Error unpacking image."));
102 return std::string();
103 }
sekaiacga28a9f32024-02-08 16:17:31 +0800104 std::string ramdisk_format;
105 auto pos = magisk_unpack_output.find(txt_to_find);
106 if (pos != std::string::npos) {
107 auto start = magisk_unpack_output.find('[', pos + txt_to_find.size());
108 if (start != std::string::npos) {
109 auto end = magisk_unpack_output.find(']', start);
110 if (end != std::string::npos) {
111 ramdisk_format = std::move(magisk_unpack_output.substr(start + 1, end - start - 1));
112 }
113 }
114 }
bigbiffad58e1b2020-07-06 20:24:34 -0400115 return ramdisk_format;
116}
117
Darth98af7fe22024-01-18 20:00:44 +0000118static bool is_AB_for_repacker() {
119 std::string slot = android::base::GetProperty("ro.boot.slot_suffix", "");
120 if (slot.empty())
121 slot = android::base::GetProperty("ro.boot.slot", "");
122 return !slot.empty();
123}
bigbiffad58e1b2020-07-06 20:24:34 -0400124
Darth98af7fe22024-01-18 20:00:44 +0000125bool twrpRepacker::Repack_Image_And_Flash(const std::string& Target_Image, const struct Repack_Options_struct& Repack_Options) {
bigbiffad58e1b2020-07-06 20:24:34 -0400126 if (!TWFunc::Path_Exists("/system/bin/magiskboot")) {
127 LOGERR("Image repacking tool not present in this TWRP build!");
128 return false;
129 }
Darth98af7fe22024-01-18 20:00:44 +0000130
131 bool recompress = false;
132 bool is_vendor_boot = false;
133 bool is_vendor_boot_v4 = false;
134 std::string dest_partition = "/boot";
135 std::string ramdisk_cpio = "ramdisk.cpio";
136
137 #ifdef BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT
138 dest_partition = "/vendor_boot";
139 is_vendor_boot = true;
140 if (DataManager::GetIntValue("tw_boot_header_version") == 4) {
141 is_vendor_boot_v4 = true;
142 ramdisk_cpio = "vendor_ramdisk_recovery.cpio";
143 LOGINFO("Vendor_boot with v4 header\n");
144 } else {
145 LOGINFO("Vendor_boot with v3 header\n");
146 }
147 #else
148 // we shouldn't reach here, because of the code in twrpRepacker::Flash_Current_Twrp(); but if we do, then handle it
149 if (PartitionManager.Find_Partition_By_Path("/recovery") && is_AB_for_repacker()) {
150 dest_partition = "/recovery";
151 }
152 #endif
153
154 if (is_vendor_boot || is_vendor_boot_v4) {
155 // placeholder for any specific vendor_boot stuff;
156 // in the meantime, stop the compiler's complaints about unused variables
157 }
158
bigbiffad58e1b2020-07-06 20:24:34 -0400159 DataManager::SetProgress(0);
nebrassy45f66b22021-07-26 22:34:24 +0200160 PartitionManager.Update_System_Details();
Darth98af7fe22024-01-18 20:00:44 +0000161 TWPartition* part = PartitionManager.Find_Partition_By_Path(dest_partition);
bigbiffad58e1b2020-07-06 20:24:34 -0400162 if (part)
163 gui_msg(Msg("unpacking_image=Unpacking {1}...")(part->Get_Display_Name()));
164 else {
Darth98af7fe22024-01-18 20:00:44 +0000165 gui_msg(Msg(msg::kError, "unable_to_locate=Unable to locate {1}.")(dest_partition.c_str()));
bigbiffad58e1b2020-07-06 20:24:34 -0400166 return false;
167 }
168 if (!Backup_Image_For_Repack(part, REPACK_ORIG_DIR, Repack_Options.Backup_First, gui_lookup("repack", "Repack")))
169 return false;
170 DataManager::SetProgress(.25);
nebrassyac29e692021-05-20 13:03:30 +0200171 if (Repack_Options.Type == REPLACE_RAMDISK_UNPACKED) {
172 if (!Prepare_Empty_Folder(REPACK_NEW_DIR))
173 return false;
174 image_ramdisk_format = "gzip";
175 } else {
176 gui_msg(Msg("unpacking_image=Unpacking {1}...")(Target_Image));
177 image_ramdisk_format = Unpack_Image(Target_Image, REPACK_NEW_DIR, true);
178 }
bigbiffad58e1b2020-07-06 20:24:34 -0400179 if (image_ramdisk_format.empty())
180 return false;
181 DataManager::SetProgress(.5);
182 gui_msg(Msg("repacking_image=Repacking {1}...")(part->Get_Display_Name()));
183 std::string path = REPACK_NEW_DIR;
184 if (Repack_Options.Type == REPLACE_KERNEL) {
185 // When we replace the kernel, what we really do is copy the boot partition ramdisk into the new image's folder
Darth98af7fe22024-01-18 20:00:44 +0000186 if (TWFunc::copy_file(REPACK_ORIG_DIR + ramdisk_cpio, REPACK_NEW_DIR + ramdisk_cpio, 0644)) {
bigbiffad58e1b2020-07-06 20:24:34 -0400187 LOGERR("Failed to copy ramdisk\n");
188 return false;
189 }
nebrassyac29e692021-05-20 13:03:30 +0200190 } else if (Repack_Options.Type == REPLACE_RAMDISK_UNPACKED) {
Darth98af7fe22024-01-18 20:00:44 +0000191 if (TWFunc::copy_file(Target_Image, REPACK_ORIG_DIR + ramdisk_cpio, 0644)) {
nebrassyac29e692021-05-20 13:03:30 +0200192 LOGERR("Failed to copy ramdisk\n");
193 return false;
194 }
Darth98af7fe22024-01-18 20:00:44 +0000195 if (TWFunc::copy_file(Target_Image, REPACK_NEW_DIR + ramdisk_cpio, 0644)) {
nebrassyac29e692021-05-20 13:03:30 +0200196 LOGERR("Failed to copy ramdisk\n");
197 return false;
198 }
199 path = REPACK_ORIG_DIR;
bigbiffad58e1b2020-07-06 20:24:34 -0400200 } else if (Repack_Options.Type == REPLACE_RAMDISK) {
201 // Repack the ramdisk
Darth98af7fe22024-01-18 20:00:44 +0000202 if (TWFunc::copy_file(REPACK_NEW_DIR + ramdisk_cpio, REPACK_ORIG_DIR + ramdisk_cpio, 0644)) {
bigbiffad58e1b2020-07-06 20:24:34 -0400203 LOGERR("Failed to copy ramdisk\n");
204 return false;
205 }
206 path = REPACK_ORIG_DIR;
207 } else {
208 LOGERR("Invalid repacking options specified\n");
209 return false;
210 }
211 if (Repack_Options.Disable_Verity)
212 LOGERR("Disabling verity is not implemented yet\n");
213 if (Repack_Options.Disable_Force_Encrypt)
214 LOGERR("Disabling force encrypt is not implemented yet\n");
215 std::string command = "cd " + path + " && /system/bin/magiskboot repack ";
216 if (original_ramdisk_format != image_ramdisk_format) {
bigbiffad58e1b2020-07-06 20:24:34 -0400217 recompress = true;
218 }
219
220 command += path + "boot.img";
221
222 std::string orig_compressed_image(REPACK_ORIG_DIR);
Darth98af7fe22024-01-18 20:00:44 +0000223 orig_compressed_image += ramdisk_cpio;
bigbiffad58e1b2020-07-06 20:24:34 -0400224 std::string copy_compressed_image(REPACK_ORIG_DIR);
225 copy_compressed_image += "ramdisk-1.cpio";
226
227 if (recompress) {
nebrassy73782542021-08-07 00:37:30 +0200228 std::string decompress_cmd = "/system/bin/magiskboot decompress " + orig_compressed_image + " " + copy_compressed_image;
229 if (TWFunc::Exec_Cmd(decompress_cmd) != 0) {
bigbiffad58e1b2020-07-06 20:24:34 -0400230 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
231 return false;
232 }
233 std::rename(copy_compressed_image.c_str(), orig_compressed_image.c_str());
234 }
235
236 if (TWFunc::Exec_Cmd(command) != 0) {
237 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
238 return false;
239 }
240
241 DataManager::SetProgress(.75);
242 std::string file = "new-boot.img";
Darth98af7fe22024-01-18 20:00:44 +0000243 DataManager::SetValue("tw_flash_partition", dest_partition + ";");
bigbiffad58e1b2020-07-06 20:24:34 -0400244 if (!PartitionManager.Flash_Image(path, file)) {
245 LOGINFO("Error flashing new image\n");
246 return false;
247 }
248 DataManager::SetProgress(1);
249 TWFunc::removeDir(REPACK_ORIG_DIR, false);
Darth9c9cc4ac2022-02-03 22:17:49 +0000250 if (part->Is_SlotSelect()) {
251 if (Repack_Options.Type == REPLACE_RAMDISK || Repack_Options.Type == REPLACE_RAMDISK_UNPACKED) {
252 LOGINFO("Switching slots to flash ramdisk to both partitions\n");
253 string Current_Slot = PartitionManager.Get_Active_Slot_Display();
254 if (Current_Slot == "A")
255 PartitionManager.Override_Active_Slot("B");
256 else
257 PartitionManager.Override_Active_Slot("A");
258 DataManager::SetProgress(.25);
259 if (!Backup_Image_For_Repack(part, REPACK_ORIG_DIR, Repack_Options.Backup_First, gui_lookup("repack", "Repack")))
260 return false;
Darth98af7fe22024-01-18 20:00:44 +0000261 if (TWFunc::copy_file(REPACK_NEW_DIR + ramdisk_cpio, REPACK_ORIG_DIR + ramdisk_cpio, 0644)) {
Darth9c9cc4ac2022-02-03 22:17:49 +0000262 LOGERR("Failed to copy ramdisk\n");
263 return false;
264 }
265 path = REPACK_ORIG_DIR;
266 std::string command = "cd " + path + " && /system/bin/magiskboot repack ";
bigbiffad58e1b2020-07-06 20:24:34 -0400267
Darth9c9cc4ac2022-02-03 22:17:49 +0000268 if (original_ramdisk_format != image_ramdisk_format) {
269 recompress = true;
270 }
271 command += path + "boot.img";
bigbiffad58e1b2020-07-06 20:24:34 -0400272
Darth9c9cc4ac2022-02-03 22:17:49 +0000273 if (recompress) {
274 std::string decompress_cmd = "/system/bin/magiskboot decompress " + orig_compressed_image + " " + copy_compressed_image;
275 if (TWFunc::Exec_Cmd(decompress_cmd) != 0) {
276 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
277 return false;
278 }
279 std::rename(copy_compressed_image.c_str(), orig_compressed_image.c_str());
280 }
281
282 if (TWFunc::Exec_Cmd(command) != 0) {
bigbiffad58e1b2020-07-06 20:24:34 -0400283 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
284 return false;
285 }
Darth9c9cc4ac2022-02-03 22:17:49 +0000286 DataManager::SetProgress(.75);
287 std::string file = "new-boot.img";
Darth98af7fe22024-01-18 20:00:44 +0000288 DataManager::SetValue("tw_flash_partition", dest_partition + ";");
Darth9c9cc4ac2022-02-03 22:17:49 +0000289 if (!PartitionManager.Flash_Image(path, file)) {
290 LOGINFO("Error flashing new image\n");
291 return false;
292 }
293 DataManager::SetProgress(1);
294 TWFunc::removeDir(REPACK_ORIG_DIR, false);
bigbiffad58e1b2020-07-06 20:24:34 -0400295 }
Darth9c9cc4ac2022-02-03 22:17:49 +0000296 }
bigbiffd1e556a2021-08-07 14:34:06 -0400297 TWFunc::removeDir(REPACK_NEW_DIR, false);
Darth98af7fe22024-01-18 20:00:44 +0000298 if (dest_partition == "/boot")
299 gui_msg(Msg(msg::kWarning, "repack_overwrite_warning=If device was previously rooted, then root has been overwritten and will need to be reinstalled."));
nebrassy07c4b902021-11-21 03:32:47 +0100300 string Current_Slot = PartitionManager.Get_Active_Slot_Display();
Darth98af7fe22024-01-18 20:00:44 +0000301 if (Current_Slot == "A")
302 PartitionManager.Override_Active_Slot("B");
303 else
304 PartitionManager.Override_Active_Slot("A");
bigbiffd1e556a2021-08-07 14:34:06 -0400305 return true;
bigbiffad58e1b2020-07-06 20:24:34 -0400306}
nebrassyac29e692021-05-20 13:03:30 +0200307
308bool twrpRepacker::Flash_Current_Twrp() {
Darth98af7fe22024-01-18 20:00:44 +0000309 // A/B with dedicated recovery partition
310 std::string slot = android::base::GetProperty("ro.boot.slot_suffix", "");
311 if (slot.empty())
312 slot = android::base::GetProperty("ro.boot.slot", "");
313 if (!slot.empty() && PartitionManager.Find_Partition_By_Path("/recovery")) {
314 std::string root,src, dest;
315 std::string dest_partition = "/recovery";
316 root = "/dev/block/bootdevice/by-name" + dest_partition;
317 if (slot == "_a" || slot == "a") {
318 src = root + "_a";
319 dest= root + "_b";
320 }
321 else {
322 src = root + "_b";
323 dest= root + "_a";
324 }
325 PartitionManager.Unlock_Block_Partitions();
326
327 // only copy the relevant active slot to the inactive slot, on the basis that the recovery currently running
328 // in the active slot can simply be copied over to the inactive slot, so that both have the same recovery image
329 std::string command = "dd bs=1048576 if=" + src + " of=" + dest;
330 LOGINFO("Command=%s\n", command.c_str());
331
332 if (TWFunc::Exec_Cmd(command) != 0) {
333 LOGERR("Failed to flash the %s image\n", dest_partition.c_str());
334 return false;
335 }
336 else {
337 gui_print("Finished flashing the %s image\n", dest_partition.c_str());
338 return true;
339 }
340 // if we reach here, something is awry - bale out
341 return false;
342 }
343
344 if (!TWFunc::Path_Exists("/ramdisk-files.txt")) {
nebrassyac29e692021-05-20 13:03:30 +0200345 LOGERR("can not find ramdisk-files.txt");
346 return false;
sekaiacg067c00c2022-06-23 19:23:11 +0800347 }
348 if (PartitionManager.Is_Mounted_By_Path("/vendor") && !PartitionManager.UnMount_By_Path("/vendor", false)) {
349 // Try to force umount /vendor
350 PartitionManager.UnMount_By_Path("/vendor", false, MNT_FORCE|MNT_DETACH);
351 }
352 Repack_Options_struct Repack_Options;
353 Repack_Options.Disable_Verity = false;
354 Repack_Options.Disable_Force_Encrypt = false;
355 Repack_Options.Type = REPLACE_RAMDISK_UNPACKED;
356 Repack_Options.Backup_First = DataManager::GetIntValue("tw_repack_backup_first") != 0;
357 std::string verifyfiles = "cd / && sha256sum --status -c ramdisk-files.sha256sum";
358 if (TWFunc::Exec_Cmd(verifyfiles) != 0) {
nebrassyac29e692021-05-20 13:03:30 +0200359 gui_msg(Msg(msg::kError, "modified_ramdisk_error=ramdisk files have been modified, unable to create ramdisk to flash, fastboot boot twrp and try this option again or use the Install Recovery Ramdisk option."));
sekaiacg067c00c2022-06-23 19:23:11 +0800360 return false;
361 }
362 std::string command = "cd / && /system/bin/cpio -H newc -o < ramdisk-files.txt > /tmp/currentramdisk.cpio && /system/bin/gzip -f /tmp/currentramdisk.cpio";
363 if (TWFunc::Exec_Cmd(command) != 0) {
364 gui_msg(Msg(msg::kError, "create_ramdisk_error=failed to create ramdisk to flash."));
365 return false;
366 }
367 if (!Repack_Image_And_Flash("/tmp/currentramdisk.cpio.gz", Repack_Options))
368 return false;
369 else
370 return true;
nebrassyac29e692021-05-20 13:03:30 +0200371}