Merge tag 'android-11.0.0_r16' into android-10.0

Android 11.0.0 release 16 - twrp bringup patch
diff --git a/install/Android.bp b/install/Android.bp
index ea893a0..aa14475 100644
--- a/install/Android.bp
+++ b/install/Android.bp
@@ -19,8 +19,8 @@
         "recovery_defaults",
     ],
 
-    header_libs: [
-        "libminadbd_headers",
+    cflags: [
+        //"-DRECOVERY_API_VERSION=3"
     ],
 
     shared_libs: [
@@ -32,7 +32,6 @@
         "libfusesideload",
         "libhidl-gen-utils",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libselinux",
         "libtinyxml2",
@@ -42,12 +41,12 @@
     ],
 
     static_libs: [
+        "librecovery_utils",
         "libotautil",
+        "libsnapshot_nobinder",
 
         // external dependencies
-        "libvintf_recovery",
         "libvintf",
-        "libfstab",
     ],
 }
 
@@ -62,11 +61,17 @@
     srcs: [
         "adb_install.cpp",
         "asn1_decoder.cpp",
-        "fuse_sdcard_install.cpp",
+        "fuse_install.cpp",
         "install.cpp",
         "package.cpp",
+        "snapshot_utils.cpp",
         "verifier.cpp",
         "wipe_data.cpp",
+        "wipe_device.cpp",
+    ],
+
+    header_libs: [
+        "libminadbd_headers",
     ],
 
     shared_libs: [
diff --git a/install/ZipUtil.cpp b/install/ZipUtil.cpp
index f8134bc..c7b6b3d 100755
--- a/install/ZipUtil.cpp
+++ b/install/ZipUtil.cpp
@@ -54,9 +54,9 @@
     if (!zip_path.empty() && zip_path.back() != '/') {
         prefix_path += '/';
     }
-    const ZipString zip_prefix(prefix_path.c_str());
+    const std::string zip_prefix(prefix_path.c_str());
 
-    int ret = StartIteration(zip, &cookie, &zip_prefix, nullptr);
+    int ret = StartIteration(zip, &cookie, zip_prefix, nullptr);
     if (ret != 0) {
         LOG(ERROR) << "failed to start iterating zip entries.";
         return false;
@@ -64,10 +64,10 @@
 
     std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
     ZipEntry entry;
-    ZipString name;
+    std::string name;
     int extractCount = 0;
     while (Next(cookie, &entry, &name) == 0) {
-        std::string entry_name(name.name, name.name + name.name_length);
+        std::string entry_name(name.c_str(), name.c_str() + name.size());
         CHECK_LE(prefix_path.size(), entry_name.size());
         std::string path = target_dir + entry_name.substr(prefix_path.size());
         // Skip dir.
diff --git a/install/adb_install.cpp b/install/adb_install.cpp
index 0db4a27..feebaee 100755
--- a/install/adb_install.cpp
+++ b/install/adb_install.cpp
@@ -44,7 +44,7 @@
 #include "fuse_sideload.h"
 #include "install/install.h"
 #include "install/wipe_data.h"
-#include "minadbd_types.h"
+#include "minadbd/types.h"
 #include "otautil/sysutil.h"
 #include "recovery_ui/device.h"
 #include "recovery_ui/ui.h"
@@ -90,7 +90,7 @@
 
 // Installs the package from FUSE. Returns the installation result and whether it should continue
 // waiting for new commands.
-static auto AdbInstallPackageHandler(int* result) {
+static auto AdbInstallPackageHandler(InstallResult* result) {
   // How long (in seconds) we wait for the package path to be ready. It doesn't need to be too long
   // because the minadbd service has already issued an install command. FUSE_SIDELOAD_HOST_PATHNAME
   // will start to exist once the host connects and starts serving a package. Poll for its
@@ -110,7 +110,10 @@
         break;
       }
     }
-    *result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0);
+
+    auto package =
+        Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME, nullptr);
+    *result = InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0);
     break;
   }
 
@@ -120,7 +123,7 @@
   return std::make_pair(*result == INSTALL_SUCCESS, should_continue);
 }
 
-static auto AdbRebootHandler(MinadbdCommand command, int* result,
+static auto AdbRebootHandler(MinadbdCommand command, InstallResult* result,
                              Device::BuiltinAction* reboot_action) {
   // Use Device::REBOOT_{FASTBOOT,RECOVERY,RESCUE}, instead of the ones with ENTER_. This allows
   // rebooting back into fastboot/recovery/rescue mode through bootloader, which may use a newly
@@ -333,7 +336,6 @@
   signal(SIGPIPE, SIG_DFL);
 }
 
-// int ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot_action) {
   int ApplyFromAdb(const char* install_file, Device::BuiltinAction* reboot_action) {
 
   // Save the usb state to restore after the sideload operation.
@@ -346,7 +348,7 @@
 
   // RecoveryUI* ui = device->GetUI();
 
-  int install_result = INSTALL_ERROR;
+  InstallResult install_result = INSTALL_ERROR;
   std::map<MinadbdCommand, CommandFunction> command_map{
   { MinadbdCommand::kInstall, std::bind(&AdbInstallPackageHandler, &install_result) },
   { MinadbdCommand::kRebootAndroid, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootAndroid,
diff --git a/install/fuse_sdcard_install.cpp b/install/fuse_install.cpp
similarity index 74%
rename from install/fuse_sdcard_install.cpp
rename to install/fuse_install.cpp
index 011847b..61e1d74 100755
--- a/install/fuse_sdcard_install.cpp
+++ b/install/fuse_install.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "install/fuse_sdcard_install.h"
+#include "install/fuse_install.h"
 
 #include <dirent.h>
 #include <signal.h>
@@ -27,6 +27,7 @@
 #include <algorithm>
 #include <functional>
 #include <memory>
+#include <string>
 #include <vector>
 
 #include <android-base/logging.h>
@@ -36,7 +37,7 @@
 #include "fuse_provider.h"
 #include "fuse_sideload.h"
 #include "install/install.h"
-#include "otautil/roots.h"
+#include "recovery_utils/roots.h"
 
 static constexpr const char* SDCARD_ROOT = "/sdcard";
 // How long (in seconds) we wait for the fuse-provided package file to
@@ -74,7 +75,8 @@
       // Skip "." and ".." entries.
       if (name == "." || name == "..") continue;
       dirs.push_back(name + "/");
-    } else if (de->d_type == DT_REG && android::base::EndsWithIgnoreCase(name, ".zip")) {
+    } else if (de->d_type == DT_REG && (android::base::EndsWithIgnoreCase(name, ".zip") ||
+                                        android::base::EndsWithIgnoreCase(name, ".map"))) {
       entries.push_back(name);
     }
   }
@@ -119,49 +121,44 @@
   // Unreachable.
 }
 
-static bool StartSdcardFuse(const std::string& path) {
-  auto file_data_reader = std::make_unique<FuseFileDataProvider>(path, 65536);
-
-  if (!file_data_reader->Valid()) {
+static bool StartInstallPackageFuse(std::string_view path) {
+  if (path.empty()) {
     return false;
   }
 
-  // The installation process expects to find the sdcard unmounted. Unmount it with MNT_DETACH so
-  // that our open file continues to work but new references see it as unmounted.
-  umount2("/sdcard", MNT_DETACH);
+  constexpr auto FUSE_BLOCK_SIZE = 65536;
+  bool is_block_map = android::base::ConsumePrefix(&path, "@");
+  auto fuse_data_provider =
+      is_block_map ? FuseBlockDataProvider::CreateFromBlockMap(std::string(path), FUSE_BLOCK_SIZE)
+                   : FuseFileDataProvider::CreateFromFile(std::string(path), FUSE_BLOCK_SIZE);
 
-  return run_fuse_sideload(std::move(file_data_reader)) == 0;
+  if (!fuse_data_provider || !fuse_data_provider->Valid()) {
+    LOG(ERROR) << "Failed to create fuse data provider.";
+    return false;
+  }
+
+  if (android::base::StartsWith(path, SDCARD_ROOT)) {
+    // The installation process expects to find the sdcard unmounted. Unmount it with MNT_DETACH so
+    // that our open file continues to work but new references see it as unmounted.
+    umount2(SDCARD_ROOT, MNT_DETACH);
+  }
+
+  return run_fuse_sideload(std::move(fuse_data_provider)) == 0;
 }
 
-int ApplyFromSdcard(Device* device, RecoveryUI* ui) {
-  if (ensure_path_mounted(SDCARD_ROOT) != 0) {
-    LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n";
-    return INSTALL_ERROR;
-  }
-
-  std::string path = BrowseDirectory(SDCARD_ROOT, device, ui);
-  if (path.empty()) {
-    LOG(ERROR) << "\n-- No package file selected.\n";
-    ensure_path_unmounted(SDCARD_ROOT);
-    return INSTALL_ERROR;
-  }
-
-  ui->Print("\n-- Install %s ...\n", path.c_str());
-  SetSdcardUpdateBootloaderMessage();
-
+InstallResult InstallWithFuseFromPath(std::string_view path, __attribute__((unused)) RecoveryUI* ui) {
   // We used to use fuse in a thread as opposed to a process. Since accessing
   // through fuse involves going from kernel to userspace to kernel, it leads
   // to deadlock when a page fault occurs. (Bug: 26313124)
   pid_t child;
   if ((child = fork()) == 0) {
-    bool status = StartSdcardFuse(path);
+    bool status = StartInstallPackageFuse(path);
 
     _exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
   }
 
-  // FUSE_SIDELOAD_HOST_PATHNAME will start to exist once the fuse in child
-  // process is ready.
-  int result = INSTALL_ERROR;
+  // FUSE_SIDELOAD_HOST_PATHNAME will start to exist once the fuse in child process is ready.
+  InstallResult result = INSTALL_ERROR;
   int status;
   bool waited = false;
   for (int i = 0; i < SDCARD_INSTALL_TIMEOUT; ++i) {
@@ -183,8 +180,10 @@
         break;
       }
     }
-
-    result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0 /*retry_count*/);
+    auto package =
+        Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME, nullptr);
+    result =
+        InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0 /* retry_count */);
     break;
   }
 
@@ -201,6 +200,32 @@
     LOG(ERROR) << "Error exit from the fuse process: " << WEXITSTATUS(status);
   }
 
+  return result;
+}
+
+InstallResult ApplyFromSdcard(Device* device) {
+  auto ui = device->GetUI();
+  if (ensure_path_mounted(SDCARD_ROOT) != 0) {
+    LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n";
+    return INSTALL_ERROR;
+  }
+
+  std::string path = BrowseDirectory(SDCARD_ROOT, device, ui);
+  if (path.empty()) {
+    LOG(ERROR) << "\n-- No package file selected.\n";
+    ensure_path_unmounted(SDCARD_ROOT);
+    return INSTALL_ERROR;
+  }
+
+  // Hint the install function to read from a block map file.
+  if (android::base::EndsWithIgnoreCase(path, ".map")) {
+    path = "@" + path;
+  }
+
+  ui->Print("\n-- Install %s ...\n", path.c_str());
+  SetSdcardUpdateBootloaderMessage();
+
+  auto result = InstallWithFuseFromPath(path, ui);
   ensure_path_unmounted(SDCARD_ROOT);
   return result;
 }
diff --git a/install/include/install/adb_install.h b/install/include/install/adb_install.h
index f7b15b2..8800223 100755
--- a/install/include/install/adb_install.h
+++ b/install/include/install/adb_install.h
@@ -16,9 +16,10 @@
 
 #pragma once
 
-#include <recovery_ui/device.h>
+#include "install/install.h"
+#include "recovery_ui/device.h"
 
-// Applies a package via `adb sideload` or `adb rescue`. Returns the install result (in `enum
-// InstallResult`). When a reboot has been requested, INSTALL_REBOOT will be the return value, with
-// the reboot target set in reboot_action.
-int ApplyFromAdb(const char* install_file, Device::BuiltinAction* reboot_action);
+// Applies a package via `adb sideload` or `adb rescue`. Returns the install result. When a reboot
+// has been requested, INSTALL_REBOOT will be the return value, with the reboot target set in
+// reboot_action.
+InstallResult ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot_action);
diff --git a/install/include/install/fuse_sdcard_install.h b/install/include/install/fuse_install.h
old mode 100755
new mode 100644
similarity index 60%
copy from install/include/install/fuse_sdcard_install.h
copy to install/include/install/fuse_install.h
index d9214ca..63b116a
--- a/install/include/install/fuse_sdcard_install.h
+++ b/install/include/install/fuse_install.h
@@ -16,7 +16,15 @@
 
 #pragma once
 
+#include <string_view>
+
+#include "install/install.h"
 #include "recovery_ui/device.h"
 #include "recovery_ui/ui.h"
 
-int ApplyFromSdcard(Device* device, RecoveryUI* ui);
+// Starts FUSE with the package from |path| as the data source. And installs the package from
+// |FUSE_SIDELOAD_HOST_PATHNAME|. The |path| can point to the location of a package zip file or a
+// block map file with the prefix '@'; e.g. /sdcard/package.zip, @/cache/recovery/block.map.
+InstallResult InstallWithFuseFromPath(std::string_view path, RecoveryUI* ui);
+
+InstallResult ApplyFromSdcard(Device* device);
diff --git a/install/include/install/install.h b/install/include/install/install.h
index fcbfc99..eb91974 100755
--- a/install/include/install/install.h
+++ b/install/include/install/install.h
@@ -44,14 +44,12 @@
   BRICK,
 };
 
-static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary";
-static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25;
-
-// Installs the given update package. This function should also wipe the cache partition after a
-// successful installation if |should_wipe_cache| is true or an updater command asks to wipe the
-// cache.
-int install_package(const std::string& package, bool should_wipe_cache, bool needs_mount,
-                    int retry_count);
+// Installs the given update package. The package_id is a string provided by the caller (e.g. the
+// package path) to identify the package and log to last_install. This function should also wipe the
+// cache partition after a successful installation if |should_wipe_cache| is true or an updater
+// command asks to wipe the cache.
+InstallResult InstallPackage(Package* package, const std::string_view package_id,
+                             bool should_wipe_cache, int retry_count);
 
 // Verifies the package by ota keys. Returns true if the package is verified successfully,
 // otherwise returns false.
@@ -61,14 +59,11 @@
 // result to |metadata|. Return true if succeed, otherwise return false.
 bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map<std::string, std::string>* metadata);
 
-// Reads the "recovery.wipe" entry in the zip archive returns a list of partitions to wipe.
-std::vector<std::string> GetWipePartitionList(Package* wipe_package);
+// Checks if the metadata in the OTA package has expected values. Mandatory checks: ota-type,
+// pre-device and serial number (if presents). A/B OTA specific checks: pre-build version,
+// fingerprint, timestamp.
+bool CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type);
 
-// Verifies the compatibility info in a Treble-compatible package. Returns true directly if the
-// entry doesn't exist.
-bool verify_package_compatibility(ZipArchiveHandle package_zip);
-
-// Checks if the the metadata in the OTA package has expected values. Returns 0 on success.
-// Mandatory checks: ota-type, pre-device and serial number(if presents)
-// AB OTA specific checks: pre-build version, fingerprint, timestamp.
-int CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type);
+// Ensures the path to the update package is mounted. Also set the |should_use_fuse| to true if the
+// package stays on a removable media.
+bool SetupPackageMount(const std::string& package_path, bool* should_use_fuse);
diff --git a/install/include/install/package.h b/install/include/install/package.h
index 50a4ffa..3699752 100755
--- a/install/include/install/package.h
+++ b/install/include/install/package.h
@@ -28,6 +28,11 @@
 
 #include "verifier.h"
 
+enum class PackageType {
+  kMemory,
+  kFile,
+};
+
 // This class serves as a wrapper for an OTA update package. It aims to provide the common
 // interface for both packages loaded in memory and packages read from fd.
 class Package : public VerifierInterface {
@@ -41,6 +46,10 @@
 
   virtual ~Package() = default;
 
+  virtual PackageType GetType() const = 0;
+
+  virtual std::string GetPath() const = 0;
+
   // Opens the package as a zip file and returns the ZipArchiveHandle.
   virtual ZipArchiveHandle GetZipArchiveHandle() = 0;
 
diff --git a/install/include/install/fuse_sdcard_install.h b/install/include/install/snapshot_utils.h
old mode 100755
new mode 100644
similarity index 62%
copy from install/include/install/fuse_sdcard_install.h
copy to install/include/install/snapshot_utils.h
index d9214ca..f4b978d
--- a/install/include/install/fuse_sdcard_install.h
+++ b/install/include/install/snapshot_utils.h
@@ -17,6 +17,14 @@
 #pragma once
 
 #include "recovery_ui/device.h"
-#include "recovery_ui/ui.h"
 
-int ApplyFromSdcard(Device* device, RecoveryUI* ui);
+bool FinishPendingSnapshotMerges(Device* device);
+
+/*
+ * This function tries to create the snapshotted devices in the case a Virtual
+ * A/B device is updating.
+ * The function returns false in case of critical failure that would prevent
+ * the further mountings of devices, or true in case of success, if either the
+ * devices were created or there was no need to.
+ */
+bool CreateSnapshotPartitions();
diff --git a/install/include/install/fuse_sdcard_install.h b/install/include/install/wipe_device.h
similarity index 63%
rename from install/include/install/fuse_sdcard_install.h
rename to install/include/install/wipe_device.h
index d9214ca..c60b999 100755
--- a/install/include/install/fuse_sdcard_install.h
+++ b/install/include/install/wipe_device.h
@@ -16,7 +16,14 @@
 
 #pragma once
 
-#include "recovery_ui/device.h"
-#include "recovery_ui/ui.h"
+#include <string>
+#include <vector>
 
-int ApplyFromSdcard(Device* device, RecoveryUI* ui);
+#include "install/package.h"
+#include "recovery_ui/device.h"
+
+// Wipes the current A/B device, with a secure wipe of all the partitions in RECOVERY_WIPE.
+bool WipeAbDevice(Device* device, size_t wipe_package_size);
+
+// Reads the "recovery.wipe" entry in the zip archive returns a list of partitions to wipe.
+std::vector<std::string> GetWipePartitionList(Package* wipe_package);
diff --git a/install/include/legacy_property_service.h b/install/include/legacy_property_service.h
deleted file mode 100644
index d20bdef..0000000
--- a/install/include/legacy_property_service.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#ifndef _LEGACY_PROPERTY_H
-#define _LEGACY_PROPERTY_H
-
-#include <stdbool.h>
-
-void legacy_get_property_workspace(int *fd, int *sz);
-int legacy_properties_init();
-
-#endif	/* _LEGACY_PROPERTY_H */
diff --git a/install/include/private/setup_commands.h b/install/include/private/setup_commands.h
index 7fdc741..dcff761 100644
--- a/install/include/private/setup_commands.h
+++ b/install/include/private/setup_commands.h
@@ -27,13 +27,13 @@
 // |zip| located at |package|. Stores the command line that should be called into |cmd|. The
 // |status_fd| is the file descriptor the child process should use to report back the progress of
 // the update.
-int SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int retry_count,
-                             int status_fd, std::vector<std::string>* cmd);
+bool SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int retry_count,
+                              int status_fd, std::vector<std::string>* cmd);
 
 // Sets up the commands for an A/B update. Extracts the needed entries from the open zip archive
 // |zip| located at |package|. Stores the command line that should be called into |cmd|. The
 // |status_fd| is the file descriptor the child process should use to report back the progress of
 // the update. Note that since this applies to the sideloading flow only, it takes one less
 // parameter |retry_count| than the non-A/B version.
-int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
-                          std::vector<std::string>* cmd);
+bool SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
+                           std::vector<std::string>* cmd);
diff --git a/install/include/zipwrap.hpp b/install/include/zipwrap.hpp
deleted file mode 100755
index 7102116..0000000
--- a/install/include/zipwrap.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) TeamWin
- * This file is part of TWRP/TeamWin Recovery 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.
- */
-
-#ifndef __ZIPWRAP_HPP
-#define __ZIPWRAP_HPP
-
-#include <string>
-#ifdef USE_MINZIP
-#include "minzip/Zip.h"
-#include "minzip/SysUtil.h"
-#else
-#include <ziparchive/zip_archive.h>
-#include "otautil/sysutil.h"
-#endif
-
-using namespace std;
-
-class ZipWrap {
-	public:
-		ZipWrap();
-		~ZipWrap();
-
-		bool Open(const char* file, MemMapping* map);
-		void Close();
-		bool EntryExists(const string& filename);
-		bool ExtractEntry(const string& source_file, const string& target_file, mode_t mode);
-
-		long GetUncompressedSize(const string& filename);
-		bool ExtractToBuffer(const string& filename, uint8_t* begin);
-		bool ExtractRecursive(const string& source_dir, const string& target_dir);
-#ifdef USE_MINZIP
-		loff_t GetEntryOffset(const string& filename);
-#else
-		off64_t GetEntryOffset(const string& filename);
-		ZipArchiveHandle GetZipArchiveHandle();
-#endif
-
-	private:
-#ifdef USE_MINZIP
-		ZipArchive Zip;
-#else
-		ZipArchiveHandle Zip;
-#endif
-		string zip_file;
-		bool zip_open;
-};
-
-#endif //__ZIPWRAP_HPP
diff --git a/install/install.cpp b/install/install.cpp
index 55d51fc..80c4bdf 100755
--- a/install/install.cpp
+++ b/install/install.cpp
@@ -30,6 +30,7 @@
 #include <atomic>
 #include <chrono>
 #include <condition_variable>
+#include <filesystem>
 #include <functional>
 #include <limits>
 #include <mutex>
@@ -44,23 +45,23 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <vintf/VintfObjectRecovery.h>
 
 #include "install/package.h"
 #include "install/verifier.h"
 #include "install/wipe_data.h"
 #include "otautil/error_code.h"
 #include "otautil/paths.h"
-#include "otautil/roots.h"
 #include "otautil/sysutil.h"
-#include "otautil/thermalutil.h"
 #include "private/setup_commands.h"
 #include "recovery_ui/ui.h"
+#include "recovery_utils/roots.h"
+#include "recovery_utils/thermalutil.h"
 
 using namespace std::chrono_literals;
 
 static constexpr int kRecoveryApiVersion = 3;
-// Assert the version defined in code and in Android.mk are consistent.
+// We define RECOVERY_API_VERSION in Android.mk, which will be picked up by build system and packed
+// into target_files.zip. Assert the version defined in code and in Android.mk are consistent.
 static_assert(kRecoveryApiVersion == RECOVERY_API_VERSION, "Mismatching recovery API versions.");
 
 // Default allocation of progress bar segments to operations
@@ -73,9 +74,8 @@
   CHECK(metadata != nullptr);
 
   static constexpr const char* METADATA_PATH = "META-INF/com/android/metadata";
-  ZipString path(METADATA_PATH);
   ZipEntry entry;
-  if (FindEntry(zip, path, &entry) != 0) {
+  if (FindEntry(zip, METADATA_PATH, &entry) != 0) {
     LOG(ERROR) << "Failed to find " << METADATA_PATH;
     return false;
   }
@@ -139,14 +139,14 @@
 // Checks the build version, fingerprint and timestamp in the metadata of the A/B package.
 // Downgrading is not allowed unless explicitly enabled in the package and only for
 // incremental packages.
-static int CheckAbSpecificMetadata(const std::map<std::string, std::string>& metadata) {
+static bool CheckAbSpecificMetadata(const std::map<std::string, std::string>& metadata) {
   // Incremental updates should match the current build.
   auto device_pre_build = android::base::GetProperty("ro.build.version.incremental", "");
   auto pkg_pre_build = get_value(metadata, "pre-build-incremental");
   if (!pkg_pre_build.empty() && pkg_pre_build != device_pre_build) {
     LOG(ERROR) << "Package is for source build " << pkg_pre_build << " but expected "
                << device_pre_build;
-    return INSTALL_ERROR;
+    return false;
   }
 
   auto device_fingerprint = android::base::GetProperty("ro.build.fingerprint", "");
@@ -154,7 +154,7 @@
   if (!pkg_pre_build_fingerprint.empty() && pkg_pre_build_fingerprint != device_fingerprint) {
     LOG(ERROR) << "Package is for source build " << pkg_pre_build_fingerprint << " but expected "
                << device_fingerprint;
-    return INSTALL_ERROR;
+    return false;
   }
 
   // Check for downgrade version.
@@ -172,36 +172,36 @@
                     "newer than timestamp "
                  << build_timestamp << " but package has timestamp " << pkg_post_timestamp
                  << " and downgrade not allowed.";
-      return INSTALL_ERROR;
+      return false;
     }
     if (pkg_pre_build_fingerprint.empty()) {
       LOG(ERROR) << "Downgrade package must have a pre-build version set, not allowed.";
-      return INSTALL_ERROR;
+      return false;
     }
   }
 
-  return 0;
+  return true;
 }
 
-int CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type) {
+bool CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type) {
   auto package_ota_type = get_value(metadata, "ota-type");
   auto expected_ota_type = OtaTypeToString(ota_type);
   if (ota_type != OtaType::AB && ota_type != OtaType::BRICK) {
     LOG(INFO) << "Skip package metadata check for ota type " << expected_ota_type;
-    return 0;
+    return true;
   }
 
   if (package_ota_type != expected_ota_type) {
     LOG(ERROR) << "Unexpected ota package type, expects " << expected_ota_type << ", actual "
                << package_ota_type;
-    return INSTALL_ERROR;
+    return false;
   }
 
   auto device = android::base::GetProperty("ro.product.device", "");
   auto pkg_device = get_value(metadata, "pre-device");
   if (pkg_device != device || pkg_device.empty()) {
     LOG(ERROR) << "Package is for product " << pkg_device << " but expected " << device;
-    return INSTALL_ERROR;
+    return false;
   }
 
   // We allow the package to not have any serialno; and we also allow it to carry multiple serial
@@ -218,7 +218,7 @@
     }
     if (!serial_number_match) {
       LOG(ERROR) << "Package is for serial " << pkg_serial_no;
-      return INSTALL_ERROR;
+      return false;
     }
   }
 
@@ -226,21 +226,20 @@
     return CheckAbSpecificMetadata(metadata);
   }
 
-  return 0;
+  return true;
 }
 
-int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
-                          std::vector<std::string>* cmd) {
+bool SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
+                           std::vector<std::string>* cmd) {
   CHECK(cmd != nullptr);
 
   // For A/B updates we extract the payload properties to a buffer and obtain the RAW payload offset
   // in the zip file.
   static constexpr const char* AB_OTA_PAYLOAD_PROPERTIES = "payload_properties.txt";
-  ZipString property_name(AB_OTA_PAYLOAD_PROPERTIES);
   ZipEntry properties_entry;
-  if (FindEntry(zip, property_name, &properties_entry) != 0) {
+  if (FindEntry(zip, AB_OTA_PAYLOAD_PROPERTIES, &properties_entry) != 0) {
     LOG(ERROR) << "Failed to find " << AB_OTA_PAYLOAD_PROPERTIES;
-    return INSTALL_CORRUPT;
+    return false;
   }
   uint32_t properties_entry_length = properties_entry.uncompressed_length;
   std::vector<uint8_t> payload_properties(properties_entry_length);
@@ -248,15 +247,14 @@
       ExtractToMemory(zip, &properties_entry, payload_properties.data(), properties_entry_length);
   if (err != 0) {
     LOG(ERROR) << "Failed to extract " << AB_OTA_PAYLOAD_PROPERTIES << ": " << ErrorCodeString(err);
-    return INSTALL_CORRUPT;
+    return false;
   }
 
   static constexpr const char* AB_OTA_PAYLOAD = "payload.bin";
-  ZipString payload_name(AB_OTA_PAYLOAD);
   ZipEntry payload_entry;
-  if (FindEntry(zip, payload_name, &payload_entry) != 0) {
+  if (FindEntry(zip, AB_OTA_PAYLOAD, &payload_entry) != 0) {
     LOG(ERROR) << "Failed to find " << AB_OTA_PAYLOAD;
-    return INSTALL_CORRUPT;
+    return false;
   }
   long payload_offset = payload_entry.offset;
   *cmd = {
@@ -266,20 +264,19 @@
     "--headers=" + std::string(payload_properties.begin(), payload_properties.end()),
     android::base::StringPrintf("--status_fd=%d", status_fd),
   };
-  return 0;
+  return true;
 }
 
-int SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int retry_count,
-                             int status_fd, std::vector<std::string>* cmd) {
+bool SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int retry_count,
+                              int status_fd, std::vector<std::string>* cmd) {
   CHECK(cmd != nullptr);
 
   // In non-A/B updates we extract the update binary from the package.
   static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary";
-  ZipString binary_name(UPDATE_BINARY_NAME);
   ZipEntry binary_entry;
-  if (FindEntry(zip, binary_name, &binary_entry) != 0) {
+  if (FindEntry(zip, UPDATE_BINARY_NAME, &binary_entry) != 0) {
     LOG(ERROR) << "Failed to find update binary " << UPDATE_BINARY_NAME;
-    return INSTALL_CORRUPT;
+    return false;
   }
 
   const std::string binary_path = Paths::Get().temporary_update_binary();
@@ -288,13 +285,12 @@
       open(binary_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0755));
   if (fd == -1) {
     PLOG(ERROR) << "Failed to create " << binary_path;
-    return INSTALL_ERROR;
+    return false;
   }
 
-  int32_t error = ExtractEntryToFile(zip, &binary_entry, fd);
-  if (error != 0) {
+  if (auto error = ExtractEntryToFile(zip, &binary_entry, fd); error != 0) {
     LOG(ERROR) << "Failed to extract " << UPDATE_BINARY_NAME << ": " << ErrorCodeString(error);
-    return INSTALL_ERROR;
+    return false;
   }
 
   // When executing the update binary contained in the package, the arguments passed are:
@@ -311,7 +307,7 @@
   if (retry_count > 0) {
     cmd->push_back("retry");
   }
-  return 0;
+  return true;
 }
 
 static void log_max_temperature(int* max_temperature, const std::atomic<bool>& logger_finished) {
@@ -325,21 +321,35 @@
 }
 
 // If the package contains an update binary, extract it and run it.
-static int try_update_binary(const std::string& package, ZipArchiveHandle zip, bool* wipe_cache,
-                             std::vector<std::string>* log_buffer, int retry_count,
-                             int* max_temperature) {
+static InstallResult TryUpdateBinary(Package* package, bool* wipe_cache,
+                                     std::vector<std::string>* log_buffer, int retry_count,
+                                     int* max_temperature) {
   std::map<std::string, std::string> metadata;
+  auto zip = package->GetZipArchiveHandle();
   if (!ReadMetadataFromPackage(zip, &metadata)) {
     LOG(ERROR) << "Failed to parse metadata in the zip file";
     return INSTALL_CORRUPT;
   }
 
-  bool is_ab = android::base::GetBoolProperty("ro.build.ab_update", false);
-  // Verifies against the metadata in the package first.
-  if (int check_status = is_ab ? CheckPackageMetadata(metadata, OtaType::AB) : 0;
-      check_status != 0) {
-    log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
-    return check_status;
+  bool package_is_ab = get_value(metadata, "ota-type") == OtaTypeToString(OtaType::AB);
+  bool device_supports_ab = android::base::GetBoolProperty("ro.build.ab_update", false);
+  bool ab_device_supports_nonab =
+      android::base::GetBoolProperty("ro.virtual_ab.allow_non_ab", false);
+  bool device_only_supports_ab = device_supports_ab && !ab_device_supports_nonab;
+
+  if (package_is_ab) {
+    CHECK(package->GetType() == PackageType::kFile);
+  }
+
+  // Verify against the metadata in the package first. Expects A/B metadata if:
+  // Package declares itself as an A/B package
+  // Package does not declare itself as an A/B package, but device only supports A/B;
+  //   still calls CheckPackageMetadata to get a meaningful error message.
+  if (package_is_ab || device_only_supports_ab) {
+    if (!CheckPackageMetadata(metadata, OtaType::AB)) {
+      log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
+      return INSTALL_ERROR;
+    }
   }
 
   ReadSourceTargetBuild(metadata, log_buffer);
@@ -385,13 +395,16 @@
   //       updater requests logging the string (e.g. cause of the failure).
   //
 
+  std::string package_path = package->GetPath();
+
   std::vector<std::string> args;
-  if (int update_status =
-          is_ab ? SetUpAbUpdateCommands(package, zip, pipe_write.get(), &args)
-                : SetUpNonAbUpdateCommands(package, zip, retry_count, pipe_write.get(), &args);
-      update_status != 0) {
+  if (auto setup_result =
+          package_is_ab
+              ? SetUpAbUpdateCommands(package_path, zip, pipe_write.get(), &args)
+              : SetUpNonAbUpdateCommands(package_path, zip, retry_count, pipe_write.get(), &args);
+      !setup_result) {
     log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
-    return update_status;
+    return INSTALL_CORRUPT;
   }
 
   pid_t pid = fork();
@@ -490,11 +503,11 @@
   }
   if (WIFEXITED(status)) {
     if (WEXITSTATUS(status) != EXIT_SUCCESS) {
-      LOG(ERROR) << "Error in " << package << " (status " << WEXITSTATUS(status) << ")";
+      LOG(ERROR) << "Error in " << package_path << " (status " << WEXITSTATUS(status) << ")";
       return INSTALL_ERROR;
     }
   } else if (WIFSIGNALED(status)) {
-    LOG(ERROR) << "Error in " << package << " (killed by signal " << WTERMSIG(status) << ")";
+    LOG(ERROR) << "Error in " << package_path << " (killed by signal " << WTERMSIG(status) << ")";
     return INSTALL_ERROR;
   } else {
     LOG(FATAL) << "Invalid status code " << status;
@@ -503,153 +516,57 @@
   return INSTALL_SUCCESS;
 }
 
-// Verifes the compatibility info in a Treble-compatible package. Returns true directly if the
-// entry doesn't exist. Note that the compatibility info is packed in a zip file inside the OTA
-// package.
-bool verify_package_compatibility(ZipArchiveHandle package_zip) {
-  LOG(INFO) << "Verifying package compatibility...";
-
-  static constexpr const char* COMPATIBILITY_ZIP_ENTRY = "compatibility.zip";
-  ZipString compatibility_entry_name(COMPATIBILITY_ZIP_ENTRY);
-  ZipEntry compatibility_entry;
-  if (FindEntry(package_zip, compatibility_entry_name, &compatibility_entry) != 0) {
-    LOG(INFO) << "Package doesn't contain " << COMPATIBILITY_ZIP_ENTRY << " entry";
-    return true;
-  }
-
-  std::string zip_content(compatibility_entry.uncompressed_length, '\0');
-  int32_t ret;
-  if ((ret = ExtractToMemory(package_zip, &compatibility_entry,
-                             reinterpret_cast<uint8_t*>(&zip_content[0]),
-                             compatibility_entry.uncompressed_length)) != 0) {
-    LOG(ERROR) << "Failed to read " << COMPATIBILITY_ZIP_ENTRY << ": " << ErrorCodeString(ret);
-    return false;
-  }
-
-  ZipArchiveHandle zip_handle;
-  ret = OpenArchiveFromMemory(static_cast<void*>(const_cast<char*>(zip_content.data())),
-                              zip_content.size(), COMPATIBILITY_ZIP_ENTRY, &zip_handle);
-  if (ret != 0) {
-    LOG(ERROR) << "Failed to OpenArchiveFromMemory: " << ErrorCodeString(ret);
-    return false;
-  }
-
-  // Iterate all the entries inside COMPATIBILITY_ZIP_ENTRY and read the contents.
-  void* cookie;
-  ret = StartIteration(zip_handle, &cookie, nullptr, nullptr);
-  if (ret != 0) {
-    LOG(ERROR) << "Failed to start iterating zip entries: " << ErrorCodeString(ret);
-    CloseArchive(zip_handle);
-    return false;
-  }
-  std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
-
-  std::vector<std::string> compatibility_info;
-  ZipEntry info_entry;
-  ZipString info_name;
-  while (Next(cookie, &info_entry, &info_name) == 0) {
-    std::string content(info_entry.uncompressed_length, '\0');
-    int32_t ret = ExtractToMemory(zip_handle, &info_entry, reinterpret_cast<uint8_t*>(&content[0]),
-                                  info_entry.uncompressed_length);
-    if (ret != 0) {
-      LOG(ERROR) << "Failed to read " << info_name.name << ": " << ErrorCodeString(ret);
-      CloseArchive(zip_handle);
-      return false;
-    }
-    compatibility_info.emplace_back(std::move(content));
-  }
-  CloseArchive(zip_handle);
-
-  // VintfObjectRecovery::CheckCompatibility returns zero on success.
-  std::string err;
-  int result = android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err);
-  if (result == 0) {
-    return true;
-  }
-
-  LOG(ERROR) << "Failed to verify package compatibility (result " << result << "): " << err;
-  return false;
-}
-
-static int really_install_package(const std::string& path, bool* wipe_cache, bool needs_mount,
-                                  std::vector<std::string>* log_buffer, int retry_count,
-                                  int* max_temperature) {
+static InstallResult VerifyAndInstallPackage(Package* package, bool* wipe_cache,
+                                             std::vector<std::string>* log_buffer, int retry_count,
+                                             int* max_temperature) {
   // ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
-  // ui->Print("Finding update package...\n");
   // Give verification half the progress bar...
   // ui->SetProgressType(RecoveryUI::DETERMINATE);
   // ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
-  LOG(INFO) << "Update location: " << path;
-
-  // Map the update package into memory.
-  // ui->Print("Opening update package...\n");
-
-  if (needs_mount) {
-    if (path[0] == '@') {
-      ensure_path_mounted(path.substr(1));
-    } else {
-      ensure_path_mounted(path);
-    }
-  }
-
-  auto package = Package::CreateMemoryPackage(
-      path);
-  if (!package) {
-    log_buffer->push_back(android::base::StringPrintf("error: %d", kMapFileFailure));
-    return INSTALL_CORRUPT;
-  }
 
   // Verify package.
-  if (!verify_package(package.get())) {
+  if (!verify_package(package)) {
     log_buffer->push_back(android::base::StringPrintf("error: %d", kZipVerificationFailure));
     return INSTALL_CORRUPT;
   }
 
-  // Try to open the package.
-  ZipArchiveHandle zip = package->GetZipArchiveHandle();
-  if (!zip) {
-    log_buffer->push_back(android::base::StringPrintf("error: %d", kZipOpenFailure));
-    return INSTALL_CORRUPT;
-  }
-
-  // Additionally verify the compatibility of the package if it's a fresh install.
-  if (retry_count == 0 && !verify_package_compatibility(zip)) {
-    log_buffer->push_back(android::base::StringPrintf("error: %d", kPackageCompatibilityFailure));
-    return INSTALL_CORRUPT;
-  }
-
   // Verify and install the contents of the package.
   // ui->Print("Installing update...\n");
   // if (retry_count > 0) {
     // ui->Print("Retry attempt: %d\n", retry_count);
   // }
   // ui->SetEnableReboot(false);
-  int result =
-      try_update_binary(path, zip, wipe_cache, log_buffer, retry_count, max_temperature);
+  auto result = TryUpdateBinary(package, wipe_cache, log_buffer, retry_count, max_temperature);
   // ui->SetEnableReboot(true);
   // ui->Print("\n");
 
   return result;
 }
 
-int install_package(const std::string& path, bool should_wipe_cache, bool needs_mount,
-                    int retry_count) {
-  CHECK(!path.empty());
-
+InstallResult InstallPackage(Package* package, const std::string_view package_id,
+                             bool should_wipe_cache, int retry_count) {
   auto start = std::chrono::system_clock::now();
 
   int start_temperature = GetMaxValueFromThermalZone();
   int max_temperature = start_temperature;
 
-  int result;
+  InstallResult result;
   std::vector<std::string> log_buffer;
-  if (setup_install_mounts() != 0) {
+
+  // ui->Print("Supported API: %d\n", kRecoveryApiVersion);
+
+  // ui->Print("Finding update package...\n");
+  LOG(INFO) << "Update package id: " << package_id;
+  if (!package) {
+    log_buffer.push_back(android::base::StringPrintf("error: %d", kMapFileFailure));
+    result = INSTALL_CORRUPT;
+  } else if (setup_install_mounts() != 0) {
     LOG(ERROR) << "failed to set up expected mounts for install; aborting";
     result = INSTALL_ERROR;
   } else {
     bool updater_wipe_cache = false;
-    result = really_install_package(path, &updater_wipe_cache, needs_mount, &log_buffer,
-                                    retry_count, &max_temperature);
+    result = VerifyAndInstallPackage(package, &updater_wipe_cache, &log_buffer, retry_count,
+                                     &max_temperature);
     should_wipe_cache = should_wipe_cache || updater_wipe_cache;
   }
 
@@ -677,7 +594,7 @@
 
   // The first two lines need to be the package name and install result.
   std::vector<std::string> log_header = {
-    path,
+    std::string(package_id),
     result == INSTALL_SUCCESS ? "1" : "0",
     "time_total: " + std::to_string(time_total),
     "retry: " + std::to_string(retry_count),
@@ -736,3 +653,49 @@
   }
   return true;
 }
+
+bool SetupPackageMount(const std::string& package_path, bool* should_use_fuse) {
+  CHECK(should_use_fuse != nullptr);
+
+  if (package_path.empty()) {
+    return false;
+  }
+
+  *should_use_fuse = true;
+  if (package_path[0] == '@') {
+    auto block_map_path = package_path.substr(1);
+    if (ensure_path_mounted(block_map_path) != 0) {
+      LOG(ERROR) << "Failed to mount " << block_map_path;
+      return false;
+    }
+    // uncrypt only produces block map only if the package stays on /data.
+    *should_use_fuse = false;
+    return true;
+  }
+
+  // Package is not a block map file.
+  if (ensure_path_mounted(package_path) != 0) {
+    LOG(ERROR) << "Failed to mount " << package_path;
+    return false;
+  }
+
+  // Reject the package if the input path doesn't equal the canonicalized path.
+  // e.g. /cache/../sdcard/update_package.
+  std::error_code ec;
+  auto canonical_path = std::filesystem::canonical(package_path, ec);
+  if (ec) {
+    LOG(ERROR) << "Failed to get canonical of " << package_path << ", " << ec.message();
+    return false;
+  }
+  if (canonical_path.string() != package_path) {
+    LOG(ERROR) << "Installation aborts. The canonical path " << canonical_path.string()
+               << " doesn't equal the original path " << package_path;
+    return false;
+  }
+
+  constexpr const char* CACHE_ROOT = "/cache";
+  if (android::base::StartsWith(package_path, CACHE_ROOT)) {
+    *should_use_fuse = false;
+  }
+  return true;
+}
diff --git a/install/legacy_property_service.cpp b/install/legacy_property_service.cpp
deleted file mode 100644
index c3990f7..0000000
--- a/install/legacy_property_service.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2007 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 <ctype.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <dirent.h>
-#include <limits.h>
-#include <errno.h>
-
-#include "../../bionic/libc/private/bionic_futex.h"
-
-#include <cutils/properties.h>
-
-#include "legacy_properties.h"
-
-#include <sys/mman.h>
-// Not available in 5.0
-//#include <sys/atomics.h>
-#include "legacy_property_service.h"
-
-#ifndef INT32_MAX
-#define INT32_MAX	(2147483647)
-#endif
-
-static int property_area_inited = 0;
-
-typedef struct {
-    void *data;
-    size_t size;
-    int fd;
-} workspace;
-
-static int init_workspace(workspace *w, size_t size)
-{
-    void *data;
-    int fd;
-
-        /* dev is a tmpfs that we can use to carve a shared workspace
-         * out of, so let's do that...
-         */
-    fd = open("/dev/__legacy_properties__", O_RDWR | O_CREAT, 0600);
-    if (fd < 0)
-        return -1;
-
-    if (ftruncate(fd, size) < 0)
-        goto out;
-
-    data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-    if(data == MAP_FAILED)
-        goto out;
-
-    close(fd);
-
-    fd = open("/dev/__legacy_properties__", O_RDONLY);
-    if (fd < 0)
-        return -1;
-
-    unlink("/dev/__legacy_properties__");
-
-    w->data = data;
-    w->size = size;
-    w->fd = fd;
-    return 0;
-
-out:
-    close(fd);
-    return -1;
-}
-
-/* (8 header words + 247 toc words) = 1020 bytes */
-/* 1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */
-
-#define PA_COUNT_MAX  247
-#define PA_INFO_START 1024
-#define PA_SIZE       32768
-
-static workspace pa_workspace;
-static prop_info *pa_info_array;
-
-prop_area *__legacy_property_area__;
-
-static int init_property_area(void)
-{
-    prop_area *pa;
-
-    if(pa_info_array)
-        return -1;
-
-    if(init_workspace(&pa_workspace, PA_SIZE))
-        return -1;
-
-    fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
-
-    pa_info_array = (prop_info*) (((char*) pa_workspace.data) + PA_INFO_START);
-
-    pa = (prop_area*)(pa_workspace.data);
-    memset(pa, 0, PA_SIZE);
-    pa->magic = PROP_AREA_MAGIC;
-    pa->version = PROP_AREA_VERSION;
-
-    /* plug into the lib property services */
-    __legacy_property_area__ = pa;
-    property_area_inited = 1;
-    return 0;
-}
-
-static void update_prop_info(prop_info *pi, const char *value, unsigned len)
-{
-    pi->serial = pi->serial | 1;
-    memcpy(pi->value, value, len + 1);
-    pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
-    __futex_wake(&pi->serial, INT32_MAX);
-}
-
-static const prop_info *__legacy_property_find(const char *name)
-{
-    prop_area *pa = __legacy_property_area__;
-    unsigned count = pa->count;
-    unsigned *toc = pa->toc;
-    unsigned len = strlen(name);
-    prop_info *pi;
-
-    while(count--) {
-        unsigned entry = *toc++;
-        if(TOC_NAME_LEN(entry) != len) continue;
-
-        pi = TOC_TO_INFO(pa, entry);
-        if(memcmp(name, pi->name, len)) continue;
-
-        return pi;
-    }
-
-    return 0;
-}
-
-static int legacy_property_set(const char *name, const char *value)
-{
-    prop_area *pa;
-    prop_info *pi;
-
-    int namelen = strlen(name);
-    int valuelen = strlen(value);
-
-    if(namelen >= PROP_NAME_MAX) return -1;
-    if(valuelen >= PROP_VALUE_MAX) return -1;
-    if(namelen < 1) return -1;
-
-    pi = (prop_info*) __legacy_property_find(name);
-
-
-    if(pi != 0) {
-        /* ro.* properties may NEVER be modified once set */
-        if(!strncmp(name, "ro.", 3)) return -1;
-
-        pa = __legacy_property_area__;
-        update_prop_info(pi, value, valuelen);
-        pa->serial++;
-        __futex_wake(&pa->serial, INT32_MAX);
-    } else {
-        pa = __legacy_property_area__;
-        if(pa->count == PA_COUNT_MAX) return -1;
-
-        pi = pa_info_array + pa->count;
-        pi->serial = (valuelen << 24);
-        memcpy(pi->name, name, namelen + 1);
-        memcpy(pi->value, value, valuelen + 1);
-
-        pa->toc[pa->count] =
-            (namelen << 24) | (((unsigned long) pi) - ((unsigned long) pa));
-
-        pa->count++;
-        pa->serial++;
-        __futex_wake(&pa->serial, INT32_MAX);
-    }
-
-    return 0;
-}
-
-void legacy_get_property_workspace(int *fd, int *sz)
-{
-    *fd = pa_workspace.fd;
-    *sz = pa_workspace.size;
-}
-
-static void copy_property_to_legacy(const char *key, const char *value, void *cookie __unused)
-{
-    legacy_property_set(key, value);
-}
-
-int legacy_properties_init()
-{
-    if(init_property_area() != 0)
-        return -1;
-
-    if(property_list(copy_property_to_legacy, 0) != 0)
-        return -1;
-
-    return 0;
-}
diff --git a/install/package.cpp b/install/package.cpp
index 22673cf..d3470bc 100755
--- a/install/package.cpp
+++ b/install/package.cpp
@@ -39,12 +39,20 @@
 
   ~MemoryPackage() override;
 
+  PackageType GetType() const override {
+    return PackageType::kMemory;
+  }
+
   // Memory maps the package file if necessary. Initializes the start address and size of the
   // package.
   uint64_t GetPackageSize() const override {
     return package_size_;
   }
 
+  std::string GetPath() const override {
+    return path_;
+  }
+
   bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override;
 
   ZipArchiveHandle GetZipArchiveHandle() override;
@@ -81,10 +89,18 @@
 
   ~FilePackage() override;
 
+  PackageType GetType() const override {
+    return PackageType::kFile;
+  }
+
   uint64_t GetPackageSize() const override {
     return package_size_;
   }
 
+  std::string GetPath() const override {
+    return path_;
+  }
+
   bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override;
 
   ZipArchiveHandle GetZipArchiveHandle() override;
@@ -248,7 +264,7 @@
     return zip_handle_;
   }
 
-  if (auto err = OpenArchiveFd(fd_.get(), path_.c_str(), &zip_handle_); err != 0) {
+  if (auto err = OpenArchiveFd(fd_.get(), path_.c_str(), &zip_handle_, false); err != 0) {
     LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err);
     return nullptr;
   }
diff --git a/install/snapshot_utils.cpp b/install/snapshot_utils.cpp
new file mode 100644
index 0000000..7235e67
--- /dev/null
+++ b/install/snapshot_utils.cpp
@@ -0,0 +1,74 @@
+
+/*
+ * Copyright (C) 2019 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 <android-base/logging.h>
+#include <android-base/properties.h>
+#include <libsnapshot/snapshot.h>
+
+#include "recovery_ui/device.h"
+#include "recovery_ui/ui.h"
+#include "recovery_utils/roots.h"
+
+using android::snapshot::CreateResult;
+using android::snapshot::SnapshotManager;
+
+bool FinishPendingSnapshotMerges(Device* device) {
+  if (!android::base::GetBoolProperty("ro.virtual_ab.enabled", false)) {
+    return true;
+  }
+
+  RecoveryUI* ui = device->GetUI();
+  auto sm = SnapshotManager::NewForFirstStageMount();
+  if (!sm) {
+    ui->Print("Could not create SnapshotManager.\n");
+    return false;
+  }
+
+  auto callback = [&]() -> void {
+    double progress;
+    sm->GetUpdateState(&progress);
+    ui->Print("Waiting for merge to complete: %.2f\n", progress);
+  };
+  if (!sm->HandleImminentDataWipe(callback)) {
+    ui->Print("Unable to check merge status and/or complete update merge.\n");
+    return false;
+  }
+  return true;
+}
+
+bool CreateSnapshotPartitions() {
+  if (!android::base::GetBoolProperty("ro.virtual_ab.enabled", false)) {
+    // If the device does not support Virtual A/B, there's no need to create
+    // snapshot devices.
+    return true;
+  }
+
+  auto sm = SnapshotManager::NewForFirstStageMount();
+  if (!sm) {
+    // SnapshotManager could not be created. The device is still in a
+    // consistent state and can continue with the mounting of the existing
+    // devices, but cannot initialize snapshot devices.
+    LOG(WARNING) << "Could not create SnapshotManager";
+    return true;
+  }
+
+  auto ret = sm->RecoveryCreateSnapshotDevices();
+  if (ret == CreateResult::ERROR) {
+    return false;
+  }
+  return true;
+}
diff --git a/install/verifier.cpp b/install/verifier.cpp
index 6ba1d77..ab75044 100644
--- a/install/verifier.cpp
+++ b/install/verifier.cpp
@@ -311,8 +311,7 @@
 
 static std::vector<Certificate> IterateZipEntriesAndSearchForKeys(const ZipArchiveHandle& handle) {
   void* cookie;
-  ZipString suffix("x509.pem");
-  int32_t iter_status = StartIteration(handle, &cookie, nullptr, &suffix);
+  int32_t iter_status = StartIteration(handle, &cookie, "", "x509.pem");
   if (iter_status != 0) {
     LOG(ERROR) << "Failed to iterate over entries in the certificate zipfile: "
                << ErrorCodeString(iter_status);
@@ -321,22 +320,21 @@
 
   std::vector<Certificate> result;
 
-  ZipString name;
+  std::string_view name;
   ZipEntry entry;
   while ((iter_status = Next(cookie, &entry, &name)) == 0) {
     std::vector<uint8_t> pem_content(entry.uncompressed_length);
     if (int32_t extract_status =
             ExtractToMemory(handle, &entry, pem_content.data(), pem_content.size());
         extract_status != 0) {
-      LOG(ERROR) << "Failed to extract " << std::string(name.name, name.name + name.name_length);
+      LOG(ERROR) << "Failed to extract " << name;
       return {};
     }
 
     Certificate cert(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
     // Aborts the parsing if we fail to load one of the key file.
     if (!LoadCertificateFromBuffer(pem_content, &cert)) {
-      LOG(ERROR) << "Failed to load keys from "
-                 << std::string(name.name, name.name + name.name_length);
+      LOG(ERROR) << "Failed to load keys from " << name;
       return {};
     }
 
diff --git a/install/wipe_data.cpp b/install/wipe_data.cpp
index b0e44c7..b2da76b 100755
--- a/install/wipe_data.cpp
+++ b/install/wipe_data.cpp
@@ -27,10 +27,11 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 
+#include "install/snapshot_utils.h"
 #include "otautil/dirutil.h"
-#include "otautil/logging.h"
-#include "otautil/roots.h"
 #include "recovery_ui/ui.h"
+#include "recovery_utils/logging.h"
+#include "recovery_utils/roots.h"
 
 constexpr const char* CACHE_ROOT = "/cache";
 constexpr const char* DATA_ROOT = "/data";
@@ -104,6 +105,12 @@
 bool WipeData(Device* device, bool convert_fbe) {
   // RecoveryUI* ui = device->GetUI();
   // ui->Print("\n-- Wiping data...\n");
+
+  // if (!FinishPendingSnapshotMerges(device)) {
+  //   ui->Print("Unable to check update status or complete merge, cannot wipe partitions.\n");
+  //   return false;
+  // }
+
   bool success = device->PreWipeData();
   if (success) {
     success &= EraseVolume(DATA_ROOT, convert_fbe);
@@ -120,4 +127,4 @@
   }
   // ui->Print("Data wipe %s.\n", success ? "complete" : "failed");
   return success;
-}
\ No newline at end of file
+}
diff --git a/install/wipe_device.cpp b/install/wipe_device.cpp
new file mode 100644
index 0000000..d1cf89f
--- /dev/null
+++ b/install/wipe_device.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 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 "install/wipe_device.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/fs.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <ziparchive/zip_archive.h>
+
+#include "bootloader_message/bootloader_message.h"
+#include "install/install.h"
+#include "install/package.h"
+#include "recovery_ui/device.h"
+#include "recovery_ui/ui.h"
+
+std::vector<std::string> GetWipePartitionList(Package* wipe_package) {
+  ZipArchiveHandle zip = wipe_package->GetZipArchiveHandle();
+  if (!zip) {
+    LOG(ERROR) << "Failed to get ZipArchiveHandle";
+    return {};
+  }
+
+  constexpr char RECOVERY_WIPE_ENTRY_NAME[] = "recovery.wipe";
+
+  std::string partition_list_content;
+  ZipEntry entry;
+  if (FindEntry(zip, RECOVERY_WIPE_ENTRY_NAME, &entry) == 0) {
+    uint32_t length = entry.uncompressed_length;
+    partition_list_content = std::string(length, '\0');
+    if (auto err = ExtractToMemory(
+            zip, &entry, reinterpret_cast<uint8_t*>(partition_list_content.data()), length);
+        err != 0) {
+      LOG(ERROR) << "Failed to extract " << RECOVERY_WIPE_ENTRY_NAME << ": "
+                 << ErrorCodeString(err);
+      return {};
+    }
+  } else {
+    LOG(INFO) << "Failed to find " << RECOVERY_WIPE_ENTRY_NAME
+              << ", falling back to use the partition list on device.";
+
+    constexpr char RECOVERY_WIPE_ON_DEVICE[] = "/etc/recovery.wipe";
+    if (!android::base::ReadFileToString(RECOVERY_WIPE_ON_DEVICE, &partition_list_content)) {
+      PLOG(ERROR) << "failed to read \"" << RECOVERY_WIPE_ON_DEVICE << "\"";
+      return {};
+    }
+  }
+
+  std::vector<std::string> result;
+  auto lines = android::base::Split(partition_list_content, "\n");
+  for (const auto& line : lines) {
+    auto partition = android::base::Trim(line);
+    // Ignore '#' comment or empty lines.
+    if (android::base::StartsWith(partition, "#") || partition.empty()) {
+      continue;
+    }
+    result.push_back(line);
+  }
+
+  return result;
+}
+
+// Secure-wipes a given partition. It uses BLKSECDISCARD, if supported. Otherwise, it goes with
+// BLKDISCARD (if device supports BLKDISCARDZEROES) or BLKZEROOUT.
+static bool SecureWipePartition(const std::string& partition) {
+  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(partition.c_str(), O_WRONLY)));
+  if (fd == -1) {
+    PLOG(ERROR) << "Failed to open \"" << partition << "\"";
+    return false;
+  }
+
+  uint64_t range[2] = { 0, 0 };
+  if (ioctl(fd, BLKGETSIZE64, &range[1]) == -1 || range[1] == 0) {
+    PLOG(ERROR) << "Failed to get partition size";
+    return false;
+  }
+  LOG(INFO) << "Secure-wiping \"" << partition << "\" from " << range[0] << " to " << range[1];
+
+  LOG(INFO) << "  Trying BLKSECDISCARD...";
+  if (ioctl(fd, BLKSECDISCARD, &range) == -1) {
+    PLOG(WARNING) << "  Failed";
+
+    // Use BLKDISCARD if it zeroes out blocks, otherwise use BLKZEROOUT.
+    unsigned int zeroes;
+    if (ioctl(fd, BLKDISCARDZEROES, &zeroes) == 0 && zeroes != 0) {
+      LOG(INFO) << "  Trying BLKDISCARD...";
+      if (ioctl(fd, BLKDISCARD, &range) == -1) {
+        PLOG(ERROR) << "  Failed";
+        return false;
+      }
+    } else {
+      LOG(INFO) << "  Trying BLKZEROOUT...";
+      if (ioctl(fd, BLKZEROOUT, &range) == -1) {
+        PLOG(ERROR) << "  Failed";
+        return false;
+      }
+    }
+  }
+
+  LOG(INFO) << "  Done";
+  return true;
+}
+
+static std::unique_ptr<Package> ReadWipePackage(size_t wipe_package_size) {
+  if (wipe_package_size == 0) {
+    LOG(ERROR) << "wipe_package_size is zero";
+    return nullptr;
+  }
+
+  std::string wipe_package;
+  if (std::string err_str; !read_wipe_package(&wipe_package, wipe_package_size, &err_str)) {
+    PLOG(ERROR) << "Failed to read wipe package" << err_str;
+    return nullptr;
+  }
+
+  return Package::CreateMemoryPackage(
+      std::vector<uint8_t>(wipe_package.begin(), wipe_package.end()));
+}
+
+// Checks if the wipe package matches expectation. If the check passes, reads the list of
+// partitions to wipe from the package. Checks include
+// 1. verify the package.
+// 2. check metadata (ota-type, pre-device and serial number if having one).
+static bool CheckWipePackage(Package* wipe_package, __attribute__((unused)) RecoveryUI* ui) {
+  if (!verify_package(wipe_package)) {
+    LOG(ERROR) << "Failed to verify package";
+    return false;
+  }
+
+  ZipArchiveHandle zip = wipe_package->GetZipArchiveHandle();
+  if (!zip) {
+    LOG(ERROR) << "Failed to get ZipArchiveHandle";
+    return false;
+  }
+
+  std::map<std::string, std::string> metadata;
+  if (!ReadMetadataFromPackage(zip, &metadata)) {
+    LOG(ERROR) << "Failed to parse metadata in the zip file";
+    return false;
+  }
+
+  return CheckPackageMetadata(metadata, OtaType::BRICK);
+}
+
+bool WipeAbDevice(Device* device, size_t wipe_package_size) {
+  auto ui = device->GetUI();
+  ui->SetBackground(RecoveryUI::ERASING);
+  ui->SetProgressType(RecoveryUI::INDETERMINATE);
+
+  auto wipe_package = ReadWipePackage(wipe_package_size);
+  if (!wipe_package) {
+    LOG(ERROR) << "Failed to open wipe package";
+    return false;
+  }
+
+  if (!CheckWipePackage(wipe_package.get(), ui)) {
+    LOG(ERROR) << "Failed to verify wipe package";
+    return false;
+  }
+
+  auto partition_list = GetWipePartitionList(wipe_package.get());
+  if (partition_list.empty()) {
+    LOG(ERROR) << "Empty wipe ab partition list";
+    return false;
+  }
+
+  for (const auto& partition : partition_list) {
+    // Proceed anyway even if it fails to wipe some partition.
+    SecureWipePartition(partition);
+  }
+  return true;
+}
diff --git a/install/zipwrap.cpp b/install/zipwrap.cpp
deleted file mode 100755
index ddd13de..0000000
--- a/install/zipwrap.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) TeamWin
- * This file is part of TWRP/TeamWin Recovery 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 "zipwrap.hpp"
-#include <string>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#ifdef USE_MINZIP
-#include "minzip/Zip.h"
-#include "minzip/SysUtil.h"
-#else
-#include <ziparchive/zip_archive.h>
-#include "ZipUtil.h"
-#include "otautil/sysutil.h"
-#endif
-
-ZipWrap::ZipWrap() {
-	zip_open = false;
-}
-
-ZipWrap::~ZipWrap() {
-	if (zip_open)
-		Close();
-}
-
-bool ZipWrap::Open(const char* file, MemMapping* map) {
-	if (zip_open) {
-		printf("ZipWrap '%s' is already open\n", zip_file.c_str());
-		return true;
-	}
-	zip_file = file;
-#ifdef USE_MINZIP
-	if (mzOpenZipArchive(map->addr, map->length, &Zip) != 0)
-		return false;
-#else
-	if (OpenArchiveFromMemory(map->addr, map->length, file, &Zip) != 0)
-		return false;
-#endif
-	zip_open = true;
-	return true;
-}
-
-void ZipWrap::Close() {
-	if (zip_open)
-#ifdef USE_MINZIP
-		mzCloseZipArchive(&Zip);
-#else
-		CloseArchive(Zip);
-#endif
-	zip_open = false;
-}
-
-bool ZipWrap::EntryExists(const string& filename) {
-#ifdef USE_MINZIP
-	const ZipEntry* file_location = mzFindZipEntry(&Zip, filename.c_str());
-	if (file_location != NULL)
-		return true;
-	return false;
-#else
-	ZipString zip_string(filename.c_str());
-	ZipEntry file_entry;
-
-	if (FindEntry(Zip, zip_string, &file_entry) != 0)
-		return false;
-	return true;
-#endif
-}
-
-bool ZipWrap::ExtractEntry(const string& source_file, const string& target_file, mode_t mode) {
-	if (access(target_file.c_str(), F_OK) == 0 && unlink(target_file.c_str()) != 0)
-		printf("Unable to unlink '%s': %s\n", target_file.c_str(), strerror(errno));
-	
-	int fd = creat(target_file.c_str(), mode);
-	if (fd < 0) {
-		printf("Failed to create '%s'\n", target_file.c_str());
-		return false;
-	}
-
-#ifdef USE_MINZIP
-	const ZipEntry* file_entry = mzFindZipEntry(&Zip, source_file.c_str());
-	if (file_entry == NULL) {
-		printf("'%s' does not exist in zip '%s'\n", source_file.c_str(), zip_file.c_str());
-		return false;
-	}
-	int ret_val = mzExtractZipEntryToFile(&Zip, file_entry, fd);
-	close(fd);
-
-	if (!ret_val) {
-		printf("Could not extract '%s'\n", target_file.c_str());
-		return false;
-	}
-#else
-	ZipString zip_string(source_file.c_str());
-	ZipEntry file_entry;
-
-	if (FindEntry(Zip, zip_string, &file_entry) != 0)
-		return false;
-	int32_t ret_val = ExtractEntryToFile(Zip, &file_entry, fd);
-	close(fd);
-
-	if (ret_val != 0) {
-		printf("Could not extract '%s'\n", target_file.c_str());
-		return false;
-	}
-#endif
-	return true;
-}
-
-bool ZipWrap::ExtractRecursive(const string& source_dir, const string& target_dir) {
-	struct utimbuf timestamp = { 1217592000, 1217592000 };  // 8/1/2008 default
-#ifdef USE_MINZIP
-	return mzExtractRecursive(&Zip, source_dir.c_str(), target_dir.c_str(), &timestamp, NULL, NULL, NULL);
-#else
-	return ExtractPackageRecursive(Zip, source_dir, target_dir, &timestamp, NULL);
-#endif
-}
-
-long ZipWrap::GetUncompressedSize(const string& filename) {
-#ifdef USE_MINZIP
-	const ZipEntry* file_entry = mzFindZipEntry(&Zip, filename.c_str());
-	if (file_entry == NULL) {
-		printf("'%s' does not exist in zip '%s'\n", filename.c_str(), zip_file.c_str());
-		return 0;
-	}
-	return file_entry->uncompLen;
-#else
-	ZipString zip_string(filename.c_str());
-	ZipEntry file_entry;
-
-	if (FindEntry(Zip, zip_string, &file_entry) != 0)
-		return 0;
-	return file_entry.uncompressed_length;
-#endif
-}
-
-bool ZipWrap::ExtractToBuffer(const string& filename, uint8_t* buffer) {
-#ifdef USE_MINZIP
-	const ZipEntry* file_entry = mzFindZipEntry(&Zip, filename.c_str());
-	if (file_entry == NULL) {
-		printf("'%s' does not exist in zip '%s'\n", filename.c_str(), zip_file.c_str());
-		return false;
-	}
-	if (!mzExtractZipEntryToBuffer(&Zip, file_entry, buffer)) {
-		printf("Failed to read '%s'\n", filename.c_str());
-		return false;
-	}
-#else
-	ZipString zip_string(filename.c_str());
-	ZipEntry file_entry;
-
-	if (FindEntry(Zip, zip_string, &file_entry) != 0)
-		return false;
-	if (ExtractToMemory(Zip, &file_entry, buffer, file_entry.uncompressed_length) != 0) {
-		printf("Failed to read '%s'\n", filename.c_str());
-		return false;
-	}
-#endif
-	return true;
-}
-
-#ifdef USE_MINZIP
-loff_t ZipWrap::GetEntryOffset(const string& filename) {
-	const ZipEntry* file_entry = mzFindZipEntry(&Zip, filename.c_str());
-	if (file_entry == NULL) {
-		printf("'%s' does not exist in zip '%s'\n", filename.c_str(), zip_file.c_str());
-		return 0;
-	}
-	return mzGetZipEntryOffset(file_entry);
-}
-#else
-off64_t ZipWrap::GetEntryOffset(const string& filename) {
-	ZipString zip_string(filename.c_str());
-	ZipEntry file_entry;
-
-	if (FindEntry(Zip, zip_string, &file_entry) != 0) {
-		printf("'%s' does not exist in zip '%s'\n", filename.c_str(), zip_file.c_str());
-		return 0;
-	}
-	return file_entry.offset;
-}
-
-ZipArchiveHandle ZipWrap::GetZipArchiveHandle() {
-	return Zip;
-}
-#endif