diff options
Diffstat (limited to '')
42 files changed, 611 insertions, 295 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk index a7ab0d9be..6bd1eb170 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -51,6 +51,10 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/sbin) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libinstall.recovery_intermediates) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/system/lib64/libinstall.so) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/nativetest/recovery_component_test) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/nativetest64/recovery_component_test) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/testcases/recovery_component_test) + # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ @@ -22,11 +22,9 @@ Running the tests # 32-bit device adb shell /data/nativetest/recovery_unit_test/recovery_unit_test - adb shell /data/nativetest/recovery_component_test/recovery_component_test # Or 64-bit device adb shell /data/nativetest64/recovery_unit_test/recovery_unit_test - adb shell /data/nativetest64/recovery_component_test/recovery_component_test Running the manual tests ------------------------ diff --git a/TEST_MAPPING b/TEST_MAPPING index c87ece24e..a3045828e 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -7,9 +7,6 @@ "name": "recovery_unit_test" }, { - "name": "recovery_component_test" - }, - { "name": "recovery_host_test", "host": true } diff --git a/bootloader_message/Android.bp b/bootloader_message/Android.bp index 5cd21323c..4ea7c8680 100644 --- a/bootloader_message/Android.bp +++ b/bootloader_message/Android.bp @@ -17,6 +17,7 @@ cc_library { name: "libbootloader_message", recovery_available: true, + host_supported: true, srcs: ["bootloader_message.cpp"], cflags: [ "-Wall", @@ -24,7 +25,22 @@ cc_library { ], shared_libs: [ "libbase", - "libfs_mgr", ], export_include_dirs: ["include"], + + target: { + android: { + shared_libs: [ + "libfs_mgr", + ], + }, + host: { + shared_libs: [ + "libcutils", // for strlcpy + ], + static_libs: [ + "libfstab", + ], + } + } } diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp index 8c1d63bdd..331a42b2a 100644 --- a/bootloader_message/bootloader_message.cpp +++ b/bootloader_message/bootloader_message.cpp @@ -29,6 +29,10 @@ #include <android-base/unique_fd.h> #include <fstab/fstab.h> +#ifndef __ANDROID__ +#include <cutils/memory.h> // for strlcpy +#endif + using android::fs_mgr::Fstab; using android::fs_mgr::ReadDefaultFstab; @@ -168,6 +172,14 @@ bool write_bootloader_message(const std::vector<std::string>& options, std::stri return write_bootloader_message(boot, err); } +bool write_bootloader_message_to(const std::vector<std::string>& options, + const std::string& misc_blk_device, std::string* err) { + bootloader_message boot = {}; + update_bootloader_message_in_struct(&boot, options); + + return write_bootloader_message_to(boot, misc_blk_device, err); +} + bool update_bootloader_message(const std::vector<std::string>& options, std::string* err) { bootloader_message boot; if (!read_bootloader_message(&boot, err)) { @@ -186,13 +198,15 @@ bool update_bootloader_message_in_struct(bootloader_message* boot, memset(boot->recovery, 0, sizeof(boot->recovery)); strlcpy(boot->command, "boot-recovery", sizeof(boot->command)); - strlcpy(boot->recovery, "recovery\n", sizeof(boot->recovery)); + + std::string recovery = "recovery\n"; for (const auto& s : options) { - strlcat(boot->recovery, s.c_str(), sizeof(boot->recovery)); + recovery += s; if (s.back() != '\n') { - strlcat(boot->recovery, "\n", sizeof(boot->recovery)); + recovery += '\n'; } } + strlcpy(boot->recovery, recovery.c_str(), sizeof(boot->recovery)); return true; } diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h index 95c19ae54..2207d4cb3 100644 --- a/bootloader_message/include/bootloader_message/bootloader_message.h +++ b/bootloader_message/include/bootloader_message/bootloader_message.h @@ -207,6 +207,11 @@ bool write_bootloader_message_to(const bootloader_message& boot, // set the command and recovery fields, and reset the rest. bool write_bootloader_message(const std::vector<std::string>& options, std::string* err); +// Write bootloader message (boots into recovery with the options) to the specific BCB device. Will +// set the command and recovery fields, and reset the rest. +bool write_bootloader_message_to(const std::vector<std::string>& options, + const std::string& misc_blk_device, std::string* err); + // Update bootloader message (boots into recovery with the options) to BCB. Will // only update the command and recovery fields. bool update_bootloader_message(const std::vector<std::string>& options, std::string* err); diff --git a/fuse_sideload/Android.bp b/fuse_sideload/Android.bp index 8548548d2..9bf19eb85 100644 --- a/fuse_sideload/Android.bp +++ b/fuse_sideload/Android.bp @@ -34,6 +34,10 @@ cc_library { "include", ], + static_libs: [ + "libotautil", + ], + shared_libs: [ "libbase", "libcrypto", diff --git a/fuse_sideload/fuse_provider.cpp b/fuse_sideload/fuse_provider.cpp index 58786f5f3..5ee6e247f 100644 --- a/fuse_sideload/fuse_provider.cpp +++ b/fuse_sideload/fuse_provider.cpp @@ -27,8 +27,11 @@ #include <functional> #include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/strings.h> #include "fuse_sideload.h" +#include "otautil/sysutil.h" FuseFileDataProvider::FuseFileDataProvider(const std::string& path, uint32_t block_size) { struct stat sb; @@ -69,3 +72,79 @@ bool FuseFileDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_ void FuseFileDataProvider::Close() { fd_.reset(); } + +FuseBlockDataProvider::FuseBlockDataProvider(uint64_t file_size, uint32_t fuse_block_size, + android::base::unique_fd&& fd, + uint32_t source_block_size, RangeSet ranges) + : FuseDataProvider(file_size, fuse_block_size), + fd_(std::move(fd)), + source_block_size_(source_block_size), + ranges_(std::move(ranges)) { + // Make sure the offset is also aligned with the blocks on the block device when we call + // ReadBlockAlignedData(). + CHECK_EQ(0, fuse_block_size_ % source_block_size_); +} + +bool FuseBlockDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size, + uint32_t start_block) const { + uint64_t offset = static_cast<uint64_t>(start_block) * fuse_block_size_; + if (fetch_size > file_size_ || offset > file_size_ - fetch_size) { + LOG(ERROR) << "Out of bound read, offset: " << offset << ", fetch size: " << fetch_size + << ", file size " << file_size_; + return false; + } + + auto read_ranges = + ranges_.GetSubRanges(offset / source_block_size_, fetch_size / source_block_size_); + if (!read_ranges) { + return false; + } + + uint8_t* next_out = buffer; + for (const auto& [range_start, range_end] : read_ranges.value()) { + uint64_t bytes_start = static_cast<uint64_t>(range_start) * source_block_size_; + uint64_t bytes_to_read = static_cast<uint64_t>(range_end - range_start) * source_block_size_; + if (!android::base::ReadFullyAtOffset(fd_, next_out, bytes_to_read, bytes_start)) { + PLOG(ERROR) << "Failed to read " << bytes_to_read << " bytes at offset " << bytes_start; + return false; + } + + next_out += bytes_to_read; + } + + if (uint64_t tailing_bytes = fetch_size % source_block_size_; tailing_bytes != 0) { + // Calculate the offset to last partial block. + uint64_t tailing_offset = + read_ranges.value() + ? static_cast<uint64_t>((read_ranges->cend() - 1)->second) * source_block_size_ + : static_cast<uint64_t>(start_block) * source_block_size_; + if (!android::base::ReadFullyAtOffset(fd_, next_out, tailing_bytes, tailing_offset)) { + PLOG(ERROR) << "Failed to read tailing " << tailing_bytes << " bytes at offset " + << tailing_offset; + return false; + } + } + return true; +} + +std::unique_ptr<FuseBlockDataProvider> FuseBlockDataProvider::CreateFromBlockMap( + const std::string& block_map_path, uint32_t fuse_block_size) { + auto block_map = BlockMapData::ParseBlockMapFile(block_map_path); + if (!block_map) { + return nullptr; + } + + android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(block_map.path().c_str(), O_RDONLY))); + if (fd == -1) { + PLOG(ERROR) << "Failed to open " << block_map.path(); + return nullptr; + } + + return std::unique_ptr<FuseBlockDataProvider>( + new FuseBlockDataProvider(block_map.file_size(), fuse_block_size, std::move(fd), + block_map.block_size(), block_map.block_ranges())); +} + +void FuseBlockDataProvider::Close() { + fd_.reset(); +} diff --git a/fuse_sideload/include/fuse_provider.h b/fuse_sideload/include/fuse_provider.h index 59059cf9b..8d4ea4073 100644 --- a/fuse_sideload/include/fuse_provider.h +++ b/fuse_sideload/include/fuse_provider.h @@ -18,10 +18,13 @@ #include <stdint.h> +#include <memory> #include <string> #include <android-base/unique_fd.h> +#include "otautil/rangeset.h" + // This is the base class to read data from source and provide the data to FUSE. class FuseDataProvider { public: @@ -70,3 +73,28 @@ class FuseFileDataProvider : public FuseDataProvider { // The underlying source to read data from. android::base::unique_fd fd_; }; + +// This class parses a block map and reads data from the underlying block device. +class FuseBlockDataProvider : public FuseDataProvider { + public: + // Constructs the fuse provider from the block map. + static std::unique_ptr<FuseBlockDataProvider> CreateFromBlockMap( + const std::string& block_map_path, uint32_t fuse_block_size); + + RangeSet ranges() const { + return ranges_; + } + bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size, + uint32_t start_block) const override; + void Close() override; + + private: + FuseBlockDataProvider(uint64_t file_size, uint32_t fuse_block_size, android::base::unique_fd&& fd, + uint32_t source_block_size, RangeSet ranges); + // The underlying block device to read data from. + android::base::unique_fd fd_; + // The block size of the source block device. + uint32_t source_block_size_; + // The block ranges from the source block device that consist of the file + RangeSet ranges_; +}; diff --git a/install/adb_install.cpp b/install/adb_install.cpp index 4dd1f1b09..2de1075d2 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,7 @@ static auto AdbInstallPackageHandler(RecoveryUI* ui, int* result) { break; } } - *result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0, ui); + *result = InstallPackage(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0, ui); break; } @@ -120,7 +120,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 +331,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 +342,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, diff --git a/install/fuse_sdcard_install.cpp b/install/fuse_sdcard_install.cpp index 1aa8768e7..a5caa6e75 100644 --- a/install/fuse_sdcard_install.cpp +++ b/install/fuse_sdcard_install.cpp @@ -133,7 +133,7 @@ static bool StartSdcardFuse(const std::string& path) { return run_fuse_sideload(std::move(file_data_reader)) == 0; } -int ApplyFromSdcard(Device* device, RecoveryUI* ui) { +InstallResult ApplyFromSdcard(Device* device, RecoveryUI* ui) { if (ensure_path_mounted(SDCARD_ROOT) != 0) { LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n"; return INSTALL_ERROR; @@ -159,9 +159,8 @@ int ApplyFromSdcard(Device* device, RecoveryUI* ui) { _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) { @@ -184,7 +183,7 @@ int ApplyFromSdcard(Device* device, RecoveryUI* ui) { } } - result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0 /*retry_count*/, ui); + result = InstallPackage(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0 /* retry_count */, ui); break; } 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_sdcard_install.h b/install/include/install/fuse_sdcard_install.h index d9214ca3b..e5bb01f09 100644 --- a/install/include/install/fuse_sdcard_install.h +++ b/install/include/install/fuse_sdcard_install.h @@ -16,7 +16,8 @@ #pragma once +#include "install/install.h" #include "recovery_ui/device.h" #include "recovery_ui/ui.h" -int ApplyFromSdcard(Device* device, RecoveryUI* ui); +InstallResult ApplyFromSdcard(Device* device, RecoveryUI* ui); diff --git a/install/include/install/install.h b/install/include/install/install.h index d90c20f3a..44a5cde91 100644 --- a/install/include/install/install.h +++ b/install/include/install/install.h @@ -47,8 +47,8 @@ enum class OtaType { // 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); +InstallResult InstallPackage(const std::string& package, bool should_wipe_cache, bool needs_mount, + int retry_count, RecoveryUI* ui); // Verifies the package by ota keys. Returns true if the package is verified successfully, // otherwise returns false. @@ -62,7 +62,7 @@ bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map<std::string, std::st // 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/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..5d514fa23 100644 --- a/install/install.cpp +++ b/install/install.cpp @@ -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,11 +226,11 @@ 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 @@ -240,7 +240,7 @@ int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int ZipEntry properties_entry; if (FindEntry(zip, property_name, &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,7 +248,7 @@ 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"; @@ -256,7 +256,7 @@ int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int ZipEntry payload_entry; if (FindEntry(zip, payload_name, &payload_entry) != 0) { LOG(ERROR) << "Failed to find " << AB_OTA_PAYLOAD; - return INSTALL_CORRUPT; + return false; } long payload_offset = payload_entry.offset; *cmd = { @@ -266,11 +266,11 @@ 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. @@ -279,7 +279,7 @@ int SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, i ZipEntry binary_entry; if (FindEntry(zip, 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 +288,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 +310,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,9 +324,9 @@ 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(const std::string& package, ZipArchiveHandle zip, + bool* wipe_cache, std::vector<std::string>* log_buffer, + int retry_count, int* max_temperature, RecoveryUI* ui) { std::map<std::string, std::string> metadata; if (!ReadMetadataFromPackage(zip, &metadata)) { LOG(ERROR) << "Failed to parse metadata in the zip file"; @@ -335,11 +334,10 @@ static int try_update_binary(const std::string& package, ZipArchiveHandle zip, b } 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) { + // 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); @@ -386,12 +384,12 @@ static int try_update_binary(const std::string& package, ZipArchiveHandle zip, b // std::vector<std::string> args; - if (int update_status = + if (auto setup_result = is_ab ? SetUpAbUpdateCommands(package, zip, pipe_write.get(), &args) : SetUpNonAbUpdateCommands(package, zip, retry_count, pipe_write.get(), &args); - update_status != 0) { + !setup_result) { log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure)); - return update_status; + return INSTALL_CORRUPT; } pid_t pid = fork(); @@ -571,9 +569,10 @@ 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(const std::string& path, bool* wipe_cache, + bool needs_mount, 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... @@ -624,16 +623,16 @@ 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(path, zip, 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) { +InstallResult InstallPackage(const std::string& path, bool should_wipe_cache, bool needs_mount, + int retry_count, RecoveryUI* ui) { CHECK(!path.empty()); auto start = std::chrono::system_clock::now(); @@ -641,15 +640,15 @@ int install_package(const std::string& path, bool should_wipe_cache, bool needs_ int start_temperature = GetMaxValueFromThermalZone(); int max_temperature = start_temperature; - int result; + InstallResult result; std::vector<std::string> log_buffer; 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(path, &updater_wipe_cache, needs_mount, &log_buffer, + retry_count, &max_temperature, ui); should_wipe_cache = should_wipe_cache || updater_wipe_cache; } diff --git a/install/wipe_device.cpp b/install/wipe_device.cpp index 72b96f7b4..5a9b512c1 100644 --- a/install/wipe_device.cpp +++ b/install/wipe_device.cpp @@ -165,7 +165,7 @@ static bool CheckWipePackage(Package* wipe_package, RecoveryUI* ui) { return false; } - return CheckPackageMetadata(metadata, OtaType::BRICK) == 0; + return CheckPackageMetadata(metadata, OtaType::BRICK); } bool WipeAbDevice(Device* device, size_t wipe_package_size) { diff --git a/minadbd/Android.bp b/minadbd/Android.bp index 007e5057b..afd57ad2d 100644 --- a/minadbd/Android.bp +++ b/minadbd/Android.bp @@ -43,6 +43,10 @@ cc_library { "minadbd_services.cpp", ], + static_libs: [ + "libotautil", + ], + shared_libs: [ "libadbd", "libbase", @@ -96,6 +100,7 @@ cc_test { static_libs: [ "libminadbd_services", "libfusesideload", + "libotautil", "libadbd", "libcrypto", ], diff --git a/otautil/include/otautil/rangeset.h b/otautil/include/otautil/rangeset.h index e91d02ca6..a18c30e29 100644 --- a/otautil/include/otautil/rangeset.h +++ b/otautil/include/otautil/rangeset.h @@ -18,6 +18,7 @@ #include <stddef.h> +#include <optional> #include <string> #include <utility> #include <vector> @@ -49,6 +50,12 @@ class RangeSet { // bounds. For example, "3,5" contains blocks 3 and 4. So "3,5" and "5,7" are not overlapped. bool Overlaps(const RangeSet& other) const; + // Returns a subset of ranges starting from |start_index| with respect to the original range. The + // output range will have |num_of_blocks| blocks in size. Returns std::nullopt if the input is + // invalid. e.g. RangeSet({{0, 5}, {10, 15}}).GetSubRanges(1, 5) returns + // RangeSet({{1, 5}, {10, 11}}). + std::optional<RangeSet> GetSubRanges(size_t start_index, size_t num_of_blocks) const; + // Returns a vector of RangeSets that contain the same set of blocks represented by the current // RangeSet. The RangeSets in the vector contain similar number of blocks, with a maximum delta // of 1-block between any two of them. For example, 14 blocks would be split into 4 + 4 + 3 + 3, diff --git a/otautil/include/otautil/sysutil.h b/otautil/include/otautil/sysutil.h index 692a99e9d..48e9011e5 100644 --- a/otautil/include/otautil/sysutil.h +++ b/otautil/include/otautil/sysutil.h @@ -14,12 +14,12 @@ * limitations under the License. */ -#ifndef _OTAUTIL_SYSUTIL -#define _OTAUTIL_SYSUTIL +#pragma once #include <sys/types.h> #include <string> +#include <string_view> #include <vector> #include "rangeset.h" @@ -101,13 +101,14 @@ class MemMapping { std::vector<MappedRange> ranges_; }; -// Wrapper function to trigger a reboot, by additionally handling quiescent reboot mode. The -// command should start with "reboot," (e.g. "reboot,bootloader" or "reboot,"). -bool reboot(const std::string& command); +// Reboots the device into the specified target, by additionally handling quiescent reboot mode. +// 'target' can be an empty string, which indicates booting into Android. +bool Reboot(std::string_view target); + +// Triggers a shutdown. +bool Shutdown(); // Returns a null-terminated char* array, where the elements point to the C-strings in the given // vector, plus an additional nullptr at the end. This is a helper function that facilitates // calling C functions (such as getopt(3)) that expect an array of C-strings. std::vector<char*> StringVectorToNullTerminatedArray(const std::vector<std::string>& args); - -#endif // _OTAUTIL_SYSUTIL diff --git a/otautil/rangeset.cpp b/otautil/rangeset.cpp index 5ab8e08fe..8ee99dd7a 100644 --- a/otautil/rangeset.cpp +++ b/otautil/rangeset.cpp @@ -184,6 +184,58 @@ bool RangeSet::Overlaps(const RangeSet& other) const { return false; } +std::optional<RangeSet> RangeSet::GetSubRanges(size_t start_index, size_t num_of_blocks) const { + size_t end_index = start_index + num_of_blocks; // The index of final block to read plus one + if (start_index > end_index || end_index > blocks_) { + LOG(ERROR) << "Failed to get the sub ranges for start_index " << start_index + << " num_of_blocks " << num_of_blocks + << " total number of blocks the range contains is " << blocks_; + return std::nullopt; + } + + if (num_of_blocks == 0) { + LOG(WARNING) << "num_of_blocks is zero when calling GetSubRanges()"; + return RangeSet(); + } + + RangeSet result; + size_t current_index = 0; + for (const auto& [range_start, range_end] : ranges_) { + CHECK_LT(range_start, range_end); + size_t blocks_in_range = range_end - range_start; + // Linear search to skip the ranges until we reach start_block. + if (current_index + blocks_in_range <= start_index) { + current_index += blocks_in_range; + continue; + } + + size_t trimmed_range_start = range_start; + // We have found the first block range to read, trim the heading blocks. + if (current_index < start_index) { + trimmed_range_start += start_index - current_index; + } + // Trim the trailing blocks if the last range has more blocks than desired; also return the + // result. + if (current_index + blocks_in_range >= end_index) { + size_t trimmed_range_end = range_end - (current_index + blocks_in_range - end_index); + if (!result.PushBack({ trimmed_range_start, trimmed_range_end })) { + return std::nullopt; + } + + return result; + } + + if (!result.PushBack({ trimmed_range_start, range_end })) { + return std::nullopt; + } + current_index += blocks_in_range; + } + + LOG(ERROR) << "Failed to construct byte ranges to read, start_block: " << start_index + << ", num_of_blocks: " << num_of_blocks << " total number of blocks: " << blocks_; + return std::nullopt; +} + // Ranges in the the set should be mutually exclusive; and they're sorted by the start block. SortedRangeSet::SortedRangeSet(std::vector<Range>&& pairs) : RangeSet(std::move(pairs)) { std::sort(ranges_.begin(), ranges_.end()); diff --git a/otautil/sysutil.cpp b/otautil/sysutil.cpp index 8366fa0ac..420db4cac 100644 --- a/otautil/sysutil.cpp +++ b/otautil/sysutil.cpp @@ -94,6 +94,11 @@ BlockMapData BlockMapData::ParseBlockMapFile(const std::string& block_map_path) remaining_blocks -= range_blocks; } + if (remaining_blocks != 0) { + LOG(ERROR) << "Invalid ranges: remaining blocks " << remaining_blocks; + return {}; + } + return BlockMapData(block_dev, file_size, blksize, std::move(ranges)); } @@ -214,14 +219,21 @@ MemMapping::~MemMapping() { ranges_.clear(); } -bool reboot(const std::string& command) { - std::string cmd = command; - if (android::base::GetBoolProperty("ro.boot.quiescent", false)) { +bool Reboot(std::string_view target) { + std::string cmd = "reboot," + std::string(target); + // Honor the quiescent mode if applicable. + if (target != "bootloader" && target != "fastboot" && + android::base::GetBoolProperty("ro.boot.quiescent", false)) { cmd += ",quiescent"; } return android::base::SetProperty(ANDROID_RB_PROPERTY, cmd); } +bool Shutdown() { + // "shutdown" doesn't need a "reason" arg nor a comma. + return android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown"); +} + std::vector<char*> StringVectorToNullTerminatedArray(const std::vector<std::string>& args) { std::vector<char*> result(args.size()); std::transform(args.cbegin(), args.cend(), result.begin(), diff --git a/recovery.cpp b/recovery.cpp index 3cb6d6de5..dbac3e01a 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -113,12 +113,12 @@ const char* reason = nullptr; * 3. main system reboots into recovery * 4. get_args() writes BCB with "boot-recovery" and "--update_package=..." * -- after this, rebooting will attempt to reinstall the update -- - * 5. install_package() attempts to install the update + * 5. InstallPackage() attempts to install the update * NOTE: the package install must itself be restartable from any point * 6. finish_recovery() erases BCB * -- after this, rebooting will (try to) restart the main system -- * 7. ** if install failed ** - * 7a. prompt_and_wait() shows an error icon and waits for the user + * 7a. PromptAndWait() shows an error icon and waits for the user * 7b. the user reboots (pulling the battery, etc) into the main system */ @@ -312,14 +312,18 @@ static void run_graphics_test() { ui->ShowText(true); } -// Returns REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER. Returning NO_ACTION means to take the default, -// which is to reboot or shutdown depending on if the --shutdown_after flag was passed to recovery. -static Device::BuiltinAction prompt_and_wait(Device* device, int status) { +// Shows the recovery UI and waits for user input. Returns one of the device builtin actions, such +// as REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER. Returning NO_ACTION means to take the default, which +// is to reboot or shutdown depending on if the --shutdown_after flag was passed to recovery. +static Device::BuiltinAction PromptAndWait(Device* device, InstallResult status) { for (;;) { finish_recovery(); switch (status) { case INSTALL_SUCCESS: case INSTALL_NONE: + case INSTALL_SKIPPED: + case INSTALL_RETRY: + case INSTALL_KEY_INTERRUPTED: ui->SetBackground(RecoveryUI::NO_COMMAND); break; @@ -327,6 +331,12 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) { case INSTALL_CORRUPT: ui->SetBackground(RecoveryUI::ERROR); break; + + case INSTALL_REBOOT: + // All the reboots should have been handled prior to entering PromptAndWait() or immediately + // after installing a package. + LOG(FATAL) << "Invalid status code of INSTALL_REBOOT"; + break; } ui->SetProgressType(RecoveryUI::EMPTY); @@ -690,7 +700,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri ui->Print("Supported API: %d\n", kRecoveryApiVersion); - int status = INSTALL_SUCCESS; + InstallResult status = INSTALL_SUCCESS; // next_action indicates the next target to reboot into upon finishing the install. It could be // overridden to a different reboot target per user request. Device::BuiltinAction next_action = shutdown_after ? Device::SHUTDOWN : Device::REBOOT; @@ -720,7 +730,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri set_retry_bootloader_message(retry_count + 1, args); } - status = install_package(update_package, should_wipe_cache, true, retry_count, ui); + status = InstallPackage(update_package, should_wipe_cache, true, retry_count, ui); if (status != INSTALL_SUCCESS) { ui->Print("Installation aborted.\n"); @@ -734,8 +744,8 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri // Print retry count on screen. ui->Print("Retry attempt %d\n", retry_count); - // Reboot and retry the update - if (!reboot("reboot,recovery")) { + // Reboot back into recovery to retry the update. + if (!Reboot("recovery")) { ui->Print("Reboot failed\n"); } else { while (true) { @@ -828,7 +838,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri // for 5s followed by an automatic reboot. if (status != INSTALL_REBOOT) { if (status == INSTALL_NONE || ui->IsTextVisible()) { - Device::BuiltinAction temp = prompt_and_wait(device, status); + auto temp = PromptAndWait(device, status); if (temp != Device::NO_ACTION) { next_action = temp; } diff --git a/recovery_main.cpp b/recovery_main.cpp index 6e69b7009..b999505fb 100644 --- a/recovery_main.cpp +++ b/recovery_main.cpp @@ -41,7 +41,6 @@ #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <bootloader_message/bootloader_message.h> -#include <cutils/android_reboot.h> #include <cutils/sockets.h> #include <private/android_logger.h> /* private pmsg functions */ #include <selinux/android.h> @@ -471,27 +470,26 @@ int main(int argc, char** argv) { switch (ret) { case Device::SHUTDOWN: ui->Print("Shutting down...\n"); - // TODO: Move all the reboots to reboot(), which should conditionally set quiescent flag. - android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,"); + Shutdown(); break; case Device::REBOOT_BOOTLOADER: ui->Print("Rebooting to bootloader...\n"); - android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader"); + Reboot("bootloader"); break; case Device::REBOOT_FASTBOOT: ui->Print("Rebooting to recovery/fastboot...\n"); - android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,fastboot"); + Reboot("fastboot"); break; case Device::REBOOT_RECOVERY: ui->Print("Rebooting to recovery...\n"); - reboot("reboot,recovery"); + Reboot("recovery"); break; case Device::REBOOT_RESCUE: { - // Not using `reboot("reboot,rescue")`, as it requires matching support in kernel and/or + // Not using `Reboot("rescue")`, as it requires matching support in kernel and/or // bootloader. bootloader_message boot = {}; strlcpy(boot.command, "boot-rescue", sizeof(boot.command)); @@ -502,14 +500,14 @@ int main(int argc, char** argv) { continue; } ui->Print("Rebooting to recovery/rescue...\n"); - reboot("reboot,recovery"); + Reboot("recovery"); break; } case Device::ENTER_FASTBOOT: if (logical_partitions_mapped()) { ui->Print("Partitions may be mounted - rebooting to enter fastboot."); - android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,fastboot"); + Reboot("fastboot"); } else { LOG(INFO) << "Entering fastboot"; fastboot = true; @@ -523,7 +521,7 @@ int main(int argc, char** argv) { default: ui->Print("Rebooting...\n"); - reboot("reboot,"); + Reboot(""); break; } } diff --git a/recovery_ui/ui.cpp b/recovery_ui/ui.cpp index b7107ff21..7ea9307c9 100644 --- a/recovery_ui/ui.cpp +++ b/recovery_ui/ui.cpp @@ -375,7 +375,7 @@ void RecoveryUI::ProcessKey(int key_code, int updown) { case RecoveryUI::REBOOT: if (reboot_enabled) { - reboot("reboot,"); + Reboot(""); while (true) { pause(); } diff --git a/tests/Android.bp b/tests/Android.bp index 2e5334d9e..67a65ae9e 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -79,6 +79,8 @@ librecovery_static_libs = [ "libinstall", "librecovery_ui", "libminui", + "libfusesideload", + "libbootloader_message", "libotautil", "libhealthhalutils", @@ -87,10 +89,8 @@ librecovery_static_libs = [ "android.hardware.health@2.0", "android.hardware.health@1.0", - "libbootloader_message", "libext4_utils", "libfs_mgr", - "libfusesideload", "libhidl-gen-utils", "libhidlbase", "libhidltransport", @@ -107,6 +107,7 @@ cc_test { defaults: [ "recovery_test_defaults", + "libupdater_defaults", ], test_suites: ["device-tests"], @@ -115,16 +116,22 @@ cc_test { "unit/*.cpp", ], - static_libs: libapplypatch_static_libs + [ - "libinstall", + static_libs: libapplypatch_static_libs + librecovery_static_libs + [ "librecovery_ui", + "libfusesideload", "libminui", "libotautil", "libupdater", + "libupdate_verifier", + "libgtest_prod", + "libprotobuf-cpp-lite", ], - data: ["testdata/*"], + data: [ + "testdata/*", + ":res-testdata", + ], } cc_test { @@ -142,33 +149,6 @@ cc_test { ], } -cc_test { - name: "recovery_component_test", - isolated: true, - - defaults: [ - "recovery_test_defaults", - "libupdater_defaults", - ], - - test_suites: ["device-tests"], - - srcs: [ - "component/*.cpp", - ], - - static_libs: libapplypatch_static_libs + librecovery_static_libs + [ - "libupdater", - "libupdate_verifier", - "libprotobuf-cpp-lite", - ], - - data: [ - "testdata/*", - ":res-testdata", - ], -} - cc_test_host { name: "recovery_host_test", isolated: true, @@ -178,7 +158,7 @@ cc_test_host { ], srcs: [ - "component/imgdiff_test.cpp", + "unit/imgdiff_test.cpp", ], static_libs: [ diff --git a/tests/component/resources_test.cpp b/tests/component/resources_test.cpp deleted file mode 100644 index d7fdb8fa0..000000000 --- a/tests/component/resources_test.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2018 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 <dirent.h> -#include <stdio.h> -#include <stdlib.h> - -#include <memory> -#include <string> -#include <vector> - -#include <android-base/file.h> -#include <android-base/strings.h> -#include <gtest/gtest.h> -#include <png.h> - -#include "minui/minui.h" -#include "private/resources.h" - -static const std::string kLocale = "zu"; - -static const std::vector<std::string> kResourceImagesDirs{ - "res-mdpi/images/", "res-hdpi/images/", "res-xhdpi/images/", - "res-xxhdpi/images/", "res-xxxhdpi/images/", -}; - -static int png_filter(const dirent* de) { - if (de->d_type != DT_REG || !android::base::EndsWith(de->d_name, "_text.png")) { - return 0; - } - return 1; -} - -// Finds out all the PNG files to test, which stay under the same dir with the executabl.. -static std::vector<std::string> add_files() { - std::vector<std::string> files; - for (const std::string& images_dir : kResourceImagesDirs) { - static std::string exec_dir = android::base::GetExecutableDirectory(); - std::string dir_path = exec_dir + "/" + images_dir; - dirent** namelist; - int n = scandir(dir_path.c_str(), &namelist, png_filter, alphasort); - if (n == -1) { - printf("Failed to scandir %s: %s\n", dir_path.c_str(), strerror(errno)); - continue; - } - if (n == 0) { - printf("No file is added for test in %s\n", dir_path.c_str()); - } - - while (n--) { - std::string file_path = dir_path + namelist[n]->d_name; - files.push_back(file_path); - free(namelist[n]); - } - free(namelist); - } - return files; -} - -class ResourcesTest : public testing::TestWithParam<std::string> { - public: - static std::vector<std::string> png_list; - - protected: - void SetUp() override { - png_ = std::make_unique<PngHandler>(GetParam()); - ASSERT_TRUE(png_); - - ASSERT_EQ(PNG_COLOR_TYPE_GRAY, png_->color_type()) << "Recovery expects grayscale PNG file."; - ASSERT_LT(static_cast<png_uint_32>(5), png_->width()); - ASSERT_LT(static_cast<png_uint_32>(0), png_->height()); - ASSERT_EQ(1, png_->channels()) << "Recovery background text images expects 1-channel PNG file."; - } - - std::unique_ptr<PngHandler> png_{ nullptr }; -}; - -// Parses a png file and tests if it's qualified for the background text image under recovery. -TEST_P(ResourcesTest, ValidateLocale) { - std::vector<unsigned char> row(png_->width()); - for (png_uint_32 y = 0; y < png_->height(); ++y) { - png_read_row(png_->png_ptr(), row.data(), nullptr); - int w = (row[1] << 8) | row[0]; - int h = (row[3] << 8) | row[2]; - int len = row[4]; - EXPECT_LT(0, w); - EXPECT_LT(0, h); - EXPECT_LT(0, len) << "Locale string should be non-empty."; - EXPECT_NE(0, row[5]) << "Locale string is missing."; - - ASSERT_GE(png_->height(), y + 1 + h) << "Locale: " << kLocale << " is not found in the file."; - char* loc = reinterpret_cast<char*>(&row[5]); - if (matches_locale(loc, kLocale.c_str())) { - EXPECT_TRUE(android::base::StartsWith(loc, kLocale)); - break; - } - for (int i = 0; i < h; ++i, ++y) { - png_read_row(png_->png_ptr(), row.data(), nullptr); - } - } -} - -std::vector<std::string> ResourcesTest::png_list = add_files(); - -INSTANTIATE_TEST_CASE_P(BackgroundTextValidation, ResourcesTest, - ::testing::ValuesIn(ResourcesTest::png_list.cbegin(), - ResourcesTest::png_list.cend())); diff --git a/tests/component/applypatch_modes_test.cpp b/tests/unit/applypatch_modes_test.cpp index 08414b796..08414b796 100644 --- a/tests/component/applypatch_modes_test.cpp +++ b/tests/unit/applypatch_modes_test.cpp diff --git a/tests/component/bootloader_message_test.cpp b/tests/unit/bootloader_message_test.cpp index b005d199c..b005d199c 100644 --- a/tests/component/bootloader_message_test.cpp +++ b/tests/unit/bootloader_message_test.cpp diff --git a/tests/component/edify_test.cpp b/tests/unit/edify_test.cpp index 8397bd38e..8397bd38e 100644 --- a/tests/component/edify_test.cpp +++ b/tests/unit/edify_test.cpp diff --git a/tests/unit/fuse_provider_test.cpp b/tests/unit/fuse_provider_test.cpp new file mode 100644 index 000000000..c5995dd7d --- /dev/null +++ b/tests/unit/fuse_provider_test.cpp @@ -0,0 +1,103 @@ +/* + * 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 <stdint.h> +#include <unistd.h> + +#include <functional> +#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 <gtest/gtest.h> + +#include "fuse_provider.h" +#include "fuse_sideload.h" +#include "install/install.h" + +TEST(FuseBlockMapTest, CreateFromBlockMap_smoke) { + TemporaryFile fake_block_device; + std::vector<std::string> lines = { + fake_block_device.path, "10000 4096", "3", "10 11", "20 21", "22 23", + }; + + TemporaryFile temp_file; + android::base::WriteStringToFile(android::base::Join(lines, '\n'), temp_file.path); + auto block_map_data = FuseBlockDataProvider::CreateFromBlockMap(temp_file.path, 4096); + + ASSERT_TRUE(block_map_data); + ASSERT_EQ(10000, block_map_data->file_size()); + ASSERT_EQ(4096, block_map_data->fuse_block_size()); + ASSERT_EQ(RangeSet({ { 10, 11 }, { 20, 21 }, { 22, 23 } }), block_map_data->ranges()); +} + +TEST(FuseBlockMapTest, ReadBlockAlignedData_smoke) { + std::string content; + content.reserve(40960); + for (char c = 0; c < 10; c++) { + content += std::string(4096, c); + } + TemporaryFile fake_block_device; + ASSERT_TRUE(android::base::WriteStringToFile(content, fake_block_device.path)); + + std::vector<std::string> lines = { + fake_block_device.path, + "20000 4096", + "1", + "0 5", + }; + TemporaryFile temp_file; + android::base::WriteStringToFile(android::base::Join(lines, '\n'), temp_file.path); + auto block_map_data = FuseBlockDataProvider::CreateFromBlockMap(temp_file.path, 4096); + + std::vector<uint8_t> result(2000); + ASSERT_TRUE(block_map_data->ReadBlockAlignedData(result.data(), 2000, 1)); + ASSERT_EQ(std::vector<uint8_t>(content.begin() + 4096, content.begin() + 6096), result); + + result.resize(20000); + ASSERT_TRUE(block_map_data->ReadBlockAlignedData(result.data(), 20000, 0)); + ASSERT_EQ(std::vector<uint8_t>(content.begin(), content.begin() + 20000), result); +} + +TEST(FuseBlockMapTest, ReadBlockAlignedData_large_fuse_block) { + std::string content; + for (char c = 0; c < 10; c++) { + content += std::string(4096, c); + } + + TemporaryFile temp_file; + ASSERT_TRUE(android::base::WriteStringToFile(content, temp_file.path)); + + std::vector<std::string> lines = { + temp_file.path, "36384 4096", "2", "0 5", "6 10", + }; + TemporaryFile block_map; + ASSERT_TRUE(android::base::WriteStringToFile(android::base::Join(lines, '\n'), block_map.path)); + + auto block_map_data = FuseBlockDataProvider::CreateFromBlockMap(block_map.path, 16384); + ASSERT_TRUE(block_map_data); + + std::vector<uint8_t> result(20000); + // Out of bound read + ASSERT_FALSE(block_map_data->ReadBlockAlignedData(result.data(), 20000, 2)); + ASSERT_TRUE(block_map_data->ReadBlockAlignedData(result.data(), 20000, 1)); + // expected source block contains: 4, 6-9 + std::string expected = content.substr(16384, 4096) + content.substr(24576, 15904); + ASSERT_EQ(std::vector<uint8_t>(expected.begin(), expected.end()), result); +} diff --git a/tests/component/sideload_test.cpp b/tests/unit/fuse_sideload_test.cpp index 6add99f41..6add99f41 100644 --- a/tests/component/sideload_test.cpp +++ b/tests/unit/fuse_sideload_test.cpp diff --git a/tests/component/imgdiff_test.cpp b/tests/unit/imgdiff_test.cpp index e76ccbdfb..e76ccbdfb 100644 --- a/tests/component/imgdiff_test.cpp +++ b/tests/unit/imgdiff_test.cpp diff --git a/tests/component/install_test.cpp b/tests/unit/install_test.cpp index 36820f837..c1d77fb7b 100644 --- a/tests/component/install_test.cpp +++ b/tests/unit/install_test.cpp @@ -205,7 +205,7 @@ TEST(InstallTest, SetUpNonAbUpdateCommands) { std::string binary_path = std::string(td.path) + "/update_binary"; Paths::Get().set_temporary_update_binary(binary_path); std::vector<std::string> cmd; - ASSERT_EQ(0, SetUpNonAbUpdateCommands(package, zip, 0, status_fd, &cmd)); + ASSERT_TRUE(SetUpNonAbUpdateCommands(package, zip, 0, status_fd, &cmd)); ASSERT_EQ(4U, cmd.size()); ASSERT_EQ(binary_path, cmd[0]); ASSERT_EQ("3", cmd[1]); // RECOVERY_API_VERSION @@ -217,7 +217,7 @@ TEST(InstallTest, SetUpNonAbUpdateCommands) { // With non-zero retry count. update_binary will be removed automatically. cmd.clear(); - ASSERT_EQ(0, SetUpNonAbUpdateCommands(package, zip, 2, status_fd, &cmd)); + ASSERT_TRUE(SetUpNonAbUpdateCommands(package, zip, 2, status_fd, &cmd)); ASSERT_EQ(5U, cmd.size()); ASSERT_EQ(binary_path, cmd[0]); ASSERT_EQ("3", cmd[1]); // RECOVERY_API_VERSION @@ -244,7 +244,7 @@ TEST(InstallTest, SetUpNonAbUpdateCommands_MissingUpdateBinary) { TemporaryDir td; Paths::Get().set_temporary_update_binary(std::string(td.path) + "/update_binary"); std::vector<std::string> cmd; - ASSERT_EQ(INSTALL_CORRUPT, SetUpNonAbUpdateCommands(package, zip, 0, status_fd, &cmd)); + ASSERT_FALSE(SetUpNonAbUpdateCommands(package, zip, 0, status_fd, &cmd)); CloseArchive(zip); } @@ -278,12 +278,12 @@ static void VerifyAbUpdateCommands(const std::string& serialno, bool success = t std::map<std::string, std::string> metadata; ASSERT_TRUE(ReadMetadataFromPackage(zip, &metadata)); if (success) { - ASSERT_EQ(0, CheckPackageMetadata(metadata, OtaType::AB)); + ASSERT_TRUE(CheckPackageMetadata(metadata, OtaType::AB)); int status_fd = 10; std::string package = "/path/to/update.zip"; std::vector<std::string> cmd; - ASSERT_EQ(0, SetUpAbUpdateCommands(package, zip, status_fd, &cmd)); + ASSERT_TRUE(SetUpAbUpdateCommands(package, zip, status_fd, &cmd)); ASSERT_EQ(5U, cmd.size()); ASSERT_EQ("/system/bin/update_engine_sideload", cmd[0]); ASSERT_EQ("--payload=file://" + package, cmd[1]); @@ -291,7 +291,7 @@ static void VerifyAbUpdateCommands(const std::string& serialno, bool success = t ASSERT_EQ("--headers=" + properties, cmd[3]); ASSERT_EQ("--status_fd=" + std::to_string(status_fd), cmd[4]); } else { - ASSERT_EQ(INSTALL_ERROR, CheckPackageMetadata(metadata, OtaType::AB)); + ASSERT_FALSE(CheckPackageMetadata(metadata, OtaType::AB)); } CloseArchive(zip); } @@ -326,7 +326,7 @@ TEST(InstallTest, SetUpAbUpdateCommands_MissingPayloadPropertiesTxt) { int status_fd = 10; std::string package = "/path/to/update.zip"; std::vector<std::string> cmd; - ASSERT_EQ(INSTALL_CORRUPT, SetUpAbUpdateCommands(package, zip, status_fd, &cmd)); + ASSERT_FALSE(SetUpAbUpdateCommands(package, zip, status_fd, &cmd)); CloseArchive(zip); } @@ -359,8 +359,8 @@ TEST(InstallTest, SetUpAbUpdateCommands_MultipleSerialnos) { VerifyAbUpdateCommands(long_serialno); } -static void test_check_package_metadata(const std::string& metadata_string, OtaType ota_type, - int exptected_result) { +static void TestCheckPackageMetadata(const std::string& metadata_string, OtaType ota_type, + bool exptected_result) { TemporaryFile temp_file; BuildZipArchive( { @@ -388,7 +388,7 @@ TEST(InstallTest, CheckPackageMetadata_ota_type) { "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()), }, "\n"); - test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR); + TestCheckPackageMetadata(metadata, OtaType::AB, false); // Checks if ota-type matches metadata = android::base::Join( @@ -398,9 +398,9 @@ TEST(InstallTest, CheckPackageMetadata_ota_type) { "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()), }, "\n"); - test_check_package_metadata(metadata, OtaType::AB, 0); + TestCheckPackageMetadata(metadata, OtaType::AB, true); - test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR); + TestCheckPackageMetadata(metadata, OtaType::BRICK, false); } TEST(InstallTest, CheckPackageMetadata_device_type) { @@ -410,7 +410,7 @@ TEST(InstallTest, CheckPackageMetadata_device_type) { "ota-type=BRICK", }, "\n"); - test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR); + TestCheckPackageMetadata(metadata, OtaType::BRICK, false); // device type mismatches metadata = android::base::Join( @@ -419,7 +419,7 @@ TEST(InstallTest, CheckPackageMetadata_device_type) { "pre-device=dummy_device_type", }, "\n"); - test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR); + TestCheckPackageMetadata(metadata, OtaType::BRICK, false); } TEST(InstallTest, CheckPackageMetadata_serial_number_smoke) { @@ -433,7 +433,7 @@ TEST(InstallTest, CheckPackageMetadata_serial_number_smoke) { "pre-device=" + device, }, "\n"); - test_check_package_metadata(metadata, OtaType::BRICK, 0); + TestCheckPackageMetadata(metadata, OtaType::BRICK, true); // Serial number mismatches metadata = android::base::Join( @@ -443,7 +443,7 @@ TEST(InstallTest, CheckPackageMetadata_serial_number_smoke) { "serialno=dummy_serial", }, "\n"); - test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR); + TestCheckPackageMetadata(metadata, OtaType::BRICK, false); std::string serialno = android::base::GetProperty("ro.serialno", ""); ASSERT_NE("", serialno); @@ -454,7 +454,7 @@ TEST(InstallTest, CheckPackageMetadata_serial_number_smoke) { "serialno=" + serialno, }, "\n"); - test_check_package_metadata(metadata, OtaType::BRICK, 0); + TestCheckPackageMetadata(metadata, OtaType::BRICK, true); } TEST(InstallTest, CheckPackageMetadata_multiple_serial_number) { @@ -478,7 +478,7 @@ TEST(InstallTest, CheckPackageMetadata_multiple_serial_number) { "serialno=" + android::base::Join(serial_numbers, '|'), }, "\n"); - test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR); + TestCheckPackageMetadata(metadata, OtaType::BRICK, false); serial_numbers.emplace_back(serialno); std::shuffle(serial_numbers.begin(), serial_numbers.end(), std::default_random_engine()); @@ -489,7 +489,7 @@ TEST(InstallTest, CheckPackageMetadata_multiple_serial_number) { "serialno=" + android::base::Join(serial_numbers, '|'), }, "\n"); - test_check_package_metadata(metadata, OtaType::BRICK, 0); + TestCheckPackageMetadata(metadata, OtaType::BRICK, true); } TEST(InstallTest, CheckPackageMetadata_ab_build_version) { @@ -507,7 +507,7 @@ TEST(InstallTest, CheckPackageMetadata_ab_build_version) { "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()), }, "\n"); - test_check_package_metadata(metadata, OtaType::AB, 0); + TestCheckPackageMetadata(metadata, OtaType::AB, true); metadata = android::base::Join( std::vector<std::string>{ @@ -517,7 +517,7 @@ TEST(InstallTest, CheckPackageMetadata_ab_build_version) { "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()), }, "\n"); - test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR); + TestCheckPackageMetadata(metadata, OtaType::AB, false); } TEST(InstallTest, CheckPackageMetadata_ab_fingerprint) { @@ -535,7 +535,7 @@ TEST(InstallTest, CheckPackageMetadata_ab_fingerprint) { "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()), }, "\n"); - test_check_package_metadata(metadata, OtaType::AB, 0); + TestCheckPackageMetadata(metadata, OtaType::AB, true); metadata = android::base::Join( std::vector<std::string>{ @@ -545,7 +545,7 @@ TEST(InstallTest, CheckPackageMetadata_ab_fingerprint) { "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()), }, "\n"); - test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR); + TestCheckPackageMetadata(metadata, OtaType::AB, false); } TEST(InstallTest, CheckPackageMetadata_ab_post_timestamp) { @@ -559,7 +559,7 @@ TEST(InstallTest, CheckPackageMetadata_ab_post_timestamp) { "pre-device=" + device, }, "\n"); - test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR); + TestCheckPackageMetadata(metadata, OtaType::AB, false); // post timestamp should be larger than the timestamp on device. metadata = android::base::Join( @@ -569,7 +569,7 @@ TEST(InstallTest, CheckPackageMetadata_ab_post_timestamp) { "post-timestamp=0", }, "\n"); - test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR); + TestCheckPackageMetadata(metadata, OtaType::AB, false); // fingerprint is required for downgrade metadata = android::base::Join( @@ -580,7 +580,7 @@ TEST(InstallTest, CheckPackageMetadata_ab_post_timestamp) { "ota-downgrade=yes", }, "\n"); - test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR); + TestCheckPackageMetadata(metadata, OtaType::AB, false); std::string finger_print = android::base::GetProperty("ro.build.fingerprint", ""); ASSERT_NE("", finger_print); @@ -594,5 +594,5 @@ TEST(InstallTest, CheckPackageMetadata_ab_post_timestamp) { "ota-downgrade=yes", }, "\n"); - test_check_package_metadata(metadata, OtaType::AB, 0); + TestCheckPackageMetadata(metadata, OtaType::AB, true); } diff --git a/tests/unit/rangeset_test.cpp b/tests/unit/rangeset_test.cpp index fc72f2f6d..699f933a0 100644 --- a/tests/unit/rangeset_test.cpp +++ b/tests/unit/rangeset_test.cpp @@ -18,6 +18,7 @@ #include <sys/types.h> #include <limits> +#include <optional> #include <vector> #include <gtest/gtest.h> @@ -248,6 +249,29 @@ TEST(RangeSetTest, ToString) { ASSERT_EQ("6,1,3,4,6,15,22", RangeSet::Parse("6,1,3,4,6,15,22").ToString()); } +TEST(RangeSetTest, GetSubRanges_invalid) { + RangeSet range0({ { 1, 11 }, { 20, 30 } }); + ASSERT_FALSE(range0.GetSubRanges(0, 21)); // too many blocks + ASSERT_FALSE(range0.GetSubRanges(21, 1)); // start block OOB +} + +TEST(RangeSetTest, GetSubRanges_empty) { + RangeSet range0({ { 1, 11 }, { 20, 30 } }); + ASSERT_EQ(RangeSet{}, range0.GetSubRanges(1, 0)); // empty num_of_blocks +} + +TEST(RangeSetTest, GetSubRanges_smoke) { + RangeSet range0({ { 10, 11 } }); + ASSERT_EQ(RangeSet({ { 10, 11 } }), range0.GetSubRanges(0, 1)); + + RangeSet range1({ { 10, 11 }, { 20, 21 }, { 30, 31 } }); + ASSERT_EQ(range1, range1.GetSubRanges(0, 3)); + ASSERT_EQ(RangeSet({ { 20, 21 } }), range1.GetSubRanges(1, 1)); + + RangeSet range2({ { 1, 11 }, { 20, 25 }, { 30, 35 } }); + ASSERT_EQ(RangeSet({ { 10, 11 }, { 20, 25 }, { 30, 31 } }), range2.GetSubRanges(9, 7)); +} + TEST(SortedRangeSetTest, Insert) { SortedRangeSet rs({ { 2, 3 }, { 4, 6 }, { 8, 14 } }); rs.Insert({ 1, 2 }); diff --git a/tests/unit/resources_test.cpp b/tests/unit/resources_test.cpp index c3f72718f..302744308 100644 --- a/tests/unit/resources_test.cpp +++ b/tests/unit/resources_test.cpp @@ -14,12 +14,62 @@ * limitations under the License. */ +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> + +#include <memory> #include <string> +#include <vector> +#include <android-base/file.h> +#include <android-base/strings.h> #include <gtest/gtest.h> +#include <png.h> #include "common/test_constants.h" #include "minui/minui.h" +#include "private/resources.h" + +static const std::string kLocale = "zu"; + +static const std::vector<std::string> kResourceImagesDirs{ + "res-mdpi/images/", "res-hdpi/images/", "res-xhdpi/images/", + "res-xxhdpi/images/", "res-xxxhdpi/images/", +}; + +static int png_filter(const dirent* de) { + if (de->d_type != DT_REG || !android::base::EndsWith(de->d_name, "_text.png")) { + return 0; + } + return 1; +} + +// Finds out all the PNG files to test, which stay under the same dir with the executabl.. +static std::vector<std::string> add_files() { + std::vector<std::string> files; + for (const std::string& images_dir : kResourceImagesDirs) { + static std::string exec_dir = android::base::GetExecutableDirectory(); + std::string dir_path = exec_dir + "/" + images_dir; + dirent** namelist; + int n = scandir(dir_path.c_str(), &namelist, png_filter, alphasort); + if (n == -1) { + printf("Failed to scandir %s: %s\n", dir_path.c_str(), strerror(errno)); + continue; + } + if (n == 0) { + printf("No file is added for test in %s\n", dir_path.c_str()); + } + + while (n--) { + std::string file_path = dir_path + namelist[n]->d_name; + files.push_back(file_path); + free(namelist[n]); + } + free(namelist); + } + return files; +} TEST(ResourcesTest, res_create_multi_display_surface) { GRSurface** frames; @@ -35,3 +85,52 @@ TEST(ResourcesTest, res_create_multi_display_surface) { } free(frames); } + +class ResourcesTest : public testing::TestWithParam<std::string> { + public: + static std::vector<std::string> png_list; + + protected: + void SetUp() override { + png_ = std::make_unique<PngHandler>(GetParam()); + ASSERT_TRUE(png_); + + ASSERT_EQ(PNG_COLOR_TYPE_GRAY, png_->color_type()) << "Recovery expects grayscale PNG file."; + ASSERT_LT(static_cast<png_uint_32>(5), png_->width()); + ASSERT_LT(static_cast<png_uint_32>(0), png_->height()); + ASSERT_EQ(1, png_->channels()) << "Recovery background text images expects 1-channel PNG file."; + } + + std::unique_ptr<PngHandler> png_{ nullptr }; +}; + +// Parses a png file and tests if it's qualified for the background text image under recovery. +TEST_P(ResourcesTest, ValidateLocale) { + std::vector<unsigned char> row(png_->width()); + for (png_uint_32 y = 0; y < png_->height(); ++y) { + png_read_row(png_->png_ptr(), row.data(), nullptr); + int w = (row[1] << 8) | row[0]; + int h = (row[3] << 8) | row[2]; + int len = row[4]; + EXPECT_LT(0, w); + EXPECT_LT(0, h); + EXPECT_LT(0, len) << "Locale string should be non-empty."; + EXPECT_NE(0, row[5]) << "Locale string is missing."; + + ASSERT_GE(png_->height(), y + 1 + h) << "Locale: " << kLocale << " is not found in the file."; + char* loc = reinterpret_cast<char*>(&row[5]); + if (matches_locale(loc, kLocale.c_str())) { + EXPECT_TRUE(android::base::StartsWith(loc, kLocale)); + break; + } + for (int i = 0; i < h; ++i, ++y) { + png_read_row(png_->png_ptr(), row.data(), nullptr); + } + } +} + +std::vector<std::string> ResourcesTest::png_list = add_files(); + +INSTANTIATE_TEST_CASE_P(BackgroundTextValidation, ResourcesTest, + ::testing::ValuesIn(ResourcesTest::png_list.cbegin(), + ResourcesTest::png_list.cend())); diff --git a/tests/unit/sysutil_test.cpp b/tests/unit/sysutil_test.cpp index 3466e8eec..64b8956f7 100644 --- a/tests/unit/sysutil_test.cpp +++ b/tests/unit/sysutil_test.cpp @@ -67,7 +67,7 @@ TEST(SysUtilTest, ParseBlockMapFile_invalid_size) { "/dev/abc", "42949672950 4294967295", "1", - "0 9", + "0 10", }; TemporaryFile temp_file; diff --git a/tests/component/uncrypt_test.cpp b/tests/unit/uncrypt_test.cpp index e97d589a6..e97d589a6 100644 --- a/tests/component/uncrypt_test.cpp +++ b/tests/unit/uncrypt_test.cpp diff --git a/tests/component/update_verifier_test.cpp b/tests/unit/update_verifier_test.cpp index e27e58c22..e27e58c22 100644 --- a/tests/component/update_verifier_test.cpp +++ b/tests/unit/update_verifier_test.cpp diff --git a/tests/component/updater_test.cpp b/tests/unit/updater_test.cpp index a0a7b66ab..a0a7b66ab 100644 --- a/tests/component/updater_test.cpp +++ b/tests/unit/updater_test.cpp diff --git a/tests/component/verifier_test.cpp b/tests/unit/verifier_test.cpp index ded23c52f..ded23c52f 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/unit/verifier_test.cpp diff --git a/updater/install.cpp b/updater/install.cpp index 20a204a83..8eba64f5d 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -778,7 +778,7 @@ Value* RebootNowFn(const char* name, State* state, const std::vector<std::unique return StringValue(""); } - reboot("reboot," + property); + Reboot(property); sleep(5); return ErrorAbort(state, kRebootFailure, "%s() failed to reboot", name); |