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