Merge remote-tracking branch 'origin/android-9.0' into android-10.0

Change-Id: Ie850f431f0d2c39c86b9c10701676a24770ab447
diff --git a/Android.mk b/Android.mk
index b17969d..2e341d9 100755
--- a/Android.mk
+++ b/Android.mk
@@ -142,7 +142,7 @@
     LOCAL_SHARED_LIBRARIES += libcrypto
 endif
 
-ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 24; echo $$?),0)
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 23; echo $$?),0)
     LOCAL_SHARED_LIBRARIES += libbase
 endif
 
@@ -390,6 +390,20 @@
 ifneq ($(TW_CLOCK_OFFSET),)
 	LOCAL_CFLAGS += -DTW_CLOCK_OFFSET=$(TW_CLOCK_OFFSET)
 endif
+ifneq ($(TW_OVERRIDE_SYSTEM_PROPS),)
+    TW_INCLUDE_LIBRESETPROP := true
+    LOCAL_CFLAGS += -DTW_OVERRIDE_SYSTEM_PROPS=$(TW_OVERRIDE_SYSTEM_PROPS)
+endif
+ifneq ($(TW_INCLUDE_LIBRESETPROP),)
+    ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 24; echo $$?),0)
+        $(warning libresetprop is not available for android < 7)
+    else
+        LOCAL_SHARED_LIBRARIES += libresetprop
+        LOCAL_C_INCLUDES += external/magisk-prebuilt/include
+        LOCAL_CFLAGS += -DTW_INCLUDE_LIBRESETPROP
+    endif
+endif
+
 TWRP_REQUIRED_MODULES += \
     relink \
     relink_init \
diff --git a/data.cpp b/data.cpp
index 088dbda..b1e8404 100755
--- a/data.cpp
+++ b/data.cpp
@@ -783,6 +783,7 @@
 #else
 	mPersist.SetValue(TW_NO_SHA2, "1");
 #endif
+	mPersist.SetValue(TW_UNMOUNT_SYSTEM, "1");
 
 #ifdef TW_NO_SCREEN_TIMEOUT
 	mConst.SetValue("tw_screen_timeout_secs", "0");
diff --git a/etc/init.rc b/etc/init.rc
index d0baeb8..73b88d2 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -13,7 +13,6 @@
     # ueventd wants to write to /acct
     mount cgroup none /acct cpuacct
     mkdir /acct/uid
-
     start ueventd
 
 on init
diff --git a/gui/theme/common/landscape.xml b/gui/theme/common/landscape.xml
index 8244c46..230b72f 100755
--- a/gui/theme/common/landscape.xml
+++ b/gui/theme/common/landscape.xml
@@ -2937,6 +2937,9 @@
 					<condition var1="tw_no_sha2" var2="0"/>
 					<data variable="tw_use_sha2"/>
 				</listitem>
+				<listitem name="{@unmount_sys_install=Unmount System before installing a ZIP}">
+					<data variable="tw_unmount_system"/>
+				</listitem>
 			</listbox>
 
 			<checkbox>
diff --git a/gui/theme/common/languages/en.xml b/gui/theme/common/languages/en.xml
index 4a0ac7f..3769da5 100755
--- a/gui/theme/common/languages/en.xml
+++ b/gui/theme/common/languages/en.xml
@@ -719,5 +719,8 @@
 		<string name="include_kernel_log">Include Kernel Log</string>
 		<string name="sha2_chk">Use SHA2 for hashing</string>
 		<string name="unable_set_boot_slot">Error changing bootloader boot slot to {1}</string>
+		<string name="unmount_sys_install">Unmount System before installing a ZIP</string>
+		<string name="unmount_system">Unmounting System...</string>
+		<string name="unmount_system_err">Failed unmounting System</string>
 	</resources>
 </language>
diff --git a/gui/theme/common/portrait.xml b/gui/theme/common/portrait.xml
index e014cc5..8370414 100755
--- a/gui/theme/common/portrait.xml
+++ b/gui/theme/common/portrait.xml
@@ -3150,6 +3150,9 @@
 					<condition var1="tw_no_sha2" var2="0"/>
 					<data variable="tw_use_sha2"/>
 				</listitem>
+				<listitem name="{@unmount_sys_install=Unmount System before installing a ZIP}">
+					<data variable="tw_unmount_system"/>
+				</listitem>
 			</listbox>
 
 			<button style="main_button_half_height">
diff --git a/gui/theme/common/watch.xml b/gui/theme/common/watch.xml
index f5d3222..05b7bd2 100755
--- a/gui/theme/common/watch.xml
+++ b/gui/theme/common/watch.xml
@@ -3640,6 +3640,9 @@
 					<condition var1="tw_no_sha2" var2="0"/>
 					<data variable="tw_use_sha2"/>
 				</listitem>
+				<listitem name="{@unmount_sys_install=Unmount System before installing a ZIP}">
+					<data variable="tw_unmount_system"/>
+				</listitem>
 			</listbox>
 
 			<action>
diff --git a/openrecoveryscript.cpp b/openrecoveryscript.cpp
index 120dfca..a52211c 100755
--- a/openrecoveryscript.cpp
+++ b/openrecoveryscript.cpp
@@ -148,8 +148,8 @@
 				// Wipe
 				if (strcmp(value, "cache") == 0 || strcmp(value, "/cache") == 0) {
 					PartitionManager.Wipe_By_Path("/cache");
-				} else if (strcmp(value, PartitionManager.Get_Android_Root_Path().c_str()) == 0 || strcmp(value, PartitionManager.Get_Android_Root_Path().c_str()) == 0) {
-					PartitionManager.Wipe_By_Path(PartitionManager.Get_Android_Root_Path());
+				} else if (strcmp(value, "system") == 0 || strcmp(value, "/system") == 0 || strcmp(value, PartitionManager.Get_Android_Root_Path().c_str()) == 0) {
+					PartitionManager.Wipe_By_Path("/system");
 				} else if (strcmp(value, "dalvik") == 0 || strcmp(value, "dalvick") == 0 || strcmp(value, "dalvikcache") == 0 || strcmp(value, "dalvickcache") == 0) {
 					PartitionManager.Wipe_Dalvik_Cache();
 				} else if (strcmp(value, "data") == 0 || strcmp(value, "/data") == 0 || strcmp(value, "factory") == 0 || strcmp(value, "factoryreset") == 0) {
@@ -301,6 +301,8 @@
 					strcat(mount, value);
 				} else
 					strcpy(mount, value);
+				if (!strcmp(mount, "/system"))
+					strcpy(mount, PartitionManager.Get_Android_Root_Path().c_str());
 				if (PartitionManager.Mount_By_Path(mount, true))
 					gui_msg(Msg("mounted=Mounted '{1}'")(mount));
 			} else if (strcmp(command, "unmount") == 0 || strcmp(command, "umount") == 0) {
@@ -311,6 +313,8 @@
 					strcat(mount, value);
 				} else
 					strcpy(mount, value);
+				if (!strcmp(mount, "/system"))
+					strcpy(mount, PartitionManager.Get_Android_Root_Path().c_str());
 				if (PartitionManager.UnMount_By_Path(mount, true))
 					gui_msg(Msg("unmounted=Unounted '{1}'")(mount));
 			} else if (strcmp(command, "set") == 0) {
diff --git a/partition.cpp b/partition.cpp
index 581593c..b6e789b 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -272,7 +272,7 @@
 	// Do nothing
 }
 
-bool TWPartition::Process_Fstab_Line(const char *fstab_line, bool Display_Error, std::map<string, Flags_Map> *twrp_flags) {
+bool TWPartition::Process_Fstab_Line(const char *fstab_line, bool Display_Error, std::map<string, Flags_Map> *twrp_flags, bool Sar_Detect) {
 	char full_line[MAX_FSTAB_LINE_LENGTH];
 	char twflags[MAX_FSTAB_LINE_LENGTH] = "";
 	char* ptr;
@@ -309,11 +309,12 @@
 			Mount_Point = ptr;
 			if (fstab_version == 2) {
 				additional_entry = PartitionManager.Find_Partition_By_Path(Mount_Point);
-				if (additional_entry) {
+				if (!Sar_Detect && additional_entry) {
 					LOGINFO("Found an additional entry for '%s'\n", Mount_Point.c_str());
 				}
 			}
-			LOGINFO("Processing '%s'\n", Mount_Point.c_str());
+			if(!Sar_Detect)
+				LOGINFO("Processing '%s'\n", Mount_Point.c_str());
 			Backup_Path = Mount_Point;
 			Storage_Path = Mount_Point;
 			Display_Name = ptr + 1;
@@ -410,13 +411,16 @@
 	if (Primary_Block_Device.find("*") != string::npos)
 		Wildcard_Block_Device = true;
 
-	if (Mount_Point == "auto") {
-		Mount_Point = "/auto";
-		char autoi[5];
-		sprintf(autoi, "%i", auto_index);
-		Mount_Point += autoi;
+	if (Sar_Detect) {
+		if(Is_File_System(Fstab_File_System) && (Mount_Point == "/" || Mount_Point == "/system" || Mount_Point == "/system_root"))
+			Find_Actual_Block_Device();
+		else
+			return true;
+	} else if (Mount_Point == "auto") {
+		Mount_Point = "/auto" + to_string(auto_index);
 		Backup_Path = Mount_Point;
 		Storage_Path = Mount_Point;
+		Backup_Name = Mount_Point.substr(1);
 		auto_index++;
 		Setup_File_System(Display_Error);
 		Display_Name = "Storage";
@@ -436,8 +440,10 @@
 	} else if (Is_File_System(Fstab_File_System)) {
 		Find_Actual_Block_Device();
 		Setup_File_System(Display_Error);
-		if (Mount_Point == PartitionManager.Get_Android_Root_Path()) {
+		Backup_Name = Display_Name = Mount_Point.substr(1, Mount_Point.size() - 1);
+		if (Mount_Point == "/" || Mount_Point == "/system" || Mount_Point == "/system_root") {
 			Display_Name = "System";
+			Backup_Name = "system";
 			Backup_Display_Name = Display_Name;
 			Storage_Name = Display_Name;
 			Wipe_Available_in_GUI = true;
@@ -598,6 +604,19 @@
 		}
 	}
 
+	if (Is_File_System(Fstab_File_System) && (Mount_Point == "/" || Mount_Point == "/system" || Mount_Point == "/system_root")) {
+		if (Sar_Detect) {
+			Mount_Point = "/s";
+			Mount_Read_Only = true;
+			Can_Be_Mounted = true;
+		} else {
+			Mount_Point = PartitionManager.Get_Android_Root_Path();
+			Backup_Path = Mount_Point;
+			Storage_Path = Mount_Point;
+			Make_Dir(Mount_Point, Display_Error);
+		}
+	}
+
 	return true;
 }
 
@@ -1074,8 +1093,6 @@
 
 	// Make the mount point folder if it doesn't exist
 	Make_Dir(Mount_Point, Display_Error);
-	Display_Name = Mount_Point.substr(1, Mount_Point.size() - 1);
-	Backup_Name = Display_Name;
 	Backup_Method = BM_FILES;
 }
 
@@ -1525,10 +1542,23 @@
 		string Command = "mount -o bind '" + Symlink_Path + "' '" + Symlink_Mount_Point + "'";
 		TWFunc::Exec_Cmd(Command);
 	}
+
+	if (Mount_Point == "/system_root") {
+		unlink("/system");
+		mkdir("/system", 0755);
+		mount("/system_root/system", "/system", "auto", MS_BIND, NULL);
+	}
+
 	return true;
 }
 
 bool TWPartition::UnMount(bool Display_Error) {
+	if (Mount_Point == "/system_root") {
+		if (umount("/system") == -1)
+			umount2("/system", MNT_DETACH);
+		rmdir("/system");
+		symlink("/system_root/system", "/system");
+	}
 	if (Is_Mounted()) {
 		int never_unmount_system;
 
@@ -2895,7 +2925,7 @@
 		TWPartition *part = new TWPartition;
 		char buffer[MAX_FSTAB_LINE_LENGTH];
 		sprintf(buffer, "%s %s-%i auto defaults defaults", item.c_str(), Mount_Point.c_str(), ++mount_point_index);
-		part->Process_Fstab_Line(buffer, false, NULL);
+		part->Process_Fstab_Line(buffer, false, NULL, false);
 		char display[MAX_FSTAB_LINE_LENGTH];
 		sprintf(display, "%s %i", Storage_Name.c_str(), mount_point_index);
 		part->Storage_Name = display;
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 1974224..159cead 100755
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -111,7 +111,7 @@
 #endif
 }
 
-int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error) {
+int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error, bool Sar_Detect) {
 	FILE *fstabFile;
 	char fstab_line[MAX_FSTAB_LINE_LENGTH];
 	TWPartition* settings_partition = NULL;
@@ -198,7 +198,7 @@
 			fstab_line[line_size] = '\n';
 
 		TWPartition* partition = new TWPartition();
-		if (partition->Process_Fstab_Line(fstab_line, Display_Error, &twrp_flags))
+		if (partition->Process_Fstab_Line(fstab_line, Display_Error, &twrp_flags, Sar_Detect))
 			Partitions.push_back(partition);
 		else
 			delete partition;
@@ -213,7 +213,7 @@
 		for (std::map<string, Flags_Map>::iterator mapit=twrp_flags.begin(); mapit!=twrp_flags.end(); mapit++) {
 			if (Find_Partition_By_Path(mapit->first) == NULL) {
 				TWPartition* partition = new TWPartition();
-				if (partition->Process_Fstab_Line(mapit->second.fstab_line, Display_Error, NULL))
+				if (partition->Process_Fstab_Line(mapit->second.fstab_line, Display_Error, NULL, Sar_Detect))
 					Partitions.push_back(partition);
 				else
 					delete partition;
@@ -227,6 +227,13 @@
 
 	std::vector<TWPartition*>::iterator iter;
 	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
+		if (Sar_Detect) {
+			if ((*iter)->Mount_Point == "/s")
+				return true;
+			else
+				continue;
+		}
+
 		(*iter)->Partition_Post_Processing(Display_Error);
 
 		if ((*iter)->Is_Storage) {
@@ -592,6 +599,8 @@
 	std::vector<TWPartition*>::iterator iter;
 	string Local_Path = TWFunc::Get_Root_Path(Path);
 
+	if (Local_Path == "/system")
+		Local_Path = Get_Android_Root_Path();
 	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
 		if ((*iter)->Mount_Point == Local_Path || (!(*iter)->Symlink_Mount_Point.empty() && (*iter)->Symlink_Mount_Point == Local_Path))
 			return (*iter);
@@ -1265,8 +1274,12 @@
 				Part->Backup_FileName.resize(Part->Backup_FileName.size() - strlen(extn) + 3);
 			}
 
-			if (!Part->Is_SubPartition)
-				Restore_List += Part->Backup_Path + ";";
+			if (!Part->Is_SubPartition) {
+				if (Part->Backup_Path == Get_Android_Root_Path())
+					Restore_List += "/system;";
+				else
+					Restore_List += Part->Backup_Path + ";";
+			}
 		}
 		closedir(d);
 	}
@@ -1289,6 +1302,8 @@
 	bool found = false;
 	string Local_Path = TWFunc::Get_Root_Path(Path);
 
+	if (Local_Path == "/system")
+		Local_Path = Get_Android_Root_Path();
 	// Iterate through all partitions
 	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
 		if ((*iter)->Mount_Point == Local_Path || (!(*iter)->Symlink_Mount_Point.empty() && (*iter)->Symlink_Mount_Point == Local_Path)) {
@@ -2839,10 +2854,9 @@
 }
 
 string TWPartitionManager::Get_Android_Root_Path() {
-	std::string Android_Root = getenv("ANDROID_ROOT");
-	if (Android_Root == "")
-		Android_Root = "/system";
-	return Android_Root;
+	if (property_get_bool("ro.twrp.sar", false))
+		return "/system_root";
+	return "/system";
 }
 
 void TWPartitionManager::Remove_Uevent_Devices(const string& Mount_Point) {
diff --git a/partitions.hpp b/partitions.hpp
index 4071b94..92970d9 100755
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -178,7 +178,7 @@
 	void Setup_Data_Media();                                                  // Sets up a partition as a /data/media emulated storage partition
 
 private:
-	bool Process_Fstab_Line(const char *fstab_line, bool Display_Error, std::map<string, Flags_Map> *twrp_flags); // Processes a fstab line
+	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
 	void Setup_Data_Partition(bool Display_Error);                            // Setup data partition after fstab processed
 	void Setup_Cache_Partition(bool Display_Error);                           // Setup cache partition after fstab processed
 	bool Find_Wildcard_Block_Devices(const string& Device);                   // Searches for and finds wildcard block devices
@@ -305,7 +305,7 @@
 	~TWPartitionManager() {}
 
 public:
-	int Process_Fstab(string Fstab_Filename, bool Display_Error);             // Parses the fstab and populates the partitions
+	int Process_Fstab(string Fstab_Filename, bool Display_Error, bool Sar_Detect);             // Parses the fstab and populates the partitions
 	int Write_Fstab();                                                        // Creates /etc/fstab file that's used by the command line for mount commands
 	void Output_Partition_Logging();                                          // Outputs partition information to the log
 	void Output_Partition(TWPartition* Part);                                 // Outputs partition details to the log
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index 5bf3cc5..f5785ff 100755
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -663,9 +663,9 @@
     endif
 endif
 
-ifeq ($(TW_INCLUDE_REPACKTOOLS), true)
+ifneq (,$(filter $(TW_INCLUDE_REPACKTOOLS) $(TW_INCLUDE_RESETPROP) $(TW_INCLUDE_LIBRESETPROP), true))
     ifeq ($(wildcard external/magisk-prebuilt/Android.mk),)
-        $(warning Magisk repacking tools not found!)
+        $(warning Magisk prebuilt tools not found!)
         $(warning Please place https://github.com/TeamWin/external_magisk-prebuilt)
         $(warning into external/magisk-prebuilt)
         $(error magiskboot prebuilts not present; exiting)
diff --git a/twinstall.cpp b/twinstall.cpp
index fb639a7..a385c51 100755
--- a/twinstall.cpp
+++ b/twinstall.cpp
@@ -341,7 +341,7 @@
 }
 
 int TWinstall_zip(const char* path, int* wipe_cache) {
-	int ret_val, zip_verify = 1;
+	int ret_val, zip_verify = 1, unmount_system = 1;
 
 	if (strcmp(path, "error") == 0) {
 		LOGERR("Failed to get adb sideload file: '%s'\n", path);
@@ -361,6 +361,8 @@
 		}
 	}
 
+	DataManager::GetValue(TW_UNMOUNT_SYSTEM, unmount_system);
+
 #ifndef TW_OEM_BUILD
 	DataManager::GetValue(TW_SIGNED_ZIP_VERIFY_VAR, zip_verify);
 #endif
@@ -412,6 +414,14 @@
 		return INSTALL_CORRUPT;
 	}
 
+	if (unmount_system) {
+		gui_msg("unmount_system=Unmounting System...");
+		if(!PartitionManager.UnMount_By_Path(PartitionManager.Get_Android_Root_Path(), true)) {
+			gui_err("unmount_system_err=Failed unmounting System");
+			return -1;
+		}
+	}
+
 	time_t start, stop;
 	time(&start);
 	if (Zip.EntryExists(ASSUMED_UPDATE_BINARY_NAME)) {
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index a3e5a07..97387b7 100755
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -59,6 +59,10 @@
 	#include "libcrecovery/common.h"
 }
 
+#ifdef TW_INCLUDE_LIBRESETPROP
+    #include <resetprop.h>
+#endif
+
 struct selabel_handle *selinux_handle;
 
 /* Execute a command */
@@ -891,19 +895,23 @@
 }
 
 string TWFunc::System_Property_Get(string Prop_Name) {
-	bool mount_state = PartitionManager.Is_Mounted_By_Path(PartitionManager.Get_Android_Root_Path());
+	return System_Property_Get(Prop_Name, PartitionManager, PartitionManager.Get_Android_Root_Path());
+}
+
+string TWFunc::System_Property_Get(string Prop_Name, TWPartitionManager &PartitionManager, string Mount_Point) {
+	bool mount_state = PartitionManager.Is_Mounted_By_Path(Mount_Point);
 	std::vector<string> buildprop;
 	string propvalue;
-	if (!PartitionManager.Mount_By_Path(PartitionManager.Get_Android_Root_Path(), true))
+	if (!PartitionManager.Mount_By_Path(Mount_Point, true))
 		return propvalue;
-	string prop_file = "/system/build.prop";
+	string prop_file = Mount_Point + "/build.prop";
 	if (!TWFunc::Path_Exists(prop_file))
-		prop_file = PartitionManager.Get_Android_Root_Path() + "/system/build.prop"; // for devices with system as a root file system (e.g. Pixel)
+		prop_file = Mount_Point + "/system/build.prop"; // for devices with system as a root file system (e.g. Pixel)
 	if (TWFunc::read_file(prop_file, buildprop) != 0) {
 		LOGINFO("Unable to open build.prop for getting '%s'.\n", Prop_Name.c_str());
 		DataManager::SetValue(TW_BACKUP_NAME, Get_Current_Date());
 		if (!mount_state)
-			PartitionManager.UnMount_By_Path(PartitionManager.Get_Android_Root_Path(), false);
+			PartitionManager.UnMount_By_Path(Mount_Point, false);
 		return propvalue;
 	}
 	int line_count = buildprop.size();
@@ -916,12 +924,12 @@
 		if (propname == Prop_Name) {
 			propvalue = buildprop.at(index).substr(end_pos + 1, buildprop.at(index).size());
 			if (!mount_state)
-				PartitionManager.UnMount_By_Path(PartitionManager.Get_Android_Root_Path(), false);
+				PartitionManager.UnMount_By_Path(Mount_Point, false);
 			return propvalue;
 		}
 	}
 	if (!mount_state)
-		PartitionManager.UnMount_By_Path(PartitionManager.Get_Android_Root_Path(), false);
+		PartitionManager.UnMount_By_Path(Mount_Point, false);
 	return propvalue;
 }
 
@@ -1315,4 +1323,13 @@
 	DataManager::SetValue("tw_app_installed_in_system", 0);
 	return false;
 }
+
+int TWFunc::Property_Override(string Prop_Name, string Prop_Value) {
+#ifdef TW_INCLUDE_LIBRESETPROP
+    return setprop(Prop_Name.c_str(), Prop_Value.c_str(), false);
+#else
+    return -2;
+#endif
+}
+
 #endif // ndef BUILD_TWRPTAR_MAIN
diff --git a/twrp-functions.hpp b/twrp-functions.hpp
index 8cea321..9d53ab6 100755
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -24,6 +24,10 @@
 
 #include "twrpDigest/twrpDigest.hpp"
 
+#ifndef BUILD_TWRPTAR_MAIN
+#include "partitions.hpp"
+#endif
+
 using namespace std;
 
 #define NON_AB_CACHE_DIR "/cache/"
@@ -90,6 +94,7 @@
 	static int write_to_file(const string& fn, const string& line);             //write to file
 	static bool Try_Decrypting_Backup(string Restore_Path, string Password); // true for success, false for failed to decrypt
 	static string System_Property_Get(string Prop_Name);                // Returns value of Prop_Name from reading /system/build.prop
+	static string System_Property_Get(string Prop_Name, TWPartitionManager &PartitionManager, string Mount_Point);                // Returns value of Prop_Name from reading /system/build.prop
 	static string Get_Current_Date(void);                               // Returns the current date in ccyy-m-dd--hh-nn-ss format
 	static void Auto_Generate_Backup_Name();                            // Populates TW_BACKUP_NAME with a backup name based on current date and ro.build.display.id from /system/build.prop
 	static void Fixup_Time_On_Boot(const string& time_paths = ""); // Fixes time on devices which need it (time_paths is a space separated list of paths to check for ats_* files)
@@ -107,6 +112,7 @@
 	static std::string get_cache_dir(); // return the cache partition existence
 	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)
 
 private:
 	static void Copy_Log(string Source, string Destination);
diff --git a/twrp.cpp b/twrp.cpp
index 8c6dcf8..2b84cbb 100755
--- a/twrp.cpp
+++ b/twrp.cpp
@@ -43,6 +43,11 @@
 #include "twrp-functions.hpp"
 #include "data.hpp"
 #include "partitions.hpp"
+#ifdef __ANDROID_API_N__
+#include <android-base/strings.h>
+#else
+#include <base/strings.h>
+#endif
 #include "openrecoveryscript.hpp"
 #include "variables.h"
 #include "twrpAdbBuFifo.hpp"
@@ -117,8 +122,78 @@
 	if (!TWFunc::Path_Exists(fstab_filename)) {
 		fstab_filename = "/etc/recovery.fstab";
 	}
+
+	// Begin SAR detection
+	{
+		TWPartitionManager SarPartitionManager;
+		printf("=> Processing %s for SAR-detection\n", fstab_filename.c_str());
+		if (!SarPartitionManager.Process_Fstab(fstab_filename, 1, 1)) {
+			LOGERR("Failing out of recovery due to problem with fstab.\n");
+			return -1;
+		}
+
+		mkdir("/s", 0755);
+
+#if defined(AB_OTA_UPDATER) || defined(__ANDROID_API_Q__)
+		bool fallback_sar = true;
+#else
+		bool fallback_sar = property_get_bool("ro.build.system_root_image", false);
+#endif
+
+		if(SarPartitionManager.Mount_By_Path("/s", false)) {
+			if (TWFunc::Path_Exists("/s/build.prop")) {
+				LOGINFO("SAR-DETECT: Non-SAR System detected\n");
+				property_set("ro.twrp.sar", "0");
+				rmdir("/system_root");
+			} else if (TWFunc::Path_Exists("/s/system/build.prop")) {
+				LOGINFO("SAR-DETECT: SAR System detected\n");
+				property_set("ro.twrp.sar", "1");
+			} else {
+				LOGINFO("SAR-DETECT: No build.prop found, falling back to %s\n", fallback_sar ? "SAR" : "Non-SAR");
+				property_set("ro.twrp.sar", fallback_sar ? "1" : "0");
+			}
+
+// We are doing this here during SAR-detection, since we are mounting the system-partition anyway
+// This way we don't need to remount it later, just for overriding properties
+#if defined(TW_INCLUDE_LIBRESETPROP) && defined(TW_OVERRIDE_SYSTEM_PROPS)
+			stringstream override_props(EXPAND(TW_OVERRIDE_SYSTEM_PROPS));
+			string current_prop;
+			while (getline(override_props, current_prop, ';')) {
+				string other_prop;
+				if (current_prop.find("=") != string::npos) {
+					other_prop = current_prop.substr(current_prop.find("=") + 1);
+					current_prop = current_prop.substr(0, current_prop.find("="));
+				} else {
+					other_prop = current_prop;
+				}
+				other_prop = android::base::Trim(other_prop);
+				current_prop = android::base::Trim(current_prop);
+				string sys_val = TWFunc::System_Property_Get(other_prop, SarPartitionManager, "/s");
+				if (!sys_val.empty()) {
+					LOGINFO("Overriding %s with value: \"%s\" from system property %s\n", current_prop.c_str(), sys_val.c_str(), other_prop.c_str());
+					int error = TWFunc::Property_Override(current_prop, sys_val);
+					if (error) {
+						LOGERR("Failed overriding property %s, error_code: %d\n", current_prop.c_str(), error);
+					}
+				} else {
+					LOGINFO("Not overriding %s with empty value from system property %s\n", current_prop.c_str(), other_prop.c_str());
+				}
+			}
+#endif
+			SarPartitionManager.UnMount_By_Path("/s", false);
+		} else {
+			LOGINFO("SAR-DETECT: Could not mount system partition, falling back to %s\n", fallback_sar ? "SAR":"Non-SAR");
+			property_set("ro.twrp.sar", fallback_sar ? "1" : "0");
+		}
+
+		rmdir("/s");
+
+		TWFunc::check_and_run_script("/sbin/sarsetup.sh", "boot");
+	}
+	// End SAR detection
+
 	printf("=> Processing %s\n", fstab_filename.c_str());
-	if (!PartitionManager.Process_Fstab(fstab_filename, 1)) {
+	if (!PartitionManager.Process_Fstab(fstab_filename, 1, 0)) {
 		LOGERR("Failing out of recovery due to problem with fstab.\n");
 		return -1;
 	}
diff --git a/variables.h b/variables.h
index 76da715..24cde92 100644
--- a/variables.h
+++ b/variables.h
@@ -140,6 +140,7 @@
 #define TW_MILITARY_TIME            "tw_military_time"
 #define TW_USE_SHA2                 "tw_use_sha2"
 #define TW_NO_SHA2                  "tw_no_sha2"
+#define TW_UNMOUNT_SYSTEM           "tw_unmount_system"
 
 // Also used:
 //   tw_boot_is_mountable