summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/vold_decrypt/Android.bp--skip_soong--15
-rw-r--r--crypto/vold_decrypt/Android.mk40
-rw-r--r--crypto/vold_decrypt/init.recovery.vold_decrypt.servicemanager.rc8
-rw-r--r--crypto/vold_decrypt/vdc_pie.cpp106
-rw-r--r--crypto/vold_decrypt/vold_decrypt.cpp223
-rw-r--r--crypto/vold_decrypt/vold_decrypt.h1
-rw-r--r--prebuilt/Android.mk15
-rwxr-xr-xprebuilt/vdc_pie-armbin0 -> 46588 bytes
-rwxr-xr-xprebuilt/vdc_pie-arm64bin0 -> 69824 bytes
9 files changed, 377 insertions, 31 deletions
diff --git a/crypto/vold_decrypt/Android.bp--skip_soong-- b/crypto/vold_decrypt/Android.bp--skip_soong--
new file mode 100644
index 000000000..f16942df2
--- /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 19c2963c0..860e61f20 100644
--- a/crypto/vold_decrypt/Android.mk
+++ b/crypto/vold_decrypt/Android.mk
@@ -27,6 +27,12 @@ ifeq ($(TW_INCLUDE_CRYPTO), true)
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 @@ ifeq ($(TW_INCLUDE_CRYPTO), true)
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 @@ ifeq ($(TW_INCLUDE_CRYPTO), true)
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 000000000..40672d737
--- /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 000000000..a84071213
--- /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 707466e4c..ac872ea28 100644
--- a/crypto/vold_decrypt/vold_decrypt.cpp
+++ b/crypto/vold_decrypt/vold_decrypt.cpp
@@ -74,6 +74,7 @@ namespace {
#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 @@ string Wait_For_Property(const string& property_name, int utimeout = SLEEP_MAX_U
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 @@ vector<AdditionalService> Get_List_Of_Additional_Services(void) {
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 @@ void Set_Needed_Properties(void) {
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 @@ int Exec_vdc_cryptfs(const string& command, const string& argument, vdc_ReturnVa
}
}
- 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 @@ int Exec_vdc_cryptfs(const string& command, const string& argument, vdc_ReturnVa
return -1;
}
}
+ if (sdkver >= 28) {
+ return WEXITSTATUS(status);
+ }
return 0;
}
}
@@ -930,32 +1009,34 @@ int Run_vdc(const string& Password) {
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);
@@ -970,6 +1051,12 @@ int Run_vdc(const string& Password) {
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 @@ int Run_vdc(const string& Password) {
*/
}
- // 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 @@ int Vold_Decrypt_Core(const string& Password) {
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 @@ int Vold_Decrypt_Core(const string& Password) {
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 @@ int Vold_Decrypt_Core(const string& Password) {
}
}
#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 @@ int Vold_Decrypt_Core(const string& Password) {
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 ba7a74720..248a42786 100644
--- a/crypto/vold_decrypt/vold_decrypt.h
+++ b/crypto/vold_decrypt/vold_decrypt.h
@@ -34,6 +34,7 @@ enum {
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/prebuilt/Android.mk b/prebuilt/Android.mk
index 235b77c86..27bcd5f41 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -499,3 +499,18 @@ LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
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/vdc_pie-arm b/prebuilt/vdc_pie-arm
new file mode 100755
index 000000000..cf05cad53
--- /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 000000000..46231402f
--- /dev/null
+++ b/prebuilt/vdc_pie-arm64
Binary files differ