summaryrefslogtreecommitdiffstats
path: root/install
diff options
context:
space:
mode:
Diffstat (limited to 'install')
-rw-r--r--install/Android.bp4
-rw-r--r--install/adb_install.cpp18
-rw-r--r--install/fuse_install.cpp (renamed from install/fuse_sdcard_install.cpp)84
-rw-r--r--install/include/install/adb_install.h11
-rw-r--r--install/include/install/fuse_install.h30
-rw-r--r--install/include/install/install.h22
-rw-r--r--install/include/install/package.h9
-rw-r--r--install/include/install/wipe_device.h (renamed from install/include/install/fuse_sdcard_install.h)11
-rw-r--r--install/include/private/setup_commands.h8
-rw-r--r--install/install.cpp166
-rw-r--r--install/package.cpp18
-rw-r--r--install/verifier.cpp10
-rw-r--r--install/wipe_device.cpp197
13 files changed, 431 insertions, 157 deletions
diff --git a/install/Android.bp b/install/Android.bp
index ea893a075..89cc3f23e 100644
--- a/install/Android.bp
+++ b/install/Android.bp
@@ -47,7 +47,6 @@ cc_defaults {
// external dependencies
"libvintf_recovery",
"libvintf",
- "libfstab",
],
}
@@ -62,11 +61,12 @@ cc_library_static {
srcs: [
"adb_install.cpp",
"asn1_decoder.cpp",
- "fuse_sdcard_install.cpp",
+ "fuse_install.cpp",
"install.cpp",
"package.cpp",
"verifier.cpp",
"wipe_data.cpp",
+ "wipe_device.cpp",
],
shared_libs: [
diff --git a/install/adb_install.cpp b/install/adb_install.cpp
index 4dd1f1b09..ed664429a 100644
--- a/install/adb_install.cpp
+++ b/install/adb_install.cpp
@@ -90,7 +90,7 @@ static bool WriteStatusToFd(MinadbdCommandStatus status, int fd) {
// Installs the package from FUSE. Returns the installation result and whether it should continue
// waiting for new commands.
-static auto AdbInstallPackageHandler(RecoveryUI* ui, int* result) {
+static auto AdbInstallPackageHandler(RecoveryUI* ui, 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,11 @@ static auto AdbInstallPackageHandler(RecoveryUI* ui, int* result) {
break;
}
}
- *result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0, ui);
+
+ auto package =
+ Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME,
+ std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
+ *result = InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0, ui);
break;
}
@@ -120,7 +124,7 @@ static auto AdbInstallPackageHandler(RecoveryUI* ui, int* result) {
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
@@ -331,7 +335,7 @@ static void CreateMinadbdServiceAndExecuteCommands(
signal(SIGPIPE, SIG_DFL);
}
-int ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot_action) {
+InstallResult ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot_action) {
// Save the usb state to restore after the sideload operation.
std::string usb_state = android::base::GetProperty("sys.usb.state", "none");
// Clean up state and stop adbd.
@@ -342,7 +346,7 @@ int ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot
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, ui, &install_result) },
{ MinadbdCommand::kRebootAndroid, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootAndroid,
@@ -363,11 +367,13 @@ int ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot
"\n\nNow send the package you want to apply\n"
"to the device with \"adb sideload <filename>\"...\n");
} else {
- ui->Print("\n\nWaiting for rescue commands...\n");
command_map.emplace(MinadbdCommand::kWipeData, [&device]() {
bool result = WipeData(device, false);
return std::make_pair(result, true);
});
+ command_map.emplace(MinadbdCommand::kNoOp, []() { return std::make_pair(true, true); });
+
+ ui->Print("\n\nWaiting for rescue commands...\n");
}
CreateMinadbdServiceAndExecuteCommands(ui, command_map, rescue_mode);
diff --git a/install/fuse_sdcard_install.cpp b/install/fuse_install.cpp
index 1aa8768e7..8a7a278e0 100644
--- 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>
@@ -74,7 +75,8 @@ static std::string BrowseDirectory(const std::string& path, Device* device, Reco
// 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 @@ static std::string BrowseDirectory(const std::string& path, Device* device, Reco
// 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;
-}
-
-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;
+ if (!fuse_data_provider || !fuse_data_provider->Valid()) {
+ LOG(ERROR) << "Failed to create fuse data provider.";
+ return false;
}
- 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;
+ 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);
}
- ui->Print("\n-- Install %s ...\n", path.c_str());
- SetSdcardUpdateBootloaderMessage();
+ return run_fuse_sideload(std::move(fuse_data_provider)) == 0;
+}
+InstallResult InstallWithFuseFromPath(std::string_view path, 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,11 @@ int ApplyFromSdcard(Device* device, RecoveryUI* ui) {
break;
}
}
-
- result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0 /*retry_count*/, ui);
+ auto package =
+ Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME,
+ std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
+ result =
+ InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0 /* retry_count */, ui);
break;
}
@@ -201,6 +201,32 @@ int ApplyFromSdcard(Device* device, RecoveryUI* ui) {
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 3a0a81747..880022361 100644
--- 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(Device* device, bool rescue_mode, 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_install.h b/install/include/install/fuse_install.h
new file mode 100644
index 000000000..63b116aeb
--- /dev/null
+++ b/install/include/install/fuse_install.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string_view>
+
+#include "install/install.h"
+#include "recovery_ui/device.h"
+#include "recovery_ui/ui.h"
+
+// 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 c0a8f1f4c..b4b3a9149 100644
--- a/install/include/install/install.h
+++ b/install/include/install/install.h
@@ -44,11 +44,12 @@ enum class OtaType {
BRICK,
};
-// 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, RecoveryUI* ui);
+// 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, RecoveryUI* ui);
// Verifies the package by ota keys. Returns true if the package is verified successfully,
// otherwise returns false.
@@ -58,14 +59,11 @@ bool verify_package(Package* package, RecoveryUI* ui);
// 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);
-
// 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);
+// 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);
diff --git a/install/include/install/package.h b/install/include/install/package.h
index cd44d10be..0b4233238 100644
--- 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 @@ class Package : public VerifierInterface {
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/wipe_device.h
index d9214ca3b..c60b99997 100644
--- a/install/include/install/fuse_sdcard_install.h
+++ b/install/include/install/wipe_device.h
@@ -16,7 +16,14 @@
#pragma once
+#include <string>
+#include <vector>
+
+#include "install/package.h"
#include "recovery_ui/device.h"
-#include "recovery_ui/ui.h"
-int ApplyFromSdcard(Device* device, RecoveryUI* ui);
+// 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/private/setup_commands.h b/install/include/private/setup_commands.h
index 7fdc741d6..dcff76112 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/install.cpp b/install/install.cpp
index e2d470096..9d67b0105 100644
--- a/install/install.cpp
+++ b/install/install.cpp
@@ -60,7 +60,8 @@
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 @@ bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map<std::string, std::st
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 @@ static void ReadSourceTargetBuild(const std::map<std::string, std::string>& meta
// 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 @@ static int CheckAbSpecificMetadata(const std::map<std::string, std::string>& met
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 @@ static int CheckAbSpecificMetadata(const std::map<std::string, std::string>& met
"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 @@ int CheckPackageMetadata(const std::map<std::string, std::string>& metadata, Ota
}
if (!serial_number_match) {
LOG(ERROR) << "Package is for serial " << pkg_serial_no;
- return INSTALL_ERROR;
+ return false;
}
}
@@ -226,21 +226,20 @@ int CheckPackageMetadata(const std::map<std::string, std::string>& metadata, Ota
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 @@ int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int
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 @@ int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int
"--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 @@ int SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, i
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 @@ int SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, i
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,25 @@ static void log_max_temperature(int* max_temperature, const std::atomic<bool>& l
}
// 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, RecoveryUI* ui) {
+static InstallResult TryUpdateBinary(Package* package, bool* wipe_cache,
+ std::vector<std::string>* log_buffer, int retry_count,
+ int* max_temperature, RecoveryUI* ui) {
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) {
+ if (is_ab) {
+ CHECK(package->GetType() == PackageType::kFile);
+ }
+
+ // Verify against the metadata in the package first.
+ if (is_ab && !CheckPackageMetadata(metadata, OtaType::AB)) {
log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
- return check_status;
+ return INSTALL_ERROR;
}
ReadSourceTargetBuild(metadata, log_buffer);
@@ -385,13 +385,15 @@ static int try_update_binary(const std::string& package, ZipArchiveHandle zip, b
// 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 =
+ 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 +492,11 @@ static int try_update_binary(const std::string& package, ZipArchiveHandle zip, b
}
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,16 +505,15 @@ static int try_update_binary(const std::string& package, ZipArchiveHandle zip, b
return INSTALL_SUCCESS;
}
-// Verifes the compatibility info in a Treble-compatible package. Returns true directly if the
+// Verifies 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) {
+ if (FindEntry(package_zip, COMPATIBILITY_ZIP_ENTRY, &compatibility_entry) != 0) {
LOG(INFO) << "Package doesn't contain " << COMPATIBILITY_ZIP_ENTRY << " entry";
return true;
}
@@ -536,7 +537,7 @@ bool verify_package_compatibility(ZipArchiveHandle package_zip) {
// Iterate all the entries inside COMPATIBILITY_ZIP_ENTRY and read the contents.
void* cookie;
- ret = StartIteration(zip_handle, &cookie, nullptr, nullptr);
+ ret = StartIteration(zip_handle, &cookie);
if (ret != 0) {
LOG(ERROR) << "Failed to start iterating zip entries: " << ErrorCodeString(ret);
CloseArchive(zip_handle);
@@ -546,13 +547,13 @@ bool verify_package_compatibility(ZipArchiveHandle package_zip) {
std::vector<std::string> compatibility_info;
ZipEntry info_entry;
- ZipString info_name;
+ std::string_view 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);
+ LOG(ERROR) << "Failed to read " << info_name << ": " << ErrorCodeString(ret);
CloseArchive(zip_handle);
return false;
}
@@ -571,36 +572,16 @@ bool verify_package_compatibility(ZipArchiveHandle package_zip) {
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, RecoveryUI* ui) {
+static InstallResult VerifyAndInstallPackage(Package* package, bool* wipe_cache,
+ std::vector<std::string>* log_buffer, int retry_count,
+ int* max_temperature, RecoveryUI* ui) {
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, std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
- if (!package) {
- log_buffer->push_back(android::base::StringPrintf("error: %d", kMapFileFailure));
- return INSTALL_CORRUPT;
- }
// Verify package.
- if (!verify_package(package.get(), ui)) {
+ if (!verify_package(package, ui)) {
log_buffer->push_back(android::base::StringPrintf("error: %d", kZipVerificationFailure));
return INSTALL_CORRUPT;
}
@@ -624,32 +605,37 @@ static int really_install_package(const std::string& path, bool* wipe_cache, boo
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, ui);
+ auto result = TryUpdateBinary(package, wipe_cache, log_buffer, retry_count, max_temperature, ui);
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, RecoveryUI* ui) {
- CHECK(!path.empty());
-
+InstallResult InstallPackage(Package* package, const std::string_view package_id,
+ bool should_wipe_cache, int retry_count, RecoveryUI* ui) {
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, ui);
+ result = VerifyAndInstallPackage(package, &updater_wipe_cache, &log_buffer, retry_count,
+ &max_temperature, ui);
should_wipe_cache = should_wipe_cache || updater_wipe_cache;
}
@@ -677,7 +663,7 @@ int install_package(const std::string& path, bool should_wipe_cache, bool needs_
// 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),
diff --git a/install/package.cpp b/install/package.cpp
index 4402f4855..86fc0647d 100644
--- a/install/package.cpp
+++ b/install/package.cpp
@@ -40,12 +40,20 @@ class MemoryPackage : public Package {
~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;
@@ -82,10 +90,18 @@ class FilePackage : public Package {
~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;
@@ -253,7 +269,7 @@ ZipArchiveHandle FilePackage::GetZipArchiveHandle() {
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/verifier.cpp b/install/verifier.cpp
index 6ba1d77c3..ab750442d 100644
--- a/install/verifier.cpp
+++ b/install/verifier.cpp
@@ -311,8 +311,7 @@ int verify_file(VerifierInterface* package, const std::vector<Certificate>& keys
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 @@ static std::vector<Certificate> IterateZipEntriesAndSearchForKeys(const ZipArchi
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_device.cpp b/install/wipe_device.cpp
new file mode 100644
index 000000000..89d5d31a3
--- /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()), nullptr);
+}
+
+// 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, RecoveryUI* ui) {
+ if (!verify_package(wipe_package, ui)) {
+ 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;
+}