Perform data wipe in recovery if ota package has powerwash set
Normally, if an ota package has --wipe_user_data flag, we set bootloader parameter --wipe_data, so that next boot into bootloader will wipe userdata. But this doesn't work in recovery, likely because after recovery we don't reboot to bootloader, but directly boot into android. Therefore perform data reset in recovery if the OTA package has POWERWASH flag. Bug: 203507329 Test: apply an OTA pkg with --wipe_user_data, verify that data wipe happened Change-Id: Icca4a5f74246bde44a5fd589395404c9f57867ee
This commit is contained in:
parent
13c721f330
commit
a4208b5f90
6 changed files with 54 additions and 25 deletions
|
@ -90,11 +90,12 @@ static bool WriteStatusToFd(MinadbdCommandStatus status, int fd) {
|
||||||
|
|
||||||
// Installs the package from FUSE. Returns the installation result and whether it should continue
|
// Installs the package from FUSE. Returns the installation result and whether it should continue
|
||||||
// waiting for new commands.
|
// waiting for new commands.
|
||||||
static auto AdbInstallPackageHandler(RecoveryUI* ui, InstallResult* result) {
|
static auto AdbInstallPackageHandler(Device* device, InstallResult* result) {
|
||||||
// How long (in seconds) we wait for the package path to be ready. It doesn't need to be too long
|
// 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
|
// 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
|
// will start to exist once the host connects and starts serving a package. Poll for its
|
||||||
// appearance. (Note that inotify doesn't work with FUSE.)
|
// appearance. (Note that inotify doesn't work with FUSE.)
|
||||||
|
auto ui = device->GetUI();
|
||||||
constexpr int ADB_INSTALL_TIMEOUT = 15;
|
constexpr int ADB_INSTALL_TIMEOUT = 15;
|
||||||
bool should_continue = true;
|
bool should_continue = true;
|
||||||
*result = INSTALL_ERROR;
|
*result = INSTALL_ERROR;
|
||||||
|
@ -114,7 +115,7 @@ static auto AdbInstallPackageHandler(RecoveryUI* ui, InstallResult* result) {
|
||||||
auto package =
|
auto package =
|
||||||
Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME,
|
Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME,
|
||||||
std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
|
std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
|
||||||
*result = InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0, ui);
|
*result = InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0, device);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,7 +349,7 @@ InstallResult ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinActi
|
||||||
|
|
||||||
InstallResult install_result = INSTALL_ERROR;
|
InstallResult install_result = INSTALL_ERROR;
|
||||||
std::map<MinadbdCommand, CommandFunction> command_map{
|
std::map<MinadbdCommand, CommandFunction> command_map{
|
||||||
{ MinadbdCommand::kInstall, std::bind(&AdbInstallPackageHandler, ui, &install_result) },
|
{ MinadbdCommand::kInstall, std::bind(&AdbInstallPackageHandler, device, &install_result) },
|
||||||
{ MinadbdCommand::kRebootAndroid, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootAndroid,
|
{ MinadbdCommand::kRebootAndroid, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootAndroid,
|
||||||
&install_result, reboot_action) },
|
&install_result, reboot_action) },
|
||||||
{ MinadbdCommand::kRebootBootloader,
|
{ MinadbdCommand::kRebootBootloader,
|
||||||
|
|
|
@ -146,10 +146,11 @@ static bool StartInstallPackageFuse(std::string_view path) {
|
||||||
return run_fuse_sideload(std::move(fuse_data_provider)) == 0;
|
return run_fuse_sideload(std::move(fuse_data_provider)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallResult InstallWithFuseFromPath(std::string_view path, RecoveryUI* ui) {
|
InstallResult InstallWithFuseFromPath(std::string_view path, Device* device) {
|
||||||
// We used to use fuse in a thread as opposed to a process. Since accessing
|
// 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
|
// through fuse involves going from kernel to userspace to kernel, it leads
|
||||||
// to deadlock when a page fault occurs. (Bug: 26313124)
|
// to deadlock when a page fault occurs. (Bug: 26313124)
|
||||||
|
auto ui = device->GetUI();
|
||||||
pid_t child;
|
pid_t child;
|
||||||
if ((child = fork()) == 0) {
|
if ((child = fork()) == 0) {
|
||||||
bool status = StartInstallPackageFuse(path);
|
bool status = StartInstallPackageFuse(path);
|
||||||
|
@ -183,8 +184,8 @@ InstallResult InstallWithFuseFromPath(std::string_view path, RecoveryUI* ui) {
|
||||||
auto package =
|
auto package =
|
||||||
Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME,
|
Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME,
|
||||||
std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
|
std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
|
||||||
result =
|
result = InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0 /* retry_count */,
|
||||||
InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0 /* retry_count */, ui);
|
device);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +227,7 @@ InstallResult ApplyFromSdcard(Device* device) {
|
||||||
ui->Print("\n-- Install %s ...\n", path.c_str());
|
ui->Print("\n-- Install %s ...\n", path.c_str());
|
||||||
SetSdcardUpdateBootloaderMessage();
|
SetSdcardUpdateBootloaderMessage();
|
||||||
|
|
||||||
auto result = InstallWithFuseFromPath(path, ui);
|
auto result = InstallWithFuseFromPath(path, device);
|
||||||
ensure_path_unmounted(SDCARD_ROOT);
|
ensure_path_unmounted(SDCARD_ROOT);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,6 @@
|
||||||
// Starts FUSE with the package from |path| as the data source. And installs the package from
|
// 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
|
// |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.
|
// block map file with the prefix '@'; e.g. /sdcard/package.zip, @/cache/recovery/block.map.
|
||||||
InstallResult InstallWithFuseFromPath(std::string_view path, RecoveryUI* ui);
|
InstallResult InstallWithFuseFromPath(std::string_view path, Device* device);
|
||||||
|
|
||||||
InstallResult ApplyFromSdcard(Device* device);
|
InstallResult ApplyFromSdcard(Device* device);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <ziparchive/zip_archive.h>
|
#include <ziparchive/zip_archive.h>
|
||||||
|
|
||||||
#include "otautil/package.h"
|
#include "otautil/package.h"
|
||||||
|
#include "recovery_ui/device.h"
|
||||||
#include "recovery_ui/ui.h"
|
#include "recovery_ui/ui.h"
|
||||||
|
|
||||||
enum InstallResult {
|
enum InstallResult {
|
||||||
|
@ -49,7 +50,8 @@ enum class OtaType {
|
||||||
// cache partition after a successful installation if |should_wipe_cache| is true or an updater
|
// cache partition after a successful installation if |should_wipe_cache| is true or an updater
|
||||||
// command asks to wipe the cache.
|
// command asks to wipe the cache.
|
||||||
InstallResult InstallPackage(Package* package, const std::string_view package_id,
|
InstallResult InstallPackage(Package* package, const std::string_view package_id,
|
||||||
bool should_wipe_cache, int retry_count, RecoveryUI* ui);
|
bool should_wipe_cache, int retry_count,
|
||||||
|
Device* ui);
|
||||||
|
|
||||||
// Verifies the package by ota keys. Returns true if the package is verified successfully,
|
// Verifies the package by ota keys. Returns true if the package is verified successfully,
|
||||||
// otherwise returns false.
|
// otherwise returns false.
|
||||||
|
|
|
@ -235,30 +235,41 @@ bool CheckPackageMetadata(const std::map<std::string, std::string>& metadata, Ot
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
|
static std::string ExtractPayloadProperties(ZipArchiveHandle zip) {
|
||||||
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
|
// For A/B updates we extract the payload properties to a buffer and obtain the RAW payload offset
|
||||||
// in the zip file.
|
// in the zip file.
|
||||||
static constexpr const char* AB_OTA_PAYLOAD_PROPERTIES = "payload_properties.txt";
|
static constexpr const char* AB_OTA_PAYLOAD_PROPERTIES = "payload_properties.txt";
|
||||||
ZipEntry64 properties_entry;
|
ZipEntry64 properties_entry;
|
||||||
if (FindEntry(zip, AB_OTA_PAYLOAD_PROPERTIES, &properties_entry) != 0) {
|
if (FindEntry(zip, AB_OTA_PAYLOAD_PROPERTIES, &properties_entry) != 0) {
|
||||||
LOG(ERROR) << "Failed to find " << AB_OTA_PAYLOAD_PROPERTIES;
|
LOG(ERROR) << "Failed to find " << AB_OTA_PAYLOAD_PROPERTIES;
|
||||||
return false;
|
return {};
|
||||||
}
|
}
|
||||||
auto properties_entry_length = properties_entry.uncompressed_length;
|
auto properties_entry_length = properties_entry.uncompressed_length;
|
||||||
if (properties_entry_length > std::numeric_limits<size_t>::max()) {
|
if (properties_entry_length > std::numeric_limits<size_t>::max()) {
|
||||||
LOG(ERROR) << "Failed to extract " << AB_OTA_PAYLOAD_PROPERTIES
|
LOG(ERROR) << "Failed to extract " << AB_OTA_PAYLOAD_PROPERTIES
|
||||||
<< " because's uncompressed size exceeds size of address space. "
|
<< " because's uncompressed size exceeds size of address space. "
|
||||||
<< properties_entry_length;
|
<< properties_entry_length;
|
||||||
return false;
|
return {};
|
||||||
}
|
}
|
||||||
std::vector<uint8_t> payload_properties(properties_entry_length);
|
std::string payload_properties(properties_entry_length, '\0');
|
||||||
int32_t err =
|
int32_t err =
|
||||||
ExtractToMemory(zip, &properties_entry, payload_properties.data(), properties_entry_length);
|
ExtractToMemory(zip, &properties_entry, reinterpret_cast<uint8_t*>(payload_properties.data()),
|
||||||
|
properties_entry_length);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
LOG(ERROR) << "Failed to extract " << AB_OTA_PAYLOAD_PROPERTIES << ": " << ErrorCodeString(err);
|
LOG(ERROR) << "Failed to extract " << AB_OTA_PAYLOAD_PROPERTIES << ": " << ErrorCodeString(err);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return payload_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
const auto payload_properties = ExtractPayloadProperties(zip);
|
||||||
|
if (payload_properties.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,10 +343,20 @@ static void log_max_temperature(int* max_temperature, const std::atomic<bool>& l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool PerformPowerwashIfRequired(ZipArchiveHandle zip, Device *device) {
|
||||||
|
const auto payload_properties = ExtractPayloadProperties(zip);
|
||||||
|
if (payload_properties.find("POWERWASH=1") != std::string::npos) {
|
||||||
|
LOG(INFO) << "Payload properties has POWERWASH=1, wiping userdata...";
|
||||||
|
return WipeData(device, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// If the package contains an update binary, extract it and run it.
|
// If the package contains an update binary, extract it and run it.
|
||||||
static InstallResult TryUpdateBinary(Package* package, bool* wipe_cache,
|
static InstallResult TryUpdateBinary(Package* package, bool* wipe_cache,
|
||||||
std::vector<std::string>* log_buffer, int retry_count,
|
std::vector<std::string>* log_buffer, int retry_count,
|
||||||
int* max_temperature, RecoveryUI* ui) {
|
int* max_temperature, Device* device) {
|
||||||
|
auto ui = device->GetUI();
|
||||||
std::map<std::string, std::string> metadata;
|
std::map<std::string, std::string> metadata;
|
||||||
auto zip = package->GetZipArchiveHandle();
|
auto zip = package->GetZipArchiveHandle();
|
||||||
if (!ReadMetadataFromPackage(zip, &metadata)) {
|
if (!ReadMetadataFromPackage(zip, &metadata)) {
|
||||||
|
@ -530,13 +551,15 @@ static InstallResult TryUpdateBinary(Package* package, bool* wipe_cache,
|
||||||
} else {
|
} else {
|
||||||
LOG(FATAL) << "Invalid status code " << status;
|
LOG(FATAL) << "Invalid status code " << status;
|
||||||
}
|
}
|
||||||
|
PerformPowerwashIfRequired(zip, device);
|
||||||
|
|
||||||
return INSTALL_SUCCESS;
|
return INSTALL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static InstallResult VerifyAndInstallPackage(Package* package, bool* wipe_cache,
|
static InstallResult VerifyAndInstallPackage(Package* package, bool* wipe_cache,
|
||||||
std::vector<std::string>* log_buffer, int retry_count,
|
std::vector<std::string>* log_buffer, int retry_count,
|
||||||
int* max_temperature, RecoveryUI* ui) {
|
int* max_temperature, Device* device) {
|
||||||
|
auto ui = device->GetUI();
|
||||||
ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
|
ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
|
||||||
// Give verification half the progress bar...
|
// Give verification half the progress bar...
|
||||||
ui->SetProgressType(RecoveryUI::DETERMINATE);
|
ui->SetProgressType(RecoveryUI::DETERMINATE);
|
||||||
|
@ -554,7 +577,8 @@ static InstallResult VerifyAndInstallPackage(Package* package, bool* wipe_cache,
|
||||||
ui->Print("Retry attempt: %d\n", retry_count);
|
ui->Print("Retry attempt: %d\n", retry_count);
|
||||||
}
|
}
|
||||||
ui->SetEnableReboot(false);
|
ui->SetEnableReboot(false);
|
||||||
auto result = TryUpdateBinary(package, wipe_cache, log_buffer, retry_count, max_temperature, ui);
|
auto result =
|
||||||
|
TryUpdateBinary(package, wipe_cache, log_buffer, retry_count, max_temperature, device);
|
||||||
ui->SetEnableReboot(true);
|
ui->SetEnableReboot(true);
|
||||||
ui->Print("\n");
|
ui->Print("\n");
|
||||||
|
|
||||||
|
@ -562,7 +586,8 @@ static InstallResult VerifyAndInstallPackage(Package* package, bool* wipe_cache,
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallResult InstallPackage(Package* package, const std::string_view package_id,
|
InstallResult InstallPackage(Package* package, const std::string_view package_id,
|
||||||
bool should_wipe_cache, int retry_count, RecoveryUI* ui) {
|
bool should_wipe_cache, int retry_count, Device* device) {
|
||||||
|
auto ui = device->GetUI();
|
||||||
auto start = std::chrono::system_clock::now();
|
auto start = std::chrono::system_clock::now();
|
||||||
|
|
||||||
int start_temperature = GetMaxValueFromThermalZone();
|
int start_temperature = GetMaxValueFromThermalZone();
|
||||||
|
@ -584,7 +609,7 @@ InstallResult InstallPackage(Package* package, const std::string_view package_id
|
||||||
} else {
|
} else {
|
||||||
bool updater_wipe_cache = false;
|
bool updater_wipe_cache = false;
|
||||||
result = VerifyAndInstallPackage(package, &updater_wipe_cache, &log_buffer, retry_count,
|
result = VerifyAndInstallPackage(package, &updater_wipe_cache, &log_buffer, retry_count,
|
||||||
&max_temperature, ui);
|
&max_temperature, device);
|
||||||
should_wipe_cache = should_wipe_cache || updater_wipe_cache;
|
should_wipe_cache = should_wipe_cache || updater_wipe_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -752,20 +752,20 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri
|
||||||
status = INSTALL_ERROR;
|
status = INSTALL_ERROR;
|
||||||
} else if (install_with_fuse || should_use_fuse) {
|
} else if (install_with_fuse || should_use_fuse) {
|
||||||
LOG(INFO) << "Installing package " << update_package << " with fuse";
|
LOG(INFO) << "Installing package " << update_package << " with fuse";
|
||||||
status = InstallWithFuseFromPath(update_package, ui);
|
status = InstallWithFuseFromPath(update_package, device);
|
||||||
} else if (auto memory_package = Package::CreateMemoryPackage(
|
} else if (auto memory_package = Package::CreateMemoryPackage(
|
||||||
update_package,
|
update_package,
|
||||||
std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
|
std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
|
||||||
memory_package != nullptr) {
|
memory_package != nullptr) {
|
||||||
status = InstallPackage(memory_package.get(), update_package, should_wipe_cache,
|
status = InstallPackage(memory_package.get(), update_package, should_wipe_cache,
|
||||||
retry_count, ui);
|
retry_count, device);
|
||||||
} else {
|
} else {
|
||||||
// We may fail to memory map the package on 32 bit builds for packages with 2GiB+ size.
|
// We may fail to memory map the package on 32 bit builds for packages with 2GiB+ size.
|
||||||
// In such cases, we will try to install the package with fuse. This is not the default
|
// In such cases, we will try to install the package with fuse. This is not the default
|
||||||
// installation method because it introduces a layer of indirection from the kernel space.
|
// installation method because it introduces a layer of indirection from the kernel space.
|
||||||
LOG(WARNING) << "Failed to memory map package " << update_package
|
LOG(WARNING) << "Failed to memory map package " << update_package
|
||||||
<< "; falling back to install with fuse";
|
<< "; falling back to install with fuse";
|
||||||
status = InstallWithFuseFromPath(update_package, ui);
|
status = InstallWithFuseFromPath(update_package, device);
|
||||||
}
|
}
|
||||||
if (status != INSTALL_SUCCESS) {
|
if (status != INSTALL_SUCCESS) {
|
||||||
ui->Print("Installation aborted.\n");
|
ui->Print("Installation aborted.\n");
|
||||||
|
|
Loading…
Reference in a new issue