Merge "slot management: add library for slot management." into android-9.0
diff --git a/crypto/vold_decrypt/Android.bp--skip_soong-- b/crypto/vold_decrypt/Android.bp--skip_soong--
new file mode 100644
index 0000000..f16942d
--- /dev/null
+++ b/crypto/vold_decrypt/Android.bp--skip_soong--
@@ -0,0 +1,15 @@
+cc_binary {
+    name: "vdc_pie",
+    defaults: ["vold_default_flags"],
+
+    srcs: ["vdc_pie.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+    static_libs: [
+        "libvold_binder",
+    ],
+}
diff --git a/crypto/vold_decrypt/Android.mk b/crypto/vold_decrypt/Android.mk
index 19c2963..860e61f 100644
--- a/crypto/vold_decrypt/Android.mk
+++ b/crypto/vold_decrypt/Android.mk
@@ -27,6 +27,12 @@
             services := $(TW_CRYPTO_USE_SYSTEM_VOLD)
         endif
 
+        # Parse TW_CRYPTO_SYSTEM_VOLD_MOUNT
+        ifneq ($(TW_CRYPTO_SYSTEM_VOLD_MOUNT),)
+            # Per device additional partitions to mount
+            partitions := $(TW_CRYPTO_SYSTEM_VOLD_MOUNT)
+        endif
+
         # List of .rc files for each additional service
         rc_files := $(foreach item,$(services),init.recovery.vold_decrypt.$(item).rc)
 
@@ -86,6 +92,10 @@
             endif
         endif
 
+        ifneq ($(partitions),)
+            LOCAL_CFLAGS += -DTW_CRYPTO_SYSTEM_VOLD_MOUNT='"$(partitions)"'
+        endif
+
         ifeq ($(TW_CRYPTO_SYSTEM_VOLD_DEBUG),true)
             # Enabling strace will expose the password in the strace logs!!
             LOCAL_CFLAGS += -DTW_CRYPTO_SYSTEM_VOLD_DEBUG
@@ -101,5 +111,35 @@
         LOCAL_SHARED_LIBRARIES := libcutils
         include $(BUILD_STATIC_LIBRARY)
 
+        ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 28; echo $$?),0)
+            include $(CLEAR_VARS)
+            LOCAL_MODULE := vdc_pie
+            LOCAL_SRC_FILES := vdc_pie.cpp
+            LOCAL_MODULE_TAGS := eng
+            LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+            LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+            LOCAL_CLANG := true
+            LOCAL_TIDY := true
+            LOCAL_TIDY_FLAGS := -warnings-as-errors=clang-analyzer-security*,cert-*
+            LOCAL_TIDY_CHECKS := -*,cert-*,clang,-analyzer-security*
+            LOCAL_STATIC_LIBRARIES := libvold_binder
+            LOCAL_SHARED_LIBRARIES := libbase libcutils libutils libbinder
+            LOCAL_CFLAGS := -Wall
+            ifeq ($(TWRP_INCLUDE_LOGCAT), true)
+                LOCAL_CFLAGS += -DTWRP_INCLUDE_LOGCAT
+            endif
+            ifneq ($(TARGET_ARCH), arm64)
+                ifneq ($(TARGET_ARCH), x86_64)
+                    LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker
+                else
+                    LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker64
+                endif
+            else
+                LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker64
+            endif
+
+            include $(BUILD_EXECUTABLE)
+        endif
+
     endif
 endif
diff --git a/crypto/vold_decrypt/init.recovery.vold_decrypt.servicemanager.rc b/crypto/vold_decrypt/init.recovery.vold_decrypt.servicemanager.rc
new file mode 100644
index 0000000..40672d7
--- /dev/null
+++ b/crypto/vold_decrypt/init.recovery.vold_decrypt.servicemanager.rc
@@ -0,0 +1,8 @@
+service sys_servicemanager /system/bin/servicemanager
+    user root
+    group root
+    setenv PATH /system/bin
+    setenv LD_LIBRARY_PATH /system/lib64:/system/lib
+    disabled
+    oneshot
+    seclabel u:r:vold:s0
diff --git a/crypto/vold_decrypt/vdc_pie.cpp b/crypto/vold_decrypt/vdc_pie.cpp
new file mode 100644
index 0000000..a840712
--- /dev/null
+++ b/crypto/vold_decrypt/vdc_pie.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <poll.h>
+
+#include <cutils/properties.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include "android/os/IVold.h"
+
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+
+#include <private/android_filesystem_config.h>
+
+static void usage();
+
+static android::sp<android::IBinder> getServiceAggressive() {
+    static char prop_value[PROPERTY_VALUE_MAX];
+    property_get("init.svc.sys_vold", prop_value, "error");
+    if (strncmp(prop_value, "running", strlen("running")) != 0) {
+        printf("vdc_pie: vold is not running, init.svc.sys_vold=%s\n", prop_value);
+        exit(EINVAL);
+    }
+
+    android::sp<android::IBinder> res;
+    auto sm = android::defaultServiceManager();
+    auto name = android::String16("vold");
+    for (int i = 0; i < 5000; i++) {
+        res = sm->checkService(name);
+        if (res) {
+            printf("vdc_pie: Got vold, waited %d ms\n", (i * 10));
+            break;
+        }
+        usleep(10000); // 10ms
+    }
+    return res;
+}
+
+static int checkStatus(android::binder::Status status) {
+    if (status.isOk()) return 0;
+    std::string ret = status.toString8().string();
+#ifdef TWRP_INCLUDE_LOGCAT
+    printf("vdc_pie: Decryption failed, vold service returned: %s,"
+		" see logcat for details\n", ret.c_str());
+#else
+	printf("vdc_pie: Decryption failed, vold service returned: %s\n", ret.c_str());
+#endif
+    return -1;
+}
+
+int main(int argc, char** argv) {
+    std::vector<std::string> args(argv + 1, argv + argc);
+
+    if (args.size() > 0 && args[0] == "--wait") {
+        // Just ignore the --wait flag
+        args.erase(args.begin());
+    }
+
+    if (args.size() < 2) {
+        usage();
+        exit(5);
+    }
+    android::sp<android::IBinder> binder = getServiceAggressive();
+    if (!binder) {
+        printf("vdc_pie: Failed to obtain vold Binder\n");
+        exit(EINVAL);
+    }
+    auto vold = android::interface_cast<android::os::IVold>(binder);
+
+    if (args[0] == "cryptfs" && args[1] == "checkpw" && args.size() == 3) {
+        return checkStatus(vold->fdeCheckPassword(args[2]));
+    } else {
+        usage();
+        exit(EINVAL);
+    }
+    return 0;
+}
+
+static void usage() {
+    printf("vdc_pie: Usage: vold_pie cryptfs checkpw <password>\n");
+}
diff --git a/crypto/vold_decrypt/vold_decrypt.cpp b/crypto/vold_decrypt/vold_decrypt.cpp
index 707466e..ac872ea 100644
--- a/crypto/vold_decrypt/vold_decrypt.cpp
+++ b/crypto/vold_decrypt/vold_decrypt.cpp
@@ -74,6 +74,7 @@
 #define LOGERROR(...) do { printf(__VA_ARGS__); if (fp_kmsg) { fprintf(fp_kmsg, "[VOLD_DECRYPT]E:" __VA_ARGS__); fflush(fp_kmsg); } } while (0)
 
 FILE *fp_kmsg = NULL;
+int sdkver = 20;
 
 
 /* Debugging Functions */
@@ -223,7 +224,7 @@
 				break;
 			LOGKMSG("waiting for %s to change from '%s' to '%s'\n", property_name.c_str(), prop_value, expected_value.c_str());
 			utimeout -= SLEEP_MIN_USEC;
-			usleep(SLEEP_MIN_USEC);;
+			usleep(SLEEP_MIN_USEC);
 		}
 	}
 	property_get(property_name.c_str(), prop_value, "error");
@@ -766,7 +767,6 @@
 void Set_Needed_Properties(void) {
 	// vold won't start without ro.storage_structure on Kitkat
 	string sdkverstr = TWFunc::System_Property_Get("ro.build.version.sdk");
-	int sdkver = 20;
 	if (!sdkverstr.empty()) {
 		sdkver = atoi(sdkverstr.c_str());
 	}
@@ -775,8 +775,79 @@
 		if (!ro_storage_structure.empty())
 			property_set("ro.storage_structure", ro_storage_structure.c_str());
 	}
+	property_set("hwservicemanager.ready", "false");
+	property_set("sys.listeners.registered", "false");
+	property_set("vendor.sys.listeners.registered", "false");
 }
 
+static unsigned int get_blkdev_size(int fd) {
+	unsigned long nr_sec;
+
+	if ( (ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) {
+		nr_sec = 0;
+	}
+
+	return (unsigned int) nr_sec;
+}
+
+#define CRYPT_FOOTER_OFFSET 0x4000
+static char footer[16 * 1024];
+const char* userdata_path;
+static off64_t offset;
+
+int footer_br(const string& command) {
+	int fd;
+
+	if (command == "backup") {
+		unsigned int nr_sec;
+		TWPartition* userdata = PartitionManager.Find_Partition_By_Path("/data");
+		userdata_path = userdata->Actual_Block_Device.c_str();
+		fd = open(userdata_path, O_RDONLY);
+		if (fd < 0) {
+			LOGERROR("E:footer_backup: Cannot open '%s': %s\n", userdata_path, strerror(errno));
+			return -1;
+		}
+		if ((nr_sec = get_blkdev_size(fd))) {
+			offset = ((off64_t)nr_sec * 512) - CRYPT_FOOTER_OFFSET;
+		} else {
+			LOGERROR("E:footer_br: Failed to get offset\n");
+			close(fd);
+			return -1;
+		}
+		if (lseek64(fd, offset, SEEK_SET) == -1) {
+			LOGERROR("E:footer_backup: Failed to lseek64\n");
+			close(fd);
+			return -1;
+		}
+		if (read(fd, footer, sizeof(footer)) != sizeof(footer)) {
+			LOGERROR("E:footer_br: Failed to read: %s\n", strerror(errno));
+			close(fd);
+			return -1;
+		}
+		close(fd);
+	} else if (command == "restore") {
+		fd = open(userdata_path, O_WRONLY);
+		if (fd < 0) {
+			LOGERROR("E:footer_restore: Cannot open '%s': %s\n", userdata_path, strerror(errno));
+			return -1;
+		}
+		if (lseek64(fd, offset, SEEK_SET) == -1) {
+			LOGERROR("E:footer_restore: Failed to lseek64\n");
+			close(fd);
+			return -1;
+		}
+		if (write(fd, footer, sizeof(footer)) != sizeof(footer)) {
+			LOGERROR("E:footer_br: Failed to write: %s\n", strerror(errno));
+			close(fd);
+			return -1;
+		}
+		close(fd);
+	} else {
+		LOGERROR("E:footer_br: wrong command argument: %s\n", command.c_str());
+		return -1;
+	}
+	return 0;
+}
 
 /* vdc Functions */
 typedef struct {
@@ -801,9 +872,14 @@
 		}
 	}
 
-	const char *cmd[] = { "/system/bin/vdc", "cryptfs" };
+	// getpwtype and checkpw commands are removed from Pie vdc, using modified vdc_pie
+	const char *cmd[] = { "/sbin/vdc_pie", "cryptfs" };
+	if (sdkver < 28)
+		cmd[0] = "/system/bin/vdc";
 	const char *env[] = { "LD_LIBRARY_PATH=/system/lib64:/system/lib", NULL };
 
+	LOGINFO("sdkver: %d, using %s\n", sdkver, cmd[0]);
+
 #ifdef TW_CRYPTO_SYSTEM_VOLD_DEBUG
 	string log_name = "/tmp/strace_vdc_" + command;
 #endif
@@ -918,6 +994,9 @@
 					return -1;
 				}
 			}
+			if (sdkver >= 28) {
+				return WEXITSTATUS(status);
+			}
 			return 0;
 		}
 	}
@@ -930,33 +1009,35 @@
 
 	LOGINFO("About to run vdc...\n");
 
-	// Wait for vold connection
-	gettimeofday(&t1, NULL);
-	t2 = t1;
-	while ((t2.tv_sec - t1.tv_sec) < 5) {
-		// cryptfs getpwtype returns: R1=213(PasswordTypeResult)   R2=?   R3="password", "pattern", "pin", "default"
-		res = Exec_vdc_cryptfs("getpwtype", "", &vdcResult);
-		if (vdcResult.ResponseCode == PASSWORD_TYPE_RESULT) {
-			res = 0;
-			break;
+	// Pie vdc communicates with vold directly, no socket so lets not waste time
+	if (sdkver < 28) {
+		// Wait for vold connection
+		gettimeofday(&t1, NULL);
+		t2 = t1;
+		while ((t2.tv_sec - t1.tv_sec) < 5) {
+			// cryptfs getpwtype returns: R1=213(PasswordTypeResult)   R2=?   R3="password", "pattern", "pin", "default"
+			res = Exec_vdc_cryptfs("getpwtype", "", &vdcResult);
+			if (vdcResult.ResponseCode == PASSWORD_TYPE_RESULT) {
+				res = 0;
+				break;
+			}
+			LOGINFO("Retrying connection to vold (Reason: %s)\n", vdcResult.Output.c_str());
+			usleep(SLEEP_MIN_USEC); // vdc usually usleep(10000), but that causes too many unnecessary attempts
+			gettimeofday(&t2, NULL);
 		}
-		LOGINFO("Retrying connection to vold (Reason: %s)\n", vdcResult.Output.c_str());
-		usleep(SLEEP_MIN_USEC); // vdc usually usleep(10000), but that causes too many unnecessary attempts
-		gettimeofday(&t2, NULL);
+
+		if (res == 0 && (t2.tv_sec - t1.tv_sec) < 5)
+			LOGINFO("Connected to vold: %s\n", vdcResult.Output.c_str());
+		else if (res == VD_ERR_VOLD_OPERATION_TIMEDOUT)
+			return VD_ERR_VOLD_OPERATION_TIMEDOUT; // should never happen for getpwtype
+		else if (res)
+			return VD_ERR_FORK_EXECL_ERROR;
+		else if (vdcResult.ResponseCode != -1)
+			return VD_ERR_VOLD_UNEXPECTED_RESPONSE;
+		else
+			return VD_ERR_VDC_FAILED_TO_CONNECT;
 	}
 
-	if (res == 0 && (t2.tv_sec - t1.tv_sec) < 5)
-		LOGINFO("Connected to vold: %s\n", vdcResult.Output.c_str());
-	else if (res == VD_ERR_VOLD_OPERATION_TIMEDOUT)
-		return VD_ERR_VOLD_OPERATION_TIMEDOUT; // should never happen for getpwtype
-	else if (res)
-		return VD_ERR_FORK_EXECL_ERROR;
-	else if (vdcResult.ResponseCode != -1)
-		return VD_ERR_VOLD_UNEXPECTED_RESPONSE;
-	else
-		return VD_ERR_VDC_FAILED_TO_CONNECT;
-
-
 	// Input password from GUI, or default password
 	res = Exec_vdc_cryptfs("checkpw", Password, &vdcResult);
 	if (res == VD_ERR_VOLD_OPERATION_TIMEDOUT)
@@ -970,6 +1051,12 @@
 		return VD_ERR_VOLD_UNEXPECTED_RESPONSE;
 	*/
 
+	// our vdc returns vold binder op status,
+    // we care about status.ok() only which is 0
+	if (sdkver >= 28) {
+		vdcResult.Message = res;
+	}
+
 	if (vdcResult.Message != 0) {
 		// try falling back to Lollipop hex passwords
 		string hexPassword = convert_key_to_hex_ascii(Password);
@@ -986,8 +1073,9 @@
 		*/
 	}
 
-	// vdc's return value is dependant upon source origin, it will either
+	// sdk < 28 vdc's return value is dependant upon source origin, it will either
 	// return 0 or ResponseCode, so disregard and focus on decryption instead
+	// our vdc always returns 0 on success
 	if (vdcResult.Message == 0) {
 		// Decryption successful wait for crypto blk dev
 		Wait_For_Property("ro.crypto.fs_crypto_blkdev");
@@ -1024,6 +1112,20 @@
 		return VD_ERR_MISSING_VDC;
 	}
 
+#ifdef TW_CRYPTO_SYSTEM_VOLD_MOUNT
+	vector<string> partitions = TWFunc::Split_String(TW_CRYPTO_SYSTEM_VOLD_MOUNT, " ");
+	for (size_t i = 0; i < partitions.size(); ++i) {
+		string mnt_point = "/" + partitions[i];
+		if(PartitionManager.Find_Partition_By_Path(mnt_point)) {
+			if (!PartitionManager.Mount_By_Path(mnt_point, true)) {
+				LOGERROR("Unable to mount %s\n", mnt_point.c_str());
+				return VD_ERR_UNABLE_TO_MOUNT_EXTRA;
+			}
+			LOGINFO("%s partition mounted\n", partitions[i].c_str());
+		}
+	}
+#endif
+
 	fp_kmsg = fopen("/dev/kmsg", "a");
 
 	LOGINFO("TW_CRYPTO_USE_SYSTEM_VOLD := true\n");
@@ -1064,8 +1166,20 @@
 	LOGINFO("Starting services...\n");
 #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES
 	for (size_t i = 0; i < Services.size(); ++i) {
-		if (Services[i].bin_exists)
+		if (Services[i].bin_exists) {
+			if (Services[i].Service_Binary.find("keymaster") != string::npos) {
+				Wait_For_Property("hwservicemanager.ready", 500000, "true");
+				LOGINFO("    hwservicemanager is ready.\n");
+			}
+
 			Services[i].is_running = Start_Service(Services[i].VOLD_Service_Name);
+
+			if (Services[i].Service_Binary == "qseecomd") {
+				if (Wait_For_Property("sys.listeners.registered", 500000, "true") == "true"
+						|| Wait_For_Property("vendor.sys.listeners.registered", 500000, "true") == "true")
+					LOGINFO("    qseecomd listeners registered.\n");
+			}
+		}
 	}
 #endif
 	is_vold_running = Start_Service("sys_vold");
@@ -1080,7 +1194,29 @@
 			}
 		}
 #endif
-		res = Run_vdc(Password);
+
+		/*
+		* Oreo and Pie vold on some devices alters footer causing
+		* system to ask for decryption password at next boot although
+		* password haven't changed so we save footer before and restore it
+		* after vold operations
+		*/
+		if (sdkver > 25) {
+			if (footer_br("backup") == 0) {
+				LOGINFO("footer_br: crypto footer backed up\n");
+				res = Run_vdc(Password);
+				if (footer_br("restore") == 0)
+					LOGINFO("footer_br: crypto footer restored\n");
+				else
+					LOGERROR("footer_br: Failed to restore crypto footer\n");
+			} else {
+				LOGERROR("footer_br: Failed to backup crypto footer, \
+					skipping decrypt to prevent data loss. Reboot recovery to try again...\n");
+				res = -1;
+			}
+		} else {
+			res = Run_vdc(Password);
+		}
 
 		if (res != 0) {
 			LOGINFO("Decryption failed\n");
@@ -1116,13 +1252,38 @@
 		umount2(PartitionManager.Get_Android_Root_Path().c_str(), MNT_DETACH);
 	}
 
+#ifdef TW_CRYPTO_SYSTEM_VOLD_MOUNT
+	for (size_t i = 0; i < partitions.size(); ++i) {
+		string mnt_point = "/" + partitions[i];
+		if(PartitionManager.Is_Mounted_By_Path(mnt_point)) {
+			if (!PartitionManager.UnMount_By_Path(mnt_point, true)) {
+				LOGINFO("WARNING: %s partition could not be unmounted normally!\n", partitions[i].c_str());
+				umount2(mnt_point.c_str(), MNT_DETACH);
+			}
+		}
+	}
+#endif
+
 	LOGINFO("Finished.\n");
 
 #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES
+	Set_Needed_Properties();
 	// Restart previously running services
 	for (size_t i = 0; i < Services.size(); ++i) {
-		if (Services[i].resume)
+		if (Services[i].resume) {
+			if (Services[i].Service_Binary.find("keymaster") != string::npos) {
+				Wait_For_Property("hwservicemanager.ready", 500000, "true");
+				LOGINFO("    hwservicemanager is ready.\n");
+			}
+
 			Start_Service(Services[i].TWRP_Service_Name);
+
+			if (Services[i].Service_Binary == "qseecomd") {
+				if (Wait_For_Property("sys.listeners.registered", 500000, "true") == "true"
+						|| Wait_For_Property("vendor.sys.listeners.registered", 500000, "true") == "true")
+					LOGINFO("    qseecomd listeners registered.\n");
+			}
+		}
 	}
 #endif
 
diff --git a/crypto/vold_decrypt/vold_decrypt.h b/crypto/vold_decrypt/vold_decrypt.h
index ba7a747..248a427 100644
--- a/crypto/vold_decrypt/vold_decrypt.h
+++ b/crypto/vold_decrypt/vold_decrypt.h
@@ -34,6 +34,7 @@
 	VD_ERR_VOLD_OPERATION_TIMEDOUT  = -8,
 	VD_ERR_FORK_EXECL_ERROR         = -9,
 	VD_ERR_PASSWORD_EMPTY           = -10,
+    VD_ERR_UNABLE_TO_MOUNT_EXTRA   = -11,
 };
 
 
diff --git a/etc/Android.mk b/etc/Android.mk
index cda0f37..4aeb251 100644
--- a/etc/Android.mk
+++ b/etc/Android.mk
@@ -88,3 +88,18 @@
         include $(BUILD_PREBUILT)
     endif
 endif
+
+ifeq ($(TW_USE_TOOLBOX), true)
+    include $(CLEAR_VARS)
+    LOCAL_MODULE := init.recovery.mksh.rc
+    LOCAL_MODULE_TAGS := eng
+    LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+
+    # Cannot send to TARGET_RECOVERY_ROOT_OUT since build system wipes init*.rc
+    # during ramdisk creation and only allows init.recovery.*.rc files to be copied
+    # from TARGET_ROOT_OUT thereafter
+    LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
+
+    LOCAL_SRC_FILES := $(LOCAL_MODULE)
+    include $(BUILD_PREBUILT)
+endif
diff --git a/etc/init.rc b/etc/init.rc
index bcd519b..348471d 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -1,4 +1,5 @@
 import /init.recovery.logd.rc
+import /init.recovery.mksh.rc
 import /init.recovery.usb.rc
 import /init.recovery.service.rc
 import /init.recovery.vold_decrypt.rc
diff --git a/etc/init.recovery.mksh.rc b/etc/init.recovery.mksh.rc
new file mode 100755
index 0000000..3afd946
--- /dev/null
+++ b/etc/init.recovery.mksh.rc
@@ -0,0 +1,2 @@
+on init
+    export ENV /etc/mkshrc
diff --git a/etc/init.recovery.service22.rc b/etc/init.recovery.service22.rc
index 43a3374..bb2853c 100644
--- a/etc/init.recovery.service22.rc
+++ b/etc/init.recovery.service22.rc
@@ -1,11 +1,5 @@
 on boot
-    export LD_CONFIG_FILE /sbin/ld.config.txt
 
 # For starting recovery on 5.0 and newer
 service recovery /sbin/recovery
     seclabel u:r:recovery:s0
-
-# This helps fix ld.config.txt errors from the linker on Android 8.1
-service ldconfigtxt /sbin/touch /sbin/ld.config.txt
-    oneshot
-    seclabel u:r:recovery:s0
diff --git a/gui/theme/landscape_hdpi/ui.xml b/gui/theme/landscape_hdpi/ui.xml
index 39f626f..f1bd647 100644
--- a/gui/theme/landscape_hdpi/ui.xml
+++ b/gui/theme/landscape_hdpi/ui.xml
@@ -430,6 +430,11 @@
 				<action function="key">back</action>
 			</button>
 
+			<fill color="%background_color%">
+				<condition var1="tw_busy" var2="1"/>
+				<placement x="0" y="%navbar_y%" w="%screen_width%" h="%navbar_height%"/>
+			</fill>
+
 			<action>
 				<touch key="power"/>
 				<action function="togglebacklight"/>
diff --git a/gui/theme/landscape_mdpi/ui.xml b/gui/theme/landscape_mdpi/ui.xml
index cde1a5b..cf30d89 100644
--- a/gui/theme/landscape_mdpi/ui.xml
+++ b/gui/theme/landscape_mdpi/ui.xml
@@ -430,6 +430,11 @@
 				<action function="key">back</action>
 			</button>
 
+			<fill color="%background_color%">
+				<condition var1="tw_busy" var2="1"/>
+				<placement x="0" y="%navbar_y%" w="%screen_width%" h="%navbar_height%"/>
+			</fill>
+
 			<action>
 				<touch key="power"/>
 				<action function="togglebacklight"/>
diff --git a/gui/theme/portrait_hdpi/ui.xml b/gui/theme/portrait_hdpi/ui.xml
index 0545b3f..3f3102a 100644
--- a/gui/theme/portrait_hdpi/ui.xml
+++ b/gui/theme/portrait_hdpi/ui.xml
@@ -334,6 +334,11 @@
 				<action function="key">back</action>
 			</button>
 
+			<fill color="%background_color%">
+				<condition var1="tw_busy" var2="1"/>
+				<placement x="0" y="%navbar_y%" w="%screen_width%" h="%navbar_height%"/>
+			</fill>
+
 			<action>
 				<touch key="power"/>
 				<action function="togglebacklight"/>
diff --git a/gui/theme/portrait_mdpi/ui.xml b/gui/theme/portrait_mdpi/ui.xml
index 061d46b..f41ff79 100644
--- a/gui/theme/portrait_mdpi/ui.xml
+++ b/gui/theme/portrait_mdpi/ui.xml
@@ -334,6 +334,11 @@
 				<action function="key">back</action>
 			</button>
 
+			<fill color="%background_color%">
+				<condition var1="tw_busy" var2="1"/>
+				<placement x="0" y="%navbar_y%" w="%screen_width%" h="%navbar_height%"/>
+			</fill>
+
 			<action>
 				<touch key="power"/>
 				<action function="togglebacklight"/>
diff --git a/minuitwrp/graphics_overlay.cpp b/minuitwrp/graphics_overlay.cpp
index e4fc419..b4efae4 100644
--- a/minuitwrp/graphics_overlay.cpp
+++ b/minuitwrp/graphics_overlay.cpp
@@ -50,7 +50,6 @@
 
 static GRSurface gr_framebuffer;
 static GRSurface* gr_draw = NULL;
-static int displayed_buffer;
 
 static fb_var_screeninfo vi;
 static int fb_fd = -1;
@@ -100,7 +99,6 @@
 
 bool target_has_overlay(char *version)
 {
-    int ret;
     int mdp_version;
     bool overlay_supported = false;
 
diff --git a/partition.cpp b/partition.cpp
index acf382a..8e30c33 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -1027,6 +1027,7 @@
 		File_System == "yaffs2" ||
 		File_System == "exfat" ||
 		File_System == "f2fs" ||
+		File_System == "squashfs" ||
 		File_System == "auto")
 		return true;
 	else
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index 9302c11..f792042 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -491,6 +491,18 @@
 	include $(BUILD_PREBUILT)
 endif
 
+ifeq ($(TW_USE_TOOLBOX), true)
+    include $(CLEAR_VARS)
+    LOCAL_MODULE := mkshrc_twrp
+    LOCAL_MODULE_TAGS := eng
+    LOCAL_MODULE_CLASS := ETC
+    LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/etc
+    LOCAL_SRC_FILES := $(LOCAL_MODULE)
+    LOCAL_POST_INSTALL_CMD := \
+        $(hide) mv $(TARGET_RECOVERY_ROOT_OUT)/etc/mkshrc_twrp $(TARGET_RECOVERY_ROOT_OUT)/etc/mkshrc
+    include $(BUILD_PREBUILT)
+endif
+
 #TWRP App "placeholder"
 include $(CLEAR_VARS)
 LOCAL_MODULE := me.twrp.twrpapp.apk
@@ -499,3 +511,18 @@
 LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
+
+ifeq ($(TW_INCLUDE_CRYPTO), true)
+    ifneq ($(TW_CRYPTO_USE_SYSTEM_VOLD),)
+        ifneq ($(shell test $(PLATFORM_SDK_VERSION) -ge 28; echo $$?),0)
+            # Prebuilt vdc_pie for pre-Pie SDK Platforms
+            include $(CLEAR_VARS)
+            LOCAL_MODULE := vdc_pie
+            LOCAL_MODULE_TAGS := eng
+            LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+            LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+            LOCAL_SRC_FILES := vdc_pie-$(TARGET_ARCH)
+            include $(BUILD_PREBUILT)
+        endif
+    endif
+endif
diff --git a/prebuilt/mkshrc_twrp b/prebuilt/mkshrc_twrp
new file mode 100755
index 0000000..c103d6c
--- /dev/null
+++ b/prebuilt/mkshrc_twrp
@@ -0,0 +1,21 @@
+# Copyright (c) 2010, 2012, 2013, 2014
+#	Thorsten Glaser <tg@mirbsd.org>
+# This file is provided under the same terms as mksh.
+#-
+# Minimal /system/etc/mkshrc for Android
+#
+# Support: https://launchpad.net/mksh
+
+: ${HOSTNAME:=$(getprop ro.product.device)}
+: ${HOSTNAME:=android}
+: ${TMPDIR:=/tmp}
+export HOSTNAME TMPDIR
+
+if (( USER_ID )); then PS1='$'; else PS1='#'; fi
+PS4='[$EPOCHREALTIME] '; PS1='${|
+	local e=$?
+
+	(( e )) && REPLY+="$e|"
+
+	return $e
+}$HOSTNAME:${PWD:-?} '"$PS1 "
diff --git a/prebuilt/vdc_pie-arm b/prebuilt/vdc_pie-arm
new file mode 100755
index 0000000..cf05cad
--- /dev/null
+++ b/prebuilt/vdc_pie-arm
Binary files differ
diff --git a/prebuilt/vdc_pie-arm64 b/prebuilt/vdc_pie-arm64
new file mode 100755
index 0000000..4623140
--- /dev/null
+++ b/prebuilt/vdc_pie-arm64
Binary files differ
diff --git a/twinstall.cpp b/twinstall.cpp
index a2f54c9..f451ca5 100644
--- a/twinstall.cpp
+++ b/twinstall.cpp
@@ -67,10 +67,12 @@
 
 #define AB_OTA "payload_properties.txt"
 
+#ifndef TW_NO_LEGACY_PROPS
 static const char* properties_path = "/dev/__properties__";
 static const char* properties_path_renamed = "/dev/__properties_kk__";
 static bool legacy_props_env_initd = false;
 static bool legacy_props_path_modified = false;
+#endif
 
 enum zip_type {
 	UNKNOWN_ZIP_TYPE = 0,
@@ -79,6 +81,7 @@
 	TWRP_THEME_ZIP_TYPE
 };
 
+#ifndef TW_NO_LEGACY_PROPS
 // to support pre-KitKat update-binaries that expect properties in the legacy format
 static int switch_to_legacy_properties()
 {
@@ -120,6 +123,7 @@
 
 	return 0;
 }
+#endif
 
 static int Install_Theme(const char* path, ZipWrap *Zip) {
 #ifdef TW_OEM_BUILD // We don't do custom themes in OEM builds
@@ -173,6 +177,7 @@
 	return INSTALL_SUCCESS;
 }
 
+#ifndef TW_NO_LEGACY_PROPS
 static bool update_binary_has_legacy_properties(const char *binary) {
 	const char str_to_match[] = "ANDROID_PROPERTY_WORKSPACE";
 	int len_to_match = sizeof(str_to_match) - 1;
@@ -205,6 +210,7 @@
 
 	return found;
 }
+#endif
 
 static int Run_Update_Binary(const char *path, ZipWrap *Zip, int* wipe_cache, zip_type ztype) {
 	int ret_val, pipe_fd[2], status, zip_verify;
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 2635934..00a57a7 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -922,7 +922,7 @@
 
 	std::vector<std::string> paths; // space separated list of paths
 	if (time_paths.empty()) {
-		paths = Split_String("/data/system/time/ /data/time/", " ");
+		paths = Split_String("/data/system/time/ /data/time/ /data/vendor/time/", " ");
 		if (!PartitionManager.Mount_By_Path("/data", false))
 			return;
 	} else {