Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(623)

Side by Side Diff: update_attempter.cc

Issue 3215006: AU: Implement exponential back off for 500 and 503 HTTP response codes. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/update_engine.git
Patch Set: elaborate on the CHECK Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « update_attempter.h ('k') | update_attempter_mock.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "update_engine/update_attempter.h" 5 #include "update_engine/update_attempter.h"
6 6
7 // From 'man clock_gettime': feature test macro: _POSIX_C_SOURCE >= 199309L 7 // From 'man clock_gettime': feature test macro: _POSIX_C_SOURCE >= 199309L
8 #ifndef _POSIX_C_SOURCE 8 #ifndef _POSIX_C_SOURCE
9 #define _POSIX_C_SOURCE 199309L 9 #define _POSIX_C_SOURCE 199309L
10 #endif // _POSIX_C_SOURCE 10 #endif // _POSIX_C_SOURCE
11 #include <time.h> 11 #include <time.h>
12 12
13 #include <tr1/memory> 13 #include <tr1/memory>
14 #include <string> 14 #include <string>
15 #include <vector> 15 #include <vector>
16 16
17 #include <glib.h> 17 #include <glib.h>
18 #include <metrics/metrics_library.h>
18 19
19 #include "metrics/metrics_library.h"
20 #include "update_engine/dbus_service.h" 20 #include "update_engine/dbus_service.h"
21 #include "update_engine/download_action.h" 21 #include "update_engine/download_action.h"
22 #include "update_engine/filesystem_copier_action.h" 22 #include "update_engine/filesystem_copier_action.h"
23 #include "update_engine/libcurl_http_fetcher.h" 23 #include "update_engine/libcurl_http_fetcher.h"
24 #include "update_engine/omaha_request_action.h" 24 #include "update_engine/omaha_request_action.h"
25 #include "update_engine/omaha_request_params.h" 25 #include "update_engine/omaha_request_params.h"
26 #include "update_engine/omaha_response_handler_action.h" 26 #include "update_engine/omaha_response_handler_action.h"
27 #include "update_engine/postinstall_runner_action.h" 27 #include "update_engine/postinstall_runner_action.h"
28 #include "update_engine/set_bootable_flag_action.h" 28 #include "update_engine/set_bootable_flag_action.h"
29 #include "update_engine/update_check_scheduler.h"
29 30
30 using base::TimeDelta; 31 using base::TimeDelta;
31 using base::TimeTicks; 32 using base::TimeTicks;
32 using std::tr1::shared_ptr; 33 using std::tr1::shared_ptr;
33 using std::string; 34 using std::string;
34 using std::vector; 35 using std::vector;
35 36
36 namespace chromeos_update_engine { 37 namespace chromeos_update_engine {
37 38
38 namespace {
39
40 const int kTimeoutOnce = 7 * 60; // at 7 minutes
41 const int kTimeoutPeriodic = 45 * 60; // every 45 minutes
42 const int kTimeoutFuzz = 10 * 60; // +/- 5 minutes
43
44 gboolean CheckForUpdatePeriodically(void* arg) {
45 UpdateAttempter* update_attempter = reinterpret_cast<UpdateAttempter*>(arg);
46 update_attempter->Update("", "");
47 update_attempter->SchedulePeriodicUpdateCheck(kTimeoutPeriodic);
48 return FALSE; // Don't run again.
49 }
50
51 } // namespace {}
52
53 const char* kUpdateCompletedMarker = "/tmp/update_engine_autoupdate_completed"; 39 const char* kUpdateCompletedMarker = "/tmp/update_engine_autoupdate_completed";
54 40
55 const char* UpdateStatusToString(UpdateStatus status) { 41 const char* UpdateStatusToString(UpdateStatus status) {
56 switch (status) { 42 switch (status) {
57 case UPDATE_STATUS_IDLE: 43 case UPDATE_STATUS_IDLE:
58 return "UPDATE_STATUS_IDLE"; 44 return "UPDATE_STATUS_IDLE";
59 case UPDATE_STATUS_CHECKING_FOR_UPDATE: 45 case UPDATE_STATUS_CHECKING_FOR_UPDATE:
60 return "UPDATE_STATUS_CHECKING_FOR_UPDATE"; 46 return "UPDATE_STATUS_CHECKING_FOR_UPDATE";
61 case UPDATE_STATUS_UPDATE_AVAILABLE: 47 case UPDATE_STATUS_UPDATE_AVAILABLE:
62 return "UPDATE_STATUS_UPDATE_AVAILABLE"; 48 return "UPDATE_STATUS_UPDATE_AVAILABLE";
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 return kActionCodeSetBootableFlagError; 83 return kActionCodeSetBootableFlagError;
98 84
99 return code; 85 return code;
100 } 86 }
101 87
102 UpdateAttempter::UpdateAttempter(PrefsInterface* prefs, 88 UpdateAttempter::UpdateAttempter(PrefsInterface* prefs,
103 MetricsLibraryInterface* metrics_lib) 89 MetricsLibraryInterface* metrics_lib)
104 : dbus_service_(NULL), 90 : dbus_service_(NULL),
105 prefs_(prefs), 91 prefs_(prefs),
106 metrics_lib_(metrics_lib), 92 metrics_lib_(metrics_lib),
93 update_check_scheduler_(NULL),
94 http_response_code_(0),
107 priority_(utils::kProcessPriorityNormal), 95 priority_(utils::kProcessPriorityNormal),
108 manage_priority_source_(NULL), 96 manage_priority_source_(NULL),
109 download_active_(false), 97 download_active_(false),
110 status_(UPDATE_STATUS_IDLE), 98 status_(UPDATE_STATUS_IDLE),
111 download_progress_(0.0), 99 download_progress_(0.0),
112 last_checked_time_(0), 100 last_checked_time_(0),
113 new_version_("0.0.0.0"), 101 new_version_("0.0.0.0"),
114 new_size_(0) { 102 new_size_(0) {
115 if (utils::FileExists(kUpdateCompletedMarker)) 103 if (utils::FileExists(kUpdateCompletedMarker))
116 status_ = UPDATE_STATUS_UPDATED_NEED_REBOOT; 104 status_ = UPDATE_STATUS_UPDATED_NEED_REBOOT;
117 } 105 }
118 106
119 UpdateAttempter::~UpdateAttempter() { 107 UpdateAttempter::~UpdateAttempter() {
120 CleanupPriorityManagement(); 108 CleanupPriorityManagement();
121 } 109 }
122 110
123 void UpdateAttempter::Update(const std::string& app_version, 111 void UpdateAttempter::Update(const std::string& app_version,
124 const std::string& omaha_url) { 112 const std::string& omaha_url) {
125 if (status_ == UPDATE_STATUS_UPDATED_NEED_REBOOT) { 113 if (status_ == UPDATE_STATUS_UPDATED_NEED_REBOOT) {
126 LOG(INFO) << "Not updating b/c we already updated and we're waiting for " 114 LOG(INFO) << "Not updating b/c we already updated and we're waiting for "
127 << "reboot"; 115 << "reboot";
128 return; 116 return;
129 } 117 }
130 if (status_ != UPDATE_STATUS_IDLE) { 118 if (status_ != UPDATE_STATUS_IDLE) {
131 // Update in progress. Do nothing 119 // Update in progress. Do nothing
132 return; 120 return;
133 } 121 }
122 http_response_code_ = 0;
134 if (!omaha_request_params_.Init(app_version, omaha_url)) { 123 if (!omaha_request_params_.Init(app_version, omaha_url)) {
135 LOG(ERROR) << "Unable to initialize Omaha request device params."; 124 LOG(ERROR) << "Unable to initialize Omaha request device params.";
136 return; 125 return;
137 } 126 }
138 CHECK(!processor_.IsRunning()); 127 CHECK(!processor_.IsRunning());
139 processor_.set_delegate(this); 128 processor_.set_delegate(this);
140 129
141 // Actions: 130 // Actions:
142 shared_ptr<OmahaRequestAction> update_check_action( 131 shared_ptr<OmahaRequestAction> update_check_action(
143 new OmahaRequestAction(prefs_, 132 new OmahaRequestAction(prefs_,
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 // Report the time it took to update the system. 253 // Report the time it took to update the system.
265 int64_t update_time = time(NULL) - last_checked_time_; 254 int64_t update_time = time(NULL) - last_checked_time_;
266 metrics_lib_->SendToUMA("Installer.UpdateTime", 255 metrics_lib_->SendToUMA("Installer.UpdateTime",
267 static_cast<int>(update_time), // sample 256 static_cast<int>(update_time), // sample
268 1, // min = 1 second 257 1, // min = 1 second
269 20 * 60, // max = 20 minutes 258 20 * 60, // max = 20 minutes
270 50); // buckets 259 50); // buckets
271 return; 260 return;
272 } 261 }
273 262
274 LOG(INFO) << "Update failed."; 263 if (ScheduleErrorEventAction()) {
275 if (ScheduleErrorEventAction())
276 return; 264 return;
265 }
266 LOG(INFO) << "No update.";
277 SetStatusAndNotify(UPDATE_STATUS_IDLE); 267 SetStatusAndNotify(UPDATE_STATUS_IDLE);
278 } 268 }
279 269
280 void UpdateAttempter::ProcessingStopped(const ActionProcessor* processor) { 270 void UpdateAttempter::ProcessingStopped(const ActionProcessor* processor) {
281 // Reset process priority back to normal. 271 // Reset process priority back to normal.
282 CleanupPriorityManagement(); 272 CleanupPriorityManagement();
283 download_progress_ = 0.0; 273 download_progress_ = 0.0;
284 SetStatusAndNotify(UPDATE_STATUS_IDLE); 274 SetStatusAndNotify(UPDATE_STATUS_IDLE);
285 actions_.clear(); 275 actions_.clear();
286 error_event_.reset(NULL); 276 error_event_.reset(NULL);
287 } 277 }
288 278
289 // Called whenever an action has finished processing, either successfully 279 // Called whenever an action has finished processing, either successfully
290 // or otherwise. 280 // or otherwise.
291 void UpdateAttempter::ActionCompleted(ActionProcessor* processor, 281 void UpdateAttempter::ActionCompleted(ActionProcessor* processor,
292 AbstractAction* action, 282 AbstractAction* action,
293 ActionExitCode code) { 283 ActionExitCode code) {
294 // Reset download progress regardless of whether or not the download action 284 // Reset download progress regardless of whether or not the download
295 // succeeded. 285 // action succeeded. Also, get the response code from HTTP request
286 // actions (update download as well as the initial update check
287 // actions).
296 const string type = action->Type(); 288 const string type = action->Type();
297 if (type == DownloadAction::StaticType()) 289 if (type == DownloadAction::StaticType()) {
298 download_progress_ = 0.0; 290 download_progress_ = 0.0;
291 DownloadAction* download_action = dynamic_cast<DownloadAction*>(action);
292 http_response_code_ = download_action->GetHTTPResponseCode();
293 } else if (type == OmahaRequestAction::StaticType()) {
294 OmahaRequestAction* omaha_request_action =
295 dynamic_cast<OmahaRequestAction*>(action);
296 // If the request is not an event, then it's the update-check.
297 if (!omaha_request_action->IsEvent()) {
298 http_response_code_ = omaha_request_action->GetHTTPResponseCode();
299 }
300 }
299 if (code != kActionCodeSuccess) { 301 if (code != kActionCodeSuccess) {
300 // On failure, schedule an error event to be sent to Omaha. 302 // On failure, schedule an error event to be sent to Omaha.
301 CreatePendingErrorEvent(action, code); 303 CreatePendingErrorEvent(action, code);
302 return; 304 return;
303 } 305 }
304 // Find out which action completed. 306 // Find out which action completed.
305 if (type == OmahaResponseHandlerAction::StaticType()) { 307 if (type == OmahaResponseHandlerAction::StaticType()) {
306 // Note that the status will be updated to DOWNLOADING when some 308 // Note that the status will be updated to DOWNLOADING when some
307 // bytes get actually downloaded from the server and the 309 // bytes get actually downloaded from the server and the
308 // BytesReceived callback is invoked. This avoids notifying the 310 // BytesReceived callback is invoked. This avoids notifying the
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 *last_checked_time = last_checked_time_; 369 *last_checked_time = last_checked_time_;
368 *progress = download_progress_; 370 *progress = download_progress_;
369 *current_operation = UpdateStatusToString(status_); 371 *current_operation = UpdateStatusToString(status_);
370 *new_version = new_version_; 372 *new_version = new_version_;
371 *new_size = new_size_; 373 *new_size = new_size_;
372 return true; 374 return true;
373 } 375 }
374 376
375 void UpdateAttempter::SetStatusAndNotify(UpdateStatus status) { 377 void UpdateAttempter::SetStatusAndNotify(UpdateStatus status) {
376 status_ = status; 378 status_ = status;
379 if (update_check_scheduler_) {
380 update_check_scheduler_->SetUpdateStatus(status_);
381 }
377 if (!dbus_service_) 382 if (!dbus_service_)
378 return; 383 return;
379 last_notify_time_ = TimeTicks::Now(); 384 last_notify_time_ = TimeTicks::Now();
380 update_engine_service_emit_status_update( 385 update_engine_service_emit_status_update(
381 dbus_service_, 386 dbus_service_,
382 last_checked_time_, 387 last_checked_time_,
383 download_progress_, 388 download_progress_,
384 UpdateStatusToString(status_), 389 UpdateStatusToString(status_),
385 new_version_.c_str(), 390 new_version_.c_str(),
386 new_size_); 391 new_size_);
(...skipping 20 matching lines...) Expand all
407 code = GetErrorCodeForAction(action, code); 412 code = GetErrorCodeForAction(action, code);
408 error_event_.reset(new OmahaEvent(OmahaEvent::kTypeUpdateComplete, 413 error_event_.reset(new OmahaEvent(OmahaEvent::kTypeUpdateComplete,
409 OmahaEvent::kResultError, 414 OmahaEvent::kResultError,
410 code)); 415 code));
411 } 416 }
412 417
413 bool UpdateAttempter::ScheduleErrorEventAction() { 418 bool UpdateAttempter::ScheduleErrorEventAction() {
414 if (error_event_.get() == NULL) 419 if (error_event_.get() == NULL)
415 return false; 420 return false;
416 421
422 LOG(INFO) << "Update failed -- reporting the error event.";
417 shared_ptr<OmahaRequestAction> error_event_action( 423 shared_ptr<OmahaRequestAction> error_event_action(
418 new OmahaRequestAction(prefs_, 424 new OmahaRequestAction(prefs_,
419 omaha_request_params_, 425 omaha_request_params_,
420 error_event_.release(), // Pass ownership. 426 error_event_.release(), // Pass ownership.
421 new LibcurlHttpFetcher)); 427 new LibcurlHttpFetcher));
422 actions_.push_back(shared_ptr<AbstractAction>(error_event_action)); 428 actions_.push_back(shared_ptr<AbstractAction>(error_event_action));
423 processor_.EnqueueAction(error_event_action.get()); 429 processor_.EnqueueAction(error_event_action.get());
424 SetStatusAndNotify(UPDATE_STATUS_REPORTING_ERROR_EVENT); 430 SetStatusAndNotify(UPDATE_STATUS_REPORTING_ERROR_EVENT);
425 processor_.StartProcessing(); 431 processor_.StartProcessing();
426 return true; 432 return true;
427 } 433 }
428 434
429 void UpdateAttempter::InitiatePeriodicUpdateChecks() {
430 if (!utils::IsOfficialBuild()) {
431 LOG(WARNING) << "Non-official build: periodic update checks disabled.";
432 return;
433 }
434 if (utils::IsRemovableDevice(utils::RootDevice(utils::BootDevice()))) {
435 LOG(WARNING) << "Removable device boot: periodic update checks disabled.";
436 return;
437 }
438 // Kick off periodic update checks. The first check is scheduled
439 // |kTimeoutOnce| seconds from now. Subsequent checks are scheduled
440 // at |kTimeoutPeriodic|-second intervals.
441 SchedulePeriodicUpdateCheck(kTimeoutOnce);
442 }
443
444 void UpdateAttempter::SchedulePeriodicUpdateCheck(int seconds) {
445 seconds = utils::FuzzInt(seconds, kTimeoutFuzz);
446 g_timeout_add_seconds(seconds, CheckForUpdatePeriodically, this);
447 LOG(INFO) << "Next update check in " << seconds << " seconds.";
448 }
449
450 void UpdateAttempter::SetPriority(utils::ProcessPriority priority) { 435 void UpdateAttempter::SetPriority(utils::ProcessPriority priority) {
451 if (priority_ == priority) { 436 if (priority_ == priority) {
452 return; 437 return;
453 } 438 }
454 if (utils::SetProcessPriority(priority)) { 439 if (utils::SetProcessPriority(priority)) {
455 priority_ = priority; 440 priority_ = priority;
456 LOG(INFO) << "Process priority = " << priority_; 441 LOG(INFO) << "Process priority = " << priority_;
457 } 442 }
458 } 443 }
459 444
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 SetPriority(utils::kProcessPriorityNormal); 476 SetPriority(utils::kProcessPriorityNormal);
492 return true; 477 return true;
493 } 478 }
494 // Set the priority to high and let GLib destroy the timeout source. 479 // Set the priority to high and let GLib destroy the timeout source.
495 SetPriority(utils::kProcessPriorityHigh); 480 SetPriority(utils::kProcessPriorityHigh);
496 manage_priority_source_ = NULL; 481 manage_priority_source_ = NULL;
497 return false; 482 return false;
498 } 483 }
499 484
500 } // namespace chromeos_update_engine 485 } // namespace chromeos_update_engine
OLDNEW
« no previous file with comments | « update_attempter.h ('k') | update_attempter_mock.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698