From 735499480d2d952af625efc2dd7234b272b8b47d Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 4 Jan 2024 16:43:53 -0800 Subject: [PATCH] Add recovery flag to reformat /data For 16K dev options, we might need to reformat /data partition as ext4 before enabling the feature. Add necessary support to recovery. Test: Trigger reboot with --wipe_data --reformat_data=ext4, make sure /data is reformatted with ext4 on next boot Bug: 293313353 Change-Id: I3cb67a62635a2df578472cd48cf6d2f5e04b5f82 --- install/include/install/wipe_data.h | 5 ++-- install/wipe_data.cpp | 21 +++++++------- recovery.cpp | 22 +++++++-------- recovery_main.cpp | 2 +- recovery_utils/include/recovery_utils/roots.h | 3 +- recovery_utils/roots.cpp | 28 ++++++------------- 6 files changed, 36 insertions(+), 45 deletions(-) diff --git a/install/include/install/wipe_data.h b/install/include/install/wipe_data.h index 255d9b17..1796bcca 100644 --- a/install/include/install/wipe_data.h +++ b/install/include/install/wipe_data.h @@ -24,7 +24,8 @@ struct selabel_handle; // Returns true on success. -bool WipeCache(RecoveryUI* ui, const std::function& confirm); +bool WipeCache(RecoveryUI* ui, const std::function& confirm, + std::string_view new_fstype = ""); // Returns true on success. -bool WipeData(Device* device, bool keep_memtag_mode = false); +bool WipeData(Device* device, bool keep_memtag_mode = false, std::string_view new_fstype = ""); diff --git a/install/wipe_data.cpp b/install/wipe_data.cpp index 7aff6226..0f57384a 100644 --- a/install/wipe_data.cpp +++ b/install/wipe_data.cpp @@ -27,7 +27,6 @@ #include "bootloader_message/bootloader_message.h" #include "install/snapshot_utils.h" -#include "otautil/dirutil.h" #include "recovery_ui/ui.h" #include "recovery_utils/logging.h" #include "recovery_utils/roots.h" @@ -36,7 +35,8 @@ constexpr const char* CACHE_ROOT = "/cache"; constexpr const char* DATA_ROOT = "/data"; constexpr const char* METADATA_ROOT = "/metadata"; -static bool EraseVolume(const char* volume, RecoveryUI* ui) { +static bool EraseVolume(const char* volume, RecoveryUI* ui, std::string_view new_fstype) { + LOG(INFO) << "Erasing volume " << volume << " with new filesystem type " << new_fstype; bool is_cache = (strcmp(volume, CACHE_ROOT) == 0); std::vector log_files; @@ -50,7 +50,7 @@ static bool EraseVolume(const char* volume, RecoveryUI* ui) { ensure_path_unmounted(volume); - int result = format_volume(volume); + int result = format_volume(volume, "", new_fstype); if (is_cache) { RestoreLogFilesAfterFormat(log_files); @@ -59,7 +59,8 @@ static bool EraseVolume(const char* volume, RecoveryUI* ui) { return (result == 0); } -bool WipeCache(RecoveryUI* ui, const std::function& confirm_func) { +bool WipeCache(RecoveryUI* ui, const std::function& confirm_func, + std::string_view new_fstype) { bool has_cache = volume_for_mount_point("/cache") != nullptr; if (!has_cache) { ui->Print("No /cache partition found.\n"); @@ -74,14 +75,14 @@ bool WipeCache(RecoveryUI* ui, const std::function& confirm_func) { ui->SetBackground(RecoveryUI::ERASING); ui->SetProgressType(RecoveryUI::INDETERMINATE); - bool success = EraseVolume("/cache", ui); + bool success = EraseVolume("/cache", ui, new_fstype); ui->Print("Cache wipe %s.\n", success ? "complete" : "failed"); return success; } -bool WipeData(Device* device, bool keep_memtag_mode) { +bool WipeData(Device* device, bool keep_memtag_mode, std::string_view data_fstype) { RecoveryUI* ui = device->GetUI(); - ui->Print("\n-- Wiping data...\n"); + ui->Print("\n-- Wiping data %.*s...\n", static_cast(data_fstype.size()), data_fstype.data()); ui->SetBackground(RecoveryUI::ERASING); ui->SetProgressType(RecoveryUI::INDETERMINATE); @@ -92,13 +93,13 @@ bool WipeData(Device* device, bool keep_memtag_mode) { bool success = device->PreWipeData(); if (success) { - success &= EraseVolume(DATA_ROOT, ui); + success &= EraseVolume(DATA_ROOT, ui, data_fstype); bool has_cache = volume_for_mount_point("/cache") != nullptr; if (has_cache) { - success &= EraseVolume(CACHE_ROOT, ui); + success &= EraseVolume(CACHE_ROOT, ui, data_fstype); } if (volume_for_mount_point(METADATA_ROOT) != nullptr) { - success &= EraseVolume(METADATA_ROOT, ui); + success &= EraseVolume(METADATA_ROOT, ui, data_fstype); } } if (keep_memtag_mode) { diff --git a/recovery.cpp b/recovery.cpp index 1a6a7d6c..e7a33a9e 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -16,11 +16,8 @@ #include "recovery.h" -#include #include #include -#include -#include #include #include #include @@ -51,7 +48,6 @@ #include "install/snapshot_utils.h" #include "install/wipe_data.h" #include "install/wipe_device.h" -#include "otautil/boot_state.h" #include "otautil/error_code.h" #include "otautil/package.h" #include "otautil/paths.h" @@ -463,7 +459,7 @@ static Device::BuiltinAction PromptAndWait(Device* device, InstallResult status) WriteUpdateInProgress(); bool adb = true; - Device::BuiltinAction reboot_action; + Device::BuiltinAction reboot_action{}; if (chosen_action == Device::ENTER_RESCUE) { // Switch to graphics screen. ui->ShowText(false); @@ -610,6 +606,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vectorSetSystemUpdateText(security_update); - int st_cur, st_max; + int st_cur = 0, st_max = 0; if (!device->GetStage().has_value() && sscanf(device->GetStage().value().c_str(), "%d/%d", &st_cur, &st_max) == 2) { ui->SetStage(st_cur, st_max); @@ -731,7 +731,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vectorPrint("battery capacity is not enough for installing package: %d%% needed\n", required_battery_level); // Log the error code to last_install when installation skips due to low battery. @@ -797,7 +797,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vectorGetReason().has_value()); - if (!WipeData(device, should_keep_memtag_mode)) { + if (!WipeData(device, should_keep_memtag_mode, data_fstype)) { status = INSTALL_ERROR; } } else if (should_prompt_and_wipe_data) { @@ -812,7 +812,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector get_args(const int argc, char** const argv, std: // Skip empty and '\0'-filled tokens. if (!it->empty() && (*it)[0] != '\0') args.push_back(std::move(*it)); } - LOG(INFO) << "Got " << args.size() << " arguments from boot message"; + LOG(INFO) << "Got " << args.size() << " arguments from boot message " << android::base::Join(args, ", "); } else if (boot.recovery[0] != 0) { LOG(ERROR) << "Bad boot message: \"" << boot_recovery << "\""; } diff --git a/recovery_utils/include/recovery_utils/roots.h b/recovery_utils/include/recovery_utils/roots.h index 92ee756f..6afefb81 100644 --- a/recovery_utils/include/recovery_utils/roots.h +++ b/recovery_utils/include/recovery_utils/roots.h @@ -48,7 +48,8 @@ int format_volume(const std::string& volume); // "/cache"), no paths permitted. Attempts to unmount the volume if // it is mounted. // Copies 'directory' to root of the newly formatted volume -int format_volume(const std::string& volume, const std::string& directory); +int format_volume(const std::string& volume, const std::string& directory, + std::string_view new_fstype); // Ensure that all and only the volumes that packages expect to find // mounted (/tmp and /cache) are mounted. Returns 0 on success. diff --git a/recovery_utils/roots.cpp b/recovery_utils/roots.cpp index 5c95cba0..6396d446 100644 --- a/recovery_utils/roots.cpp +++ b/recovery_utils/roots.cpp @@ -130,7 +130,8 @@ static int64_t get_file_size(int fd, uint64_t reserve_len) { return computed_size; } -int format_volume(const std::string& volume, const std::string& directory) { +int format_volume(const std::string& volume, const std::string& directory, + std::string_view new_fstype) { const FstabEntry* v = android::fs_mgr::GetEntryForPath(&fstab, volume); if (v == nullptr) { LOG(ERROR) << "unknown volume \"" << volume << "\""; @@ -176,25 +177,11 @@ int format_volume(const std::string& volume, const std::string& directory) { } // If the raw disk will be used as a metadata encrypted device mapper target, - // next boot will do encrypt_in_place the raw disk which gives a subtle duration - // to get any failure in the process. In order to avoid it, let's simply wipe - // the raw disk if we don't reserve any space, which behaves exactly same as booting - // after "fastboot -w". - if (!v->metadata_key_dir.empty() && length == 0) { - android::base::unique_fd fd(open(v->blk_device.c_str(), O_RDWR)); - if (fd == -1) { - PLOG(ERROR) << "format_volume: failed to open " << v->blk_device; - return -1; - } - int64_t device_size = get_file_size(fd.get(), 0); - if (device_size > 0 && !wipe_block_device(fd.get(), device_size)) { - LOG(INFO) << "format_volume: wipe metadata encrypted " << v->blk_device << " with size " - << device_size; - return 0; - } - } + // next boot will first mount this partition as read only, and then unmount, + // call encrypt_inplace. - if (v->fs_type == "ext4") { + if ((v->fs_type == "ext4" && new_fstype.empty()) || new_fstype == "ext4") { + LOG(INFO) << "Formatting " << v->blk_device << " as ext4"; static constexpr int kBlockSize = 4096; std::vector mke2fs_args = { "/system/bin/mke2fs", "-F", "-t", "ext4", "-b", std::to_string(kBlockSize), @@ -246,6 +233,7 @@ int format_volume(const std::string& volume, const std::string& directory) { } // Has to be f2fs because we checked earlier. + LOG(INFO) << "Formatting " << v->blk_device << " as f2fs"; static constexpr int kSectorSize = 4096; std::vector make_f2fs_cmd = { "/system/bin/make_f2fs", @@ -290,7 +278,7 @@ int format_volume(const std::string& volume, const std::string& directory) { } int format_volume(const std::string& volume) { - return format_volume(volume, ""); + return format_volume(volume, "", ""); } int setup_install_mounts() {