Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 99b73be3 authored by Tianjie Xu's avatar Tianjie Xu
Browse files

Detect interrupted update due to power off

An interrupted update may stash extra blocks in /cache, leading to a
failure when checking the cache size. We can save the incremented
retry_count in the BCB before installing the update; and distinguish
a fresh update from an interrupted one this way.

Bug: 68679601
Test: An interrupted update reapplies successfully.
Change-Id: Ic1403e1fd25a937c91ef34c14b92a0f6c8f1c0f4
parent 5ce9fe35
Loading
Loading
Loading
Loading
+297 −268
Original line number Diff line number Diff line
@@ -1313,6 +1313,7 @@ static bool is_battery_ok() {
    }
}

// Set the retry count to |retry_count| in BCB.
static void set_retry_bootloader_message(int retry_count, const std::vector<std::string>& args) {
  std::vector<std::string> options;
  for (const auto& arg : args) {
@@ -1321,8 +1322,8 @@ static void set_retry_bootloader_message(int retry_count, const std::vector<std:
    }
  }

  // Increment the retry counter by 1.
  options.push_back(android::base::StringPrintf("--retry_count=%d", retry_count + 1));
  // Update the retry counter in BCB.
  options.push_back(android::base::StringPrintf("--retry_count=%d", retry_count));
  std::string err;
  if (!update_bootloader_message(options, &err)) {
    LOG(ERROR) << err;
@@ -1366,13 +1367,9 @@ int main(int argc, char **argv) {
  // Do we need to rotate?
  bool doRotate = false;

    __android_log_pmsg_file_read(
        LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter,
        logbasename, &doRotate);
  __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logbasename, &doRotate);
  // Take action to refresh pmsg contents
    __android_log_pmsg_file_read(
        LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter,
        logrotate, &doRotate);
  __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logrotate, &doRotate);

  // If this binary is started with the single argument "--adbd",
  // instead of being the normal recovery binary, it turns into kind
@@ -1386,7 +1383,7 @@ int main(int argc, char **argv) {
    return 0;
  }

    time_t start = time(NULL);
  time_t start = time(nullptr);

  // redirect_stdio should be called only in non-sideload mode. Otherwise
  // we may have two logger instances with different timestamps.
@@ -1402,7 +1399,7 @@ int main(int argc, char **argv) {
  std::transform(args.cbegin(), args.cend(), args_to_parse.begin(),
                 [](const std::string& arg) { return const_cast<char*>(arg.c_str()); });

    const char *update_package = NULL;
  const char* update_package = nullptr;
  bool should_wipe_data = false;
  bool should_prompt_and_wipe_data = false;
  bool should_wipe_cache = false;
@@ -1421,18 +1418,43 @@ int main(int argc, char **argv) {
  while ((arg = getopt_long(args_to_parse.size(), args_to_parse.data(), "", OPTIONS,
                            &option_index)) != -1) {
    switch (arg) {
        case 'n': android::base::ParseInt(optarg, &retry_count, 0); break;
        case 'u': update_package = optarg; break;
        case 'w': should_wipe_data = true; break;
        case 'c': should_wipe_cache = true; break;
        case 't': show_text = true; break;
        case 's': sideload = true; break;
        case 'a': sideload = true; sideload_auto_reboot = true; break;
        case 'x': just_exit = true; break;
        case 'l': locale = optarg; break;
        case 'p': shutdown_after = true; break;
        case 'r': reason = optarg; break;
        case 'e': security_update = true; break;
      case 'n':
        android::base::ParseInt(optarg, &retry_count, 0);
        break;
      case 'u':
        update_package = optarg;
        break;
      case 'w':
        should_wipe_data = true;
        break;
      case 'c':
        should_wipe_cache = true;
        break;
      case 't':
        show_text = true;
        break;
      case 's':
        sideload = true;
        break;
      case 'a':
        sideload = true;
        sideload_auto_reboot = true;
        break;
      case 'x':
        just_exit = true;
        break;
      case 'l':
        locale = optarg;
        break;
      case 'p':
        shutdown_after = true;
        break;
      case 'r':
        reason = optarg;
        break;
      case 'e':
        security_update = true;
        break;
      case 0: {
        std::string option = OPTIONS[option_index].name;
        if (option == "wipe_ab") {
@@ -1503,14 +1525,14 @@ int main(int argc, char **argv) {
  }
  printf("\n\n");

    property_list(print_property, NULL);
  property_list(print_property, nullptr);
  printf("\n");

  ui->Print("Supported API: %d\n", kRecoveryApiVersion);

  int status = INSTALL_SUCCESS;

    if (update_package != NULL) {
  if (update_package != nullptr) {
    // It's not entirely true that we will modify the flash. But we want
    // to log the update attempt since update_package is non-NULL.
    modified_flash = true;
@@ -1528,8 +1550,14 @@ int main(int argc, char **argv) {
      log_failure_code(kBootreasonInBlacklist, update_package);
      status = INSTALL_SKIPPED;
    } else {
            status = install_package(update_package, &should_wipe_cache,
                                     TEMPORARY_INSTALL_FILE, true, retry_count);
      // It's a fresh update. Initialize the retry_count in the BCB to 1; therefore we can later
      // identify the interrupted update due to unexpected reboots.
      if (retry_count == 0) {
        set_retry_bootloader_message(retry_count + 1, args);
      }

      status = install_package(update_package, &should_wipe_cache, TEMPORARY_INSTALL_FILE, true,
                               retry_count);
      if (status == INSTALL_SUCCESS && should_wipe_cache) {
        wipe_cache(false, device);
      }
@@ -1539,6 +1567,7 @@ int main(int argc, char **argv) {
        // times before we abandon this OTA update.
        if (status == INSTALL_RETRY && retry_count < RETRY_LIMIT) {
          copy_logs();
          retry_count += 1;
          set_retry_bootloader_message(retry_count, args);
          // Print retry count on screen.
          ui->Print("Retry attempt %d\n", retry_count);
+5 −1
Original line number Diff line number Diff line
@@ -569,7 +569,11 @@ Value* ApplyPatchSpaceFn(const char* name, State* state, const std::vector<std::
                      name, bytes_str.c_str());
  }

  return StringValue(CacheSizeCheck(bytes) ? "" : "t");
  // Skip the cache size check if the update is a retry.
  if (state->is_retry || CacheSizeCheck(bytes) == 0) {
    return StringValue("t");
  }
  return StringValue("");
}

// apply_patch(src_file, tgt_file, tgt_sha1, tgt_size, patch1_sha1, patch1_blob, [...])