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