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