super partition: mount super partitions using fs_mgr

We are now requiring fstab v2 for android-10+ trees. You can
specify twrp flags using /etc/twrp.flags to label and
annotate partitions.

This patchset uses fs_mgr to load the super partition and build
device mapper blocks off vendor and system depending on the slot
in use. These are mapped to partitions in TWRP and allowed to
be mounted read-only. The super partition is also mapped into a
TWRP partition in order to backup the entire partition. You cannot
backup individual device mapper blocks due to the device can only
be read-only. Therefore you cannot write back to the device mapper.

Change-Id: Icc1d895dcf96ad5ba03989c9bf759419d83673a3
diff --git a/Android.mk b/Android.mk
index 6875d03..0bbad69 100755
--- a/Android.mk
+++ b/Android.mk
@@ -52,6 +52,9 @@
 
 TARGET_RECOVERY_GUI := true
 
+LOCAL_STATIC_LIBRARIES :=
+LOCAL_SHARED_LIBRARIES :=
+
 ifneq ($(TW_DEVICE_VERSION),)
     LOCAL_CFLAGS += -DTW_DEVICE_VERSION='"-$(TW_DEVICE_VERSION)"'
 else
@@ -77,6 +80,19 @@
     tarWrite.c \
     twrpAdbBuFifo.cpp
 
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 29; echo $$?),0)
+    LOCAL_STATIC_LIBRARIES += libavb
+    LOCAL_SHARED_LIBRARIES += libfs_mgr libinit
+    LOCAL_C_INCLUDES += \
+        system/core/fs_mgr/libfs_avb/include/ \
+        system/core/fs_mgr/include_fstab/ \
+        system/core/fs_mgr/include/ \
+        system/core/fs_mgr/libdm/include/ \
+        system/core/fs_mgr/liblp/include/ \
+        system/gsid/include/ \
+        system/core/init/
+endif
+
 ifneq ($(TARGET_RECOVERY_REBOOT_SRC),)
   LOCAL_SRC_FILES += $(TARGET_RECOVERY_REBOOT_SRC)
 endif
@@ -117,9 +133,6 @@
     LOCAL_C_INCLUDES += external/boringssl/include external/libcxx/include
 endif
 
-LOCAL_STATIC_LIBRARIES :=
-LOCAL_SHARED_LIBRARIES :=
-
 LOCAL_STATIC_LIBRARIES += libguitwrp
 LOCAL_SHARED_LIBRARIES += libz libc libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libtwadbbu libbootloader_message_twrp
 LOCAL_SHARED_LIBRARIES += libcrecovery libtwadbbu libtwrpdigest libc++ libaosprecovery
@@ -153,7 +166,6 @@
     else
         LOCAL_SHARED_LIBRARIES += libziparchive
         LOCAL_C_INCLUDES += system/core/libziparchive/include
-        LOCAL_C_FLAGS += -DUSE_
     endif
 else
     LOCAL_SHARED_LIBRARIES += libminzip
@@ -190,6 +202,10 @@
     TWRP_REQUIRED_MODULES += libhardware
 endif
 
+ifeq ($(PRODUCT_USE_DYNAMIC_PARTITIONS),true)
+    LOCAL_CFLAGS += -DPRODUCT_USE_DYNAMIC_PARTITIONS=1
+endif
+
 LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
 
 ifeq ($(TARGET_RECOVERY_TWRP_LIB),)
diff --git a/data.cpp b/data.cpp
index 85834d2..6ba278f 100755
--- a/data.cpp
+++ b/data.cpp
@@ -778,8 +778,12 @@
 #ifdef TW_HAS_NO_BOOT_PARTITION
 	mPersist.SetValue("tw_backup_list", "/system;/data;");
 #else
+#ifdef PRODUCT_USE_DYNAMIC_PARTITIONS
+	mPersist.SetValue("tw_backup_list", "/data;");
+#else
 	mPersist.SetValue("tw_backup_list", "/system;/data;/boot;");
 #endif
+#endif
 	mConst.SetValue(TW_MIN_SYSTEM_VAR, TW_MIN_SYSTEM_SIZE);
 	mData.SetValue(TW_BACKUP_NAME, "(Auto Generate)");
 
@@ -814,6 +818,7 @@
 	mData.SetValue("tw_background_thread_running", "0");
 	mData.SetValue(TW_RESTORE_FILE_DATE, "0");
 	mPersist.SetValue("tw_military_time", "0");
+	mData.SetValue(TW_IS_SUPER, "0");
 
 #ifdef TW_INCLUDE_CRYPTO
 	mPersist.SetValue(TW_USE_SHA2, "1");
diff --git a/gui/partitionlist.cpp b/gui/partitionlist.cpp
old mode 100644
new mode 100755
index 16e0997..570b16a
--- a/gui/partitionlist.cpp
+++ b/gui/partitionlist.cpp
@@ -142,6 +142,7 @@
 			currentValue = value;
 			SetPosition();
 		} else if (ListType == "backup") {
+			updateList = true;
 			MatchList();
 		} else if (ListType == "restore") {
 			updateList = true;
diff --git a/gui/theme/common/landscape.xml b/gui/theme/common/landscape.xml
index 3af174e..85b65b8 100755
--- a/gui/theme/common/landscape.xml
+++ b/gui/theme/common/landscape.xml
@@ -2485,7 +2485,10 @@
 			</partitionlist>
 
 			<button style="checkbox">
-				<condition var1="tw_mount_system_ro" op="=" var2="0"/>
+				<conditions>
+					<condition var1="tw_mount_system_ro" op="!=" var2="0"/>
+					<condition var1="tw_is_super" op="=" var2="0"/>
+				</conditions>
 				<placement x="%col1_x_left%" y="%row14_y%" textplacement="6"/>
 				<text>{@mount_sys_ro_chk=Mount system partition read-only}</text>
 				<image resource="checkbox_false"/>
@@ -2493,7 +2496,10 @@
 			</button>
 
 			<button style="checkbox">
-				<condition var1="tw_mount_system_ro" op="!=" var2="0"/>
+				<conditions>
+					<condition var1="tw_mount_system_ro" op="!=" var2="0"/>
+					<condition var1="tw_is_super" op="=" var2="0"/>
+				</conditions>
 				<placement x="%col1_x_left%" y="%row14_y%" textplacement="6"/>
 				<text>{@mount_sys_ro_chk=Mount system partition read-only}</text>
 				<image resource="checkbox_true"/>
diff --git a/gui/theme/common/portrait.xml b/gui/theme/common/portrait.xml
index 64b8776..b3b4312 100755
--- a/gui/theme/common/portrait.xml
+++ b/gui/theme/common/portrait.xml
@@ -2641,7 +2641,10 @@
 			</partitionlist>
 
 			<button style="checkbox">
-				<condition var1="tw_mount_system_ro" op="=" var2="0"/>
+				<conditions>
+					<condition var1="tw_mount_system_ro" op="!=" var2="0"/>
+					<condition var1="tw_is_super" op="=" var2="0"/>
+				</conditions>
 				<placement x="%indent%" y="%row15a_y%" textplacement="6"/>
 				<text>{@mount_sys_ro_chk=Mount system partition read-only}</text>
 				<image resource="checkbox_false"/>
@@ -2649,7 +2652,10 @@
 			</button>
 
 			<button style="checkbox">
-				<condition var1="tw_mount_system_ro" op="!=" var2="0"/>
+				<conditions>
+					<condition var1="tw_mount_system_ro" op="!=" var2="0"/>
+					<condition var1="tw_is_super" op="=" var2="0"/>
+				</conditions>
 				<placement x="%indent%" y="%row15a_y%" textplacement="6"/>
 				<text>{@mount_sys_ro_chk=Mount system partition read-only}</text>
 				<image resource="checkbox_true"/>
diff --git a/gui/theme/common/watch.xml b/gui/theme/common/watch.xml
index 70ccf38..71cce19 100755
--- a/gui/theme/common/watch.xml
+++ b/gui/theme/common/watch.xml
@@ -3101,7 +3101,10 @@
 			</fill>
 
 			<button style="checkbox">
-				<condition var1="tw_mount_system_ro" op="=" var2="0"/>
+				<conditions>
+					<condition var1="tw_mount_system_ro" op="!=" var2="0"/>
+					<condition var1="tw_is_super" op="=" var2="0"/>
+				</conditions>
 				<placement x="%col1_x_left%" y="%row11_y%" textplacement="6"/>
 				<text>{@mount_sys_ro_s_chk=Mount System RO}</text>
 				<image resource="checkbox_false"/>
@@ -3109,7 +3112,10 @@
 			</button>
 
 			<button style="checkbox">
-				<condition var1="tw_mount_system_ro" op="!=" var2="0"/>
+				<conditions>
+					<condition var1="tw_mount_system_ro" op="!=" var2="0"/>
+					<condition var1="tw_is_super" op="=" var2="0"/>
+				</conditions>
 				<placement x="%col1_x_left%" y="%row11_y%" textplacement="6"/>
 				<text>{@mount_sys_ro_s_chk=Mount System RO}</text>
 				<image resource="checkbox_true"/>
diff --git a/openrecoveryscript.cpp b/openrecoveryscript.cpp
index a52211c..05bac0c 100755
--- a/openrecoveryscript.cpp
+++ b/openrecoveryscript.cpp
@@ -412,6 +412,8 @@
 					gui_err("no_pwd=No password provided.");
 					ret_val = 1; // failure
 				}
+			} else if (strcmp(command, "listmounts") == 0) {
+				TWFunc::List_Mounts();
 			} else {
 				LOGERR("Unrecognized script command: '%s'\n", command);
 				ret_val = 1;
diff --git a/orscmd/orscmd.cpp b/orscmd/orscmd.cpp
old mode 100644
new mode 100755
index c47c0f6..df4a6a7
--- a/orscmd/orscmd.cpp
+++ b/orscmd/orscmd.cpp
@@ -50,6 +50,7 @@
 	printf("  fixperms\n");
 	printf("  mount <path>\n");
 	printf("  unmount <path>\n");
+	printf("  listmounts\n");
 	printf("  print <value>\n");
 	printf("  mkdir <directory>\n");
 	printf("  reboot [recovery|poweroff|bootloader|download|edl]\n");
diff --git a/partition.cpp b/partition.cpp
old mode 100644
new mode 100755
index 7f4189a..9bea8e7
--- a/partition.cpp
+++ b/partition.cpp
@@ -268,6 +268,7 @@
 	Adopted_GUID = "";
 	SlotSelect = false;
 	Key_Directory = "";
+	Is_Super = false;
 }
 
 TWPartition::~TWPartition(void) {
@@ -285,6 +286,7 @@
 	std::map<string, Flags_Map>::iterator it;
 
 	strlcpy(full_line, fstab_line, sizeof(full_line));
+
 	for (index = 0; index < line_len; index++) {
 		if (full_line[index] == 34)
 			skip = !skip;
@@ -300,6 +302,14 @@
 		fs_index = 2;
 	}
 
+	Is_Super = PartitionManager.Is_Super_Partition(fstab_line);
+	if (Is_Super) {
+		block_device_index = 0;
+		fstab_version = 2;
+		mount_point_index = 1;
+		fs_index = 2;
+	}
+
 	index = 0;
 	while (index < line_len) {
 		while (index < line_len && full_line[index] == '\0')
@@ -309,7 +319,7 @@
 		ptr = full_line + index;
 		if (item_index == mount_point_index) {
 			Mount_Point = ptr;
-			if (fstab_version == 2) {
+			if (fstab_version == 2 && Is_Super == false) {
 				additional_entry = PartitionManager.Find_Partition_By_Path(Mount_Point);
 				if (!Sar_Detect && additional_entry) {
 					LOGINFO("Found an additional entry for '%s'\n", Mount_Point.c_str());
@@ -342,11 +352,13 @@
 				if (*ptr != '/')
 					LOGERR("Until we get better BML support, you will have to find and provide the full block device path to the BML devices e.g. /dev/block/bml9 instead of the partition name\n");
 			} else if (*ptr != '/') {
-				if (Display_Error)
-					LOGERR("Invalid block device '%s' in fstab line '%s'", ptr, fstab_line);
-				else
-					LOGINFO("Invalid block device '%s' in fstab line '%s'", ptr, fstab_line);
-				return false;
+				if (!Is_Super) {
+					if (Display_Error)
+						LOGERR("Invalid block device '%s' in fstab line '%s'", ptr, fstab_line);
+					else
+						LOGINFO("Invalid block device '%s' in fstab line '%s'", ptr, fstab_line);
+					return false;
+				}
 			} else {
 				Primary_Block_Device = ptr;
 				Find_Real_Block_Device(Primary_Block_Device, Display_Error);
@@ -617,6 +629,11 @@
 			Storage_Path = Mount_Point;
 			Make_Dir(Mount_Point, Display_Error);
 		}
+		if (Is_Super) {
+			Can_Be_Backed_Up = false;
+			Can_Be_Wiped = false;
+			Wipe_Available_in_GUI = false;
+		}
 	}
 
 	return true;
@@ -1410,7 +1427,6 @@
 
 	// Compare the device IDs -- if they match then we're (probably) using tmpfs instead of an actual device
 	int ret = (st1.st_dev != st2.st_dev) ? true : false;
-
 	return ret;
 }
 
@@ -2865,6 +2881,9 @@
 
 	Find_Actual_Block_Device();
 
+	if (Actual_Block_Device.empty())
+		return false;
+
 	if (!Can_Be_Mounted && !Is_Encrypted) {
 		if (TWFunc::Path_Exists(Actual_Block_Device) && Find_Partition_Size()) {
 			Used = Size;
@@ -2875,6 +2894,7 @@
 	}
 
 	Was_Already_Mounted = Is_Mounted();
+
 	if (Removable || Is_Encrypted) {
 		if (!Mount(false))
 			return true;
@@ -3374,3 +3394,24 @@
 string TWPartition::Get_Backup_Name() {
 	return Backup_Name;
 }
+
+string TWPartition::Get_Mount_Point() {
+	return Mount_Point;
+}
+
+void TWPartition::Set_Block_Device(std::string block_device) {
+	Primary_Block_Device = Actual_Block_Device = block_device;
+}
+
+bool TWPartition::Get_Super_Status() {
+	return Is_Super;
+}
+
+void TWPartition::Set_Can_Be_Backed_Up(bool val) {
+	Can_Be_Backed_Up = val;
+}
+
+void TWPartition::Set_Can_Be_Wiped(bool val) {
+	Can_Be_Wiped = val;
+	Wipe_Available_in_GUI = val;
+}
\ No newline at end of file
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 23e5953..848d00a 100755
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -1,5 +1,5 @@
 /*
-	Copyright 2014 to 2017 TeamWin
+	Copyright 2014 to 2020 TeamWin
 	This file is part of TWRP/TeamWin Recovery Project.
 
 	TWRP is free software: you can redistribute it and/or modify
@@ -35,10 +35,22 @@
 #include <linux/fs.h>
 #include <sys/mount.h>
 
+
 #include <sys/poll.h>
 #include <sys/socket.h>
 #include <linux/types.h>
 #include <linux/netlink.h>
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <fstab/fstab.h>
+#include <fs_avb/fs_avb.h>
+#include <fs_mgr.h>
+#include <fs_mgr_dm_linear.h>
+#include <fs_mgr_overlayfs.h>
+#include <libgsi/libgsi.h>
+#include <liblp/liblp.h>
 
 #include "variables.h"
 #include "twcommon.h"
@@ -91,8 +103,11 @@
 #include <hardware/boot_control.h>
 #endif
 
-extern bool datamedia;
+using android::fs_mgr::Fstab;
+using android::fs_mgr::FstabEntry;
 
+extern bool datamedia;
+ 
 TWPartitionManager::TWPartitionManager(void) {
 	mtp_was_enabled = false;
 	mtp_write_fd = -1;
@@ -187,7 +202,9 @@
 		LOGINFO("Reading %s\n", Fstab_Filename.c_str());
 
 	while (fgets(fstab_line, sizeof(fstab_line), fstabFile) != NULL) {
-		if (fstab_line[0] != '/')
+		bool isSuper = Is_Super_Partition(fstab_line);
+
+		if (!isSuper && fstab_line[0] != '/')
 			continue;
 
 		if (strstr(fstab_line, "swap"))
@@ -2917,7 +2934,9 @@
 			}
 		}
 	}
-	LOGINFO("Found no matching fstab entry for uevent device '%s' - %s\n", uevent_data.sysfs_path.c_str(), uevent_data.action.c_str());
+
+	if (!PartitionManager.Get_Super_Status())
+		LOGINFO("Found no matching fstab entry for uevent device '%s' - %s\n", uevent_data.sysfs_path.c_str(), uevent_data.action.c_str());
 }
 
 void TWPartitionManager::setup_uevent() {
@@ -3226,3 +3245,99 @@
 	TWFunc::removeDir(REPACK_NEW_DIR, false);
 	return true;
 }
+
+bool TWPartitionManager::Prepare_Super_Volume(TWPartition* twrpPart) {
+    Fstab fstab;
+	std::string bare_partition_name;
+
+	if (twrpPart->Get_Mount_Point() == "/system_root")
+		bare_partition_name = "system";
+	else
+		bare_partition_name = TWFunc::Remove_Beginning_Slash(twrpPart->Get_Mount_Point());
+
+	LOGINFO("Trying to prepare %s from super partition\n", bare_partition_name.c_str());
+
+	std::string blk_device_partition;
+#ifdef AB_OTA_UPDATER
+	blk_device_partition = bare_partition_name + PartitionManager.Get_Active_Slot_Suffix();
+#else
+	blk_device_partition = bare_partition_name;
+#endif
+
+	FstabEntry fstabEntry = {
+        .blk_device =  blk_device_partition,
+        .mount_point = twrpPart->Get_Mount_Point(),
+        .fs_type = twrpPart->Current_File_System,
+        .fs_mgr_flags.logical = twrpPart->Is_Super,
+    };
+
+    fstab.emplace_back(fstabEntry);
+    if (!fs_mgr_update_logical_partition(&fstabEntry)) {
+        LOGERR("unable to update logical partition: %s\n", twrpPart->Get_Mount_Point().c_str());
+        return false;
+    }
+
+	twrpPart->Set_Block_Device(fstabEntry.blk_device);
+	twrpPart->Update_Size(true);
+	twrpPart->Change_Mount_Read_Only(true);
+	twrpPart->Set_Can_Be_Backed_Up(false);
+	twrpPart->Set_Can_Be_Wiped(false);
+    return true;
+}
+
+bool TWPartitionManager::Prepare_All_Super_Volumes() {
+	bool status = true;
+	std::vector<TWPartition*>::iterator iter;
+
+	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
+		if ((*iter)->Is_Super) {
+			if (!Prepare_Super_Volume(*iter)) {
+				status = false;
+			}
+			PartitionManager.Output_Partition(*iter);
+		}
+	}
+	Update_System_Details();
+	return status;
+}
+
+bool TWPartitionManager::Is_Super_Partition(const char* fstab_line) {
+	std::vector<std::string> super_partition_list = {"system", "vendor", "odm", "product", "system_ext"};
+
+	for (auto&& fstab_partition_check: super_partition_list) {
+		if (strncmp(fstab_line, fstab_partition_check.c_str(), fstab_partition_check.size()) == 0) {
+			DataManager::SetValue(TW_IS_SUPER, "1");
+			return true;
+		}
+	}
+	return false;
+}
+
+std::string TWPartitionManager::Get_Super_Partition() {
+	int slot_number = Get_Active_Slot_Display() == "A" ? 0 : 1;
+	std::string super_device = 	fs_mgr_get_super_partition_name(slot_number);
+	return "/dev/block/by-name/" + super_device;
+}
+
+void TWPartitionManager::Setup_Super_Devices() {
+	std::string superPart = Get_Super_Partition();
+	android::fs_mgr::CreateLogicalPartitions(superPart);
+	TWPartition* superPartition = new TWPartition();
+	superPartition->Mount_Point = "super";
+	superPartition->Actual_Block_Device = superPart;
+	superPartition->Alternate_Block_Device = superPart;
+	superPartition->Backup_Display_Name = "super";
+	superPartition->Can_Flash_Img = true;
+	superPartition->Change_Mount_Read_Only(true);
+	superPartition->Current_File_System = "emmc";
+	superPartition->Can_Be_Backed_Up = true;
+	superPartition->Is_Present = true;
+	superPartition->Is_SubPartition = false;
+	Add_Partition(superPartition);
+	PartitionManager.Output_Partition(superPartition);
+	Update_System_Details();
+}
+
+bool TWPartitionManager::Get_Super_Status() {
+	return access(Get_Super_Partition().c_str(), F_OK) == 0;
+}
diff --git a/partitions.hpp b/partitions.hpp
index 92970d9..cfe6970 100755
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -100,7 +100,7 @@
 	std::string Backup_Folder;                                                // Path to restore folder
 	bool adbbackup;                                                           // tell the system we are backing up over adb
 	bool adb_compression;                                                     // 0 == uncompressed, 1 == compressed
-	bool generate_digest;                                                      // tell system to create digest for partitions
+	bool generate_digest;                                                     // tell system to create digest for partitions
 	bool generate_md5;                                                        // tell system to create md5 for partitions
 	uint64_t total_restore_size;                                              // Total size of restored backup
 	uint64_t img_bytes_remaining;                                             // remaining img/emmc bytes to backup for progress indicator
@@ -162,6 +162,10 @@
 	void Set_Backup_FileName(string fname);                                   // Set Backup_FileName for partition
 	string Get_Backup_Name();                                                 // Get Backup_Name for partition
 	bool Decrypt_FBE_DE();                                                    // If FBE is present, backup exclusions are set up and DE decrypt is attempted
+	string Get_Mount_Point();												  // Return Mount_Point or directory the current partition is mounted on
+	bool Get_Super_Status();												  // Returns true if partition is a super volume mounted partitions
+	void Set_Can_Be_Backed_Up(bool val);									  // Update whether the partition can be backed up or not
+	void Set_Can_Be_Wiped(bool val);										  // Update whether the partition can be wiped or not
 
 public:
 	string Current_File_System;                                               // Current file system
@@ -176,6 +180,7 @@
 protected:
 	bool Has_Data_Media;                                                      // Indicates presence of /data/media, may affect wiping and backup methods
 	void Setup_Data_Media();                                                  // Sets up a partition as a /data/media emulated storage partition
+	void Set_Block_Device(std::string block_device);						  // Allow super partition setup to change block device
 
 private:
 	bool Process_Fstab_Line(const char *fstab_line, bool Display_Error, std::map<string, Flags_Map> *twrp_flags, bool Sar_Detect); // Processes a fstab line
@@ -281,8 +286,7 @@
 	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)
-	string Key_Directory;                                                      // Metadata key directory needed for mounting FBE encrypted data partitions using metadata encryption
-
+	string Key_Directory;                                                     // Metadata key directory needed for mounting FBE encrypted data partitions using metadata encryption
 	struct partition_fs_flags_struct {                                        // This struct is used to store mount flags and options for different file systems for the same partition
 		string File_System;
 		int Mount_Flags;
@@ -290,6 +294,7 @@
 	};
 
 	std::vector<partition_fs_flags_struct> fs_flags;                          // This vector stores mount flags and options for different file systems for the same partition
+	bool Is_Super;															  // States whether partition should be loaded from the super partition
 
 friend class TWPartitionManager;
 friend class DataManager;
@@ -361,7 +366,8 @@
 	void Translate_Partition_Display_Names();                                 // Updates display names based on translations
 	bool Decrypt_Adopted();                                                   // Attempt to identy and decrypt any adopted storage partitions
 	void Remove_Partition_By_Path(string Path);                               // Removes / erases a partition entry from the partition list
-
+	bool Prepare_All_Super_Volumes();										  // Prepare all known super volumes from super partition
+	bool Is_Super_Partition(const char* fstab_line);						  // Checks if partition entry is a super partition
 	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;
@@ -380,6 +386,10 @@
 	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
+    bool Prepare_Super_Volume(TWPartition* twrpPart);					  	  // Prepare logical super partition volume for mounting
+	std::string Get_Super_Partition();										  // Get Super Partition block device path
+	void Setup_Super_Devices();												  // Setup logical dm devices on super partition
+	bool Get_Super_Status();												  // Return whether device has a super partition
 
 private:
 	void Setup_Settings_Storage_Partition(TWPartition* Part);                 // Sets up settings storage
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 593ad9d..fa4e35d 100755
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -317,6 +317,15 @@
 	return st.st_size;
 }
 
+std::string TWFunc::Remove_Beginning_Slash(const std::string& path) {
+	std::string res;
+	size_t pos = path.find_first_of("/");
+	if (pos != std::string::npos) {
+		res = path.substr(pos+1);
+	}
+	return res;
+}
+
 std::string TWFunc::Remove_Trailing_Slashes(const std::string& path, bool leaveLast)
 {
 	std::string res;
@@ -1306,19 +1315,24 @@
 }
 
 bool TWFunc::Is_TWRP_App_In_System() {
-	if (PartitionManager.Mount_By_Path(PartitionManager.Get_Android_Root_Path(), false)) {
-		string base_path = PartitionManager.Get_Android_Root_Path();
-		if (TWFunc::Path_Exists(PartitionManager.Get_Android_Root_Path() + "/system"))
-			base_path += "/system"; // For devices with system as a root file system (e.g. Pixel)
-		string install_path = base_path + "/priv-app";
-		if (!TWFunc::Path_Exists(install_path))
-			install_path = base_path + "/app";
-		install_path += "/twrpapp";
-		if (TWFunc::Path_Exists(install_path)) {
-			LOGINFO("App found at '%s'\n", install_path.c_str());
-			DataManager::SetValue("tw_app_installed_in_system", 1);
-			return true;
+	LOGINFO("checking for twrp app\n");
+	TWPartition* sys = PartitionManager.Find_Partition_By_Path(PartitionManager.Get_Android_Root_Path());
+	if (!sys->Get_Super_Status()) {
+		if (PartitionManager.Mount_By_Path(PartitionManager.Get_Android_Root_Path(), false)) {
+			string base_path = PartitionManager.Get_Android_Root_Path();
+			if (TWFunc::Path_Exists(PartitionManager.Get_Android_Root_Path() + "/system"))
+				base_path += "/system"; // For devices with system as a root file system (e.g. Pixel)
+			string install_path = base_path + "/priv-app";
+			if (!TWFunc::Path_Exists(install_path))
+				install_path = base_path + "/app";
+			install_path += "/twrpapp";
+			if (TWFunc::Path_Exists(install_path)) {
+				LOGINFO("App found at '%s'\n", install_path.c_str());
+				DataManager::SetValue("tw_app_installed_in_system", 1);
+				return true;
+			}
 		}
+		DataManager::SetValue("tw_app_installed_in_system", 0);
 	}
 	DataManager::SetValue("tw_app_installed_in_system", 0);
 	PartitionManager.UnMount_By_Path(PartitionManager.Get_Android_Root_Path(), false);
@@ -1333,4 +1347,13 @@
 #endif
 }
 
+void TWFunc::List_Mounts() {
+	std::vector<std::string> mounts;
+	read_file("/proc/mounts", mounts);
+	LOGINFO("Mounts:\n");
+	for (auto&& mount: mounts) {
+		LOGINFO("%s\n", mount.c_str());
+	}
+}
+
 #endif // ndef BUILD_TWRPTAR_MAIN
diff --git a/twrp-functions.hpp b/twrp-functions.hpp
index 9d53ab6..412920a 100755
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -67,7 +67,8 @@
 	static bool Path_Exists(string Path);                                       // Returns true if the path exists
 	static Archive_Type Get_File_Type(string fn);                               // Determines file type, 0 for unknown, 1 for gzip, 2 for OAES encrypted
 	static int Try_Decrypting_File(string fn, string password); // -1 for some error, 0 for failed to decrypt, 1 for decrypted, 3 for decrypted and found gzip format
-	static unsigned long Get_File_Size(const string& Path);                            // Returns the size of a file
+	static unsigned long Get_File_Size(const string& Path);                     // Returns the size of a file
+	static std::string Remove_Beginning_Slash(const std::string& path);        // Remove the beginning slash of a path
 	static std::string Remove_Trailing_Slashes(const std::string& path, bool leaveLast = false); // Normalizes the path, e.g /data//media/ -> /data/media
 	static void Strip_Quotes(char* &str);                                       // Remove leading & trailing double-quotes from a string
 	static vector<string> split_string(const string &in, char del, bool skip_empty);
@@ -113,6 +114,7 @@
 	static void check_selinux_support(); // print whether selinux support is enabled to console
 	static bool Is_TWRP_App_In_System(); // Check if the TWRP app is installed in the system partition
 	static int Property_Override(string Prop_Name, string Prop_Value); // Override properties (including ro. properties)
+	static void List_Mounts();
 
 private:
 	static void Copy_Log(string Source, string Destination);
diff --git a/twrp.cpp b/twrp.cpp
index 2b84cbb..6d6e5ba 100755
--- a/twrp.cpp
+++ b/twrp.cpp
@@ -198,6 +198,10 @@
 		return -1;
 	}
 	PartitionManager.Output_Partition_Logging();
+
+	if (PartitionManager.Get_Super_Status())
+		PartitionManager.Setup_Super_Devices();
+
 	// Load up all the resources
 	gui_loadResources();
 
@@ -374,23 +378,29 @@
 	TWPartition* ven = PartitionManager.Find_Partition_By_Path("/vendor");
 
 	if (sys) {
-		if ((DataManager::GetIntValue("tw_mount_system_ro") == 0 && sys->Check_Lifetime_Writes() == 0) || DataManager::GetIntValue("tw_mount_system_ro") == 2) {
-			if (DataManager::GetIntValue("tw_never_show_system_ro_page") == 0) {
-				DataManager::SetValue("tw_back", "main");
-				if (gui_startPage("system_readonly", 1, 1) != 0) {
-					LOGERR("Failed to start system_readonly GUI page.\n");
+		if (sys->Get_Super_Status()) {
+			if (!PartitionManager.Prepare_All_Super_Volumes()) {
+				LOGERR("Unable to prepare super volumes.\n");
+			}
+		} else {
+			if ((DataManager::GetIntValue("tw_mount_system_ro") == 0 && sys->Check_Lifetime_Writes() == 0) || DataManager::GetIntValue("tw_mount_system_ro") == 2) {
+				if (DataManager::GetIntValue("tw_never_show_system_ro_page") == 0) {
+					DataManager::SetValue("tw_back", "main");
+					if (gui_startPage("system_readonly", 1, 1) != 0) {
+						LOGERR("Failed to start system_readonly GUI page.\n");
+					}
+				} else if (DataManager::GetIntValue("tw_mount_system_ro") == 0) {
+					sys->Change_Mount_Read_Only(false);
+					if (ven)
+						ven->Change_Mount_Read_Only(false);
 				}
-			} else if (DataManager::GetIntValue("tw_mount_system_ro") == 0) {
+			} else if (DataManager::GetIntValue("tw_mount_system_ro") == 1) {
+				// Do nothing, user selected to leave system read only
+			} else {
 				sys->Change_Mount_Read_Only(false);
 				if (ven)
 					ven->Change_Mount_Read_Only(false);
 			}
-		} else if (DataManager::GetIntValue("tw_mount_system_ro") == 1) {
-			// Do nothing, user selected to leave system read only
-		} else {
-			sys->Change_Mount_Read_Only(false);
-			if (ven)
-				ven->Change_Mount_Read_Only(false);
 		}
 	}
 #endif
diff --git a/variables.h b/variables.h
old mode 100644
new mode 100755
index 32a7b99..51ee09f
--- a/variables.h
+++ b/variables.h
@@ -23,7 +23,7 @@
 #define TW_USE_COMPRESSION_VAR      "tw_use_compression"
 #define TW_FILENAME                 "tw_filename"
 #define TW_ZIP_INDEX                "tw_zip_index"
-#define TW_ZIP_QUEUE_COUNT       "tw_zip_queue_count"
+#define TW_ZIP_QUEUE_COUNT          "tw_zip_queue_count"
 
 #define MAX_BACKUP_NAME_LEN 64
 #define TW_BACKUP_TEXT              "tw_backup_text"
@@ -141,6 +141,7 @@
 #define TW_USE_SHA2                 "tw_use_sha2"
 #define TW_NO_SHA2                  "tw_no_sha2"
 #define TW_UNMOUNT_SYSTEM           "tw_unmount_system"
+#define TW_IS_SUPER                 "tw_is_super"
 
 // Also used:
 //   tw_boot_is_mountable