From 1b190166eb1295c6339f6100e4fbb92c81b81ea6 Mon Sep 17 00:00:00 2001 From: Ethan Yonker Date: Mon, 5 Dec 2016 15:25:19 -0600 Subject: Add boot slot support Change-Id: I7eaf80e327985f53791f90fbdebad022a9650d31 --- Android.mk | 4 ++- data.cpp | 7 ++++ gui/action.cpp | 13 +++++++ gui/objects.hpp | 1 + gui/theme/common/languages/en.xml | 6 ++++ gui/theme/common/portrait.xml | 76 +++++++++++++++++++++++++++++++++++++++ partition.cpp | 46 +++++++++++++++--------- partitionmanager.cpp | 64 ++++++++++++++++++++++++++++++++- partitions.hpp | 11 ++++-- prebuilt/Android.mk | 6 ++++ 10 files changed, 212 insertions(+), 22 deletions(-) diff --git a/Android.mk b/Android.mk index 94b2cd666..467ce6187 100644 --- a/Android.mk +++ b/Android.mk @@ -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 \ diff --git a/data.cpp b/data.cpp index b034bf802..62709a59c 100644 --- a/data.cpp +++ b/data.cpp @@ -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); } diff --git a/gui/action.cpp b/gui/action.cpp index 223d75e25..8600186ee 100644 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -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; +} diff --git a/gui/objects.hpp b/gui/objects.hpp index 0d969279a..8d4484aec 100644 --- a/gui/objects.hpp +++ b/gui/objects.hpp @@ -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; }; diff --git a/gui/theme/common/languages/en.xml b/gui/theme/common/languages/en.xml index b82aecff4..ee772bfd9 100644 --- a/gui/theme/common/languages/en.xml +++ b/gui/theme/common/languages/en.xml @@ -209,6 +209,11 @@ Enable compression Skip MD5 generation during backup Disable free space check before backup + Current Slot: %tw_active_slot% + Slot A + Slot B + Changing Boot Slot + Changing Boot Slot Complete Refresh Sizes Swipe to Backup Append Date @@ -675,5 +680,6 @@ path: {1} not found in partititon list Copied kernel log to {1} Include Kernel Log + Error changing bootloader boot slot to {1} diff --git a/gui/theme/common/portrait.xml b/gui/theme/common/portrait.xml index 11ae8740e..f0ba791fb 100644 --- a/gui/theme/common/portrait.xml +++ b/gui/theme/common/portrait.xml @@ -1699,6 +1699,44 @@ + + + + {@current_boot_slot=Current Slot: %tw_active_slot%} + + + + + + main @@ -2779,6 +2817,44 @@ + + + + {@current_boot_slot=Current Slot: %tw_active_slot%} + + + + + + main diff --git a/partition.cpp b/partition.cpp index 78b11ecab..00b23b79f 100644 --- a/partition.cpp +++ b/partition.cpp @@ -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 { diff --git a/partitionmanager.cpp b/partitionmanager.cpp index 079d476b3..9e23ccb94 100644 --- a/partitionmanager.cpp +++ b/partitionmanager.cpp @@ -64,12 +64,26 @@ extern "C" { #include "gui/pages.hpp" #endif +#ifdef AB_OTA_UPDATER +#include +#include +#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; +} diff --git a/partitions.hpp b/partitions.hpp index 3f2e40a5d..a6af5b1a4 100644 --- a/partitions.hpp +++ b/partitions.hpp @@ -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 Partitions; // Vector list of all partitions + string Active_Slot_Display; // Current Active Slot (A or B) for display purposes }; extern TWPartitionManager PartitionManager; diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk index a81781bf7..390c3f1f0 100644 --- a/prebuilt/Android.mk +++ b/prebuilt/Android.mk @@ -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 -- cgit v1.2.3