update_attempter.cc revision 58dd1348495a13a59edf630f54b1d236ee869339
1// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/update_attempter.h"
6
7// From 'man clock_gettime': feature test macro: _POSIX_C_SOURCE >= 199309L
8#ifndef _POSIX_C_SOURCE
9#define _POSIX_C_SOURCE 199309L
10#endif  // _POSIX_C_SOURCE
11#include <time.h>
12
13#include <string>
14#include <tr1/memory>
15#include <vector>
16
17#include <base/rand_util.h>
18#include <glib.h>
19#include <metrics/metrics_library.h>
20
21#include "update_engine/dbus_service.h"
22#include "update_engine/download_action.h"
23#include "update_engine/filesystem_copier_action.h"
24#include "update_engine/libcurl_http_fetcher.h"
25#include "update_engine/multi_range_http_fetcher.h"
26#include "update_engine/omaha_request_action.h"
27#include "update_engine/omaha_request_params.h"
28#include "update_engine/omaha_response_handler_action.h"
29#include "update_engine/postinstall_runner_action.h"
30#include "update_engine/prefs_interface.h"
31#include "update_engine/subprocess.h"
32#include "update_engine/update_check_scheduler.h"
33
34using base::TimeDelta;
35using base::TimeTicks;
36using google::protobuf::NewPermanentCallback;
37using std::make_pair;
38using std::tr1::shared_ptr;
39using std::string;
40using std::vector;
41
42namespace chromeos_update_engine {
43
44const int UpdateAttempter::kMaxDeltaUpdateFailures = 3;
45
46const char* kUpdateCompletedMarker =
47    "/var/run/update_engine_autoupdate_completed";
48
49namespace {
50const int kMaxConsecutiveObeyProxyRequests = 20;
51}  // namespace {}
52
53const char* UpdateStatusToString(UpdateStatus status) {
54  switch (status) {
55    case UPDATE_STATUS_IDLE:
56      return "UPDATE_STATUS_IDLE";
57    case UPDATE_STATUS_CHECKING_FOR_UPDATE:
58      return "UPDATE_STATUS_CHECKING_FOR_UPDATE";
59    case UPDATE_STATUS_UPDATE_AVAILABLE:
60      return "UPDATE_STATUS_UPDATE_AVAILABLE";
61    case UPDATE_STATUS_DOWNLOADING:
62      return "UPDATE_STATUS_DOWNLOADING";
63    case UPDATE_STATUS_VERIFYING:
64      return "UPDATE_STATUS_VERIFYING";
65    case UPDATE_STATUS_FINALIZING:
66      return "UPDATE_STATUS_FINALIZING";
67    case UPDATE_STATUS_UPDATED_NEED_REBOOT:
68      return "UPDATE_STATUS_UPDATED_NEED_REBOOT";
69    case UPDATE_STATUS_REPORTING_ERROR_EVENT:
70      return "UPDATE_STATUS_REPORTING_ERROR_EVENT";
71    default:
72      return "unknown status";
73  }
74}
75
76// Turns a generic kActionCodeError to a generic error code specific
77// to |action| (e.g., kActionCodeFilesystemCopierError). If |code| is
78// not kActionCodeError, or the action is not matched, returns |code|
79// unchanged.
80ActionExitCode GetErrorCodeForAction(AbstractAction* action,
81                                     ActionExitCode code) {
82  if (code != kActionCodeError)
83    return code;
84
85  const string type = action->Type();
86  if (type == OmahaRequestAction::StaticType())
87    return kActionCodeOmahaRequestError;
88  if (type == OmahaResponseHandlerAction::StaticType())
89    return kActionCodeOmahaResponseHandlerError;
90  if (type == FilesystemCopierAction::StaticType())
91    return kActionCodeFilesystemCopierError;
92  if (type == PostinstallRunnerAction::StaticType())
93    return kActionCodePostinstallRunnerError;
94
95  return code;
96}
97
98UpdateAttempter::UpdateAttempter(PrefsInterface* prefs,
99                                 MetricsLibraryInterface* metrics_lib,
100                                 DbusGlibInterface* dbus_iface)
101    : processor_(new ActionProcessor()),
102      dbus_service_(NULL),
103      prefs_(prefs),
104      metrics_lib_(metrics_lib),
105      update_check_scheduler_(NULL),
106      fake_update_success_(false),
107      http_response_code_(0),
108      priority_(utils::kProcessPriorityNormal),
109      manage_priority_source_(NULL),
110      download_active_(false),
111      status_(UPDATE_STATUS_IDLE),
112      download_progress_(0.0),
113      last_checked_time_(0),
114      new_version_("0.0.0.0"),
115      new_size_(0),
116      is_full_update_(false),
117      proxy_manual_checks_(0),
118      obeying_proxies_(true),
119      chrome_proxy_resolver_(dbus_iface),
120      updated_boot_flags_(false),
121      update_boot_flags_running_(false),
122      start_action_processor_(false) {
123  if (utils::FileExists(kUpdateCompletedMarker))
124    status_ = UPDATE_STATUS_UPDATED_NEED_REBOOT;
125}
126
127UpdateAttempter::~UpdateAttempter() {
128  CleanupPriorityManagement();
129}
130
131void UpdateAttempter::Update(const std::string& app_version,
132                             const std::string& omaha_url,
133                             bool obey_proxies) {
134  chrome_proxy_resolver_.Init();
135  fake_update_success_ = false;
136  if (status_ == UPDATE_STATUS_UPDATED_NEED_REBOOT) {
137    // Although we have applied an update, we still want to ping Omaha
138    // to ensure the number of active statistics is accurate.
139    LOG(INFO) << "Not updating b/c we already updated and we're waiting for "
140              << "reboot, we'll ping Omaha instead";
141    PingOmaha();
142    return;
143  }
144  if (status_ != UPDATE_STATUS_IDLE) {
145    // Update in progress. Do nothing
146    return;
147  }
148  http_response_code_ = 0;
149  if (!omaha_request_params_.Init(app_version, omaha_url)) {
150    LOG(ERROR) << "Unable to initialize Omaha request device params.";
151    return;
152  }
153
154  obeying_proxies_ = true;
155  if (obey_proxies || proxy_manual_checks_ == 0) {
156    LOG(INFO) << "forced to obey proxies";
157    // If forced to obey proxies, every 20th request will not use proxies
158    proxy_manual_checks_++;
159    LOG(INFO) << "proxy manual checks: " << proxy_manual_checks_;
160    if (proxy_manual_checks_ >= kMaxConsecutiveObeyProxyRequests) {
161      proxy_manual_checks_ = 0;
162      obeying_proxies_ = false;
163    }
164  } else if (base::RandInt(0, 4) == 0) {
165    obeying_proxies_ = false;
166  }
167  LOG_IF(INFO, !obeying_proxies_) << "To help ensure updates work, this update "
168      "check we are ignoring the proxy settings and using "
169      "direct connections.";
170
171  DisableDeltaUpdateIfNeeded();
172  CHECK(!processor_->IsRunning());
173  processor_->set_delegate(this);
174
175  // Actions:
176  LibcurlHttpFetcher* update_check_fetcher =
177      new LibcurlHttpFetcher(GetProxyResolver());
178  // Try harder to connect to the network. See comment in
179  // libcurl_http_fetcher.cc.
180  update_check_fetcher->set_no_network_max_retries(3);
181  shared_ptr<OmahaRequestAction> update_check_action(
182      new OmahaRequestAction(prefs_,
183                             omaha_request_params_,
184                             NULL,
185                             update_check_fetcher,  // passes ownership
186                             false));
187  shared_ptr<OmahaResponseHandlerAction> response_handler_action(
188      new OmahaResponseHandlerAction(prefs_));
189  shared_ptr<FilesystemCopierAction> filesystem_copier_action(
190      new FilesystemCopierAction(false, false));
191  shared_ptr<FilesystemCopierAction> kernel_filesystem_copier_action(
192      new FilesystemCopierAction(true, false));
193  shared_ptr<OmahaRequestAction> download_started_action(
194      new OmahaRequestAction(prefs_,
195                             omaha_request_params_,
196                             new OmahaEvent(
197                                 OmahaEvent::kTypeUpdateDownloadStarted),
198                             new LibcurlHttpFetcher(GetProxyResolver()),
199                             false));
200  shared_ptr<DownloadAction> download_action(
201      new DownloadAction(prefs_, new MultiRangeHTTPFetcher(
202          new LibcurlHttpFetcher(GetProxyResolver()))));
203  // This action is always initially in place to warn OS vendor of a
204  // signature failure.  If it's not needed, it will be told to skip.
205  shared_ptr<OmahaRequestAction> download_signature_warning(
206      new OmahaRequestAction(
207          prefs_,
208          omaha_request_params_,
209          new OmahaEvent(
210              OmahaEvent::kTypeUpdateDownloadFinished,
211              OmahaEvent::kResultError,
212              kActionCodeDownloadPayloadPubKeyVerificationError),
213          new LibcurlHttpFetcher(GetProxyResolver()),
214          false));
215  download_action->set_skip_reporting_signature_fail(
216      NewPermanentCallback(download_signature_warning.get(),
217                           &OmahaRequestAction::set_should_skip,
218                           true));
219  shared_ptr<OmahaRequestAction> download_finished_action(
220      new OmahaRequestAction(prefs_,
221                             omaha_request_params_,
222                             new OmahaEvent(
223                                 OmahaEvent::kTypeUpdateDownloadFinished),
224                             new LibcurlHttpFetcher(GetProxyResolver()),
225                             false));
226  shared_ptr<FilesystemCopierAction> filesystem_verifier_action(
227      new FilesystemCopierAction(false, true));
228  shared_ptr<FilesystemCopierAction> kernel_filesystem_verifier_action(
229      new FilesystemCopierAction(true, true));
230  shared_ptr<PostinstallRunnerAction> postinstall_runner_action(
231      new PostinstallRunnerAction);
232  shared_ptr<OmahaRequestAction> update_complete_action(
233      new OmahaRequestAction(prefs_,
234                             omaha_request_params_,
235                             new OmahaEvent(OmahaEvent::kTypeUpdateComplete),
236                             new LibcurlHttpFetcher(GetProxyResolver()),
237                             false));
238
239  download_action->set_delegate(this);
240  response_handler_action_ = response_handler_action;
241  download_action_ = download_action;
242
243  actions_.push_back(shared_ptr<AbstractAction>(update_check_action));
244  actions_.push_back(shared_ptr<AbstractAction>(response_handler_action));
245  actions_.push_back(shared_ptr<AbstractAction>(filesystem_copier_action));
246  actions_.push_back(shared_ptr<AbstractAction>(
247      kernel_filesystem_copier_action));
248  actions_.push_back(shared_ptr<AbstractAction>(download_started_action));
249  actions_.push_back(shared_ptr<AbstractAction>(download_action));
250  actions_.push_back(shared_ptr<AbstractAction>(download_signature_warning));
251  actions_.push_back(shared_ptr<AbstractAction>(download_finished_action));
252  actions_.push_back(shared_ptr<AbstractAction>(filesystem_verifier_action));
253  actions_.push_back(shared_ptr<AbstractAction>(
254      kernel_filesystem_verifier_action));
255  actions_.push_back(shared_ptr<AbstractAction>(postinstall_runner_action));
256  actions_.push_back(shared_ptr<AbstractAction>(update_complete_action));
257
258  // Enqueue the actions
259  for (vector<shared_ptr<AbstractAction> >::iterator it = actions_.begin();
260       it != actions_.end(); ++it) {
261    processor_->EnqueueAction(it->get());
262  }
263
264  // Bond them together. We have to use the leaf-types when calling
265  // BondActions().
266  BondActions(update_check_action.get(),
267              response_handler_action.get());
268  BondActions(response_handler_action.get(),
269              filesystem_copier_action.get());
270  BondActions(filesystem_copier_action.get(),
271              kernel_filesystem_copier_action.get());
272  BondActions(kernel_filesystem_copier_action.get(),
273              download_action.get());
274  BondActions(download_action.get(),
275              filesystem_verifier_action.get());
276  BondActions(filesystem_verifier_action.get(),
277              kernel_filesystem_verifier_action.get());
278  BondActions(kernel_filesystem_verifier_action.get(),
279              postinstall_runner_action.get());
280
281  SetStatusAndNotify(UPDATE_STATUS_CHECKING_FOR_UPDATE);
282
283  // Just in case we didn't update boot flags yet, make sure they're updated
284  // before any update processing starts.
285  start_action_processor_ = true;
286  UpdateBootFlags();
287}
288
289void UpdateAttempter::CheckForUpdate(const std::string& app_version,
290                                     const std::string& omaha_url) {
291  if (status_ != UPDATE_STATUS_IDLE) {
292    LOG(INFO) << "Check for update requested, but status is "
293              << UpdateStatusToString(status_) << ", so not checking.";
294    return;
295  }
296  Update(app_version, omaha_url, true);
297}
298
299bool UpdateAttempter::RebootIfNeeded() {
300  if (status_ != UPDATE_STATUS_UPDATED_NEED_REBOOT) {
301    LOG(INFO) << "Reboot requested, but status is "
302              << UpdateStatusToString(status_) << ", so not rebooting.";
303    return false;
304  }
305  TEST_AND_RETURN_FALSE(utils::Reboot());
306  return true;
307}
308
309// Delegate methods:
310void UpdateAttempter::ProcessingDone(const ActionProcessor* processor,
311                                     ActionExitCode code) {
312  CHECK(response_handler_action_);
313  LOG(INFO) << "Processing Done.";
314  actions_.clear();
315
316  // Reset process priority back to normal.
317  CleanupPriorityManagement();
318
319  if (status_ == UPDATE_STATUS_REPORTING_ERROR_EVENT) {
320    LOG(INFO) << "Error event sent.";
321    SetStatusAndNotify(UPDATE_STATUS_IDLE);
322    if (!fake_update_success_) {
323      return;
324    }
325    LOG(INFO) << "Booted from FW B and tried to install new firmware, "
326        "so requesting reboot from user.";
327  }
328
329  if (code == kActionCodeSuccess) {
330    utils::WriteFile(kUpdateCompletedMarker, "", 0);
331    prefs_->SetInt64(kPrefsDeltaUpdateFailures, 0);
332    prefs_->SetString(kPrefsPreviousVersion, omaha_request_params_.app_version);
333    DeltaPerformer::ResetUpdateProgress(prefs_, false);
334    SetStatusAndNotify(UPDATE_STATUS_UPDATED_NEED_REBOOT);
335
336    // Report the time it took to update the system.
337    int64_t update_time = time(NULL) - last_checked_time_;
338    if (!fake_update_success_)
339      metrics_lib_->SendToUMA("Installer.UpdateTime",
340                              static_cast<int>(update_time),  // sample
341                              1,  // min = 1 second
342                              20 * 60,  // max = 20 minutes
343                              50);  // buckets
344    return;
345  }
346
347  if (ScheduleErrorEventAction()) {
348    return;
349  }
350  LOG(INFO) << "No update.";
351  SetStatusAndNotify(UPDATE_STATUS_IDLE);
352}
353
354void UpdateAttempter::ProcessingStopped(const ActionProcessor* processor) {
355  // Reset process priority back to normal.
356  CleanupPriorityManagement();
357  download_progress_ = 0.0;
358  SetStatusAndNotify(UPDATE_STATUS_IDLE);
359  actions_.clear();
360  error_event_.reset(NULL);
361}
362
363// Called whenever an action has finished processing, either successfully
364// or otherwise.
365void UpdateAttempter::ActionCompleted(ActionProcessor* processor,
366                                      AbstractAction* action,
367                                      ActionExitCode code) {
368  // Reset download progress regardless of whether or not the download
369  // action succeeded. Also, get the response code from HTTP request
370  // actions (update download as well as the initial update check
371  // actions).
372  const string type = action->Type();
373  if (type == DownloadAction::StaticType()) {
374    download_progress_ = 0.0;
375    DownloadAction* download_action = dynamic_cast<DownloadAction*>(action);
376    http_response_code_ = download_action->GetHTTPResponseCode();
377  } else if (type == OmahaRequestAction::StaticType()) {
378    OmahaRequestAction* omaha_request_action =
379        dynamic_cast<OmahaRequestAction*>(action);
380    // If the request is not an event, then it's the update-check.
381    if (!omaha_request_action->IsEvent()) {
382      http_response_code_ = omaha_request_action->GetHTTPResponseCode();
383      // Forward the server-dictated poll interval to the update check
384      // scheduler, if any.
385      if (update_check_scheduler_) {
386        update_check_scheduler_->set_poll_interval(
387            omaha_request_action->GetOutputObject().poll_interval);
388      }
389    }
390  }
391  if (code != kActionCodeSuccess) {
392    // If this was a delta update attempt and the current state is at or past
393    // the download phase, count the failure in case a switch to full update
394    // becomes necessary. Ignore network transfer timeouts and failures.
395    if (status_ >= UPDATE_STATUS_DOWNLOADING &&
396        !is_full_update_ &&
397        code != kActionCodeDownloadTransferError) {
398      MarkDeltaUpdateFailure();
399    }
400    // On failure, schedule an error event to be sent to Omaha.
401    CreatePendingErrorEvent(action, code);
402    return;
403  }
404  // Find out which action completed.
405  if (type == OmahaResponseHandlerAction::StaticType()) {
406    // Note that the status will be updated to DOWNLOADING when some bytes get
407    // actually downloaded from the server and the BytesReceived callback is
408    // invoked. This avoids notifying the user that a download has started in
409    // cases when the server and the client are unable to initiate the download.
410    CHECK(action == response_handler_action_.get());
411    const InstallPlan& plan = response_handler_action_->install_plan();
412    last_checked_time_ = time(NULL);
413    // TODO(adlr): put version in InstallPlan
414    new_version_ = "0.0.0.0";
415    new_size_ = plan.size;
416    is_full_update_ = plan.is_full_update;
417    SetupDownload();
418    SetupPriorityManagement();
419    SetStatusAndNotify(UPDATE_STATUS_UPDATE_AVAILABLE);
420  } else if (type == DownloadAction::StaticType()) {
421    SetStatusAndNotify(UPDATE_STATUS_FINALIZING);
422  }
423}
424
425// Stop updating. An attempt will be made to record status to the disk
426// so that updates can be resumed later.
427void UpdateAttempter::Terminate() {
428  // TODO(adlr): implement this method.
429  NOTIMPLEMENTED();
430}
431
432// Try to resume from a previously Terminate()d update.
433void UpdateAttempter::ResumeUpdating() {
434  // TODO(adlr): implement this method.
435  NOTIMPLEMENTED();
436}
437
438void UpdateAttempter::SetDownloadStatus(bool active) {
439  download_active_ = active;
440  LOG(INFO) << "Download status: " << (active ? "active" : "inactive");
441}
442
443void UpdateAttempter::BytesReceived(uint64_t bytes_received, uint64_t total) {
444  if (!download_active_) {
445    LOG(ERROR) << "BytesReceived called while not downloading.";
446    return;
447  }
448  double progress = static_cast<double>(bytes_received) /
449      static_cast<double>(total);
450  // Self throttle based on progress. Also send notifications if
451  // progress is too slow.
452  const double kDeltaPercent = 0.01;  // 1%
453  if (status_ != UPDATE_STATUS_DOWNLOADING ||
454      bytes_received == total ||
455      progress - download_progress_ >= kDeltaPercent ||
456      TimeTicks::Now() - last_notify_time_ >= TimeDelta::FromSeconds(10)) {
457    download_progress_ = progress;
458    SetStatusAndNotify(UPDATE_STATUS_DOWNLOADING);
459  }
460}
461
462bool UpdateAttempter::GetStatus(int64_t* last_checked_time,
463                                double* progress,
464                                std::string* current_operation,
465                                std::string* new_version,
466                                int64_t* new_size) {
467  *last_checked_time = last_checked_time_;
468  *progress = download_progress_;
469  *current_operation = UpdateStatusToString(status_);
470  *new_version = new_version_;
471  *new_size = new_size_;
472  return true;
473}
474
475void UpdateAttempter::UpdateBootFlags() {
476  if (update_boot_flags_running_) {
477    LOG(INFO) << "Update boot flags running, nothing to do.";
478    return;
479  }
480  if (updated_boot_flags_) {
481    LOG(INFO) << "Already updated boot flags. Skipping.";
482    if (start_action_processor_) {
483      ScheduleProcessingStart();
484    }
485    return;
486  }
487  // This is purely best effort. Failures should be logged by Subprocess. Run
488  // the script asynchronously to avoid blocking the event loop regardless of
489  // the script runtime.
490  update_boot_flags_running_ = true;
491  LOG(INFO) << "Updating boot flags...";
492  vector<string> cmd(1, "/usr/sbin/chromeos-setgoodkernel");
493  if (!Subprocess::Get().Exec(cmd, StaticCompleteUpdateBootFlags, this)) {
494    CompleteUpdateBootFlags(1);
495  }
496}
497
498void UpdateAttempter::CompleteUpdateBootFlags(int return_code) {
499  update_boot_flags_running_ = false;
500  updated_boot_flags_ = true;
501  if (start_action_processor_) {
502    ScheduleProcessingStart();
503  }
504}
505
506void UpdateAttempter::StaticCompleteUpdateBootFlags(
507    int return_code,
508    const std::string& output,
509    void* p) {
510  reinterpret_cast<UpdateAttempter*>(p)->CompleteUpdateBootFlags(return_code);
511}
512
513void UpdateAttempter::SetStatusAndNotify(UpdateStatus status) {
514  status_ = status;
515  if (update_check_scheduler_) {
516    update_check_scheduler_->SetUpdateStatus(status_);
517  }
518  if (!dbus_service_)
519    return;
520  last_notify_time_ = TimeTicks::Now();
521  update_engine_service_emit_status_update(
522      dbus_service_,
523      last_checked_time_,
524      download_progress_,
525      UpdateStatusToString(status_),
526      new_version_.c_str(),
527      new_size_);
528}
529
530void UpdateAttempter::CreatePendingErrorEvent(AbstractAction* action,
531                                              ActionExitCode code) {
532  if (error_event_.get()) {
533    // This shouldn't really happen.
534    LOG(WARNING) << "There's already an existing pending error event.";
535    return;
536  }
537
538  // For now assume that a generic Omaha response action failure means that
539  // there's no update so don't send an event. Also, double check that the
540  // failure has not occurred while sending an error event -- in which case
541  // don't schedule another. This shouldn't really happen but just in case...
542  if ((action->Type() == OmahaResponseHandlerAction::StaticType() &&
543       code == kActionCodeError) ||
544      status_ == UPDATE_STATUS_REPORTING_ERROR_EVENT) {
545    return;
546  }
547
548  code = GetErrorCodeForAction(action, code);
549  fake_update_success_ = code == kActionCodePostinstallBootedFromFirmwareB;
550  error_event_.reset(new OmahaEvent(OmahaEvent::kTypeUpdateComplete,
551                                    OmahaEvent::kResultError,
552                                    code));
553}
554
555bool UpdateAttempter::ScheduleErrorEventAction() {
556  if (error_event_.get() == NULL)
557    return false;
558
559  LOG(INFO) << "Update failed -- reporting the error event.";
560  shared_ptr<OmahaRequestAction> error_event_action(
561      new OmahaRequestAction(prefs_,
562                             omaha_request_params_,
563                             error_event_.release(),  // Pass ownership.
564                             new LibcurlHttpFetcher(GetProxyResolver()),
565                             false));
566  actions_.push_back(shared_ptr<AbstractAction>(error_event_action));
567  processor_->EnqueueAction(error_event_action.get());
568  SetStatusAndNotify(UPDATE_STATUS_REPORTING_ERROR_EVENT);
569  processor_->StartProcessing();
570  return true;
571}
572
573void UpdateAttempter::SetPriority(utils::ProcessPriority priority) {
574  if (priority_ == priority) {
575    return;
576  }
577  if (utils::SetProcessPriority(priority)) {
578    priority_ = priority;
579    LOG(INFO) << "Process priority = " << priority_;
580  }
581}
582
583void UpdateAttempter::SetupPriorityManagement() {
584  if (manage_priority_source_) {
585    LOG(ERROR) << "Process priority timeout source hasn't been destroyed.";
586    CleanupPriorityManagement();
587  }
588  const int kPriorityTimeout = 2 * 60 * 60;  // 2 hours
589  manage_priority_source_ = g_timeout_source_new_seconds(kPriorityTimeout);
590  g_source_set_callback(manage_priority_source_,
591                        StaticManagePriorityCallback,
592                        this,
593                        NULL);
594  g_source_attach(manage_priority_source_, NULL);
595  SetPriority(utils::kProcessPriorityLow);
596}
597
598void UpdateAttempter::CleanupPriorityManagement() {
599  if (manage_priority_source_) {
600    g_source_destroy(manage_priority_source_);
601    manage_priority_source_ = NULL;
602  }
603  SetPriority(utils::kProcessPriorityNormal);
604}
605
606gboolean UpdateAttempter::StaticManagePriorityCallback(gpointer data) {
607  return reinterpret_cast<UpdateAttempter*>(data)->ManagePriorityCallback();
608}
609
610gboolean UpdateAttempter::StaticStartProcessing(gpointer data) {
611  reinterpret_cast<UpdateAttempter*>(data)->processor_->StartProcessing();
612  return FALSE;  // Don't call this callback again.
613}
614
615void UpdateAttempter::ScheduleProcessingStart() {
616  LOG(INFO) << "Scheduling an action processor start.";
617  start_action_processor_ = false;
618  g_idle_add(&StaticStartProcessing, this);
619}
620
621bool UpdateAttempter::ManagePriorityCallback() {
622  SetPriority(utils::kProcessPriorityNormal);
623  manage_priority_source_ = NULL;
624  return false;  // Destroy the timeout source.
625}
626
627void UpdateAttempter::DisableDeltaUpdateIfNeeded() {
628  int64_t delta_failures;
629  if (omaha_request_params_.delta_okay &&
630      prefs_->GetInt64(kPrefsDeltaUpdateFailures, &delta_failures) &&
631      delta_failures >= kMaxDeltaUpdateFailures) {
632    LOG(WARNING) << "Too many delta update failures, forcing full update.";
633    omaha_request_params_.delta_okay = false;
634  }
635}
636
637void UpdateAttempter::MarkDeltaUpdateFailure() {
638  CHECK(!is_full_update_);
639  // Don't try to resume a failed delta update.
640  DeltaPerformer::ResetUpdateProgress(prefs_, false);
641  int64_t delta_failures;
642  if (!prefs_->GetInt64(kPrefsDeltaUpdateFailures, &delta_failures) ||
643      delta_failures < 0) {
644    delta_failures = 0;
645  }
646  prefs_->SetInt64(kPrefsDeltaUpdateFailures, ++delta_failures);
647}
648
649void UpdateAttempter::SetupDownload() {
650  MultiRangeHTTPFetcher* fetcher =
651      dynamic_cast<MultiRangeHTTPFetcher*>(download_action_->http_fetcher());
652  fetcher->ClearRanges();
653  if (response_handler_action_->install_plan().is_resume) {
654    // Resuming an update so fetch the update manifest metadata first.
655    int64_t manifest_metadata_size = 0;
656    prefs_->GetInt64(kPrefsManifestMetadataSize, &manifest_metadata_size);
657    fetcher->AddRange(0, manifest_metadata_size);
658    // If there're remaining unprocessed data blobs, fetch them. Be careful not
659    // to request data beyond the end of the payload to avoid 416 HTTP response
660    // error codes.
661    int64_t next_data_offset = 0;
662    prefs_->GetInt64(kPrefsUpdateStateNextDataOffset, &next_data_offset);
663    uint64_t resume_offset = manifest_metadata_size + next_data_offset;
664    if (resume_offset < response_handler_action_->install_plan().size) {
665      fetcher->AddRange(resume_offset, -1);
666    }
667  } else {
668    fetcher->AddRange(0, -1);
669  }
670}
671
672void UpdateAttempter::PingOmaha() {
673  if (processor_->IsRunning()) {
674    LOG(WARNING) << "Action processor running, Omaha ping suppressed.";
675    return;
676  }
677  shared_ptr<OmahaRequestAction> ping_action(
678      new OmahaRequestAction(prefs_,
679                             omaha_request_params_,
680                             NULL,
681                             new LibcurlHttpFetcher(GetProxyResolver()),
682                             true));
683  actions_.push_back(shared_ptr<OmahaRequestAction>(ping_action));
684  processor_->set_delegate(NULL);
685  processor_->EnqueueAction(ping_action.get());
686  ScheduleProcessingStart();
687  SetStatusAndNotify(UPDATE_STATUS_UPDATED_NEED_REBOOT);
688}
689
690}  // namespace chromeos_update_engine
691