OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |