diff options
-rwxr-xr-x | data.cpp | 7 | ||||
-rwxr-xr-x | gui/action.cpp | 94 | ||||
-rw-r--r-- | gui/objects.hpp | 2 | ||||
-rwxr-xr-x | gui/theme/common/landscape.xml | 169 | ||||
-rwxr-xr-x | gui/theme/common/languages/en.xml | 22 | ||||
-rwxr-xr-x | gui/theme/common/portrait.xml | 169 | ||||
-rwxr-xr-x | gui/theme/common/watch.xml | 150 | ||||
-rwxr-xr-x | openrecoveryscript.cpp | 2 | ||||
-rwxr-xr-x | partitionmanager.cpp | 190 | ||||
-rw-r--r-- | partitions.hpp | 22 | ||||
-rw-r--r-- | prebuilt/Android.mk | 9 | ||||
-rwxr-xr-x | twrp-functions.cpp | 7 |
12 files changed, 821 insertions, 22 deletions
@@ -916,7 +916,12 @@ void DataManager::SetDefaultValues() mData.SetValue("tw_app_install_status", "0"); // 0 = no status, 1 = not installed, 2 = already installed #endif - mData.SetValue("tw_enable_adb_backup", "0"); + mData.SetValue("tw_enable_adb_backup", "0"); + + if (TWFunc::Path_Exists("/sbin/magiskboot")) + mConst.SetValue("tw_has_repack_tools", "1"); + else + mConst.SetValue("tw_has_repack_tools", "0"); pthread_mutex_unlock(&m_valuesLock); } diff --git a/gui/action.cpp b/gui/action.cpp index 4b644a9b4..c4e78cf26 100755 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -231,6 +231,8 @@ GUIAction::GUIAction(xml_node<>* node) ADD_ACTION(twcmd); ADD_ACTION(setbootslot); ADD_ACTION(installapp); + ADD_ACTION(repackimage); + ADD_ACTION(fixabrecoverybootloop); } // First, get the action @@ -1196,7 +1198,7 @@ int GUIAction::nandroid(std::string arg) string Backup_Name; DataManager::GetValue(TW_BACKUP_NAME, Backup_Name); string auto_gen = gui_lookup("auto_generate", "(Auto Generate)"); - if (Backup_Name == auto_gen || Backup_Name == gui_lookup("curr_date", "(Current Date)") || Backup_Name == "0" || Backup_Name == "(" || PartitionManager.Check_Backup_Name(true) == 0) { + if (Backup_Name == auto_gen || Backup_Name == gui_lookup("curr_date", "(Current Date)") || Backup_Name == "0" || Backup_Name == "(" || PartitionManager.Check_Backup_Name(Backup_Name, true, true) == 0) { ret = PartitionManager.Run_Backup(false); DataManager::SetValue("tw_encrypt_backup", 0); // reset value so we don't encrypt every subsequent backup if (!PartitionManager.stop_backup.get_value()) { @@ -1472,7 +1474,9 @@ int GUIAction::checkbackupname(std::string arg __unused) if (simulate) { simulate_progress_bar(); } else { - op_status = PartitionManager.Check_Backup_Name(true); + string Backup_Name; + DataManager::GetValue(TW_BACKUP_NAME, Backup_Name); + op_status = PartitionManager.Check_Backup_Name(Backup_Name, true, true); if (op_status != 0) op_status = 1; } @@ -2053,3 +2057,89 @@ exit: operation_end(0); return 0; } + +int GUIAction::repackimage(std::string arg __unused) +{ + int op_status = 1; + operation_start("Repack Image"); + if (!simulate) + { + std::string path = DataManager::GetStrValue("tw_filename"); + Repack_Options_struct Repack_Options; + Repack_Options.Disable_Verity = false; + Repack_Options.Disable_Force_Encrypt = false; + Repack_Options.Backup_First = DataManager::GetIntValue("tw_repack_backup_first") != 0; + if (DataManager::GetIntValue("tw_repack_kernel") == 1) + Repack_Options.Type = REPLACE_KERNEL; + else + Repack_Options.Type = REPLACE_RAMDISK; + if (!PartitionManager.Repack_Images(path, Repack_Options)) + goto exit; + } else + simulate_progress_bar(); + op_status = 0; +exit: + operation_end(op_status); + return 0; +} + +int GUIAction::fixabrecoverybootloop(std::string arg __unused) +{ + int op_status = 1; + operation_start("Repack Image"); + if (!simulate) + { + if (!TWFunc::Path_Exists("/sbin/magiskboot")) { + LOGERR("Image repacking tool not present in this TWRP build!"); + goto exit; + } + DataManager::SetProgress(0); + TWPartition* part = PartitionManager.Find_Partition_By_Path("/boot"); + if (part) + gui_msg(Msg("unpacking_image=Unpacking {1}...")(part->Display_Name)); + else { + gui_msg(Msg(msg::kError, "unable_to_locate=Unable to locate {1}.")("/boot")); + goto exit; + } + if (!PartitionManager.Prepare_Repack(part, REPACK_ORIG_DIR, DataManager::GetIntValue("tw_repack_backup_first") != 0, gui_lookup("repack", "Repack"))) + goto exit; + DataManager::SetProgress(.25); + gui_msg("fixing_recovery_loop_patch=Patching kernel..."); + std::string command = "cd " REPACK_ORIG_DIR " && /sbin/magiskboot --hexpatch kernel 77616E745F696E697472616D667300 736B69705F696E697472616D667300"; + if (TWFunc::Exec_Cmd(command) != 0) { + gui_msg(Msg(msg::kError, "fix_recovery_loop_patch_error=Error patching kernel.")); + goto exit; + } + std::string header_path = REPACK_ORIG_DIR; + header_path += "header"; + if (TWFunc::Path_Exists(header_path)) { + command = "cd " REPACK_ORIG_DIR " && sed -i \"s|$(grep '^cmdline=' header | cut -d= -f2-)|$(grep '^cmdline=' header | cut -d= -f2- | sed -e 's/skip_override//' -e 's/ */ /g' -e 's/[ \t]*$//')|\" header"; + if (TWFunc::Exec_Cmd(command) != 0) { + gui_msg(Msg(msg::kError, "fix_recovery_loop_patch_error=Error patching kernel.")); + goto exit; + } + } + DataManager::SetProgress(.5); + gui_msg(Msg("repacking_image=Repacking {1}...")(part->Display_Name)); + command = "cd " REPACK_ORIG_DIR " && /sbin/magiskboot --repack " REPACK_ORIG_DIR "boot.img"; + if (TWFunc::Exec_Cmd(command) != 0) { + gui_msg(Msg(msg::kError, "repack_error=Error repacking image.")); + goto exit; + } + DataManager::SetProgress(.75); + std::string path = REPACK_ORIG_DIR; + std::string file = "new-boot.img"; + DataManager::SetValue("tw_flash_partition", "/boot;"); + if (!PartitionManager.Flash_Image(path, file)) { + LOGINFO("Error flashing new image\n"); + goto exit; + } + DataManager::SetProgress(1); + TWFunc::removeDir(REPACK_ORIG_DIR, false); + } else + simulate_progress_bar(); + op_status = 0; +exit: + operation_end(op_status); + return 0; +} diff --git a/gui/objects.hpp b/gui/objects.hpp index 630cf7102..2e306e0f7 100644 --- a/gui/objects.hpp +++ b/gui/objects.hpp @@ -367,6 +367,8 @@ protected: int twcmd(std::string arg); int setbootslot(std::string arg); int installapp(std::string arg); + int repackimage(std::string arg); + int fixabrecoverybootloop(std::string arg); int simulate; }; diff --git a/gui/theme/common/landscape.xml b/gui/theme/common/landscape.xml index a3e6ed82a..bb9878fd6 100755 --- a/gui/theme/common/landscape.xml +++ b/gui/theme/common/landscape.xml @@ -3398,6 +3398,41 @@ <action function="page">confirm_action</action> </actions> </listitem> + <listitem name="{@install_twrp_ramdisk=Install Recovery Ramdisk}"> + <conditions> + <condition var1="tw_has_boot_slots" var2="1"/> + <condition var1="tw_has_repack_tools" var2="1"/> + </conditions> + <actions> + <action function="set">tw_repack_kernel=0</action> + <action function="page">repackselect</action> + </actions> + </listitem> + <listitem name="{@install_kernel=Install Kernel}"> + <conditions> + <condition var1="tw_has_boot_slots" var2="1"/> + <condition var1="tw_has_repack_tools" var2="1"/> + </conditions> + <actions> + <action function="set">tw_repack_kernel=1</action> + <action function="page">repackselect</action> + </actions> + </listitem> + <listitem name="{@fix_recovery_loop=Fix Recovery Bootloop}"> + <conditions> + <condition var1="tw_has_boot_slots" var2="1"/> + <condition var1="tw_has_repack_tools" var2="1"/> + </conditions> + <actions> + <action function="set">tw_back=advanced</action> + <action function="set">tw_action=fixabrecoverybootloop</action> + <action function="set">tw_text1={@fix_recovery_loop_confirm=Fix Recovery Bootloop?}</action> + <action function="set">tw_action_text1={@fixing_recovery_loop=Fixing Recovery Bootloop...}</action> + <action function="set">tw_complete_text1={@fix_recovery_loop_complete=Fix Recovery Bootloop Complete}</action> + <action function="set">tw_slider_text={@swipe_to_confirm=Swipe to Confirm}</action> + <action function="page">confirm_action</action> + </actions> + </listitem> </listbox> <action> @@ -3657,6 +3692,140 @@ </action> </page> + <page name="repackselect"> + <template name="page"/> + + <text style="text_l"> + <placement x="%col1_x_header%" y="%row3_header_y%"/> + <text>{@repack_image_hdr=Select Image}</text> + </text> + + <text style="text_m"> + <placement x="%col1_x_header%" y="%row4_header_y%"/> + <text>{@select_file_from_storage=Select File from %tw_storage_display_name% (%tw_storage_free_size% MB)}</text> + </text> + + <template name="sort_options"/> + + <fileselector> + <placement x="%col1_x_left%" y="%row1a_y%" w="%content_quarter_width%" h="%fileselector_filemanager_height%"/> + <text>%tw_zip_location%</text> + <filter extn=".img" folders="1" files="1"/> + <path name="tw_zip_location" default="/sdcard"/> + <data name="tw_filename"/> + <selection name="tw_file"/> + </fileselector> + + <button style="main_button_half_width_low"> + <placement x="%col_button_right%" y="%row16a_y%"/> + <text>{@select_storage_btn=Select Storage}</text> + <actions> + <action function="set">tw_back=install</action> + <action function="overlay">select_storage</action> + </actions> + </button> + + <action> + <conditions> + <condition var1="tw_filename" op="modified"/> + </conditions> + <action function="page">repackconfirm</action> + </action> + + <action> + <touch key="back"/> + <action function="page">advanced</action> + </action> + + <action> + <touch key="home"/> + <action function="page">main</action> + </action> + </page> + + <page name="repackconfirm"> + <template name="page"/> + + <text style="text_l"> + <condition var1="tw_repack_kernel" var2="1"/> + <placement x="%col1_x_header%" y="%row3_header_y%"/> + <text>{@repack_kernel_confirm_hdr=Install Kernel}</text> + </text> + + <text style="text_l"> + <condition var1="tw_repack_kernel" var2="0"/> + <placement x="%col1_x_header%" y="%row3_header_y%"/> + <text>{@repack_ramdisk_confirm_hdr=Install Recovery}</text> + </text> + + <text style="text_m"> + <condition var1="tw_repack_kernel" var2="1"/> + <placement x="%col1_x_header%" y="%row4_header_y%"/> + <text>{@repack_kernel_confirm=Install Kernel?}</text> + </text> + + <text style="text_m"> + <condition var1="tw_repack_kernel" var2="0"/> + <placement x="%col1_x_header%" y="%row4_header_y%"/> + <text>{@repack_ramdisk_confirm=Install Recovery?}</text> + </text> + + <text style="text_m_accent"> + <placement x="%indent%" y="%row2_y%"/> + <text>{@folder=Folder:}</text> + </text> + + <text style="text_m"> + <placement x="%indent%" y="%row3_y%"/> + <text>%tw_zip_location%</text> + </text> + + <text style="text_m_accent"> + <placement x="%indent%" y="%row4_y%"/> + <text>{@file=File:}</text> + </text> + + <text style="text_m"> + <placement x="%indent%" y="%row5_y%"/> + <text>%tw_file%</text> + </text> + + <checkbox> + <placement x="%indent%" y="%row7_y%"/> + <text>{@repack_backup_first=Back up existing image first}</text> + <data variable="tw_repack_backup_first"/> + </checkbox> + + <button style="main_button_half_width"> + <placement x="%col1_x_left%" y="%row15a_y%"/> + <text>{@install_cancel=Do not Install}</text> + <action function="page">repackselect</action> + </button> + + <slider style="slider_centered"> + <text>{@swipe_to_install=Swipe to Install}</text> + <actions> + <action function="set">tw_back=advanced</action> + <action function="set">tw_action=repackimage</action> + <action function="set">tw_action_param=/boot</action> + <action function="set">tw_action_text1={@installing=Installing...}</action> + <action function="set">tw_action_text2=</action> + <action function="set">tw_complete_text1={@install_complete=Install Complete}</action> + <action function="page">action_page</action> + </actions> + </slider> + + <action> + <touch key="back"/> + <action function="page">repackselect</action> + </action> + + <action> + <touch key="home"/> + <action function="page">main</action> + </action> + </page> + <page name="lock"> <background color="%semi_transparent%"/> diff --git a/gui/theme/common/languages/en.xml b/gui/theme/common/languages/en.xml index e61f6c0a8..7a6012074 100755 --- a/gui/theme/common/languages/en.xml +++ b/gui/theme/common/languages/en.xml @@ -486,6 +486,28 @@ <string name="install_cancel">Do Not Install</string> <string name="sel_storage_list">Select Storage</string> <string name="ok_btn">OK</string> + <string name="install_twrp_ramdisk">Install Recovery Ramdisk</string> + <string name="install_kernel">Install Kernel</string> + <string name="repack_kernel_confirm_hdr">Install Kernel</string> + <string name="repack_ramdisk_confirm_hdr">Install Recovery</string> + <string name="repack_kernel_confirm">Install Kernel?</string> + <string name="repack_ramdisk_confirm">Install Recovery?</string> + <string name="repack_backup_first">Back up existing image first</string> + <string name="repack">Repack</string> + <string name="swipe_to_install">Swipe to Install</string> + <string name="installing">Installing...</string> + <string name="install_complete">Install Complete</string> + <string name="unpack_error">Error unpacking image.</string> + <string name="repack_error">Error repacking image.</string> + <string name="unpacking_image">Unpacking {1}...</string> + <string name="repacking_image">Repacking {1}...</string> + <string name="repack_image_hdr">Select Image</string> + <string name="fix_recovery_loop">Fix Recovery Bootloop</string> + <string name="fix_recovery_loop_confirm">Fix Recovery Bootloop?</string> + <string name="fixing_recovery_loop">Fixing Recovery Bootloop...</string> + <string name="fix_recovery_loop_complete">Fix Recovery Bootloop Complete</string> + <string name="fixing_recovery_loop_patch">Patching kernel...</string> + <string name="fix_recovery_loop_patch_error">Error patching kernel.</string> <!-- Various console messages - these consist of user displayed messages, oftentimes errors --> <string name="no_kernel_selinux">Kernel does not have support for reading SELinux contexts.</string> diff --git a/gui/theme/common/portrait.xml b/gui/theme/common/portrait.xml index c993225bb..691f149e0 100755 --- a/gui/theme/common/portrait.xml +++ b/gui/theme/common/portrait.xml @@ -3559,6 +3559,41 @@ <action function="page">confirm_action</action> </actions> </listitem> + <listitem name="{@install_twrp_ramdisk=Install Recovery Ramdisk}"> + <conditions> + <condition var1="tw_has_boot_slots" var2="1"/> + <condition var1="tw_has_repack_tools" var2="1"/> + </conditions> + <actions> + <action function="set">tw_repack_kernel=0</action> + <action function="page">repackselect</action> + </actions> + </listitem> + <listitem name="{@install_kernel=Install Kernel}"> + <conditions> + <condition var1="tw_has_boot_slots" var2="1"/> + <condition var1="tw_has_repack_tools" var2="1"/> + </conditions> + <actions> + <action function="set">tw_repack_kernel=1</action> + <action function="page">repackselect</action> + </actions> + </listitem> + <listitem name="{@fix_recovery_loop=Fix Recovery Bootloop}"> + <conditions> + <condition var1="tw_has_boot_slots" var2="1"/> + <condition var1="tw_has_repack_tools" var2="1"/> + </conditions> + <actions> + <action function="set">tw_back=advanced</action> + <action function="set">tw_action=fixabrecoverybootloop</action> + <action function="set">tw_text1={@fix_recovery_loop_confirm=Fix Recovery Bootloop?}</action> + <action function="set">tw_action_text1={@fixing_recovery_loop=Fixing Recovery Bootloop...}</action> + <action function="set">tw_complete_text1={@fix_recovery_loop_complete=Fix Recovery Bootloop Complete}</action> + <action function="set">tw_slider_text={@swipe_to_confirm=Swipe to Confirm}</action> + <action function="page">confirm_action</action> + </actions> + </listitem> </listbox> <action> @@ -3821,6 +3856,140 @@ </action> </page> + <page name="repackselect"> + <template name="page"/> + + <text style="text_l"> + <placement x="%col1_x_header%" y="%row3_header_y%"/> + <text>{@repack_image_hdr=Select Image}</text> + </text> + + <text style="text_m"> + <placement x="%col1_x_header%" y="%row4_header_y%"/> + <text>{@select_file_from_storage=Select File from %tw_storage_display_name% (%tw_storage_free_size% MB)}</text> + </text> + + <template name="sort_options"/> + + <fileselector> + <placement x="%indent%" y="%row3_y%" w="%content_width%" h="%fileselector_install_height%"/> + <text>%tw_zip_location%</text> + <filter extn=".img" folders="1" files="1"/> + <path name="tw_zip_location" default="/sdcard"/> + <data name="tw_filename"/> + <selection name="tw_file"/> + </fileselector> + + <button style="main_button_half_height"> + <placement x="%indent%" y="%row21a_y%"/> + <text>{@select_storage_btn=Select Storage}</text> + <actions> + <action function="set">tw_back=repackselect</action> + <action function="overlay">select_storage</action> + </actions> + </button> + + <action> + <conditions> + <condition var1="tw_filename" op="modified"/> + </conditions> + <action function="page">repackconfirm</action> + </action> + + <action> + <touch key="back"/> + <action function="page">advanced</action> + </action> + + <action> + <touch key="home"/> + <action function="page">main</action> + </action> + </page> + + <page name="repackconfirm"> + <template name="page"/> + + <text style="text_l"> + <condition var1="tw_repack_kernel" var2="1"/> + <placement x="%col1_x_header%" y="%row3_header_y%"/> + <text>{@repack_kernel_confirm_hdr=Install Kernel}</text> + </text> + + <text style="text_l"> + <condition var1="tw_repack_kernel" var2="0"/> + <placement x="%col1_x_header%" y="%row3_header_y%"/> + <text>{@repack_ramdisk_confirm_hdr=Install Recovery}</text> + </text> + + <text style="text_m"> + <condition var1="tw_repack_kernel" var2="1"/> + <placement x="%col1_x_header%" y="%row4_header_y%"/> + <text>{@repack_kernel_confirm=Install Kernel?}</text> + </text> + + <text style="text_m"> + <condition var1="tw_repack_kernel" var2="0"/> + <placement x="%col1_x_header%" y="%row4_header_y%"/> + <text>{@repack_ramdisk_confirm=Install Recovery?}</text> + </text> + + <text style="text_m_accent"> + <placement x="%indent%" y="%row2_y%"/> + <text>{@folder=Folder:}</text> + </text> + + <text style="text_m"> + <placement x="%indent%" y="%row3_y%"/> + <text>%tw_zip_location%</text> + </text> + + <text style="text_m_accent"> + <placement x="%indent%" y="%row4_y%"/> + <text>{@file=File:}</text> + </text> + + <text style="text_m"> + <placement x="%indent%" y="%row5_y%"/> + <text>%tw_file%</text> + </text> + + <checkbox> + <placement x="%indent%" y="%row7_y%"/> + <text>{@repack_backup_first=Back up existing image first}</text> + <data variable="tw_repack_backup_first"/> + </checkbox> + + <button style="main_button_half_height"> + <placement x="%indent%" y="%row16_y%"/> + <text>{@install_cancel=Do not Install}</text> + <action function="page">repackselect</action> + </button> + + <slider> + <text>{@swipe_to_install=Swipe to Install}</text> + <actions> + <action function="set">tw_back=advanced</action> + <action function="set">tw_action=repackimage</action> + <action function="set">tw_action_param=/boot</action> + <action function="set">tw_action_text1={@installing=Installing...}</action> + <action function="set">tw_action_text2=</action> + <action function="set">tw_complete_text1={@install_complete=Install Complete}</action> + <action function="page">action_page</action> + </actions> + </slider> + + <action> + <touch key="back"/> + <action function="page">repackselect</action> + </action> + + <action> + <touch key="home"/> + <action function="page">main</action> + </action> + </page> + <page name="lock"> <background color="%semi_transparent%"/> diff --git a/gui/theme/common/watch.xml b/gui/theme/common/watch.xml index 79ac5ecad..fcb00bccf 100755 --- a/gui/theme/common/watch.xml +++ b/gui/theme/common/watch.xml @@ -4170,6 +4170,41 @@ <action function="page">confirm_action</action> </actions> </listitem> + <listitem name="{@install_twrp_ramdisk=Install Recovery Ramdisk}"> + <conditions> + <condition var1="tw_has_boot_slots" var2="1"/> + <condition var1="tw_has_repack_tools" var2="1"/> + </conditions> + <actions> + <action function="set">tw_repack_kernel=0</action> + <action function="page">repackselect</action> + </actions> + </listitem> + <listitem name="{@install_kernel=Install Kernel}"> + <conditions> + <condition var1="tw_has_boot_slots" var2="1"/> + <condition var1="tw_has_repack_tools" var2="1"/> + </conditions> + <actions> + <action function="set">tw_repack_kernel=1</action> + <action function="page">repackselect</action> + </actions> + </listitem> + <listitem name="{@fix_recovery_loop=Fix Recovery Bootloop}"> + <conditions> + <condition var1="tw_has_boot_slots" var2="1"/> + <condition var1="tw_has_repack_tools" var2="1"/> + </conditions> + <actions> + <action function="set">tw_back=advanced</action> + <action function="set">tw_action=fixabrecoverybootloop</action> + <action function="set">tw_text1={@fix_recovery_loop_confirm=Fix Recovery Bootloop?}</action> + <action function="set">tw_action_text1={@fixing_recovery_loop=Fixing Recovery Bootloop...}</action> + <action function="set">tw_complete_text1={@fix_recovery_loop_complete=Fix Recovery Bootloop Complete}</action> + <action function="set">tw_slider_text={@swipe_to_confirm=Swipe to Confirm}</action> + <action function="page">confirm_action</action> + </actions> + </listitem> </listbox> <button> @@ -4576,6 +4611,121 @@ </action> </page> + <page name="repackselect"> + <template name="page"/> + + <template name="statusbar"/> + + <text style="text_m"> + <placement x="%col1_x_left%" y="%row1_header_y%"/> + <text>{@repack_image_hdr=Select Image}</text> + </text> + + <fileselector> + <placement x="%indent%" y="%row2_header_y%" w="%content_width%" h="%fileselector_install_height%"/> + <text>%tw_zip_location%</text> + <filter extn=".img" folders="1" files="1"/> + <path name="tw_zip_location" default="/sdcard"/> + <data name="tw_filename"/> + <selection name="tw_file"/> + </fileselector> + + <button> + <placement x="%btn4_col4_x%" y="%row11_y%"/> + <highlight color="%highlight_color%"/> + <image resource="q_btn_storage"/> + <actions> + <action function="set">tw_storagetext={@install_hdr=Install} > {@select_storage_hdr=Select Storage}</action> + <action function="set">tw_back=install</action> + <action function="page">select_storage</action> + </actions> + </button> + + <action> + <conditions> + <condition var1="tw_filename" op="modified"/> + </conditions> + <action function="page">repackconfirm</action> + </action> + + <action> + <touch key="back"/> + <action function="page">advanced</action> + </action> + + <action> + <touch key="home"/> + <action function="page">main</action> + </action> + </page> + + <page name="repackconfirm"> + <template name="page"/> + + <template name="statusbar"/> + + <text style="text_m"> + <condition var1="tw_repack_kernel" var2="1"/> + <placement x="%col1_x_left%" y="%row1_header_y%"/> + <text>{@repack_kernel_confirm=Install Kernel?}</text> + </text> + + <text style="text_m"> + <condition var1="tw_repack_kernel" var2="0"/> + <placement x="%col1_x_left%" y="%row1_header_y%"/> + <text>{@repack_ramdisk_confirm=Install Recovery?}</text> + </text> + + <text style="text_m_accent"> + <placement x="%indent%" y="%row2_y%"/> + <text>{@folder=Folder:}</text> + </text> + + <text style="text_m"> + <placement x="%indent%" y="%row3_y%"/> + <text>%tw_zip_location%</text> + </text> + + <text style="text_m_accent"> + <placement x="%indent%" y="%row4_y%"/> + <text>{@file=File:}</text> + </text> + + <text style="text_m"> + <placement x="%indent%" y="%row5_y%"/> + <text>%tw_file%</text> + </text> + + <checkbox> + <placement x="%indent%" y="%row7_y%"/> + <text>{@repack_backup_first=Back up existing image first}</text> + <data variable="tw_repack_backup_first"/> + </checkbox> + + <slider> + <text>{@swipe_to_install=Swipe to Install}</text> + <actions> + <action function="set">tw_back=advanced</action> + <action function="set">tw_action=repackimage</action> + <action function="set">tw_action_param=/boot</action> + <action function="set">tw_action_text1={@installing=Installing...}</action> + <action function="set">tw_action_text2=</action> + <action function="set">tw_complete_text1={@install_complete=Install Complete}</action> + <action function="page">action_page</action> + </actions> + </slider> + + <action> + <touch key="back"/> + <action function="page">repackselect</action> + </action> + + <action> + <touch key="home"/> + <action function="page">main</action> + </action> + </page> + <page name="lock"> <background color="%semi_transparent%"/> diff --git a/openrecoveryscript.cpp b/openrecoveryscript.cpp index 9478cd751..165211523 100755 --- a/openrecoveryscript.cpp +++ b/openrecoveryscript.cpp @@ -178,7 +178,7 @@ int OpenRecoveryScript::run_script_file(void) { strncpy(value2, tok, line_len - remove_nl); DataManager::SetValue(TW_BACKUP_NAME, value2); gui_msg(Msg("backup_folder_set=Backup folder set to '{1}'")(value2)); - if (PartitionManager.Check_Backup_Name(true) != 0) { + if (PartitionManager.Check_Backup_Name(value2, true, true) != 0) { ret_val = 1; continue; } diff --git a/partitionmanager.cpp b/partitionmanager.cpp index 34ba6aea6..79068f79d 100755 --- a/partitionmanager.cpp +++ b/partitionmanager.cpp @@ -602,16 +602,15 @@ TWPartition* TWPartitionManager::Find_Partition_By_Block_Device(const string& Bl return NULL; } -int TWPartitionManager::Check_Backup_Name(bool Display_Error) { +int TWPartitionManager::Check_Backup_Name(const std::string& Backup_Name, bool Display_Error, bool Must_Be_Unique) { // Check the backup name to ensure that it is the correct size and contains only valid characters // and that a backup with that name doesn't already exist char backup_name[MAX_BACKUP_NAME_LEN]; char backup_loc[255], tw_image_dir[255]; int copy_size; int index, cur_char; - string Backup_Name, Backup_Loc; + string Backup_Loc; - DataManager::GetValue(TW_BACKUP_NAME, Backup_Name); copy_size = Backup_Name.size(); // Check size if (copy_size > MAX_BACKUP_NAME_LEN) { @@ -640,17 +639,20 @@ int TWPartitionManager::Check_Backup_Name(bool Display_Error) { } } - // Check to make sure that a backup with this name doesn't already exist - DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, Backup_Loc); - strcpy(backup_loc, Backup_Loc.c_str()); - sprintf(tw_image_dir,"%s/%s", backup_loc, Backup_Name.c_str()); - if (TWFunc::Path_Exists(tw_image_dir)) { - if (Display_Error) - gui_err("backup_name_exists=A backup with that name already exists!"); + if (Must_Be_Unique) { + // Check to make sure that a backup with this name doesn't already exist + DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, Backup_Loc); + strcpy(backup_loc, Backup_Loc.c_str()); + sprintf(tw_image_dir,"%s/%s", backup_loc, Backup_Name.c_str()); + if (TWFunc::Path_Exists(tw_image_dir)) { + if (Display_Error) + gui_err("backup_name_exists=A backup with that name already exists!"); - return -4; + return -4; + } + // Backup is unique } - // No problems found, return 0 + // No problems found return 0; } @@ -2210,6 +2212,22 @@ void TWPartitionManager::Get_Partition_List(string ListType, std::vector<Partiti Partition_List->push_back(part); } } + if (DataManager::GetIntValue("tw_has_repack_tools") != 0 && DataManager::GetIntValue("tw_has_boot_slots") != 0) { + TWPartition* boot = Find_Partition_By_Path("/boot"); + if (boot) { + // Allow flashing kernels and ramdisks + struct PartitionList repack_ramdisk; + repack_ramdisk.Display_Name = gui_lookup("install_twrp_ramdisk", "Install Recovery Ramdisk"); + repack_ramdisk.Mount_Point = "/repack_ramdisk"; + repack_ramdisk.selected = 0; + Partition_List->push_back(repack_ramdisk); + /*struct PartitionList repack_kernel; For now let's leave repacking kernels under advanced only + repack_kernel.Display_Name = gui_lookup("install_kernel", "Install Kernel"); + repack_kernel.Mount_Point = "/repack_kernel"; + repack_kernel.selected = 0; + Partition_List->push_back(repack_kernel);*/ + } + } } else { LOGERR("Unknown list type '%s' requested for TWPartitionManager::Get_Partition_List\n", ListType.c_str()); } @@ -2512,6 +2530,21 @@ bool TWPartitionManager::Flash_Image(string& path, string& filename) { } } + DataManager::GetValue("tw_flash_partition", Flash_List); + Repack_Type repack = REPLACE_NONE; + if (Flash_List == "/repack_ramdisk;") { + repack = REPLACE_RAMDISK; + } else if (Flash_List == "/repack_kernel;") { + repack = REPLACE_KERNEL; + } + if (repack != REPLACE_NONE) { + Repack_Options_struct Repack_Options; + Repack_Options.Type = repack; + Repack_Options.Disable_Verity = false; + Repack_Options.Disable_Force_Encrypt = false; + Repack_Options.Backup_First = DataManager::GetIntValue("tw_repack_backup_first") != 0; + return Repack_Images(full_filename, Repack_Options); + } PartitionSettings part_settings; part_settings.Backup_Folder = path; unsigned long long total_bytes = TWFunc::Get_File_Size(full_filename); @@ -2519,9 +2552,7 @@ bool TWPartitionManager::Flash_Image(string& path, string& filename) { part_settings.progress = &progress; part_settings.adbbackup = false; part_settings.PM_Method = PM_RESTORE; - gui_msg("calc_restore=Calculating restore details..."); - DataManager::GetValue("tw_flash_partition", Flash_List); if (!Flash_List.empty()) { end_pos = Flash_List.find(";", start_pos); while (end_pos != string::npos && start_pos < Flash_List.size()) { @@ -2995,3 +3026,134 @@ void TWPartitionManager::Coldboot() { if (sysfs_entries.size() > 0) Coldboot_Scan(&sysfs_entries, "/sys/block", 0); } + +bool TWPartitionManager::Prepare_Empty_Folder(const std::string& Folder) { + if (TWFunc::Path_Exists(Folder)) + TWFunc::removeDir(Folder, false); + return TWFunc::Recursive_Mkdir(Folder); +} + +bool TWPartitionManager::Prepare_Repack(TWPartition* Part, const std::string& Temp_Folder_Destination, const bool Create_Backup, const std::string& Backup_Name) { + if (!Part) { + LOGERR("Partition was null!\n"); + return false; + } + if (!Prepare_Empty_Folder(Temp_Folder_Destination)) + return false; + std::string target_image = Temp_Folder_Destination + "boot.img"; + PartitionSettings part_settings; + part_settings.Part = Part; + if (Create_Backup) { + if (Check_Backup_Name(Backup_Name, true, false) != 0) + return false; + DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, part_settings.Backup_Folder); + part_settings.Backup_Folder = part_settings.Backup_Folder + "/" + TWFunc::Get_Current_Date() + " " + Backup_Name + "/"; + if (!TWFunc::Recursive_Mkdir(part_settings.Backup_Folder)) + return false; + } else + part_settings.Backup_Folder = Temp_Folder_Destination; + part_settings.adbbackup = false; + part_settings.generate_digest = false; + part_settings.generate_md5 = false; + part_settings.PM_Method = PM_BACKUP; + part_settings.progress = NULL; + pid_t not_a_pid = 0; + if (!Part->Backup(&part_settings, ¬_a_pid)) + return false; + std::string backed_up_image = part_settings.Backup_Folder; + backed_up_image += Part->Backup_FileName; + target_image = Temp_Folder_Destination + "boot.img"; + if (Create_Backup) { + std::string source = part_settings.Backup_Folder + Part->Backup_FileName; + if (TWFunc::copy_file(source, target_image, 0644) != 0) { + LOGERR("Failed to copy backup file '%s' to temp folder target '%s'\n", source.c_str(), target_image.c_str()); + return false; + } + } else { + if (rename(backed_up_image.c_str(), target_image.c_str()) != 0) { + LOGERR("Failed to rename '%s' to '%s'\n", backed_up_image.c_str(), target_image.c_str()); + return false; + } + } + return Prepare_Repack(target_image, Temp_Folder_Destination, false, false); +} + +bool TWPartitionManager::Prepare_Repack(const std::string& Source_Path, const std::string& Temp_Folder_Destination, const bool Copy_Source, const bool Create_Destination) { + if (Create_Destination) { + if (!Prepare_Empty_Folder(Temp_Folder_Destination)) + return false; + } + if (Copy_Source) { + std::string destination = Temp_Folder_Destination + "/boot.img"; + if (TWFunc::copy_file(Source_Path, destination, 0644)) + return false; + } + std::string command = "cd " + Temp_Folder_Destination + " && /sbin/magiskboot --unpack -h " + Source_Path; + if (TWFunc::Exec_Cmd(command) != 0) { + LOGINFO("Error unpacking %s!\n", Source_Path.c_str()); + gui_msg(Msg(msg::kError, "unpack_error=Error unpacking image.")); + return false; + } + return true; +} + +bool TWPartitionManager::Repack_Images(const std::string& Target_Image, const struct Repack_Options_struct& Repack_Options) { + if (!TWFunc::Path_Exists("/sbin/magiskboot")) { + LOGERR("Image repacking tool not present in this TWRP build!"); + return false; + } + DataManager::SetProgress(0); + TWPartition* part = PartitionManager.Find_Partition_By_Path("/boot"); + if (part) + gui_msg(Msg("unpacking_image=Unpacking {1}...")(part->Display_Name)); + else { + gui_msg(Msg(msg::kError, "unable_to_locate=Unable to locate {1}.")("/boot")); + return false; + } + if (!PartitionManager.Prepare_Repack(part, REPACK_ORIG_DIR, Repack_Options.Backup_First, gui_lookup("repack", "Repack"))) + return false; + DataManager::SetProgress(.25); + gui_msg(Msg("unpacking_image=Unpacking {1}...")(Target_Image)); + if (!PartitionManager.Prepare_Repack(Target_Image, REPACK_NEW_DIR, true)) + return false; + DataManager::SetProgress(.5); + gui_msg(Msg("repacking_image=Repacking {1}...")(part->Display_Name)); + std::string path = REPACK_NEW_DIR; + if (Repack_Options.Type == REPLACE_KERNEL) { + // When we replace the kernel, what we really do is copy the boot partition ramdisk into the new image's folder + if (TWFunc::copy_file(REPACK_ORIG_DIR "ramdisk.cpio", REPACK_NEW_DIR "ramdisk.cpio", 0644)) { + LOGERR("Failed to copy ramdisk\n"); + return false; + } + } else if (Repack_Options.Type == REPLACE_RAMDISK) { + // Repack the ramdisk + if (TWFunc::copy_file(REPACK_NEW_DIR "ramdisk.cpio", REPACK_ORIG_DIR "ramdisk.cpio", 0644)) { + LOGERR("Failed to copy ramdisk\n"); + return false; + } + path = REPACK_ORIG_DIR; + } else { + LOGERR("Invalid repacking options specified\n"); + return false; + } + if (Repack_Options.Disable_Verity) + LOGERR("Disabling verity is not implemented yet\n"); + if (Repack_Options.Disable_Force_Encrypt) + LOGERR("Disabling force encrypt is not implemented yet\n"); + std::string command = "cd " + path + " && /sbin/magiskboot --repack " + path + "boot.img"; + if (TWFunc::Exec_Cmd(command) != 0) { + gui_msg(Msg(msg::kError, "repack_error=Error repacking image.")); + return false; + } + DataManager::SetProgress(.75); + std::string file = "new-boot.img"; + DataManager::SetValue("tw_flash_partition", "/boot;"); + if (!PartitionManager.Flash_Image(path, file)) { + LOGINFO("Error flashing new image\n"); + return false; + } + DataManager::SetProgress(1); + TWFunc::removeDir(REPACK_ORIG_DIR, false); + TWFunc::removeDir(REPACK_NEW_DIR, false); + return true; +} diff --git a/partitions.hpp b/partitions.hpp index c124457f6..4071b942c 100644 --- a/partitions.hpp +++ b/partitions.hpp @@ -29,6 +29,9 @@ #define MAX_FSTAB_LINE_LENGTH 2048 +#define REPACK_ORIG_DIR "/tmp/repackorig/" +#define REPACK_NEW_DIR "/tmp/repacknew/" + using namespace std; // BasePartition is used for overriding so we can run custom, device @@ -72,6 +75,19 @@ struct Flags_Map { char* fstab_line; }; +enum Repack_Type { + REPLACE_NONE = 0, + REPLACE_RAMDISK = 1, + REPLACE_KERNEL = 2, +}; + +struct Repack_Options_struct { + Repack_Type Type; + bool Backup_First; + bool Disable_Verity; + bool Disable_Force_Encrypt; +}; + enum PartitionManager_Op { // PartitionManager Restore Mode for Raw_Read_Write() PM_BACKUP = 0, PM_RESTORE = 1, @@ -300,7 +316,7 @@ public: int Mount_Settings_Storage(bool Display_Error); // Mounts the settings file storage location (usually internal) TWPartition* Find_Partition_By_Path(const string& Path); // Returns a pointer to a partition based on path TWPartition* Find_Partition_By_Block_Device(const string& Block_Device); // Returns a pointer to a partition based on block device - int Check_Backup_Name(bool Display_Error); // Checks the current backup name to ensure that it is valid + int Check_Backup_Name(const std::string& Backup_Name, bool Display_Error, bool Must_Be_Unique); // Checks the current backup name to ensure that it is valid and optionally that a backup with that name doesn't already exist int Run_Backup(bool adbbackup); // Initiates a backup in the current storage int Run_Restore(const string& Restore_Name); // Restores a backup bool Write_ADB_Stream_Header(uint64_t partition_count); // Write ADB header over twrpbu FIFO @@ -361,6 +377,9 @@ public: void read_uevent(); // Reads uevent data into a buffer void close_uevent(); // Closes the uevent netlink socket void Add_Partition(TWPartition* Part); // Adds a new partition to the Partitions vector + bool Prepare_Repack(TWPartition* Part, const std::string& Temp_Folder_Destination, const bool Create_Backup, const std::string& Backup_Name); // Prepares an image for repacking by unpacking it to the temp folder destination + bool Prepare_Repack(const std::string& Source_Path, const std::string& Temp_Folder_Destination, const bool Copy_Source, const bool Create_Destination = true); // Prepares an image for repacking by unpacking it to the temp folder destination + bool Repack_Images(const std::string& Target_Image, const struct Repack_Options_struct& Repack_Options); // Repacks the boot image with a new kernel or a new ramdisk private: void Setup_Settings_Storage_Partition(TWPartition* Part); // Sets up settings storage @@ -373,6 +392,7 @@ private: void Post_Decrypt(const string& Block_Device); // Completes various post-decrypt tasks void Coldboot_Scan(std::vector<string> *sysfs_entries, const string& Path, int depth); // Scans subfolders to find matches to the paths stored in sysfs_entries so we can trigger the uevent system to "re-add" devices void Coldboot(); // Starts the scan of the /sys/block folder + bool Prepare_Empty_Folder(const std::string& Folder); // Creates an empty folder at Folder. If the folder already exists, the folder is deleted, then created pid_t mtppid; bool mtp_was_enabled; int mtp_write_fd; diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk index 0b0fa8613..4d67e5b77 100644 --- a/prebuilt/Android.mk +++ b/prebuilt/Android.mk @@ -558,3 +558,12 @@ ifeq ($(TW_INCLUDE_CRYPTO), true) endif endif endif + +ifeq ($(TW_INCLUDE_REPACKTOOLS), true) + ifeq ($(wildcard external/magisk-prebuilt/Android.mk),) + $(warning Magisk repacking tools not found!) + $(warning Please place https://github.com/TeamWin/external_magisk-prebuilt) + $(warning into external/magisk-prebuilt) + $(error magiskboot prebuilts not present; exiting) + endif +endif diff --git a/twrp-functions.cpp b/twrp-functions.cpp index 28a0f0cc7..5b618e2ac 100755 --- a/twrp-functions.cpp +++ b/twrp-functions.cpp @@ -879,10 +879,11 @@ void TWFunc::Auto_Generate_Backup_Name() { space_check = Backup_Name.substr(Backup_Name.size() - 1, 1); } replace(Backup_Name.begin(), Backup_Name.end(), ' ', '_'); - DataManager::SetValue(TW_BACKUP_NAME, Backup_Name); - if (PartitionManager.Check_Backup_Name(false) != 0) { - LOGINFO("Auto generated backup name '%s' contains invalid characters, using date instead.\n", Backup_Name.c_str()); + if (PartitionManager.Check_Backup_Name(Backup_Name, false, true) != 0) { + LOGINFO("Auto generated backup name '%s' is not valid, using date instead.\n", Backup_Name.c_str()); DataManager::SetValue(TW_BACKUP_NAME, Get_Current_Date()); + } else { + DataManager::SetValue(TW_BACKUP_NAME, Backup_Name); } } |