Support for processing multiple URLs in update_engine.

Main changes:
1. Added a new PayloadState class which encapsulates all the persisted
state we use for multiple URLs, back-off (TBD), etc.
2. Added support for handling multiple URLs stored in the OmahaResponse in
OmahaRequestAction and OmahaResponseHandlerAction code.
3. Added support for picking the right URL in OmahaResponseHandlerAction
and putting it in the install_plan. This way, the rest of the code that
uses the install_plan is oblivious to the presence of multiple URLs :-)
4. Added support for advancing to next URL when an update fails. The full
error classification is a new work item (chromium-os:37206). Right now,
it's a basic round-robin on every error.
5. Updated the conditions for determining when hash checks are mandatory.
Previously since there was only one URL, if it was HTTPS, the checks were
waived. Now, even if there's one HTTP URL, we make hash checks mandatory
even if other HTTPS URLs are present.

6. Added new unit tests for PayloadState and the new logic added to other
places.

Noisy changes:
1. Instead of passing PrefsInterface to OmahaRequestAction and
OmahaResponseHandlerAction, we're now passing SystemState which will now
contain PrefsInterface and the newly added PayloadState object that these
actions need to do their work.
2. Renamed a bunch of setters/getters to set_x() and x() instead of SetX()
and GetX() methods - this was pending from Gilad's old CR. As I'm
adding new methods in the correct style, I went ahead and fixed it to
avoid the confusing styles.
3. Updated all existing unit tests to reflect these changes.

BUG=chromium-os:36807
TEST=All Single/Multiple URL scenarios work fine on my ZGB as expected.
TEST=Old and new unit tests run fine.

Change-Id: Id31f9ccb220471f3ec3a475f624dc03c16119144
Reviewed-on: https://gerrit.chromium.org/gerrit/39638
Commit-Ready: Jay Srinivasan <jaysri@chromium.org>
Reviewed-by: Jay Srinivasan <jaysri@chromium.org>
Tested-by: Jay Srinivasan <jaysri@chromium.org>
diff --git a/payload_state.cc b/payload_state.cc
new file mode 100644
index 0000000..b153fa7
--- /dev/null
+++ b/payload_state.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/payload_state.h"
+
+#include <base/logging.h>
+#include <base/stringprintf.h>
+
+#include "update_engine/omaha_request_action.h"
+#include "update_engine/prefs.h"
+
+using std::string;
+
+namespace chromeos_update_engine {
+
+// Returns a string containing that subset of the fields from the OmahaResponse
+// which we're interested in persisting for the purpose of detecting whether
+// we should clear the rest of the payload state when we get a new
+// OmahaResponse.
+static string GetFilteredResponse(const OmahaResponse& response) {
+  string mini_response = StringPrintf("NumURLs = %d\n",
+                                      response.payload_urls.size());
+
+  for (size_t i = 0; i < response.payload_urls.size(); i++)
+    mini_response += StringPrintf("Url%d = %s\n",
+                                  i, response.payload_urls[i].c_str());
+
+  mini_response += StringPrintf("Payload Size = %llu\n"
+                                "Payload Sha256 Hash = %s\n"
+                                "Metadata Size = %llu\n"
+                                "Metadata Signature = %s\n",
+                                response.size,
+                                response.hash.c_str(),
+                                response.metadata_size,
+                                response.metadata_signature.c_str());
+  return mini_response;
+}
+
+bool PayloadState::Initialize(PrefsInterface* prefs) {
+  CHECK(prefs);
+  prefs_ = prefs;
+  LoadResponse();
+  LoadUrlIndex();
+  LogPayloadState();
+  return true;
+}
+
+void PayloadState::LogPayloadState() {
+  LOG(INFO) << "Current Payload State:\n"
+            << "Current Response = \n" << response_
+            << "Current URL Index = " << url_index_;
+}
+
+void PayloadState::SetResponse(const OmahaResponse& omaha_response) {
+  CHECK(prefs_);
+  num_urls_ = omaha_response.payload_urls.size();
+  string new_response = GetFilteredResponse(omaha_response);
+  bool has_response_changed = (response_ != new_response);
+  response_ = new_response;
+  LOG(INFO) << "Stored Response = \n" << response_;
+  prefs_->SetString(kPrefsCurrentResponse, response_);
+
+  if (has_response_changed) {
+    LOG(INFO) << "Resetting all payload state as this is a new response";
+    SetUrlIndex(0);
+  }
+}
+
+void PayloadState::UpdateFailed(ActionExitCode error) {
+  LOG(INFO) << "Updating payload state for error code: " << error;
+
+  if (!num_urls_) {
+    // Since we don't persist num_urls_, it's possible that we get an error in
+    // our communication to Omaha before even OmahaRequestAction code had a
+    // chance to call SetResponse (which sets num_urls_). So we should not
+    // advance the url_index_ in such cases.
+    LOG(INFO) << "Ignoring failures until we get a valid Omaha response.";
+    return;
+  }
+
+  // chromium-os:37206: Classify the errors and advance the URL index at
+  // different rates for different errors in the next CL. Until then, advance
+  // URL index on every single error.
+  uint32_t next_url_index = GetUrlIndex() + 1;
+  if (next_url_index < num_urls_) {
+    LOG(INFO) << "Advancing the URL index for next attempt";
+  } else {
+    LOG(INFO) << "Resetting the current URL index (" << GetUrlIndex() << ") to "
+              << "0 as we only have " << num_urls_ << " URL(s)";
+    next_url_index = 0;
+
+    // TODO(jaysri): This is the place where we should increment the
+    // payload_attempt_number so that we can back-off appropriately.
+  }
+
+  SetUrlIndex(next_url_index);
+}
+
+string PayloadState::LoadResponse() {
+  CHECK(prefs_);
+  string stored_value;
+  if (prefs_->Exists(kPrefsCurrentResponse) &&
+      prefs_->GetString(kPrefsCurrentResponse, &stored_value)) {
+    response_ = stored_value;
+  }
+  return response_;
+}
+
+uint32_t PayloadState::LoadUrlIndex() {
+  CHECK(prefs_);
+  int64_t stored_value;
+  if (prefs_->Exists(kPrefsCurrentUrlIndex) &&
+      prefs_->GetInt64(kPrefsCurrentUrlIndex, &stored_value)) {
+    url_index_ = stored_value;
+  }
+  return url_index_;
+}
+
+void PayloadState::SetUrlIndex(uint32_t url_index) {
+  CHECK(prefs_);
+  // TODO(jaysri): When we implement failure count, make sure to reset
+  // the failure count when url index changes.
+  url_index_ = url_index;
+  LOG(INFO) << "Current URL Index = " << url_index_;
+  prefs_->SetInt64(kPrefsCurrentUrlIndex, url_index_);
+}
+
+}  // namespace chromeos_update_engine