Mount system as read-only by default

Mounting system as rw can prevent future OTA updates. The purpose
of this patch set is to prevent TWRP from mounting sytem as rw on
the first boot. Device maintainers should update their twrp.fstab
files on these devices to include an additional line:
/system_image emmc /dev/block/../system

This line will allow TWRP to create a raw system image backup to
ensure that the user can return to an original state for future
OTA updates.

Change-Id: I8929d85bc3a5b96cc564bc7f734b58d5612ec833
diff --git a/gui/action.cpp b/gui/action.cpp
index 3425512..7ecd0b4 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -196,6 +196,8 @@
 		ADD_ACTION(startmtp);
 		ADD_ACTION(stopmtp);
 		ADD_ACTION(cancelbackup);
+		ADD_ACTION(checkpartitionlifetimewrites);
+		ADD_ACTION(mountsystemtoggle);
 
 		// remember actions that run in the caller thread
 		for (mapFunc::const_iterator it = mf.begin(); it != mf.end(); ++it)
@@ -1737,3 +1739,55 @@
 
 	return atol(key.c_str());
 }
+
+int GUIAction::checkpartitionlifetimewrites(std::string arg)
+{
+	int op_status = 0;
+	TWPartition* sys = PartitionManager.Find_Partition_By_Path(arg);
+
+	operation_start("Check Partition Lifetime Writes");
+	if (sys) {
+		if (sys->Check_Lifetime_Writes() != 0)
+			DataManager::SetValue("tw_lifetime_writes", 1);
+		else
+			DataManager::SetValue("tw_lifetime_writes", 0);
+		op_status = 0; // success
+	} else {
+		DataManager::SetValue("tw_lifetime_writes", 1);
+		op_status = 1; // fail
+	}
+
+	operation_end(op_status);
+	return 0;
+}
+
+int GUIAction::mountsystemtoggle(std::string arg)
+{
+	int op_status = 0;
+	bool remount_system = PartitionManager.Is_Mounted_By_Path("/system");
+
+	operation_start("Toggle System Mount");
+	if (!PartitionManager.UnMount_By_Path("/system", true)) {
+		op_status = 1; // fail
+	} else {
+		TWPartition* Part = PartitionManager.Find_Partition_By_Path("/system");
+		if (Part) {
+			if (DataManager::GetIntValue("tw_mount_system_ro")) {
+				DataManager::SetValue("tw_mount_system_ro", 0);
+				Part->Change_Mount_Read_Only(false);
+			} else {
+				DataManager::SetValue("tw_mount_system_ro", 1);
+				Part->Change_Mount_Read_Only(true);
+			}
+			if (remount_system) {
+				Part->Mount(true);
+			}
+			op_status = 0; // success
+		} else {
+			op_status = 1; // fail
+		}
+	}
+
+	operation_end(op_status);
+	return 0;
+}
diff --git a/gui/devices/1080x1920/res/ui.xml b/gui/devices/1080x1920/res/ui.xml
index 3135a03..a611d05 100644
--- a/gui/devices/1080x1920/res/ui.xml
+++ b/gui/devices/1080x1920/res/ui.xml
@@ -86,6 +86,7 @@
 		<variable name="tz_selected_y" value="240" />
 		<variable name="tz_set_y" value="1500" />
 		<variable name="tz_current_y" value="1425" />
+		<variable name="system_ro_y" value="1770" />
 		<variable name="col_progressbar_x" value="351" />
 		<variable name="row_progressbar_y" value="1650" />
 		<variable name="col1_medium_x" value="10" />
diff --git a/gui/devices/320x320/res/ui.xml b/gui/devices/320x320/res/ui.xml
index 5495b77..1dec405 100644
--- a/gui/devices/320x320/res/ui.xml
+++ b/gui/devices/320x320/res/ui.xml
@@ -174,6 +174,7 @@
 		<variable name="row_offset_medium_y" value="206" />
 		<variable name="tz_set_y" value="271" />
 		<variable name="tz_current_y" value="249" />
+		<variable name="system_ro_y" value="216" />
 		<variable name="button_fill_color" value="#303030" />
 		<variable name="button_fill_full_width" value="308" />
 		<variable name="button_fill_main_width" value="150" />
@@ -189,7 +190,7 @@
 		<variable name="backup_button_row1" value="214" />
 		<variable name="backup_button_row2" value="242" />
 		<variable name="mount_list_height" value="190" />
-		<variable name="mount_storage_row" value="200" />
+		<variable name="mount_storage_row" value="193" />
 		<variable name="storage_list_height" value="134" />
 		<variable name="wipe_list_height" value="216" />
 		<variable name="wipe_button_y" value="170" />
diff --git a/gui/devices/480x800/res/ui.xml b/gui/devices/480x800/res/ui.xml
index 3c320a7..9844541 100644
--- a/gui/devices/480x800/res/ui.xml
+++ b/gui/devices/480x800/res/ui.xml
@@ -82,6 +82,7 @@
 		<variable name="tz_selected_y" value="110" />
 		<variable name="tz_set_y" value="580" />
 		<variable name="tz_current_y" value="730" />
+		<variable name="system_ro_y" value="550" />
 		<variable name="col_progressbar_x" value="114" />
 		<variable name="row_progressbar_y" value="720" />
 		<variable name="col1_medium_x" value="10" />
diff --git a/gui/devices/landscape/res/landscape.xml b/gui/devices/landscape/res/landscape.xml
index 25b9b17..12c6629 100644
--- a/gui/devices/landscape/res/landscape.xml
+++ b/gui/devices/landscape/res/landscape.xml
@@ -989,6 +989,27 @@
 				</actions>
 			</object>
 
+			<object type="button">
+				<placement x="%col3_x%" y="%row10_text_y%" />
+				<font resource="font" color="%text_color%" />
+				<condition var1="tw_mount_system_ro" op="=" var2="0" />
+				<text>Only mount system read-only</text>
+				<image resource="checkbox_false" />
+				<action function="mountsystemtoggle"></action>
+			</object>
+
+			<object type="button">
+				<placement x="%col3_x%" y="%row10_text_y%" />
+				<font resource="font" color="%text_color%" />
+				<condition var1="tw_mount_system_ro" op="!=" var2="0" />
+				<text>Only mount system read-only</text>
+				<image resource="checkbox_true" />
+				<actions>
+					<action function="set">tw_lifetime_writes=2</action>
+					<action function="page">system_readonly_check</action>
+				</actions>
+			</object>
+
 			<object type="action">
 				<touch key="home" />
 				<action function="page">main</action>
@@ -1035,6 +1056,31 @@
 			<object type="template" name="footer" />
 		</page>
 
+		<page name="system_readonly_check">
+			<object type="action">
+				<action function="checkpartitionlifetimewrites">/system</action>
+			</object>
+
+			<object type="action">
+				<conditions>
+					<condition var1="tw_operation_state" var2="1" />
+					<condition var1="tw_lifetime_writes" var2="1" />
+				</conditions>
+				<action function="page">mount</action>
+			</object>
+
+			<object type="action">
+				<conditions>
+					<condition var1="tw_operation_state" var2="1" />
+					<condition var1="tw_lifetime_writes" var2="0" />
+				</conditions>
+				<actions>
+					<action function="set">tw_back=mount</action>
+					<action function="page">system_readonly</action>
+				</actions>
+			</object>
+		</page>
+
 		<page name="wipe">
 			<object type="template" name="header" />
 
@@ -3596,5 +3642,57 @@
 				</actions>
 			</object>
 		</page>
+
+		<page name="system_readonly">
+			<object type="template" name="header" />
+
+			<object type="text">
+				<placement x="%center_x%" y="%row1_text_y%" placement="5" />
+				<text>TWRP has detected an unmodified system partition.</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>TWRP can leave your system partition unmodified to make it easier for you to take official updates.</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>TWRP will be unable to prevent the stock ROM from replacing TWRP and will not offer to root your device.</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row4_text_y%" placement="5" />
+				<text>Installing zips or performing adb operations may still modify the system partition.</text>
+			</object>
+
+			<object type="checkbox">
+				<condition var1="tw_is_encrypted" var2="0" />
+				<placement x="%col1_x%" y="%row5_text_y%" />
+				<text>Never show this screen during boot again</text>
+				<data variable="tw_never_show_system_ro_page" />
+			</object>
+
+			<object type="button">
+				<placement x="%col_center_x%" y="%row7_text_y%" />
+				<text>Keep Read Only</text>
+				<actions>
+					<action function="set">tw_mount_system_ro=1</action>
+					<action function="set">tw_page_done=1</action>
+					<action function="page">%tw_back%</action>
+				</actions>
+			</object>
+
+			<object type="slider">
+				<text>Swipe to Allow Modifications</text>
+				<actions>
+					<action function="set">tw_mount_system_ro=0</action>
+					<action function="set">tw_page_done=1</action>
+					<action function="page">%tw_back%</action>
+				</actions>
+			</object>
+
+			<object type="template" name="footer" />
+		</page>
 	</pages>
 </recovery>
diff --git a/gui/devices/portrait/res/portrait.xml b/gui/devices/portrait/res/portrait.xml
index bd23598..997da9d 100644
--- a/gui/devices/portrait/res/portrait.xml
+++ b/gui/devices/portrait/res/portrait.xml
@@ -2105,6 +2105,27 @@
 				<action function="page">decrypt</action>
 			</object>
 
+			<object type="button">
+				<placement x="%col1_x%" y="%system_ro_y%" />
+				<font resource="font" color="%text_color%" />
+				<condition var1="tw_mount_system_ro" op="=" var2="0" />
+				<text>Only mount system read-only</text>
+				<image resource="checkbox_false" />
+				<action function="mountsystemtoggle"></action>
+			</object>
+
+			<object type="button">
+				<placement x="%col1_x%" y="%system_ro_y%" />
+				<font resource="font" color="%text_color%" />
+				<condition var1="tw_mount_system_ro" op="!=" var2="0" />
+				<text>Only mount system read-only</text>
+				<image resource="checkbox_true" />
+				<actions>
+					<action function="set">tw_lifetime_writes=2</action>
+					<action function="page">system_readonly_check</action>
+				</actions>
+			</object>
+
 			<object type="action">
 				<touch key="home" />
 				<action function="page">main</action>
@@ -2161,6 +2182,31 @@
 			</object>
 		</page>
 
+		<page name="system_readonly_check">
+			<object type="action">
+				<action function="checkpartitionlifetimewrites">/system</action>
+			</object>
+
+			<object type="action">
+				<conditions>
+					<condition var1="tw_operation_state" var2="1" />
+					<condition var1="tw_lifetime_writes" var2="1" />
+				</conditions>
+				<action function="page">mount</action>
+			</object>
+
+			<object type="action">
+				<conditions>
+					<condition var1="tw_operation_state" var2="1" />
+					<condition var1="tw_lifetime_writes" var2="0" />
+				</conditions>
+				<actions>
+					<action function="set">tw_back=mount</action>
+					<action function="page">system_readonly</action>
+				</actions>
+			</object>
+		</page>
+
 		<page name="reboot">
 			<object type="template" name="header" />
 
@@ -3607,5 +3653,72 @@
 				</actions>
 			</object>
 		</page>
+
+		<page name="system_readonly">
+			<object type="template" name="header" />
+
+			<object type="text">
+				<placement x="%center_x%" y="%row1_header_y%" placement="5" />
+				<text>TWRP has detected an unmodified system partition.</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>TWRP can leave your system partition unmodified</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>to make it easier for you to take official updates.</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row4_text_y%" placement="5" />
+				<text>TWRP will be unable to prevent the stock ROM from</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row5_text_y%" placement="5" />
+				<text>replacing TWRP and will not offer to root your device.</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row6_text_y%" placement="5" />
+				<text>Installing zips or performing adb operations may still</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row7_text_y%" placement="5" />
+				<text>modify the system partition.</text>
+			</object>
+
+			<object type="checkbox">
+				<condition var1="tw_is_encrypted" var2="0" />
+				<placement x="%col1_x%" y="%row8_text_y%" />
+				<text>Never show this screen during boot again</text>
+				<data variable="tw_never_show_system_ro_page" />
+			</object>
+
+			<object type="button">
+				<placement x="%col_center_x%" y="%row10_text_y%" />
+				<text>Keep Read Only</text>
+				<actions>
+					<action function="set">tw_mount_system_ro=1</action>
+					<action function="set">tw_page_done=1</action>
+					<action function="page">%tw_back%</action>
+				</actions>
+			</object>
+
+			<object type="slider">
+				<text>Swipe to Allow Modifications</text>
+				<actions>
+					<action function="set">tw_mount_system_ro=0</action>
+					<action function="set">tw_page_done=1</action>
+					<action function="page">%tw_back%</action>
+				</actions>
+			</object>
+
+			<object type="template" name="footer" />
+		</page>
 	</pages>
 </recovery>
diff --git a/gui/devices/watch/res/watch.xml b/gui/devices/watch/res/watch.xml
index 872c47b..f0f383d 100644
--- a/gui/devices/watch/res/watch.xml
+++ b/gui/devices/watch/res/watch.xml
@@ -2113,6 +2113,27 @@
 				<action function="page">decrypt</action>
 			</object>
 
+			<object type="button">
+				<placement x="%col1_x%" y="%system_ro_y%" />
+				<font resource="font" color="%text_color%" />
+				<condition var1="tw_mount_system_ro" op="=" var2="0" />
+				<text>Only mount system read-only</text>
+				<image resource="checkbox_false" />
+				<action function="mountsystemtoggle"></action>
+			</object>
+
+			<object type="button">
+				<placement x="%col1_x%" y="%system_ro_y%" />
+				<font resource="font" color="%text_color%" />
+				<condition var1="tw_mount_system_ro" op="!=" var2="0" />
+				<text>Only mount system read-only</text>
+				<image resource="checkbox_true" />
+				<actions>
+					<action function="set">tw_lifetime_writes=2</action>
+					<action function="page">system_readonly_check</action>
+				</actions>
+			</object>
+
 			<object type="action">
 				<touch key="home" />
 				<action function="page">main</action>
@@ -2168,6 +2189,31 @@
 			</object>
 		</page>
 
+		<page name="system_readonly_check">
+			<object type="action">
+				<action function="checkpartitionlifetimewrites">/system</action>
+			</object>
+
+			<object type="action">
+				<conditions>
+					<condition var1="tw_operation_state" var2="1" />
+					<condition var1="tw_lifetime_writes" var2="1" />
+				</conditions>
+				<action function="page">mount</action>
+			</object>
+
+			<object type="action">
+				<conditions>
+					<condition var1="tw_operation_state" var2="1" />
+					<condition var1="tw_lifetime_writes" var2="0" />
+				</conditions>
+				<actions>
+					<action function="set">tw_back=mount</action>
+					<action function="page">system_readonly</action>
+				</actions>
+			</object>
+		</page>
+
 		<page name="reboot">
 			<object type="template" name="header" />
 
@@ -3596,5 +3642,70 @@
 				</actions>
 			</object>
 		</page>
+
+		<page name="system_readonly">
+			<object type="template" name="header" />
+
+			<object type="text">
+				<placement x="%center_x%" y="%row1_header_y%" placement="5" />
+				<text>TWRP has detected an unmodified system partition.</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row1_text_y%" placement="5" />
+				<text>TWRP can leave your system partition unmodified</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>to make it easier for you to take official updates.</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>TWRP will be unable to prevent the stock ROM from</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row4_text_y%" placement="5" />
+				<text>replacing TWRP and will not offer to root your device.</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row5_text_y%" placement="5" />
+				<text>Installing zips or performing adb operations may still</text>
+			</object>
+
+			<object type="text">
+				<placement x="%center_x%" y="%row6_text_y%" placement="5" />
+				<text>modify the system partition.</text>
+			</object>
+
+			<object type="checkbox">
+				<condition var1="tw_is_encrypted" var2="0" />
+				<placement x="%col1_x%" y="%row7_text_y%" />
+				<text>Never show this screen during boot again</text>
+				<data variable="tw_never_show_system_ro_page" />
+			</object>
+
+			<object type="button">
+				<placement x="%col_center_x%" y="%row9_text_y%" />
+				<text>Keep Read Only</text>
+				<actions>
+					<action function="set">tw_mount_system_ro=1</action>
+					<action function="set">tw_page_done=1</action>
+					<action function="page">%tw_back%</action>
+				</actions>
+			</object>
+
+			<object type="slider">
+				<text>Swipe to Allow Modifications</text>
+				<actions>
+					<action function="set">tw_mount_system_ro=0</action>
+					<action function="set">tw_page_done=1</action>
+					<action function="page">%tw_back%</action>
+				</actions>
+			</object>
+		</page>
 	</pages>
 </recovery>
diff --git a/gui/objects.hpp b/gui/objects.hpp
index e70053e..ee0f08b 100644
--- a/gui/objects.hpp
+++ b/gui/objects.hpp
@@ -359,6 +359,8 @@
 	int stopmtp(std::string arg);
 	int flashimage(std::string arg);
 	int cancelbackup(std::string arg);
+	int checkpartitionlifetimewrites(std::string arg);
+	int mountsystemtoggle(std::string arg);
 
 	int simulate;
 };