Parse postinstall program progress updates.

In Android postinstall is expected to take a long time in common cases.
This patch allows the postinstall program to report back to the updater
a progress indication, which will then be forwarded to all the clients
listening. These progress updates are part of the FINALIZING status.

Bug: 27880754
TEST=Added unittests. Deployed an update to an edison-eng and post-install reported progress back with the postinstall_example.

Change-Id: I35f96b92f090219c54cca48d8ab07c54cf8b4ab1
diff --git a/update_attempter.cc b/update_attempter.cc
index 7194402..81f2ab0 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -88,6 +88,10 @@
 namespace {
 const int kMaxConsecutiveObeyProxyRequests = 20;
 
+// Minimum threshold to broadcast an status update in progress and time.
+const double kBroadcastThresholdProgress = 0.01;  // 1%
+const int kBroadcastThresholdSeconds = 10;
+
 // By default autest bypasses scattering. If we want to test scattering,
 // use kScheduledAUTestURLRequest. The URL used is same in both cases, but
 // different params are passed to CheckForUpdate().
@@ -582,6 +586,7 @@
     InstallPlanAction* previous_action) {
   shared_ptr<PostinstallRunnerAction> postinstall_runner_action(
       new PostinstallRunnerAction(system_state_->boot_control()));
+  postinstall_runner_action->set_delegate(this);
   actions_.push_back(shared_ptr<AbstractAction>(postinstall_runner_action));
   BondActions(previous_action,
               postinstall_runner_action.get());
@@ -1069,17 +1074,14 @@
   // from a given URL for the URL skipping logic.
   system_state_->payload_state()->DownloadProgress(bytes_progressed);
 
-  double progress = static_cast<double>(bytes_received) /
-      static_cast<double>(total);
-  // Self throttle based on progress. Also send notifications if
-  // progress is too slow.
-  const double kDeltaPercent = 0.01;  // 1%
-  if (status_ != UpdateStatus::DOWNLOADING ||
-      bytes_received == total ||
-      progress - download_progress_ >= kDeltaPercent ||
-      TimeTicks::Now() - last_notify_time_ >= TimeDelta::FromSeconds(10)) {
+  double progress = 0;
+  if (total)
+    progress = static_cast<double>(bytes_received) / static_cast<double>(total);
+  if (status_ != UpdateStatus::DOWNLOADING || bytes_received == total) {
     download_progress_ = progress;
     SetStatusAndNotify(UpdateStatus::DOWNLOADING);
+  } else {
+    ProgressUpdate(progress);
   }
 }
 
@@ -1125,6 +1127,18 @@
   return true;
 }
 
+void UpdateAttempter::ProgressUpdate(double progress) {
+  // Self throttle based on progress. Also send notifications if progress is
+  // too slow.
+  if (progress == 1.0 ||
+      progress - download_progress_ >= kBroadcastThresholdProgress ||
+      TimeTicks::Now() - last_notify_time_ >=
+          TimeDelta::FromSeconds(kBroadcastThresholdSeconds)) {
+    download_progress_ = progress;
+    BroadcastStatus();
+  }
+}
+
 bool UpdateAttempter::ResetStatus() {
   LOG(INFO) << "Attempting to reset state from "
             << UpdateStatusToString(status_) << " to UpdateStatus::IDLE";