diff options
-rw-r--r-- | install.cpp | 52 | ||||
-rw-r--r-- | otautil/Android.mk | 12 | ||||
-rw-r--r-- | otautil/ThermalUtil.cpp | 80 | ||||
-rw-r--r-- | otautil/ThermalUtil.h | 24 | ||||
-rw-r--r-- | roots.cpp | 4 | ||||
-rw-r--r-- | update_verifier/update_verifier.cpp | 59 |
6 files changed, 194 insertions, 37 deletions
diff --git a/install.cpp b/install.cpp index 7cef44a37..0a2fa3ca4 100644 --- a/install.cpp +++ b/install.cpp @@ -26,11 +26,15 @@ #include <sys/wait.h> #include <unistd.h> +#include <algorithm> #include <chrono> +#include <condition_variable> #include <functional> #include <limits> #include <map> +#include <mutex> #include <string> +#include <thread> #include <vector> #include <android-base/file.h> @@ -46,10 +50,13 @@ #include "error_code.h" #include "minui/minui.h" #include "otautil/SysUtil.h" +#include "otautil/ThermalUtil.h" #include "roots.h" #include "ui.h" #include "verifier.h" +using namespace std::chrono_literals; + #define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary" static constexpr const char* AB_OTA_PAYLOAD_PROPERTIES = "payload_properties.txt"; static constexpr const char* AB_OTA_PAYLOAD = "payload.bin"; @@ -63,6 +70,8 @@ static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25; static constexpr float DEFAULT_FILES_PROGRESS_FRACTION = 0.4; static constexpr float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1; +static std::condition_variable finish_log_temperature; + // This function parses and returns the build.version.incremental static int parse_build_number(const std::string& str) { size_t pos = str.find('='); @@ -299,9 +308,19 @@ update_binary_command(const char* path, ZipArchiveHandle zip, int retry_count, } #endif // !AB_OTA_UPDATER +static void log_max_temperature(int* max_temperature) { + CHECK(max_temperature != nullptr); + std::mutex mtx; + std::unique_lock<std::mutex> lck(mtx); + while (finish_log_temperature.wait_for(lck, 20s) == std::cv_status::timeout) { + *max_temperature = std::max(*max_temperature, GetMaxValueFromThermalZone()); + } +} + // If the package contains an update binary, extract it and run it. static int try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_cache, - std::vector<std::string>& log_buffer, int retry_count) { + std::vector<std::string>& log_buffer, int retry_count, + int* max_temperature) { read_source_target_build(zip, log_buffer); int pipefd[2]; @@ -392,6 +411,8 @@ static int try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_ } close(pipefd[1]); + std::thread temperature_logger(log_max_temperature, max_temperature); + *wipe_cache = false; bool retry_update = false; @@ -453,6 +474,10 @@ static int try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_ int status; waitpid(pid, &status, 0); + + finish_log_temperature.notify_one(); + temperature_logger.join(); + if (retry_update) { return INSTALL_RETRY; } @@ -466,7 +491,7 @@ static int try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_ static int really_install_package(const char *path, bool* wipe_cache, bool needs_mount, - std::vector<std::string>& log_buffer, int retry_count) + std::vector<std::string>& log_buffer, int retry_count, int* max_temperature) { ui->SetBackground(RecoveryUI::INSTALLING_UPDATE); ui->Print("Finding update package...\n"); @@ -517,7 +542,7 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount, ui->Print("Retry attempt: %d\n", retry_count); } ui->SetEnableReboot(false); - int result = try_update_binary(path, zip, wipe_cache, log_buffer, retry_count); + int result = try_update_binary(path, zip, wipe_cache, log_buffer, retry_count, max_temperature); ui->SetEnableReboot(true); ui->Print("\n"); @@ -533,13 +558,17 @@ install_package(const char* path, bool* wipe_cache, const char* install_file, modified_flash = true; auto start = std::chrono::system_clock::now(); + int start_temperature = GetMaxValueFromThermalZone(); + int max_temperature = start_temperature; + int 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 { - result = really_install_package(path, wipe_cache, needs_mount, log_buffer, retry_count); + result = really_install_package(path, wipe_cache, needs_mount, log_buffer, retry_count, + &max_temperature); } // Measure the time spent to apply OTA update in seconds. @@ -570,8 +599,21 @@ install_package(const char* path, bool* wipe_cache, const char* install_file, "time_total: " + std::to_string(time_total), "retry: " + std::to_string(retry_count), }; + + int end_temperature = GetMaxValueFromThermalZone(); + max_temperature = std::max(end_temperature, max_temperature); + if (start_temperature > 0) { + log_buffer.push_back("temperature_start: " + std::to_string(start_temperature)); + } + if (end_temperature > 0) { + log_buffer.push_back("temperature_end: " + std::to_string(end_temperature)); + } + if (max_temperature > 0) { + log_buffer.push_back("temperature_max: " + std::to_string(max_temperature)); + } + std::string log_content = android::base::Join(log_header, "\n") + "\n" + - android::base::Join(log_buffer, "\n"); + android::base::Join(log_buffer, "\n") + "\n"; if (!android::base::WriteStringToFile(log_content, install_file)) { PLOG(ERROR) << "failed to write " << install_file; } diff --git a/otautil/Android.mk b/otautil/Android.mk index e602f19ee..f7ca9a9ee 100644 --- a/otautil/Android.mk +++ b/otautil/Android.mk @@ -18,12 +18,16 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ SysUtil.cpp \ DirUtil.cpp \ - ZipUtil.cpp + ZipUtil.cpp \ + ThermalUtil.cpp -LOCAL_STATIC_LIBRARIES := libselinux libbase +LOCAL_STATIC_LIBRARIES := \ + libselinux \ + libbase LOCAL_MODULE := libotautil - -LOCAL_CFLAGS += -Werror -Wall +LOCAL_CFLAGS := \ + -Werror \ + -Wall include $(BUILD_STATIC_LIBRARY) diff --git a/otautil/ThermalUtil.cpp b/otautil/ThermalUtil.cpp new file mode 100644 index 000000000..13d36432a --- /dev/null +++ b/otautil/ThermalUtil.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2017 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 "ThermalUtil.h" + +#include <dirent.h> +#include <stdio.h> + +#include <algorithm> +#include <string> +#include <vector> + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/parseint.h> +#include <android-base/strings.h> + +static constexpr auto THERMAL_PREFIX = "/sys/class/thermal/"; + +static int thermal_filter(const dirent* de) { + if (android::base::StartsWith(de->d_name, "thermal_zone")) { + return 1; + } + return 0; +} + +static std::vector<std::string> InitThermalPaths() { + dirent** namelist; + int n = scandir(THERMAL_PREFIX, &namelist, thermal_filter, alphasort); + if (n == -1) { + PLOG(ERROR) << "Failed to scandir " << THERMAL_PREFIX; + return {}; + } + if (n == 0) { + LOG(ERROR) << "Failed to find CPU thermal info in " << THERMAL_PREFIX; + return {}; + } + + std::vector<std::string> thermal_paths; + while (n--) { + thermal_paths.push_back(THERMAL_PREFIX + std::string(namelist[n]->d_name) + "/temp"); + free(namelist[n]); + } + free(namelist); + return thermal_paths; +} + +int GetMaxValueFromThermalZone() { + static std::vector<std::string> thermal_paths = InitThermalPaths(); + int max_temperature = -1; + for (const auto& path : thermal_paths) { + std::string content; + if (!android::base::ReadFileToString(path, &content)) { + PLOG(WARNING) << "Failed to read " << path; + continue; + } + + int temperature; + if (!android::base::ParseInt(android::base::Trim(content), &temperature)) { + LOG(WARNING) << "Failed to parse integer in " << content; + continue; + } + max_temperature = std::max(temperature, max_temperature); + } + LOG(INFO) << "current maximum temperature: " << max_temperature; + return max_temperature; +}
\ No newline at end of file diff --git a/otautil/ThermalUtil.h b/otautil/ThermalUtil.h new file mode 100644 index 000000000..43ab55940 --- /dev/null +++ b/otautil/ThermalUtil.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OTAUTIL_THERMALUTIL_H +#define OTAUTIL_THERMALUTIL_H + +// We can find the temperature reported by all sensors in /sys/class/thermal/thermal_zone*/temp. +// Their values are in millidegree Celsius; and we will log the maximum one. +int GetMaxValueFromThermalZone(); + +#endif // OTAUTIL_THERMALUTIL_H @@ -44,9 +44,9 @@ void load_volume_table() int i; int ret; - fstab = fs_mgr_read_fstab_with_dt("/etc/recovery.fstab"); + fstab = fs_mgr_read_fstab_default(); if (!fstab) { - LOG(ERROR) << "failed to read /etc/recovery.fstab"; + LOG(ERROR) << "failed to read default fstab"; return; } diff --git a/update_verifier/update_verifier.cpp b/update_verifier/update_verifier.cpp index 83b1c46c4..72b6dccc5 100644 --- a/update_verifier/update_verifier.cpp +++ b/update_verifier/update_verifier.cpp @@ -19,9 +19,14 @@ * update. It gets invoked by init, and will only perform the verification if * it's the first boot post an A/B OTA update. * - * It relies on dm-verity to capture any corruption on the partitions being - * verified. dm-verity must be in enforcing mode, so that it will reboot the - * device on dm-verity failures. When that happens, the bootloader should + * Update_verifier relies on dm-verity to capture any corruption on the partitions + * being verified. And its behavior varies depending on the dm-verity mode. + * Upon detection of failures: + * enforcing mode: dm-verity reboots the device + * eio mode: dm-verity fails the read and update_verifier reboots the device + * other mode: not supported and update_verifier reboots the device + * + * After a predefined number of failing boot attempts, the bootloader should * mark the slot as unbootable and stops trying. Other dm-verity modes ( * for example, veritymode=EIO) are not accepted and simply lead to a * verification failure. @@ -35,6 +40,7 @@ #include <fcntl.h> #include <stdio.h> #include <string.h> +#include <unistd.h> #include <string> #include <vector> @@ -46,6 +52,7 @@ #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <android/hardware/boot/1.0/IBootControl.h> +#include <cutils/android_reboot.h> using android::sp; using android::hardware::boot::V1_0::IBootControl; @@ -66,18 +73,9 @@ static int dm_name_filter(const dirent* de) { return 0; } -static bool read_blocks(const std::string& blk_device, const std::string& range_str) { - // Parse the partition in the end of the block_device string. - // Here is one example: "/dev/block/bootdevice/by-name/system" - std::string partition; - if (android::base::EndsWith(blk_device, "system")) { - partition = "system"; - } else if (android::base::EndsWith(blk_device, "vendor")) { - partition = "vendor"; - } else { - LOG(ERROR) << "Failed to parse partition string in " << blk_device; - return false; - } +static bool read_blocks(const std::string& partition, const std::string& range_str) { + CHECK(partition == "system" || partition == "vendor") + << "partition name should be system or vendor" << partition; // Iterate the content of "/sys/block/dm-X/dm/name". If it matches "system" // (or "vendor"), then dm-X is a dm-wrapped system/vendor partition. @@ -172,7 +170,7 @@ static bool verify_image(const std::string& care_map_name) { return true; } // Care map file has four lines (two lines if vendor partition is not present): - // First line has the block device name, e.g./dev/block/.../by-name/system. + // First line has the block partition name (system/vendor). // Second line holds all ranges of blocks to verify. // The next two lines have the same format but for vendor partition. std::string file_content; @@ -198,6 +196,14 @@ static bool verify_image(const std::string& care_map_name) { return true; } +static int reboot_device() { + if (android_reboot(ANDROID_RB_RESTART2, 0, nullptr) == -1) { + LOG(ERROR) << "Failed to reboot."; + return -1; + } + while (true) pause(); +} + int main(int argc, char** argv) { for (int i = 1; i < argc; i++) { LOG(INFO) << "Started with arg " << i << ": " << argv[i]; @@ -206,7 +212,7 @@ int main(int argc, char** argv) { sp<IBootControl> module = IBootControl::getService(); if (module == nullptr) { LOG(ERROR) << "Error getting bootctrl module."; - return -1; + return reboot_device(); } uint32_t current_slot = module->getCurrentSlot(); @@ -221,18 +227,19 @@ int main(int argc, char** argv) { std::string verity_mode = android::base::GetProperty("ro.boot.veritymode", ""); if (verity_mode.empty()) { LOG(ERROR) << "Failed to get dm-verity mode."; - return -1; + return reboot_device(); } else if (android::base::EqualsIgnoreCase(verity_mode, "eio")) { - // We shouldn't see verity in EIO mode if the current slot hasn't booted - // successfully before. Therefore, fail the verification when veritymode=eio. - LOG(ERROR) << "Found dm-verity in EIO mode, skip verification."; - return -1; + // We shouldn't see verity in EIO mode if the current slot hasn't booted successfully before. + // Continue the verification until we fail to read some blocks. + LOG(WARNING) << "Found dm-verity in EIO mode."; } else if (verity_mode != "enforcing") { LOG(ERROR) << "Unexpected dm-verity mode : " << verity_mode << ", expecting enforcing."; - return -1; - } else if (!verify_image(CARE_MAP_FILE)) { + return reboot_device(); + } + + if (!verify_image(CARE_MAP_FILE)) { LOG(ERROR) << "Failed to verify all blocks in care map file."; - return -1; + return reboot_device(); } #else LOG(WARNING) << "dm-verity not enabled; marking without verification."; @@ -242,7 +249,7 @@ int main(int argc, char** argv) { module->markBootSuccessful([&cr](CommandResult result) { cr = result; }); if (!cr.success) { LOG(ERROR) << "Error marking booted successfully: " << cr.errMsg; - return -1; + return reboot_device(); } LOG(INFO) << "Marked slot " << current_slot << " as booted successfully."; } |