update_engine: refactor manifest parsing

DeltaPerformer write is quite long and complex. Let's move manifest
parsing to it's own method for readability.

Test: th
Change-Id: Id8ce50c3bd62959b1b70a4f05eef4718f3d30867
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index fe263c2..fe581b6 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -451,158 +451,14 @@
   UpdateOverallProgress(false, "Completed ");
 
   while (!manifest_valid_) {
-    // Read data up to the needed limit; this is either maximium payload header
-    // size, or the full metadata size (once it becomes known).
-    const bool do_read_header = !IsHeaderParsed();
-    CopyDataToBuffer(
-        &c_bytes,
-        &count,
-        (do_read_header ? kMaxPayloadHeaderSize
-                        : metadata_size_ + metadata_signature_size_));
-
-    MetadataParseResult result = ParsePayloadMetadata(buffer_, error);
-    if (result == MetadataParseResult::kError)
+    bool insufficient_bytes = false;
+    if (!ParseManifest(&c_bytes, &count, error, &insufficient_bytes)) {
+      LOG(ERROR) << "Failed to parse manifest";
       return false;
-    if (result == MetadataParseResult::kInsufficientData) {
-      // If we just processed the header, make an attempt on the manifest.
-      if (do_read_header && IsHeaderParsed())
-        continue;
-
+    }
+    if (insufficient_bytes) {
       return true;
     }
-
-    // Checks the integrity of the payload manifest.
-    if ((*error = ValidateManifest()) != ErrorCode::kSuccess)
-      return false;
-    manifest_valid_ = true;
-    if (!install_plan_->is_resume) {
-      auto begin = reinterpret_cast<const char*>(buffer_.data());
-      prefs_->SetString(kPrefsManifestBytes, {begin, buffer_.size()});
-    }
-
-    // Clear the download buffer.
-    DiscardBuffer(false, metadata_size_);
-
-    block_size_ = manifest_.block_size();
-
-    if (!install_plan_->spl_downgrade && !CheckSPLDowngrade()) {
-      *error = ErrorCode::kPayloadTimestampError;
-      return false;
-    }
-
-    // update estimate_cow_size if VABC is disabled
-    // new_cow_size per partition = partition_size - (#blocks in Copy
-    // operations part of the partition)
-    if (install_plan_->vabc_none) {
-      LOG(INFO) << "Setting Virtual AB Compression algorithm to none. This "
-                   "would also disable VABC XOR as XOR only saves space if "
-                   "compression is enabled.";
-      manifest_.mutable_dynamic_partition_metadata()
-          ->set_vabc_compression_param("none");
-      for (auto& partition : *manifest_.mutable_partitions()) {
-        if (!partition.has_estimate_cow_size()) {
-          continue;
-        }
-        auto new_cow_size = partition.new_partition_info().size();
-        for (const auto& operation : partition.merge_operations()) {
-          if (operation.type() == CowMergeOperation::COW_COPY) {
-            new_cow_size -=
-                operation.dst_extent().num_blocks() * manifest_.block_size();
-          }
-        }
-        // Remove all COW_XOR merge ops, as XOR without compression is useless.
-        // It increases CPU usage but does not reduce space usage at all.
-        auto&& merge_ops = *partition.mutable_merge_operations();
-        merge_ops.erase(std::remove_if(merge_ops.begin(),
-                                       merge_ops.end(),
-                                       [](const auto& op) {
-                                         return op.type() ==
-                                                CowMergeOperation::COW_XOR;
-                                       }),
-                        merge_ops.end());
-
-        // Every block written to COW device will come with a header which
-        // stores src/dst block info along with other data.
-        const auto cow_metadata_size = partition.new_partition_info().size() /
-                                       manifest_.block_size() *
-                                       sizeof(android::snapshot::CowOperation);
-        // update_engine will emit a label op every op or every two seconds,
-        // whichever one is longer. In the worst case, we add 1 label per
-        // InstallOp. So take size of label ops into account.
-        const auto label_ops_size = partition.operations_size() *
-                                    sizeof(android::snapshot::CowOperation);
-        // Adding extra 2MB headroom just for any unexpected space usage.
-        // If we overrun reserved COW size, entire OTA will fail
-        // and no way for user to retry OTA
-        partition.set_estimate_cow_size(new_cow_size + (1024 * 1024 * 2) +
-                                        cow_metadata_size + label_ops_size);
-        // Setting op count max to 0 will defer to num_blocks as the op buffer
-        // size.
-        partition.set_estimate_op_count_max(0);
-        LOG(INFO) << "New COW size for partition " << partition.partition_name()
-                  << " is " << partition.estimate_cow_size();
-      }
-    }
-    if (install_plan_->disable_vabc) {
-      manifest_.mutable_dynamic_partition_metadata()->set_vabc_enabled(false);
-    }
-    if (install_plan_->enable_threading) {
-      manifest_.mutable_dynamic_partition_metadata()
-          ->mutable_vabc_feature_set()
-          ->set_threaded(install_plan_->enable_threading.value());
-      LOG(INFO) << "Attempting to "
-                << (install_plan_->enable_threading.value() ? "enable"
-                                                            : "disable")
-                << " multi-threaded compression for VABC";
-    }
-    if (install_plan_->batched_writes) {
-      manifest_.mutable_dynamic_partition_metadata()
-          ->mutable_vabc_feature_set()
-          ->set_batch_writes(true);
-      LOG(INFO) << "Attempting to enable batched writes for VABC";
-    }
-
-    // This populates |partitions_| and the |install_plan.partitions| with the
-    // list of partitions from the manifest.
-    if (!ParseManifestPartitions(error))
-      return false;
-
-    // |install_plan.partitions| was filled in, nothing need to be done here if
-    // the payload was already applied, returns false to terminate http fetcher,
-    // but keep |error| as ErrorCode::kSuccess.
-    if (payload_->already_applied)
-      return false;
-
-    num_total_operations_ = 0;
-    for (const auto& partition : partitions_) {
-      num_total_operations_ += partition.operations_size();
-      acc_num_operations_.push_back(num_total_operations_);
-    }
-
-    LOG_IF(WARNING,
-           !prefs_->SetInt64(kPrefsManifestMetadataSize, metadata_size_))
-        << "Unable to save the manifest metadata size.";
-    LOG_IF(WARNING,
-           !prefs_->SetInt64(kPrefsManifestSignatureSize,
-                             metadata_signature_size_))
-        << "Unable to save the manifest signature size.";
-
-    if (!PrimeUpdateState()) {
-      *error = ErrorCode::kDownloadStateInitializationError;
-      LOG(ERROR) << "Unable to prime the update state.";
-      return false;
-    }
-
-    if (next_operation_num_ < acc_num_operations_[current_partition_]) {
-      if (!OpenCurrentPartition()) {
-        *error = ErrorCode::kInstallDeviceOpenError;
-        return false;
-      }
-    }
-
-    if (next_operation_num_ > 0)
-      UpdateOverallProgress(true, "Resuming after ");
-    LOG(INFO) << "Starting to apply update payload operations";
   }
 
   while (next_operation_num_ < num_total_operations_) {
@@ -693,6 +549,163 @@
   return true;
 }
 
+bool DeltaPerformer::ParseManifest(const char** c_bytes,
+                                   size_t* count,
+                                   ErrorCode* error,
+                                   bool* should_return) {
+  // Read data up to the needed limit; this is either maximium payload header
+  // size, or the full metadata size (once it becomes known).
+  const bool do_read_header = !IsHeaderParsed();
+  CopyDataToBuffer(
+      c_bytes,
+      count,
+      (do_read_header ? kMaxPayloadHeaderSize
+                      : metadata_size_ + metadata_signature_size_));
+  MetadataParseResult result = ParsePayloadMetadata(buffer_, error);
+  if (result == MetadataParseResult::kError)
+    return false;
+  if (result == MetadataParseResult::kInsufficientData) {
+    // If we just processed the header, make an attempt on the manifest.
+    if (do_read_header && IsHeaderParsed()) {
+      return true;
+    }
+    *should_return = true;
+    return true;
+  }
+
+  // Checks the integrity of the payload manifest.
+  if ((*error = ValidateManifest()) != ErrorCode::kSuccess)
+    return false;
+  manifest_valid_ = true;
+  if (!install_plan_->is_resume) {
+    auto begin = reinterpret_cast<const char*>(buffer_.data());
+    prefs_->SetString(kPrefsManifestBytes, {begin, buffer_.size()});
+  }
+
+  // Clear the download buffer.
+  DiscardBuffer(false, metadata_size_);
+
+  block_size_ = manifest_.block_size();
+
+  if (!install_plan_->spl_downgrade && !CheckSPLDowngrade()) {
+    *error = ErrorCode::kPayloadTimestampError;
+    return false;
+  }
+
+  // update estimate_cow_size if VABC is disabled
+  // new_cow_size per partition = partition_size - (#blocks in Copy
+  // operations part of the partition)
+  if (install_plan_->vabc_none) {
+    LOG(INFO) << "Setting Virtual AB Compression algorithm to none. This "
+                 "would also disable VABC XOR as XOR only saves space if "
+                 "compression is enabled.";
+    manifest_.mutable_dynamic_partition_metadata()->set_vabc_compression_param(
+        "none");
+    for (auto& partition : *manifest_.mutable_partitions()) {
+      if (!partition.has_estimate_cow_size()) {
+        continue;
+      }
+      auto new_cow_size = partition.new_partition_info().size();
+      for (const auto& operation : partition.merge_operations()) {
+        if (operation.type() == CowMergeOperation::COW_COPY) {
+          new_cow_size -=
+              operation.dst_extent().num_blocks() * manifest_.block_size();
+        }
+      }
+      // Remove all COW_XOR merge ops, as XOR without compression is useless.
+      // It increases CPU usage but does not reduce space usage at all.
+      auto&& merge_ops = *partition.mutable_merge_operations();
+      merge_ops.erase(std::remove_if(merge_ops.begin(),
+                                     merge_ops.end(),
+                                     [](const auto& op) {
+                                       return op.type() ==
+                                              CowMergeOperation::COW_XOR;
+                                     }),
+                      merge_ops.end());
+
+      // Every block written to COW device will come with a header which
+      // stores src/dst block info along with other data.
+      const auto cow_metadata_size = partition.new_partition_info().size() /
+                                     manifest_.block_size() *
+                                     sizeof(android::snapshot::CowOperation);
+      // update_engine will emit a label op every op or every two seconds,
+      // whichever one is longer. In the worst case, we add 1 label per
+      // InstallOp. So take size of label ops into account.
+      const auto label_ops_size =
+          partition.operations_size() * sizeof(android::snapshot::CowOperation);
+      // Adding extra 2MB headroom just for any unexpected space usage.
+      // If we overrun reserved COW size, entire OTA will fail
+      // and no way for user to retry OTA
+      partition.set_estimate_cow_size(new_cow_size + (1024 * 1024 * 2) +
+                                      cow_metadata_size + label_ops_size);
+      // Setting op count max to 0 will defer to num_blocks as the op buffer
+      // size.
+      partition.set_estimate_op_count_max(0);
+      LOG(INFO) << "New COW size for partition " << partition.partition_name()
+                << " is " << partition.estimate_cow_size();
+    }
+  }
+  if (install_plan_->disable_vabc) {
+    manifest_.mutable_dynamic_partition_metadata()->set_vabc_enabled(false);
+  }
+  if (install_plan_->enable_threading) {
+    manifest_.mutable_dynamic_partition_metadata()
+        ->mutable_vabc_feature_set()
+        ->set_threaded(install_plan_->enable_threading.value());
+    LOG(INFO) << "Attempting to "
+              << (install_plan_->enable_threading.value() ? "enable"
+                                                          : "disable")
+              << " multi-threaded compression for VABC";
+  }
+  if (install_plan_->batched_writes) {
+    manifest_.mutable_dynamic_partition_metadata()
+        ->mutable_vabc_feature_set()
+        ->set_batch_writes(true);
+    LOG(INFO) << "Attempting to enable batched writes for VABC";
+  }
+
+  // This populates |partitions_| and the |install_plan.partitions| with the
+  // list of partitions from the manifest.
+  if (!ParseManifestPartitions(error))
+    return false;
+
+  // |install_plan.partitions| was filled in, nothing need to be done here if
+  // the payload was already applied, returns false to terminate http fetcher,
+  // but keep |error| as ErrorCode::kSuccess.
+  if (payload_->already_applied)
+    return false;
+
+  num_total_operations_ = 0;
+  for (const auto& partition : partitions_) {
+    num_total_operations_ += partition.operations_size();
+    acc_num_operations_.push_back(num_total_operations_);
+  }
+
+  LOG_IF(WARNING, !prefs_->SetInt64(kPrefsManifestMetadataSize, metadata_size_))
+      << "Unable to save the manifest metadata size.";
+  LOG_IF(
+      WARNING,
+      !prefs_->SetInt64(kPrefsManifestSignatureSize, metadata_signature_size_))
+      << "Unable to save the manifest signature size.";
+
+  if (!PrimeUpdateState()) {
+    *error = ErrorCode::kDownloadStateInitializationError;
+    LOG(ERROR) << "Unable to prime the update state.";
+    return false;
+  }
+
+  if (next_operation_num_ < acc_num_operations_[current_partition_]) {
+    if (!OpenCurrentPartition()) {
+      *error = ErrorCode::kInstallDeviceOpenError;
+      return false;
+    }
+  }
+
+  if (next_operation_num_ > 0)
+    UpdateOverallProgress(true, "Resuming after ");
+  LOG(INFO) << "Starting to apply update payload operations";
+  return true;
+}
 bool DeltaPerformer::ProcessOperation(const InstallOperation* op,
                                       ErrorCode* error) {
   // Validate the operation unconditionally. This helps prevent the
diff --git a/payload_consumer/delta_performer.h b/payload_consumer/delta_performer.h
index 1584dc6..76d64c5 100644
--- a/payload_consumer/delta_performer.h
+++ b/payload_consumer/delta_performer.h
@@ -246,6 +246,11 @@
   // to be able to perform a given install operation.
   bool CanPerformInstallOperation(const InstallOperation& operation);
 
+  bool ParseManifest(const char** c_bytes,
+                     size_t* count,
+                     ErrorCode* error,
+                     bool* should_return);
+
   // Process one InstallOperation
   bool ProcessOperation(const InstallOperation* op, ErrorCode* error);
   // Checks the integrity of the payload manifest. Returns true upon success,