Use magiskboot to repack the boot partition

Set TW_INCLUDE_REPACKTOOLS := true

Must also have:
AB_OTA_UPDATER := true

Use magiskboot and provide GUI options to allow users to repack
their existing boot image to install TWRP (or kernels) so we can
stop having to provide installation zips for AB devices. There is
also an option to try to fix a recovery bootloop if the kernel
has been patched to always boot the ramdisk for root, etc.

You will need to pull the below repo into external/magisk-prebuilt
https://github.com/TeamWin/external_magisk-prebuilt

Change-Id: I74196cc6f095a7576d61886dc96cbc18deba9b04
This commit is contained in:
Ethan Yonker
2019-01-11 22:49:52 -06:00
parent 9a4d7403d9
commit 53796e7333
12 changed files with 821 additions and 22 deletions

View File

@@ -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);
}

View File

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

View File

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

View File

@@ -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%"/>

View File

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

View File

@@ -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%"/>

View File

@@ -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%"/>

View File

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

View File

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

View File

@@ -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;

View File

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

View File

@@ -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);
}
}