Parse multiple packages from Omaha response.

The multi-payload info are stored in OmahaResponse and InstallPlan, but
we still can only apply the first payload for now.

Bug: 36252799
Test: mma -j
Test: update_engine_unittests

Change-Id: I5ca63944ae9082670d0e67888409374f140d4245
(cherry picked from commit 2aba8a87d4fac245a2e2d238b3159f8eabce630f)
diff --git a/payload_state.cc b/payload_state.cc
index 1da472f..287e24c 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -126,7 +126,8 @@
   // we loaded from the persisted state is a valid value. If the response
   // hasn't changed but the URL index is invalid, it's indicative of some
   // tampering of the persisted state.
-  if (static_cast<uint32_t>(url_index_) >= candidate_urls_.size()) {
+  if (payload_index_ >= candidate_urls_.size() ||
+      url_index_ >= candidate_urls_[payload_index_].size()) {
     LOG(INFO) << "Resetting all payload state as the url index seems to have "
                  "been tampered with";
     ResetPersistedState();
@@ -444,21 +445,23 @@
 }
 
 void PayloadState::IncrementUrlIndex() {
-  uint32_t next_url_index = GetUrlIndex() + 1;
-  if (next_url_index < candidate_urls_.size()) {
+  size_t next_url_index = url_index_ + 1;
+  size_t max_url_size = 0;
+  for (const auto& urls : candidate_urls_)
+    max_url_size = std::max(max_url_size, urls.size());
+  if (next_url_index < max_url_size) {
     LOG(INFO) << "Incrementing the URL index for next attempt";
     SetUrlIndex(next_url_index);
   } else {
-    LOG(INFO) << "Resetting the current URL index (" << GetUrlIndex() << ") to "
-              << "0 as we only have " << candidate_urls_.size()
-              << " candidate URL(s)";
+    LOG(INFO) << "Resetting the current URL index (" << url_index_ << ") to "
+              << "0 as we only have " << max_url_size << " candidate URL(s)";
     SetUrlIndex(0);
     IncrementPayloadAttemptNumber();
     IncrementFullPayloadAttemptNumber();
   }
 
   // If we have multiple URLs, record that we just switched to another one
-  if (candidate_urls_.size() > 1)
+  if (max_url_size > 1)
     SetUrlSwitchCount(url_switch_count_ + 1);
 
   // Whenever we update the URL index, we should also clear the URL failure
@@ -519,12 +522,14 @@
 
   if (using_p2p_for_downloading_) {
     current_download_source_ = kDownloadSourceHttpPeer;
-  } else if (GetUrlIndex() < candidate_urls_.size())  {
-    string current_url = candidate_urls_[GetUrlIndex()];
-    if (base::StartsWith(current_url, "https://",
-                         base::CompareCase::INSENSITIVE_ASCII)) {
+  } else if (payload_index_ < candidate_urls_.size() &&
+             candidate_urls_[payload_index_].size() != 0) {
+    const string& current_url = candidate_urls_[payload_index_][GetUrlIndex()];
+    if (base::StartsWith(
+            current_url, "https://", base::CompareCase::INSENSITIVE_ASCII)) {
       current_download_source_ = kDownloadSourceHttpsServer;
-    } else if (base::StartsWith(current_url, "http://",
+    } else if (base::StartsWith(current_url,
+                                "http://",
                                 base::CompareCase::INSENSITIVE_ASCII)) {
       current_download_source_ = kDownloadSourceHttpServer;
     }
@@ -569,7 +574,7 @@
 
   PayloadType payload_type = CalculatePayloadType();
 
-  int64_t payload_size = response_.size;
+  int64_t payload_size = GetPayloadSize();
 
   int64_t payload_bytes_downloaded = attempt_num_bytes_downloaded_;
 
@@ -715,7 +720,7 @@
 
   PayloadType payload_type = CalculatePayloadType();
 
-  int64_t payload_size = response_.size;
+  int64_t payload_size = GetPayloadSize();
 
   int attempt_count = GetPayloadAttemptNumber();
 
@@ -803,26 +808,32 @@
 }
 
 string PayloadState::CalculateResponseSignature() {
-  string response_sign = base::StringPrintf(
-      "NumURLs = %d\n", static_cast<int>(candidate_urls_.size()));
+  string response_sign;
+  for (size_t i = 0; i < response_.packages.size(); i++) {
+    const auto& package = response_.packages[i];
+    response_sign += base::StringPrintf(
+        "Payload %zu:\n"
+        "  Size = %ju\n"
+        "  Sha256 Hash = %s\n"
+        "  Metadata Size = %ju\n"
+        "  Metadata Signature = %s\n"
+        "  NumURLs = %zu\n",
+        i,
+        static_cast<uintmax_t>(package.size),
+        package.hash.c_str(),
+        static_cast<uintmax_t>(package.metadata_size),
+        package.metadata_signature.c_str(),
+        candidate_urls_[i].size());
 
-  for (size_t i = 0; i < candidate_urls_.size(); i++)
-    response_sign += base::StringPrintf("Candidate Url%d = %s\n",
-                                        static_cast<int>(i),
-                                        candidate_urls_[i].c_str());
+    for (size_t j = 0; j < candidate_urls_[i].size(); j++)
+      response_sign += base::StringPrintf(
+          "  Candidate Url%zu = %s\n", j, candidate_urls_[i][j].c_str());
+  }
 
   response_sign += base::StringPrintf(
-      "Payload Size = %ju\n"
-      "Payload Sha256 Hash = %s\n"
-      "Metadata Size = %ju\n"
-      "Metadata Signature = %s\n"
       "Is Delta Payload = %d\n"
       "Max Failure Count Per Url = %d\n"
       "Disable Payload Backoff = %d\n",
-      static_cast<uintmax_t>(response_.size),
-      response_.hash.c_str(),
-      static_cast<uintmax_t>(response_.metadata_size),
-      response_.metadata_signature.c_str(),
       response_.is_delta_payload,
       response_.max_failure_count_per_url,
       response_.disable_payload_backoff);
@@ -1172,20 +1183,22 @@
   }
 
   candidate_urls_.clear();
-  for (size_t i = 0; i < response_.payload_urls.size(); i++) {
-    string candidate_url = response_.payload_urls[i];
-    if (base::StartsWith(candidate_url, "http://",
-                         base::CompareCase::INSENSITIVE_ASCII) &&
-        !http_url_ok) {
-      continue;
+  for (const auto& package : response_.packages) {
+    candidate_urls_.emplace_back();
+    for (const string& candidate_url : package.payload_urls) {
+      if (base::StartsWith(
+              candidate_url, "http://", base::CompareCase::INSENSITIVE_ASCII) &&
+          !http_url_ok) {
+        continue;
+      }
+      candidate_urls_.back().push_back(candidate_url);
+      LOG(INFO) << "Candidate Url" << (candidate_urls_.back().size() - 1)
+                << ": " << candidate_url;
     }
-    candidate_urls_.push_back(candidate_url);
-    LOG(INFO) << "Candidate Url" << (candidate_urls_.size() - 1)
-              << ": " << candidate_url;
+    LOG(INFO) << "Found " << candidate_urls_.back().size() << " candidate URLs "
+              << "out of " << package.payload_urls.size()
+              << " URLs supplied in package " << candidate_urls_.size() - 1;
   }
-
-  LOG(INFO) << "Found " << candidate_urls_.size() << " candidate URLs "
-            << "out of " << response_.payload_urls.size() << " URLs supplied";
 }
 
 void PayloadState::CreateSystemUpdatedMarkerFile() {
@@ -1394,4 +1407,11 @@
   return true;
 }
 
+int64_t PayloadState::GetPayloadSize() {
+  int64_t payload_size = 0;
+  for (const auto& package : response_.packages)
+    payload_size += package.size;
+  return payload_size;
+}
+
 }  // namespace chromeos_update_engine