1 // Copyright 2014 The Chromium 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 "components/component_updater/component_updater_service.h" 6 7 #include <algorithm> 8 #include <set> 9 #include <vector> 10 11 #include "base/at_exit.h" 12 #include "base/bind.h" 13 #include "base/bind_helpers.h" 14 #include "base/callback.h" 15 #include "base/compiler_specific.h" 16 #include "base/files/file_path.h" 17 #include "base/files/file_util.h" 18 #include "base/logging.h" 19 #include "base/macros.h" 20 #include "base/memory/scoped_ptr.h" 21 #include "base/message_loop/message_loop_proxy.h" 22 #include "base/observer_list.h" 23 #include "base/sequenced_task_runner.h" 24 #include "base/stl_util.h" 25 #include "base/threading/sequenced_worker_pool.h" 26 #include "base/threading/thread_checker.h" 27 #include "base/timer/timer.h" 28 #include "components/component_updater/component_patcher_operation.h" 29 #include "components/component_updater/component_unpacker.h" 30 #include "components/component_updater/component_updater_configurator.h" 31 #include "components/component_updater/component_updater_ping_manager.h" 32 #include "components/component_updater/component_updater_utils.h" 33 #include "components/component_updater/crx_downloader.h" 34 #include "components/component_updater/crx_update_item.h" 35 #include "components/component_updater/update_checker.h" 36 #include "components/component_updater/update_response.h" 37 #include "url/gurl.h" 38 39 namespace component_updater { 40 41 // The component updater is designed to live until process shutdown, so 42 // base::Bind() calls are not refcounted. 43 44 namespace { 45 46 // Returns true if the |proposed| version is newer than |current| version. 47 bool IsVersionNewer(const Version& current, const std::string& proposed) { 48 Version proposed_ver(proposed); 49 return proposed_ver.IsValid() && current.CompareTo(proposed_ver) < 0; 50 } 51 52 // Returns true if a differential update is available, it has not failed yet, 53 // and the configuration allows it. 54 bool CanTryDiffUpdate(const CrxUpdateItem* update_item, 55 const Configurator& config) { 56 return HasDiffUpdate(update_item) && !update_item->diff_update_failed && 57 config.DeltasEnabled(); 58 } 59 60 void AppendDownloadMetrics( 61 const std::vector<CrxDownloader::DownloadMetrics>& source, 62 std::vector<CrxDownloader::DownloadMetrics>* destination) { 63 destination->insert(destination->end(), source.begin(), source.end()); 64 } 65 66 } // namespace 67 68 CrxUpdateItem::CrxUpdateItem() 69 : status(kNew), 70 on_demand(false), 71 diff_update_failed(false), 72 error_category(0), 73 error_code(0), 74 extra_code1(0), 75 diff_error_category(0), 76 diff_error_code(0), 77 diff_extra_code1(0) { 78 } 79 80 CrxUpdateItem::~CrxUpdateItem() { 81 } 82 83 CrxComponent::CrxComponent() 84 : installer(NULL), allow_background_download(true) { 85 } 86 87 CrxComponent::~CrxComponent() { 88 } 89 90 ////////////////////////////////////////////////////////////////////////////// 91 // The one and only implementation of the ComponentUpdateService interface. In 92 // charge of running the show. The main method is ProcessPendingItems() which 93 // is called periodically to do the upgrades/installs or the update checks. 94 // An important consideration here is to be as "low impact" as we can to the 95 // rest of the browser, so even if we have many components registered and 96 // eligible for update, we only do one thing at a time with pauses in between 97 // the tasks. Also when we do network requests there is only one |url_fetcher_| 98 // in flight at a time. 99 // There are no locks in this code, the main structure |work_items_| is mutated 100 // only from the main thread. The unpack and installation is done in a blocking 101 // pool thread. The network requests are done in the IO thread or in the file 102 // thread. 103 class CrxUpdateService : public ComponentUpdateService, public OnDemandUpdater { 104 public: 105 explicit CrxUpdateService(Configurator* config); 106 virtual ~CrxUpdateService(); 107 108 // Overrides for ComponentUpdateService. 109 virtual void AddObserver(Observer* observer) OVERRIDE; 110 virtual void RemoveObserver(Observer* observer) OVERRIDE; 111 virtual Status Start() OVERRIDE; 112 virtual Status Stop() OVERRIDE; 113 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE; 114 virtual std::vector<std::string> GetComponentIDs() const OVERRIDE; 115 virtual OnDemandUpdater& GetOnDemandUpdater() OVERRIDE; 116 virtual void MaybeThrottle(const std::string& crx_id, 117 const base::Closure& callback) OVERRIDE; 118 virtual scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() 119 OVERRIDE; 120 121 // Context for a crx download url request. 122 struct CRXContext { 123 ComponentInstaller* installer; 124 std::vector<uint8_t> pk_hash; 125 std::string id; 126 std::string fingerprint; 127 CRXContext() : installer(NULL) {} 128 }; 129 130 private: 131 enum ErrorCategory { 132 kErrorNone = 0, 133 kNetworkError, 134 kUnpackError, 135 kInstallError, 136 }; 137 138 enum StepDelayInterval { 139 kStepDelayShort = 0, 140 kStepDelayMedium, 141 kStepDelayLong, 142 }; 143 144 // Overrides for ComponentUpdateService. 145 virtual bool GetComponentDetails(const std::string& component_id, 146 CrxUpdateItem* item) const OVERRIDE; 147 148 // Overrides for OnDemandUpdater. 149 virtual Status OnDemandUpdate(const std::string& component_id) OVERRIDE; 150 151 void UpdateCheckComplete(const GURL& original_url, 152 int error, 153 const std::string& error_message, 154 const UpdateResponse::Results& results); 155 void OnUpdateCheckSucceeded(const UpdateResponse::Results& results); 156 void OnUpdateCheckFailed(int error, const std::string& error_message); 157 158 void DownloadProgress(const std::string& component_id, 159 const CrxDownloader::Result& download_result); 160 161 void DownloadComplete(scoped_ptr<CRXContext> crx_context, 162 const CrxDownloader::Result& download_result); 163 164 Status OnDemandUpdateInternal(CrxUpdateItem* item); 165 Status OnDemandUpdateWithCooldown(CrxUpdateItem* item); 166 167 void ProcessPendingItems(); 168 169 // Find a component that is ready to update. 170 CrxUpdateItem* FindReadyComponent() const; 171 172 // Prepares the components for an update check and initiates the request. 173 // Returns true if an update check request has been made. Returns false if 174 // no update check was needed or an error occured. 175 bool CheckForUpdates(); 176 177 void UpdateComponent(CrxUpdateItem* workitem); 178 179 void ScheduleNextRun(StepDelayInterval step_delay); 180 181 void ParseResponse(const std::string& xml); 182 183 void Install(scoped_ptr<CRXContext> context, const base::FilePath& crx_path); 184 185 void EndUnpacking(const std::string& component_id, 186 const base::FilePath& crx_path, 187 ComponentUnpacker::Error error, 188 int extended_error); 189 190 void DoneInstalling(const std::string& component_id, 191 ComponentUnpacker::Error error, 192 int extended_error); 193 194 void ChangeItemState(CrxUpdateItem* item, CrxUpdateItem::Status to); 195 196 size_t ChangeItemStatus(CrxUpdateItem::Status from, CrxUpdateItem::Status to); 197 198 CrxUpdateItem* FindUpdateItemById(const std::string& id) const; 199 200 void NotifyObservers(Observer::Events event, const std::string& id); 201 202 bool HasOnDemandItems() const; 203 204 Status GetServiceStatus(const CrxUpdateItem::Status status); 205 206 scoped_ptr<Configurator> config_; 207 208 scoped_ptr<UpdateChecker> update_checker_; 209 210 scoped_ptr<PingManager> ping_manager_; 211 212 scoped_refptr<ComponentUnpacker> unpacker_; 213 214 scoped_ptr<CrxDownloader> crx_downloader_; 215 216 // A collection of every work item. 217 typedef std::vector<CrxUpdateItem*> UpdateItems; 218 UpdateItems work_items_; 219 220 base::OneShotTimer<CrxUpdateService> timer_; 221 222 base::ThreadChecker thread_checker_; 223 224 // Used to post responses back to the main thread. 225 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; 226 227 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; 228 229 bool running_; 230 231 ObserverList<Observer> observer_list_; 232 233 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService); 234 }; 235 236 ////////////////////////////////////////////////////////////////////////////// 237 238 CrxUpdateService::CrxUpdateService(Configurator* config) 239 : config_(config), 240 ping_manager_(new PingManager(*config)), 241 main_task_runner_(base::MessageLoopProxy::current()), 242 blocking_task_runner_(config->GetSequencedTaskRunner()), 243 running_(false) { 244 } 245 246 CrxUpdateService::~CrxUpdateService() { 247 // Because we are a singleton, at this point only the main thread should be 248 // alive, this simplifies the management of the work that could be in 249 // flight in other threads. 250 Stop(); 251 STLDeleteElements(&work_items_); 252 } 253 254 void CrxUpdateService::AddObserver(Observer* observer) { 255 DCHECK(thread_checker_.CalledOnValidThread()); 256 observer_list_.AddObserver(observer); 257 } 258 259 void CrxUpdateService::RemoveObserver(Observer* observer) { 260 DCHECK(thread_checker_.CalledOnValidThread()); 261 observer_list_.RemoveObserver(observer); 262 } 263 264 ComponentUpdateService::Status CrxUpdateService::Start() { 265 // Note that RegisterComponent will call Start() when the first 266 // component is registered, so it can be called twice. This way 267 // we avoid scheduling the timer if there is no work to do. 268 VLOG(1) << "CrxUpdateService starting up"; 269 running_ = true; 270 if (work_items_.empty()) 271 return kOk; 272 273 NotifyObservers(Observer::COMPONENT_UPDATER_STARTED, ""); 274 275 VLOG(1) << "First update attempt will take place in " 276 << config_->InitialDelay() << " seconds"; 277 timer_.Start(FROM_HERE, 278 base::TimeDelta::FromSeconds(config_->InitialDelay()), 279 this, 280 &CrxUpdateService::ProcessPendingItems); 281 return kOk; 282 } 283 284 // Stop the main check + update loop. In flight operations will be 285 // completed. 286 ComponentUpdateService::Status CrxUpdateService::Stop() { 287 VLOG(1) << "CrxUpdateService stopping"; 288 running_ = false; 289 timer_.Stop(); 290 return kOk; 291 } 292 293 bool CrxUpdateService::HasOnDemandItems() const { 294 class Helper { 295 public: 296 static bool IsOnDemand(CrxUpdateItem* item) { return item->on_demand; } 297 }; 298 return std::find_if(work_items_.begin(), 299 work_items_.end(), 300 Helper::IsOnDemand) != work_items_.end(); 301 } 302 303 // This function sets the timer which will call ProcessPendingItems() or 304 // ProcessRequestedItem() if there is an on_demand item. There 305 // are three kinds of waits: 306 // - a short delay, when there is immediate work to be done. 307 // - a medium delay, when there are updates to be applied within the current 308 // update cycle, or there are components that are still unchecked. 309 // - a long delay when a full check/update cycle has completed for all 310 // components. 311 void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) { 312 DCHECK(thread_checker_.CalledOnValidThread()); 313 DCHECK(!update_checker_); 314 CHECK(!timer_.IsRunning()); 315 // It could be the case that Stop() had been called while a url request 316 // or unpacking was in flight, if so we arrive here but |running_| is 317 // false. In that case do not loop again. 318 if (!running_) 319 return; 320 321 // Keep the delay short if in the middle of an update (step_delay), 322 // or there are new requested_work_items_ that have not been processed yet. 323 int64_t delay_seconds = 0; 324 if (!HasOnDemandItems()) { 325 switch (step_delay) { 326 case kStepDelayShort: 327 delay_seconds = config_->StepDelay(); 328 break; 329 case kStepDelayMedium: 330 delay_seconds = config_->StepDelayMedium(); 331 break; 332 case kStepDelayLong: 333 delay_seconds = config_->NextCheckDelay(); 334 break; 335 } 336 } else { 337 delay_seconds = config_->StepDelay(); 338 } 339 340 if (step_delay != kStepDelayShort) { 341 NotifyObservers(Observer::COMPONENT_UPDATER_SLEEPING, ""); 342 343 // Zero is only used for unit tests. 344 if (0 == delay_seconds) 345 return; 346 } 347 348 VLOG(1) << "Scheduling next run to occur in " << delay_seconds << " seconds"; 349 timer_.Start(FROM_HERE, 350 base::TimeDelta::FromSeconds(delay_seconds), 351 this, 352 &CrxUpdateService::ProcessPendingItems); 353 } 354 355 // Given a extension-like component id, find the associated component. 356 CrxUpdateItem* CrxUpdateService::FindUpdateItemById( 357 const std::string& id) const { 358 DCHECK(thread_checker_.CalledOnValidThread()); 359 CrxUpdateItem::FindById finder(id); 360 UpdateItems::const_iterator it = 361 std::find_if(work_items_.begin(), work_items_.end(), finder); 362 return it != work_items_.end() ? *it : NULL; 363 } 364 365 // Changes a component's status, clearing on_demand and firing notifications as 366 // necessary. By convention, this is the only function that can change a 367 // CrxUpdateItem's |status|. 368 // TODO(waffles): Do we want to add DCHECKS for valid state transitions here? 369 void CrxUpdateService::ChangeItemState(CrxUpdateItem* item, 370 CrxUpdateItem::Status to) { 371 DCHECK(thread_checker_.CalledOnValidThread()); 372 if (to == CrxUpdateItem::kNoUpdate || to == CrxUpdateItem::kUpdated || 373 to == CrxUpdateItem::kUpToDate) { 374 item->on_demand = false; 375 } 376 377 item->status = to; 378 379 switch (to) { 380 case CrxUpdateItem::kCanUpdate: 381 NotifyObservers(Observer::COMPONENT_UPDATE_FOUND, item->id); 382 break; 383 case CrxUpdateItem::kUpdatingDiff: 384 case CrxUpdateItem::kUpdating: 385 NotifyObservers(Observer::COMPONENT_UPDATE_READY, item->id); 386 break; 387 case CrxUpdateItem::kUpdated: 388 NotifyObservers(Observer::COMPONENT_UPDATED, item->id); 389 break; 390 case CrxUpdateItem::kUpToDate: 391 case CrxUpdateItem::kNoUpdate: 392 NotifyObservers(Observer::COMPONENT_NOT_UPDATED, item->id); 393 break; 394 case CrxUpdateItem::kNew: 395 case CrxUpdateItem::kChecking: 396 case CrxUpdateItem::kDownloading: 397 case CrxUpdateItem::kDownloadingDiff: 398 case CrxUpdateItem::kLastStatus: 399 // No notification for these states. 400 break; 401 } 402 403 // Free possible pending network requests. 404 if ((to == CrxUpdateItem::kUpdated) || (to == CrxUpdateItem::kUpToDate) || 405 (to == CrxUpdateItem::kNoUpdate)) { 406 for (std::vector<base::Closure>::iterator it = 407 item->ready_callbacks.begin(); 408 it != item->ready_callbacks.end(); 409 ++it) { 410 it->Run(); 411 } 412 item->ready_callbacks.clear(); 413 } 414 } 415 416 // Changes all the components in |work_items_| that have |from| status to 417 // |to| status and returns how many have been changed. 418 size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from, 419 CrxUpdateItem::Status to) { 420 DCHECK(thread_checker_.CalledOnValidThread()); 421 size_t count = 0; 422 for (UpdateItems::iterator it = work_items_.begin(); 423 it != work_items_.end(); 424 ++it) { 425 CrxUpdateItem* item = *it; 426 if (item->status == from) { 427 ChangeItemState(item, to); 428 ++count; 429 } 430 } 431 return count; 432 } 433 434 // Adds a component to be checked for upgrades. If the component exists it 435 // it will be replaced and the return code is kReplaced. 436 ComponentUpdateService::Status CrxUpdateService::RegisterComponent( 437 const CrxComponent& component) { 438 DCHECK(thread_checker_.CalledOnValidThread()); 439 if (component.pk_hash.empty() || !component.version.IsValid() || 440 !component.installer) 441 return kError; 442 443 std::string id(GetCrxComponentID(component)); 444 CrxUpdateItem* uit = FindUpdateItemById(id); 445 if (uit) { 446 uit->component = component; 447 return kReplaced; 448 } 449 450 uit = new CrxUpdateItem; 451 uit->id.swap(id); 452 uit->component = component; 453 454 work_items_.push_back(uit); 455 456 // If this is the first component registered we call Start to 457 // schedule the first timer. Otherwise, reset the timer to trigger another 458 // pass over the work items, if the component updater is sleeping, fact 459 // indicated by a running timer. If the timer is not running, it means that 460 // the service is busy updating something, and in that case, this component 461 // will be picked up at the next pass. 462 if (running_) { 463 if (work_items_.size() == 1) { 464 Start(); 465 } else if (timer_.IsRunning()) { 466 timer_.Start(FROM_HERE, 467 base::TimeDelta::FromSeconds(config_->InitialDelay()), 468 this, 469 &CrxUpdateService::ProcessPendingItems); 470 } 471 } 472 473 return kOk; 474 } 475 476 std::vector<std::string> CrxUpdateService::GetComponentIDs() const { 477 DCHECK(thread_checker_.CalledOnValidThread()); 478 std::vector<std::string> component_ids; 479 for (UpdateItems::const_iterator it = work_items_.begin(); 480 it != work_items_.end(); 481 ++it) { 482 const CrxUpdateItem* item = *it; 483 component_ids.push_back(item->id); 484 } 485 return component_ids; 486 } 487 488 OnDemandUpdater& CrxUpdateService::GetOnDemandUpdater() { 489 return *this; 490 } 491 492 void CrxUpdateService::MaybeThrottle(const std::string& crx_id, 493 const base::Closure& callback) { 494 DCHECK(thread_checker_.CalledOnValidThread()); 495 // Check if we can on-demand update, else unblock the request anyway. 496 CrxUpdateItem* item = FindUpdateItemById(crx_id); 497 Status status = OnDemandUpdateWithCooldown(item); 498 if (status == kOk || status == kInProgress) { 499 item->ready_callbacks.push_back(callback); 500 return; 501 } 502 callback.Run(); 503 } 504 505 scoped_refptr<base::SequencedTaskRunner> 506 CrxUpdateService::GetSequencedTaskRunner() { 507 return config_->GetSequencedTaskRunner(); 508 } 509 510 bool CrxUpdateService::GetComponentDetails(const std::string& component_id, 511 CrxUpdateItem* item) const { 512 DCHECK(thread_checker_.CalledOnValidThread()); 513 const CrxUpdateItem* crx_update_item(FindUpdateItemById(component_id)); 514 if (crx_update_item) 515 *item = *crx_update_item; 516 return crx_update_item != NULL; 517 } 518 519 // Start the process of checking for an update, for a particular component 520 // that was previously registered. 521 // |component_id| is a value returned from GetCrxComponentID(). 522 ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate( 523 const std::string& component_id) { 524 return OnDemandUpdateInternal(FindUpdateItemById(component_id)); 525 } 526 527 // This is the main loop of the component updater. It updates one component 528 // at a time if updates are available. Otherwise, it does an update check or 529 // takes a long sleep until the loop runs again. 530 void CrxUpdateService::ProcessPendingItems() { 531 DCHECK(thread_checker_.CalledOnValidThread()); 532 533 CrxUpdateItem* ready_upgrade = FindReadyComponent(); 534 if (ready_upgrade) { 535 UpdateComponent(ready_upgrade); 536 return; 537 } 538 539 if (!CheckForUpdates()) 540 ScheduleNextRun(kStepDelayLong); 541 } 542 543 CrxUpdateItem* CrxUpdateService::FindReadyComponent() const { 544 class Helper { 545 public: 546 static bool IsReadyOnDemand(CrxUpdateItem* item) { 547 return item->on_demand && IsReady(item); 548 } 549 static bool IsReady(CrxUpdateItem* item) { 550 return item->status == CrxUpdateItem::kCanUpdate; 551 } 552 }; 553 554 std::vector<CrxUpdateItem*>::const_iterator it = std::find_if( 555 work_items_.begin(), work_items_.end(), Helper::IsReadyOnDemand); 556 if (it != work_items_.end()) 557 return *it; 558 it = std::find_if(work_items_.begin(), work_items_.end(), Helper::IsReady); 559 if (it != work_items_.end()) 560 return *it; 561 return NULL; 562 } 563 564 // Prepares the components for an update check and initiates the request. 565 // On demand components are always included in the update check request. 566 // Otherwise, only include components that have not been checked recently. 567 bool CrxUpdateService::CheckForUpdates() { 568 const base::TimeDelta minimum_recheck_wait_time = 569 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait()); 570 const base::Time now(base::Time::Now()); 571 572 std::vector<CrxUpdateItem*> items_to_check; 573 for (size_t i = 0; i != work_items_.size(); ++i) { 574 CrxUpdateItem* item = work_items_[i]; 575 DCHECK(item->status == CrxUpdateItem::kNew || 576 item->status == CrxUpdateItem::kNoUpdate || 577 item->status == CrxUpdateItem::kUpToDate || 578 item->status == CrxUpdateItem::kUpdated); 579 580 const base::TimeDelta time_since_last_checked(now - item->last_check); 581 582 if (!item->on_demand && 583 time_since_last_checked < minimum_recheck_wait_time) { 584 VLOG(1) << "Skipping check for component update: id=" << item->id 585 << ", time_since_last_checked=" 586 << time_since_last_checked.InSeconds() 587 << " seconds: too soon to check for an update"; 588 continue; 589 } 590 591 VLOG(1) << "Scheduling update check for component id=" << item->id 592 << ", time_since_last_checked=" 593 << time_since_last_checked.InSeconds() << " seconds"; 594 595 item->last_check = now; 596 item->crx_urls.clear(); 597 item->crx_diffurls.clear(); 598 item->previous_version = item->component.version; 599 item->next_version = Version(); 600 item->previous_fp = item->component.fingerprint; 601 item->next_fp.clear(); 602 item->diff_update_failed = false; 603 item->error_category = 0; 604 item->error_code = 0; 605 item->extra_code1 = 0; 606 item->diff_error_category = 0; 607 item->diff_error_code = 0; 608 item->diff_extra_code1 = 0; 609 item->download_metrics.clear(); 610 611 items_to_check.push_back(item); 612 613 ChangeItemState(item, CrxUpdateItem::kChecking); 614 } 615 616 if (items_to_check.empty()) 617 return false; 618 619 update_checker_ = UpdateChecker::Create(*config_).Pass(); 620 return update_checker_->CheckForUpdates( 621 items_to_check, 622 config_->ExtraRequestParams(), 623 base::Bind(&CrxUpdateService::UpdateCheckComplete, 624 base::Unretained(this))); 625 } 626 627 void CrxUpdateService::UpdateComponent(CrxUpdateItem* workitem) { 628 scoped_ptr<CRXContext> crx_context(new CRXContext); 629 crx_context->pk_hash = workitem->component.pk_hash; 630 crx_context->id = workitem->id; 631 crx_context->installer = workitem->component.installer; 632 crx_context->fingerprint = workitem->next_fp; 633 const std::vector<GURL>* urls = NULL; 634 bool allow_background_download = false; 635 if (CanTryDiffUpdate(workitem, *config_)) { 636 urls = &workitem->crx_diffurls; 637 ChangeItemState(workitem, CrxUpdateItem::kDownloadingDiff); 638 } else { 639 // Background downloads are enabled only for selected components and 640 // only for full downloads (see issue 340448). 641 allow_background_download = workitem->component.allow_background_download; 642 urls = &workitem->crx_urls; 643 ChangeItemState(workitem, CrxUpdateItem::kDownloading); 644 } 645 646 // On demand component updates are always downloaded in foreground. 647 const bool is_background_download = !workitem->on_demand && 648 allow_background_download && 649 config_->UseBackgroundDownloader(); 650 651 crx_downloader_.reset( 652 CrxDownloader::Create(is_background_download, 653 config_->RequestContext(), 654 blocking_task_runner_, 655 config_->GetSingleThreadTaskRunner())); 656 crx_downloader_->set_progress_callback( 657 base::Bind(&CrxUpdateService::DownloadProgress, 658 base::Unretained(this), 659 crx_context->id)); 660 crx_downloader_->StartDownload(*urls, 661 base::Bind(&CrxUpdateService::DownloadComplete, 662 base::Unretained(this), 663 base::Passed(&crx_context))); 664 } 665 666 void CrxUpdateService::UpdateCheckComplete( 667 const GURL& original_url, 668 int error, 669 const std::string& error_message, 670 const UpdateResponse::Results& results) { 671 DCHECK(thread_checker_.CalledOnValidThread()); 672 VLOG(1) << "Update check completed from: " << original_url.spec(); 673 update_checker_.reset(); 674 if (!error) 675 OnUpdateCheckSucceeded(results); 676 else 677 OnUpdateCheckFailed(error, error_message); 678 } 679 680 // Handles a valid Omaha update check response by matching the results with 681 // the registered components which were checked for updates. 682 // If updates are found, prepare the components for the actual version upgrade. 683 // One of these components will be drafted for the upgrade next time 684 // ProcessPendingItems is called. 685 void CrxUpdateService::OnUpdateCheckSucceeded( 686 const UpdateResponse::Results& results) { 687 size_t num_updates_pending = 0; 688 DCHECK(thread_checker_.CalledOnValidThread()); 689 VLOG(1) << "Update check succeeded."; 690 std::vector<UpdateResponse::Result>::const_iterator it; 691 for (it = results.list.begin(); it != results.list.end(); ++it) { 692 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id); 693 if (!crx) 694 continue; 695 696 if (crx->status != CrxUpdateItem::kChecking) { 697 NOTREACHED(); 698 continue; // Not updating this component now. 699 } 700 701 if (it->manifest.version.empty()) { 702 // No version means no update available. 703 ChangeItemState(crx, CrxUpdateItem::kNoUpdate); 704 VLOG(1) << "No update available for component: " << crx->id; 705 continue; 706 } 707 708 if (!IsVersionNewer(crx->component.version, it->manifest.version)) { 709 // The component is up to date. 710 ChangeItemState(crx, CrxUpdateItem::kUpToDate); 711 VLOG(1) << "Component already up-to-date: " << crx->id; 712 continue; 713 } 714 715 if (!it->manifest.browser_min_version.empty()) { 716 if (IsVersionNewer(config_->GetBrowserVersion(), 717 it->manifest.browser_min_version)) { 718 // The component is not compatible with this Chrome version. 719 VLOG(1) << "Ignoring incompatible component: " << crx->id; 720 ChangeItemState(crx, CrxUpdateItem::kNoUpdate); 721 continue; 722 } 723 } 724 725 if (it->manifest.packages.size() != 1) { 726 // Assume one and only one package per component. 727 VLOG(1) << "Ignoring multiple packages for component: " << crx->id; 728 ChangeItemState(crx, CrxUpdateItem::kNoUpdate); 729 continue; 730 } 731 732 // Parse the members of the result and queue an upgrade for this component. 733 crx->next_version = Version(it->manifest.version); 734 735 VLOG(1) << "Update found for component: " << crx->id; 736 737 typedef UpdateResponse::Result::Manifest::Package Package; 738 const Package& package(it->manifest.packages[0]); 739 crx->next_fp = package.fingerprint; 740 741 // Resolve the urls by combining the base urls with the package names. 742 for (size_t i = 0; i != it->crx_urls.size(); ++i) { 743 const GURL url(it->crx_urls[i].Resolve(package.name)); 744 if (url.is_valid()) 745 crx->crx_urls.push_back(url); 746 } 747 for (size_t i = 0; i != it->crx_diffurls.size(); ++i) { 748 const GURL url(it->crx_diffurls[i].Resolve(package.namediff)); 749 if (url.is_valid()) 750 crx->crx_diffurls.push_back(url); 751 } 752 753 ChangeItemState(crx, CrxUpdateItem::kCanUpdate); 754 ++num_updates_pending; 755 } 756 757 // All components that are not included in the update response are 758 // considered up to date. 759 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate); 760 761 // If there are updates pending we do a short wait, otherwise we take 762 // a longer delay until we check the components again. 763 ScheduleNextRun(num_updates_pending > 0 ? kStepDelayShort : kStepDelayLong); 764 } 765 766 void CrxUpdateService::OnUpdateCheckFailed(int error, 767 const std::string& error_message) { 768 DCHECK(thread_checker_.CalledOnValidThread()); 769 DCHECK(error); 770 size_t count = 771 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kNoUpdate); 772 DCHECK_GT(count, 0ul); 773 VLOG(1) << "Update check failed."; 774 ScheduleNextRun(kStepDelayLong); 775 } 776 777 // Called when progress is being made downloading a CRX. The progress may 778 // not monotonically increase due to how the CRX downloader switches between 779 // different downloaders and fallback urls. 780 void CrxUpdateService::DownloadProgress( 781 const std::string& component_id, 782 const CrxDownloader::Result& download_result) { 783 DCHECK(thread_checker_.CalledOnValidThread()); 784 NotifyObservers(Observer::COMPONENT_UPDATE_DOWNLOADING, component_id); 785 } 786 787 // Called when the CRX package has been downloaded to a temporary location. 788 // Here we fire the notifications and schedule the component-specific installer 789 // to be called in the file thread. 790 void CrxUpdateService::DownloadComplete( 791 scoped_ptr<CRXContext> crx_context, 792 const CrxDownloader::Result& download_result) { 793 DCHECK(thread_checker_.CalledOnValidThread()); 794 795 CrxUpdateItem* crx = FindUpdateItemById(crx_context->id); 796 DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff || 797 crx->status == CrxUpdateItem::kDownloading); 798 799 AppendDownloadMetrics(crx_downloader_->download_metrics(), 800 &crx->download_metrics); 801 802 crx_downloader_.reset(); 803 804 if (download_result.error) { 805 if (crx->status == CrxUpdateItem::kDownloadingDiff) { 806 crx->diff_error_category = kNetworkError; 807 crx->diff_error_code = download_result.error; 808 crx->diff_update_failed = true; 809 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff, 810 CrxUpdateItem::kCanUpdate); 811 DCHECK_EQ(count, 1ul); 812 813 ScheduleNextRun(kStepDelayShort); 814 return; 815 } 816 crx->error_category = kNetworkError; 817 crx->error_code = download_result.error; 818 size_t count = 819 ChangeItemStatus(CrxUpdateItem::kDownloading, CrxUpdateItem::kNoUpdate); 820 DCHECK_EQ(count, 1ul); 821 822 // At this point, since both the differential and the full downloads failed, 823 // the update for this component has finished with an error. 824 ping_manager_->OnUpdateComplete(crx); 825 826 // Move on to the next update, if there is one available. 827 ScheduleNextRun(kStepDelayMedium); 828 } else { 829 size_t count = 0; 830 if (crx->status == CrxUpdateItem::kDownloadingDiff) { 831 count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff, 832 CrxUpdateItem::kUpdatingDiff); 833 } else { 834 count = ChangeItemStatus(CrxUpdateItem::kDownloading, 835 CrxUpdateItem::kUpdating); 836 } 837 DCHECK_EQ(count, 1ul); 838 839 // Why unretained? See comment at top of file. 840 blocking_task_runner_->PostDelayedTask( 841 FROM_HERE, 842 base::Bind(&CrxUpdateService::Install, 843 base::Unretained(this), 844 base::Passed(&crx_context), 845 download_result.response), 846 base::TimeDelta::FromMilliseconds(config_->StepDelay())); 847 } 848 } 849 850 // Install consists of digital signature verification, unpacking and then 851 // calling the component specific installer. All that is handled by the 852 // |unpacker_|. If there is an error this function is in charge of deleting 853 // the files created. 854 void CrxUpdateService::Install(scoped_ptr<CRXContext> context, 855 const base::FilePath& crx_path) { 856 // This function owns the file at |crx_path| and the |context| object. 857 unpacker_ = new ComponentUnpacker(context->pk_hash, 858 crx_path, 859 context->fingerprint, 860 context->installer, 861 config_->CreateOutOfProcessPatcher(), 862 blocking_task_runner_); 863 unpacker_->Unpack(base::Bind(&CrxUpdateService::EndUnpacking, 864 base::Unretained(this), 865 context->id, 866 crx_path)); 867 } 868 869 void CrxUpdateService::EndUnpacking(const std::string& component_id, 870 const base::FilePath& crx_path, 871 ComponentUnpacker::Error error, 872 int extended_error) { 873 if (!DeleteFileAndEmptyParentDirectory(crx_path)) 874 NOTREACHED() << crx_path.value(); 875 main_task_runner_->PostDelayedTask( 876 FROM_HERE, 877 base::Bind(&CrxUpdateService::DoneInstalling, 878 base::Unretained(this), 879 component_id, 880 error, 881 extended_error), 882 base::TimeDelta::FromMilliseconds(config_->StepDelay())); 883 // Reset the unpacker last, otherwise we free our own arguments. 884 unpacker_ = NULL; 885 } 886 887 // Installation has been completed. Adjust the component status and 888 // schedule the next check. Schedule a short delay before trying the full 889 // update when the differential update failed. 890 void CrxUpdateService::DoneInstalling(const std::string& component_id, 891 ComponentUnpacker::Error error, 892 int extra_code) { 893 DCHECK(thread_checker_.CalledOnValidThread()); 894 895 ErrorCategory error_category = kErrorNone; 896 switch (error) { 897 case ComponentUnpacker::kNone: 898 break; 899 case ComponentUnpacker::kInstallerError: 900 error_category = kInstallError; 901 break; 902 default: 903 error_category = kUnpackError; 904 break; 905 } 906 907 const bool is_success = error == ComponentUnpacker::kNone; 908 909 CrxUpdateItem* item = FindUpdateItemById(component_id); 910 if (item->status == CrxUpdateItem::kUpdatingDiff && !is_success) { 911 item->diff_error_category = error_category; 912 item->diff_error_code = error; 913 item->diff_extra_code1 = extra_code; 914 item->diff_update_failed = true; 915 size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff, 916 CrxUpdateItem::kCanUpdate); 917 DCHECK_EQ(count, 1ul); 918 ScheduleNextRun(kStepDelayShort); 919 return; 920 } 921 922 if (is_success) { 923 item->component.version = item->next_version; 924 item->component.fingerprint = item->next_fp; 925 ChangeItemState(item, CrxUpdateItem::kUpdated); 926 } else { 927 item->error_category = error_category; 928 item->error_code = error; 929 item->extra_code1 = extra_code; 930 ChangeItemState(item, CrxUpdateItem::kNoUpdate); 931 } 932 933 ping_manager_->OnUpdateComplete(item); 934 935 // Move on to the next update, if there is one available. 936 ScheduleNextRun(kStepDelayMedium); 937 } 938 939 void CrxUpdateService::NotifyObservers(Observer::Events event, 940 const std::string& id) { 941 DCHECK(thread_checker_.CalledOnValidThread()); 942 FOR_EACH_OBSERVER(Observer, observer_list_, OnEvent(event, id)); 943 } 944 945 ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateWithCooldown( 946 CrxUpdateItem* uit) { 947 if (!uit) 948 return kError; 949 950 // Check if the request is too soon. 951 base::TimeDelta delta = base::Time::Now() - uit->last_check; 952 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay())) 953 return kError; 954 955 return OnDemandUpdateInternal(uit); 956 } 957 958 ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateInternal( 959 CrxUpdateItem* uit) { 960 if (!uit) 961 return kError; 962 963 uit->on_demand = true; 964 965 // If there is an update available for this item, then continue processing 966 // the update. This is an artifact of how update checks are done: in addition 967 // to the on-demand item, the update check may include other items as well. 968 if (uit->status != CrxUpdateItem::kCanUpdate) { 969 Status service_status = GetServiceStatus(uit->status); 970 // If the item is already in the process of being updated, there is 971 // no point in this call, so return kInProgress. 972 if (service_status == kInProgress) 973 return service_status; 974 975 // Otherwise the item was already checked a while back (or it is new), 976 // set its status to kNew to give it a slightly higher priority. 977 ChangeItemState(uit, CrxUpdateItem::kNew); 978 } 979 980 // In case the current delay is long, set the timer to a shorter value 981 // to get the ball rolling. 982 if (timer_.IsRunning()) { 983 timer_.Stop(); 984 timer_.Start(FROM_HERE, 985 base::TimeDelta::FromSeconds(config_->StepDelay()), 986 this, 987 &CrxUpdateService::ProcessPendingItems); 988 } 989 990 return kOk; 991 } 992 993 ComponentUpdateService::Status CrxUpdateService::GetServiceStatus( 994 CrxUpdateItem::Status status) { 995 switch (status) { 996 case CrxUpdateItem::kChecking: 997 case CrxUpdateItem::kCanUpdate: 998 case CrxUpdateItem::kDownloadingDiff: 999 case CrxUpdateItem::kDownloading: 1000 case CrxUpdateItem::kUpdatingDiff: 1001 case CrxUpdateItem::kUpdating: 1002 return kInProgress; 1003 case CrxUpdateItem::kNew: 1004 case CrxUpdateItem::kUpdated: 1005 case CrxUpdateItem::kUpToDate: 1006 case CrxUpdateItem::kNoUpdate: 1007 return kOk; 1008 case CrxUpdateItem::kLastStatus: 1009 NOTREACHED() << status; 1010 } 1011 return kError; 1012 } 1013 1014 /////////////////////////////////////////////////////////////////////////////// 1015 1016 // The component update factory. Using the component updater as a singleton 1017 // is the job of the browser process. 1018 ComponentUpdateService* ComponentUpdateServiceFactory(Configurator* config) { 1019 DCHECK(config); 1020 return new CrxUpdateService(config); 1021 } 1022 1023 } // namespace component_updater 1024