summaryrefslogtreecommitdiffstats
path: root/recovery.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'recovery.cpp')
-rw-r--r--recovery.cpp125
1 files changed, 110 insertions, 15 deletions
diff --git a/recovery.cpp b/recovery.cpp
index 343d123d6..88c77d2f8 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";
@@ -908,12 +915,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 << "\"";
@@ -1346,6 +1417,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 */,
@@ -1442,6 +1540,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;
@@ -1478,6 +1577,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;
}
@@ -1567,19 +1669,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,
@@ -1623,7 +1718,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) {