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(), ×tamp, NULL, NULL, NULL);
-#else
- return ExtractPackageRecursive(Zip, source_dir, target_dir, ×tamp, 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