AU: Resume interrupted update attempts.

BUG=7390,7520
TEST=unit tests

Change-Id: I9baf72aa444dd855409f865f03fb665e91f8d03d

Review URL: http://codereview.chromium.org/3620013
diff --git a/update_attempter.cc b/update_attempter.cc
index 2db91a6..f408d82 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -10,8 +10,8 @@
 #endif  // _POSIX_C_SOURCE
 #include <time.h>
 
-#include <tr1/memory>
 #include <string>
+#include <tr1/memory>
 #include <vector>
 
 #include <glib.h>
@@ -21,6 +21,7 @@
 #include "update_engine/download_action.h"
 #include "update_engine/filesystem_copier_action.h"
 #include "update_engine/libcurl_http_fetcher.h"
+#include "update_engine/multi_http_fetcher.h"
 #include "update_engine/omaha_request_action.h"
 #include "update_engine/omaha_request_params.h"
 #include "update_engine/omaha_response_handler_action.h"
@@ -31,6 +32,7 @@
 
 using base::TimeDelta;
 using base::TimeTicks;
+using std::make_pair;
 using std::tr1::shared_ptr;
 using std::string;
 using std::vector;
@@ -153,7 +155,7 @@
                                  OmahaEvent::kTypeUpdateDownloadStarted),
                              new LibcurlHttpFetcher));
   shared_ptr<DownloadAction> download_action(
-      new DownloadAction(prefs_, new LibcurlHttpFetcher));
+      new DownloadAction(prefs_, new MultiHttpFetcher<LibcurlHttpFetcher>));
   shared_ptr<OmahaRequestAction> download_finished_action(
       new OmahaRequestAction(prefs_,
                              omaha_request_params_,
@@ -174,6 +176,7 @@
 
   download_action->set_delegate(this);
   response_handler_action_ = response_handler_action;
+  download_action_ = download_action;
 
   actions_.push_back(shared_ptr<AbstractAction>(update_check_action));
   actions_.push_back(shared_ptr<AbstractAction>(response_handler_action));
@@ -254,9 +257,10 @@
   }
 
   if (code == kActionCodeSuccess) {
-    SetStatusAndNotify(UPDATE_STATUS_UPDATED_NEED_REBOOT);
     utils::WriteFile(kUpdateCompletedMarker, "", 0);
     prefs_->SetInt64(kPrefsDeltaUpdateFailures, 0);
+    DeltaPerformer::ResetUpdateProgress(prefs_, false);
+    SetStatusAndNotify(UPDATE_STATUS_UPDATED_NEED_REBOOT);
 
     // Report the time it took to update the system.
     int64_t update_time = time(NULL) - last_checked_time_;
@@ -327,20 +331,18 @@
   }
   // Find out which action completed.
   if (type == OmahaResponseHandlerAction::StaticType()) {
-    // Note that the status will be updated to DOWNLOADING when some
-    // bytes get actually downloaded from the server and the
-    // BytesReceived callback is invoked. This avoids notifying the
-    // user that a download has started in cases when the server and
-    // the client are unable to initiate the download.
-    OmahaResponseHandlerAction* omaha_response_handler_action =
-        dynamic_cast<OmahaResponseHandlerAction*>(action);
-    CHECK(omaha_response_handler_action);
-    const InstallPlan& plan = omaha_response_handler_action->install_plan();
+    // Note that the status will be updated to DOWNLOADING when some bytes get
+    // actually downloaded from the server and the BytesReceived callback is
+    // invoked. This avoids notifying the user that a download has started in
+    // cases when the server and the client are unable to initiate the download.
+    CHECK(action == response_handler_action_.get());
+    const InstallPlan& plan = response_handler_action_->install_plan();
     last_checked_time_ = time(NULL);
     // TODO(adlr): put version in InstallPlan
     new_version_ = "0.0.0.0";
     new_size_ = plan.size;
     is_full_update_ = plan.is_full_update;
+    SetupDownload();
     SetupPriorityManagement();
   } else if (type == DownloadAction::StaticType()) {
     SetStatusAndNotify(UPDATE_STATUS_FINALIZING);
@@ -517,6 +519,11 @@
 
 void UpdateAttempter::MarkDeltaUpdateFailure() {
   CHECK(!is_full_update_);
+  // If a delta update fails after the downloading phase, don't try to resume it
+  // the next time.
+  if (status_ > UPDATE_STATUS_DOWNLOADING) {
+    DeltaPerformer::ResetUpdateProgress(prefs_, false);
+  }
   int64_t delta_failures;
   if (!prefs_->GetInt64(kPrefsDeltaUpdateFailures, &delta_failures) ||
       delta_failures < 0) {
@@ -525,4 +532,22 @@
   prefs_->SetInt64(kPrefsDeltaUpdateFailures, ++delta_failures);
 }
 
+void UpdateAttempter::SetupDownload() {
+  MultiHttpFetcher<LibcurlHttpFetcher>* fetcher =
+      dynamic_cast<MultiHttpFetcher<LibcurlHttpFetcher>*>(
+          download_action_->http_fetcher());
+  MultiHttpFetcher<LibcurlHttpFetcher>::RangesVect ranges;
+  if (response_handler_action_->install_plan().is_resume) {
+    int64_t manifest_metadata_size = 0;
+    prefs_->GetInt64(kPrefsManifestMetadataSize, &manifest_metadata_size);
+    int64_t next_data_offset = 0;
+    prefs_->GetInt64(kPrefsUpdateStateNextDataOffset, &next_data_offset);
+    ranges.push_back(make_pair(0, manifest_metadata_size));
+    ranges.push_back(make_pair(manifest_metadata_size + next_data_offset, -1));
+  } else {
+    ranges.push_back(make_pair(0, -1));
+  }
+  fetcher->set_ranges(ranges);
+}
+
 }  // namespace chromeos_update_engine