summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xdata.cpp7
-rwxr-xr-xgui/action.cpp94
-rw-r--r--gui/objects.hpp2
-rwxr-xr-xgui/theme/common/landscape.xml169
-rwxr-xr-xgui/theme/common/languages/en.xml22
-rwxr-xr-xgui/theme/common/portrait.xml169
-rwxr-xr-xgui/theme/common/watch.xml150
-rwxr-xr-xopenrecoveryscript.cpp2
-rwxr-xr-xpartitionmanager.cpp190
-rw-r--r--partitions.hpp22
-rw-r--r--prebuilt/Android.mk9
-rwxr-xr-xtwrp-functions.cpp7
12 files changed, 821 insertions, 22 deletions
diff --git a/data.cpp b/data.cpp
index 92255357c..cd03d78ac 100755
--- a/data.cpp
+++ b/data.cpp
@@ -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} &gt; {@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, &not_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);
}
}