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