diff options
Diffstat (limited to '')
-rw-r--r-- | recovery.cpp | 125 |
1 files changed, 110 insertions, 15 deletions
diff --git a/recovery.cpp b/recovery.cpp index dc17c9527..4d1ad1df2 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -86,9 +86,16 @@ static const struct option OPTIONS[] = { { "reason", required_argument, NULL, 'r' }, { "security", no_argument, NULL, 'e'}, { "wipe_ab", no_argument, NULL, 0 }, + { "wipe_package_size", required_argument, NULL, 0 }, { NULL, 0, NULL, 0 }, }; +// More bootreasons can be found in "system/core/bootstat/bootstat.cpp". +static const std::vector<std::string> bootreason_blacklist { + "kernel_panic", + "Panic", +}; + static const char *CACHE_LOG_DIR = "/cache/recovery"; static const char *COMMAND_FILE = "/cache/recovery/command"; static const char *LOG_FILE = "/cache/recovery/log"; @@ -902,12 +909,76 @@ static bool secure_wipe_partition(const std::string& partition) { return true; } +// Check if the wipe package matches expectation: +// 1. verify the package. +// 2. check metadata (ota-type, pre-device and serial number if having one). +static bool check_wipe_package(size_t wipe_package_size) { + if (wipe_package_size == 0) { + LOG(ERROR) << "wipe_package_size is zero"; + return false; + } + std::string wipe_package; + std::string err_str; + if (!read_wipe_package(&wipe_package, wipe_package_size, &err_str)) { + PLOG(ERROR) << "Failed to read wipe package"; + return false; + } + if (!verify_package(reinterpret_cast<const unsigned char*>(wipe_package.data()), + wipe_package.size())) { + LOG(ERROR) << "Failed to verify package"; + return false; + } + + // Extract metadata + ZipArchiveHandle zip; + int err = OpenArchiveFromMemory(reinterpret_cast<void*>(&wipe_package[0]), + wipe_package.size(), "wipe_package", &zip); + if (err != 0) { + LOG(ERROR) << "Can't open wipe package : " << ErrorCodeString(err); + return false; + } + std::string metadata; + if (!read_metadata_from_package(&zip, &metadata)) { + CloseArchive(zip); + return false; + } + CloseArchive(zip); + + // Check metadata + std::vector<std::string> lines = android::base::Split(metadata, "\n"); + bool ota_type_matched = false; + bool device_type_matched = false; + bool has_serial_number = false; + bool serial_number_matched = false; + for (const auto& line : lines) { + if (line == "ota-type=BRICK") { + ota_type_matched = true; + } else if (android::base::StartsWith(line, "pre-device=")) { + std::string device_type = line.substr(strlen("pre-device=")); + char real_device_type[PROPERTY_VALUE_MAX]; + property_get("ro.build.product", real_device_type, ""); + device_type_matched = (device_type == real_device_type); + } else if (android::base::StartsWith(line, "serialno=")) { + std::string serial_no = line.substr(strlen("serialno=")); + char real_serial_no[PROPERTY_VALUE_MAX]; + property_get("ro.serialno", real_serial_no, ""); + has_serial_number = true; + serial_number_matched = (serial_no == real_serial_no); + } + } + return ota_type_matched && device_type_matched && (!has_serial_number || serial_number_matched); +} + // Wipe the current A/B device, with a secure wipe of all the partitions in // RECOVERY_WIPE. -static bool wipe_ab_device() { +static bool wipe_ab_device(size_t wipe_package_size) { ui->SetBackground(RecoveryUI::ERASING); ui->SetProgressType(RecoveryUI::INDETERMINATE); + if (!check_wipe_package(wipe_package_size)) { + LOG(ERROR) << "Failed to verify wipe package"; + return false; + } std::string partition_list; if (!android::base::ReadFileToString(RECOVERY_WIPE, &partition_list)) { LOG(ERROR) << "failed to read \"" << RECOVERY_WIPE << "\""; @@ -1330,6 +1401,33 @@ static void set_retry_bootloader_message(int retry_count, int argc, char** argv) } } +static bool bootreason_in_blacklist() { + char bootreason[PROPERTY_VALUE_MAX]; + if (property_get("ro.boot.bootreason", bootreason, nullptr) > 0) { + for (const auto& str : bootreason_blacklist) { + if (strcasecmp(str.c_str(), bootreason) == 0) { + return true; + } + } + } + return false; +} + +static void log_failure_code(ErrorCode code, const char *update_package) { + std::vector<std::string> log_buffer = { + update_package, + "0", // install result + "error: " + std::to_string(code), + }; + std::string log_content = android::base::Join(log_buffer, "\n"); + if (!android::base::WriteStringToFile(log_content, TEMPORARY_INSTALL_FILE)) { + PLOG(ERROR) << "failed to write " << TEMPORARY_INSTALL_FILE; + } + + // Also write the info into last_log. + LOG(INFO) << log_content; +} + static ssize_t logbasename( log_id_t /* logId */, char /* prio */, @@ -1426,6 +1524,7 @@ int main(int argc, char **argv) { bool should_wipe_data = false; bool should_wipe_cache = false; bool should_wipe_ab = false; + size_t wipe_package_size = 0; bool show_text = false; bool sideload = false; bool sideload_auto_reboot = false; @@ -1462,6 +1561,9 @@ int main(int argc, char **argv) { if (strcmp(OPTIONS[option_index].name, "wipe_ab") == 0) { should_wipe_ab = true; break; + } else if (strcmp(OPTIONS[option_index].name, "wipe_package_size") == 0) { + android::base::ParseUint(optarg, &wipe_package_size); + break; } break; } @@ -1551,19 +1653,12 @@ int main(int argc, char **argv) { BATTERY_OK_PERCENTAGE); // Log the error code to last_install when installation skips due to // low battery. - std::vector<std::string> log_buffer = { - update_package, - "0", // install result - "error: " + std::to_string(kLowBattery), - }; - std::string log_content = android::base::Join(log_buffer, "\n"); - if (!android::base::WriteStringToFile(log_content, LAST_INSTALL_FILE)) { - PLOG(ERROR) << "failed to write " << LAST_INSTALL_FILE; - } - - // Also write the info into last_log. - LOG(INFO) << log_content; - + log_failure_code(kLowBattery, update_package); + status = INSTALL_SKIPPED; + } else if (bootreason_in_blacklist()) { + // Skip update-on-reboot when bootreason is kernel_panic or similar + ui->Print("bootreason is in the blacklist; skip OTA installation\n"); + log_failure_code(kBootreasonInBlacklist, update_package); status = INSTALL_SKIPPED; } else { status = install_package(update_package, &should_wipe_cache, @@ -1607,7 +1702,7 @@ int main(int argc, char **argv) { status = INSTALL_ERROR; } } else if (should_wipe_ab) { - if (!wipe_ab_device()) { + if (!wipe_ab_device(wipe_package_size)) { status = INSTALL_ERROR; } } else if (sideload) { |