Add boot slot support

Change-Id: I7eaf80e327985f53791f90fbdebad022a9650d31
This commit is contained in:
Ethan Yonker
2016-12-05 15:25:19 -06:00
parent 941a899695
commit 1b190166eb
10 changed files with 212 additions and 22 deletions
+3 -1
View File
@@ -177,6 +177,8 @@ endif
ifeq ($(AB_OTA_UPDATER),true)
LOCAL_CFLAGS += -DAB_OTA_UPDATER=1
LOCAL_SHARED_LIBRARIES += libhardware
LOCAL_ADDITIONAL_DEPENDENCIES += libhardware
endif
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
@@ -346,7 +348,7 @@ else
LOCAL_CFLAGS += -DTW_DEFAULT_LANGUAGE=en
endif
LOCAL_ADDITIONAL_DEPENDENCIES := \
LOCAL_ADDITIONAL_DEPENDENCIES += \
dump_image \
erase_image \
flash_image \
+7
View File
@@ -820,6 +820,13 @@ void DataManager::SetDefaultValues()
mData.SetValue("tw_has_adopted_storage", "0");
#ifdef AB_OTA_UPDATER
LOGINFO("AB_OTA_UPDATER := true\n");
mConst.SetValue("tw_has_boot_slots", "1");
#else
mConst.SetValue("tw_has_boot_slots", "0");
#endif
pthread_mutex_unlock(&m_valuesLock);
}
+13
View File
@@ -228,6 +228,7 @@ GUIAction::GUIAction(xml_node<>* node)
ADD_ACTION(changefilesystem);
ADD_ACTION(flashimage);
ADD_ACTION(twcmd);
ADD_ACTION(setbootslot);
}
// First, get the action
@@ -1866,3 +1867,15 @@ int GUIAction::setlanguage(std::string arg __unused)
operation_end(op_status);
return 0;
}
int GUIAction::setbootslot(std::string arg)
{
operation_start("Set Boot Slot");
if (!simulate)
{
PartitionManager.Set_Active_Slot(arg);
} else
simulate_progress_bar();
operation_end(0);
return 0;
}
+1
View File
@@ -357,6 +357,7 @@ protected:
int mountsystemtoggle(std::string arg);
int setlanguage(std::string arg);
int twcmd(std::string arg);
int setbootslot(std::string arg);
int simulate;
};
+6
View File
@@ -209,6 +209,11 @@
<string name="enable_backup_comp_chk">Enable compression</string>
<string name="skip_md5_backup_chk">Skip MD5 generation during backup</string>
<string name="disable_backup_space_chk" version="2">Disable free space check before backup</string>
<string name="current_boot_slot">Current Slot: %tw_active_slot%</string>
<string name="boot_slot_a">Slot A</string>
<string name="boot_slot_b">Slot B</string>
<string name="changing_boot_slot">Changing Boot Slot</string>
<string name="changing_boot_slot_complete">Changing Boot Slot Complete</string>
<string name="refresh_sizes_btn">Refresh Sizes</string>
<string name="swipe_backup">Swipe to Backup</string>
<string name="append_date_btn">Append Date</string>
@@ -675,5 +680,6 @@
<string name="partition_not_found">path: {1} not found in partititon list</string>
<string name="copy_kernel_log">Copied kernel log to {1}</string>
<string name="include_kernel_log">Include Kernel Log</string>
<string name="unable_set_boot_slot">Error changing bootloader boot slot to {1}</string>
</resources>
</language>
+76
View File
@@ -1699,6 +1699,44 @@
<data variable="tw_disable_free_space"/>
</checkbox>
<text style="text_m">
<condition var1="tw_has_boot_slots" var2="1"/>
<placement x="%center_x%" y="%row17_y%" placement="5"/>
<text>{@current_boot_slot=Current Slot: %tw_active_slot%}</text>
</text>
<button style="main_button">
<condition var1="tw_has_boot_slots" var2="1"/>
<placement x="%indent%" y="%row19_y%"/>
<text>{@boot_slot_a=Slot A}</text>
<actions>
<action function="set">tw_back=backup_options</action>
<action function="set">tw_action=setbootslot</action>
<action function="set">tw_action_param=A</action>
<action function="set">tw_has_action2=0</action>
<action function="set">tw_action_text1={@changing_boot_slot=Changing Boot Slot}</action>
<action function="set">tw_action_text2=</action>
<action function="set">tw_complete_text1={@changing_boot_slot_complete=Change Boot Slot Complete}</action>
<action function="page">action_page</action>
</actions>
</button>
<button style="main_button">
<condition var1="tw_has_boot_slots" var2="1"/>
<placement x="%center_x%" y="%row19_y%"/>
<text>{@boot_slot_b=Slot B}</text>
<actions>
<action function="set">tw_back=backup_options</action>
<action function="set">tw_action=setbootslot</action>
<action function="set">tw_action_param=B</action>
<action function="set">tw_has_action2=0</action>
<action function="set">tw_action_text1={@changing_boot_slot=Changing Boot Slot}</action>
<action function="set">tw_action_text2=</action>
<action function="set">tw_complete_text1={@changing_boot_slot_complete=Change Boot Slot Complete}</action>
<action function="page">action_page</action>
</actions>
</button>
<action>
<touch key="home"/>
<action function="page">main</action>
@@ -2779,6 +2817,44 @@
</actions>
</button>
<text style="text_m">
<condition var1="tw_has_boot_slots" var2="1"/>
<placement x="%center_x%" y="%row17_y%" placement="5"/>
<text>{@current_boot_slot=Current Slot: %tw_active_slot%}</text>
</text>
<button style="main_button">
<condition var1="tw_has_boot_slots" var2="1"/>
<placement x="%indent%" y="%row19_y%"/>
<text>{@boot_slot_a=Slot A}</text>
<actions>
<action function="set">tw_back=reboot</action>
<action function="set">tw_action=setbootslot</action>
<action function="set">tw_action_param=A</action>
<action function="set">tw_has_action2=0</action>
<action function="set">tw_action_text1={@changing_boot_slot=Changing Boot Slot}</action>
<action function="set">tw_action_text2=</action>
<action function="set">tw_complete_text1={@changing_boot_slot_complete=Change Boot Slot Complete}</action>
<action function="page">action_page</action>
</actions>
</button>
<button style="main_button">
<condition var1="tw_has_boot_slots" var2="1"/>
<placement x="%center_x%" y="%row19_y%"/>
<text>{@boot_slot_b=Slot B}</text>
<actions>
<action function="set">tw_back=reboot</action>
<action function="set">tw_action=setbootslot</action>
<action function="set">tw_action_param=B</action>
<action function="set">tw_has_action2=0</action>
<action function="set">tw_action_text1={@changing_boot_slot=Changing Boot Slot}</action>
<action function="set">tw_action_text2=</action>
<action function="set">tw_complete_text1={@changing_boot_slot_complete=Change Boot Slot Complete}</action>
<action function="page">action_page</action>
</actions>
</button>
<action>
<touch key="home"/>
<action function="page">main</action>
+29 -17
View File
@@ -139,6 +139,7 @@ enum TW_FSTAB_FLAGS {
TWFLAG_USERMRF,
TWFLAG_WIPEDURINGFACTORYRESET,
TWFLAG_WIPEINGUI,
TWFLAG_SLOTSELECT,
};
/* Flags without a trailing '=' are considered dual format flags and can be
@@ -172,6 +173,7 @@ const struct flag_list tw_flags[] = {
{ "usermrf", TWFLAG_USERMRF },
{ "wipeduringfactoryreset", TWFLAG_WIPEDURINGFACTORYRESET },
{ "wipeingui", TWFLAG_WIPEINGUI },
{ "slotselect", TWFLAG_SLOTSELECT },
{ 0, 0 },
};
@@ -231,6 +233,7 @@ TWPartition::TWPartition() {
Mount_Read_Only = false;
Is_Adopted_Storage = false;
Adopted_GUID = "";
SlotSelect = false;
}
TWPartition::~TWPartition(void) {
@@ -411,7 +414,7 @@ bool TWPartition::Process_Fstab_Line(const char *fstab_line, bool Display_Error)
#endif
} else if (Is_Image(Fstab_File_System)) {
Find_Actual_Block_Device();
Setup_Image(Display_Error);
Setup_Image();
if (Mount_Point == "/boot") {
Display_Name = "Boot";
Backup_Display_Name = Display_Name;
@@ -498,7 +501,7 @@ void TWPartition::Setup_Data_Partition(bool Display_Error) {
Is_Decrypted = false;
Can_Be_Mounted = false;
Current_File_System = "emmc";
Setup_Image(Display_Error);
Setup_Image();
DataManager::SetValue(TW_IS_ENCRYPTED, 1);
DataManager::SetValue(TW_CRYPTO_PWTYPE, cryptfs_get_password_type());
DataManager::SetValue(TW_CRYPTO_PASSWORD, "");
@@ -665,6 +668,9 @@ void TWPartition::Apply_TW_Flag(const unsigned flag, const char* str, const bool
if (Wipe_Available_in_GUI)
Can_Be_Wiped = true;
break;
case TWFLAG_SLOTSELECT:
SlotSelect = true;
break;
default:
// Should not get here
LOGINFO("Flag identified for processing, but later unmatched: %i\n", flag);
@@ -808,7 +814,7 @@ void TWPartition::Setup_File_System(bool Display_Error) {
Backup_Method = BM_FILES;
}
void TWPartition::Setup_Image(bool Display_Error) {
void TWPartition::Setup_Image() {
Display_Name = Mount_Point.substr(1, Mount_Point.size() - 1);
Backup_Name = Display_Name;
if (Current_File_System == "emmc")
@@ -817,15 +823,6 @@ void TWPartition::Setup_Image(bool Display_Error) {
Backup_Method = BM_FLASH_UTILS;
else
LOGINFO("Unhandled file system '%s' on image '%s'\n", Current_File_System.c_str(), Display_Name.c_str());
if (Find_Partition_Size()) {
Used = Size;
Backup_Size = Size;
} else {
if (Display_Error)
LOGERR("Unable to find partition size for '%s'\n", Mount_Point.c_str());
else
LOGINFO("Unable to find partition size for '%s'\n", Mount_Point.c_str());
}
}
void TWPartition::Setup_AndSec(void) {
@@ -1727,7 +1724,7 @@ bool TWPartition::Wipe_Encryption() {
Has_Data_Media = false;
Decrypted_Block_Device = "";
#ifdef TW_INCLUDE_CRYPTO
if (Is_Decrypted) {
if (Is_Decrypted && !Decrypted_Block_Device.empty()) {
if (!UnMount(true))
return false;
if (delete_crypto_blk_dev((char*)("userdata")) != 0) {
@@ -2474,8 +2471,16 @@ bool TWPartition::Restore_Image(PartitionSettings *part_settings) {
bool TWPartition::Update_Size(bool Display_Error) {
bool ret = false, Was_Already_Mounted = false;
if (!Can_Be_Mounted && !Is_Encrypted)
Find_Actual_Block_Device();
if (!Can_Be_Mounted && !Is_Encrypted) {
if (TWFunc::Path_Exists(Actual_Block_Device) && Find_Partition_Size()) {
Used = Size;
Backup_Size = Size;
return true;
}
return false;
}
Was_Already_Mounted = Is_Mounted();
if (Removable || Is_Encrypted) {
@@ -2523,15 +2528,22 @@ bool TWPartition::Update_Size(bool Display_Error) {
void TWPartition::Find_Actual_Block_Device(void) {
if (Is_Decrypted && !Decrypted_Block_Device.empty()) {
Actual_Block_Device = Decrypted_Block_Device;
if (TWFunc::Path_Exists(Decrypted_Block_Device))
if (TWFunc::Path_Exists(Decrypted_Block_Device)) {
Is_Present = true;
return;
}
} else if (SlotSelect && TWFunc::Path_Exists(Primary_Block_Device + PartitionManager.Get_Active_Slot_Suffix())) {
Actual_Block_Device = Primary_Block_Device + PartitionManager.Get_Active_Slot_Suffix();
unlink(Primary_Block_Device.c_str());
symlink(Actual_Block_Device.c_str(), Primary_Block_Device.c_str()); // we create a non-slot symlink pointing to the currently selected slot which may assist zips with installing
Is_Present = true;
return;
} else if (TWFunc::Path_Exists(Primary_Block_Device)) {
Is_Present = true;
Actual_Block_Device = Primary_Block_Device;
return;
}
if (Is_Decrypted) {
} else if (!Alternate_Block_Device.empty() && TWFunc::Path_Exists(Alternate_Block_Device)) {
if (!Alternate_Block_Device.empty() && TWFunc::Path_Exists(Alternate_Block_Device)) {
Actual_Block_Device = Alternate_Block_Device;
Is_Present = true;
} else {
+63 -1
View File
@@ -64,12 +64,26 @@ extern "C" {
#include "gui/pages.hpp"
#endif
#ifdef AB_OTA_UPDATER
#include <hardware/hardware.h>
#include <hardware/boot_control.h>
#endif
extern bool datamedia;
TWPartitionManager::TWPartitionManager(void) {
mtp_was_enabled = false;
mtp_write_fd = -1;
stop_backup.set_value(0);
#ifdef AB_OTA_UPDATER
char slot_suffix[PROPERTY_VALUE_MAX];
property_get("ro.boot.slot_suffix", slot_suffix, "_a");
Active_Slot_Display = "";
if (strcmp(slot_suffix, "_a") == 0)
Set_Active_Slot("A");
else
Set_Active_Slot("B");
#endif
}
int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error) {
@@ -182,6 +196,9 @@ int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error)
#endif
Update_System_Details();
UnMount_Main_Partitions();
#ifdef AB_OTA_UPDATER
DataManager::SetValue("tw_active_slot", Get_Active_Slot_Display());
#endif
return true;
}
@@ -290,6 +307,8 @@ void TWPartitionManager::Output_Partition(TWPartition* Part) {
printf("Can_Flash_Img ");
if (Part->Is_Adopted_Storage)
printf("Is_Adopted_Storage ");
if (Part->SlotSelect)
printf("SlotSelect ");
printf("\n");
if (!Part->SubPartition_Of.empty())
printf(" SubPartition_Of: %s\n", Part->SubPartition_Of.c_str());
@@ -1376,8 +1395,8 @@ void TWPartitionManager::Update_System_Details(void) {
gui_msg("update_part_details=Updating partition details...");
for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
(*iter)->Update_Size(true);
if ((*iter)->Can_Be_Mounted) {
(*iter)->Update_Size(true);
if ((*iter)->Mount_Point == "/system") {
int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
DataManager::SetValue(TW_BACKUP_SYSTEM_SIZE, backup_display_size);
@@ -2473,3 +2492,46 @@ void TWPartitionManager::Remove_Partition_By_Path(string Path) {
}
}
}
void TWPartitionManager::Set_Active_Slot(const string& Slot) {
if (Slot != "A" && Slot != "B") {
LOGERR("Set_Active_Slot invalid slot '%s'\n", Slot.c_str());
return;
}
if (Active_Slot_Display == Slot)
return;
LOGINFO("Setting active slot %s\n", Slot.c_str());
#ifdef AB_OTA_UPDATER
if (!Active_Slot_Display.empty()) {
const hw_module_t *hw_module;
boot_control_module_t *module;
int ret;
ret = hw_get_module("bootctrl", &hw_module);
if (ret != 0) {
LOGERR("Error getting bootctrl module.\n");
} else {
module = (boot_control_module_t*) hw_module;
module->init(module);
int slot_number = 0;
if (Slot == "B")
slot_number = 1;
if (module->setActiveBootSlot(module, slot_number))
gui_msg(Msg(msg::kError, "unable_set_boot_slot=Error changing bootloader boot slot to {1}")(Slot));
}
DataManager::SetValue("tw_active_slot", Slot); // Doing this outside of this if block may result in a seg fault because the DataManager may not be ready yet
}
#else
LOGERR("Boot slot feature not present\n");
#endif
Active_Slot_Display = Slot;
if (Fstab_Processed())
Update_System_Details();
}
string TWPartitionManager::Get_Active_Slot_Suffix() {
if (Active_Slot_Display == "A")
return "_a";
return "_b";
}
string TWPartitionManager::Get_Active_Slot_Display() {
return Active_Slot_Display;
}
+8 -3
View File
@@ -133,7 +133,7 @@ private:
bool Is_File_System(string File_System); // Checks to see if the file system given is considered a file system
bool Is_Image(string File_System); // Checks to see if the file system given is considered an image
void Setup_File_System(bool Display_Error); // Sets defaults for a file system partition
void Setup_Image(bool Display_Error); // Sets defaults for an image partition
void Setup_Image(); // Sets defaults for an image partition
void Setup_AndSec(void); // Sets up .android_secure settings
void Find_Real_Block_Device(string& Block_Device, bool Display_Error); // Checks the block device given and follows symlinks until it gets to the real block device
unsigned long long IOCTL_Get_Block_Size(); // Finds the partition size using ioctl
@@ -215,8 +215,9 @@ private:
bool Can_Flash_Img; // Indicates if this partition can have images flashed to it via the GUI
bool Mount_Read_Only; // Only mount this partition as read-only
bool Is_Adopted_Storage; // Indicates that this partition is for adopted storage (android_expand)
TWExclude backup_exclusions;
TWExclude wipe_exclusions;
bool SlotSelect; // Partition has A/B slots
TWExclude backup_exclusions; // Exclusions for file based backups
TWExclude wipe_exclusions; // Exclusions for file based wipes (data/media devices only)
friend class TWPartitionManager;
friend class DataManager;
@@ -289,6 +290,9 @@ public:
bool Flash_Image(string& path, string& filename); // Flashes an image to a selected partition from the partition list
bool Restore_Partition(struct PartitionSettings *part_settings); // Restore the partitions based on type
TWAtomicInt stop_backup;
void Set_Active_Slot(const string& Slot); // Sets the active slot to A or B
string Get_Active_Slot_Suffix(); // Returns active slot _a or _b
string Get_Active_Slot_Display(); // Returns active slot A or B for display purposes
private:
void Setup_Settings_Storage_Partition(TWPartition* Part); // Sets up settings storage
@@ -308,6 +312,7 @@ private:
private:
std::vector<TWPartition*> Partitions; // Vector list of all partitions
string Active_Slot_Display; // Current Active Slot (A or B) for display purposes
};
extern TWPartitionManager PartitionManager;
+6
View File
@@ -177,6 +177,12 @@ ifeq ($(TW_INCLUDE_CRYPTO), true)
RELINK_SOURCE_FILES += $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)/libcryptfs_hw.so
endif
endif
ifeq ($(AB_OTA_UPDATER), true)
RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/bootctl
ifneq ($(TW_INCLUDE_CRYPTO), true)
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libhardware.so
endif
endif
ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/make_ext4fs
endif