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/extensions/updater/extension_updater.h" 6 7 #include <algorithm> 8 #include <set> 9 10 #include "base/bind.h" 11 #include "base/files/file_util.h" 12 #include "base/logging.h" 13 #include "base/metrics/histogram.h" 14 #include "base/prefs/pref_service.h" 15 #include "base/rand_util.h" 16 #include "base/stl_util.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_split.h" 19 #include "chrome/browser/chrome_notification_types.h" 20 #include "chrome/browser/extensions/api/module/module.h" 21 #include "chrome/browser/extensions/crx_installer.h" 22 #include "chrome/browser/extensions/extension_service.h" 23 #include "chrome/browser/extensions/pending_extension_manager.h" 24 #include "chrome/browser/profiles/profile.h" 25 #include "chrome/common/pref_names.h" 26 #include "components/omaha_query_params/omaha_query_params.h" 27 #include "content/public/browser/browser_thread.h" 28 #include "content/public/browser/notification_details.h" 29 #include "content/public/browser/notification_service.h" 30 #include "content/public/browser/notification_source.h" 31 #include "crypto/sha2.h" 32 #include "extensions/browser/extension_prefs.h" 33 #include "extensions/browser/extension_registry.h" 34 #include "extensions/browser/pref_names.h" 35 #include "extensions/common/constants.h" 36 #include "extensions/common/extension.h" 37 #include "extensions/common/extension_set.h" 38 #include "extensions/common/manifest.h" 39 #include "extensions/common/manifest_constants.h" 40 41 using base::RandDouble; 42 using base::RandInt; 43 using base::Time; 44 using base::TimeDelta; 45 using content::BrowserThread; 46 using extensions::Extension; 47 using extensions::ExtensionSet; 48 using omaha_query_params::OmahaQueryParams; 49 50 typedef extensions::ExtensionDownloaderDelegate::Error Error; 51 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult; 52 53 namespace { 54 55 // Wait at least 5 minutes after browser startup before we do any checks. If you 56 // change this value, make sure to update comments where it is used. 57 const int kStartupWaitSeconds = 60 * 5; 58 59 // For sanity checking on update frequency - enforced in release mode only. 60 #if defined(NDEBUG) 61 const int kMinUpdateFrequencySeconds = 30; 62 #endif 63 const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days 64 65 // Require at least 5 seconds between consecutive non-succesful extension update 66 // checks. 67 const int kMinUpdateThrottleTime = 5; 68 69 // The installsource query parameter to use when forcing updates due to NaCl 70 // arch mismatch. 71 const char kWrongMultiCrxInstallSource[] = "wrong_multi_crx"; 72 73 // When we've computed a days value, we want to make sure we don't send a 74 // negative value (due to the system clock being set backwards, etc.), since -1 75 // is a special sentinel value that means "never pinged", and other negative 76 // values don't make sense. 77 int SanitizeDays(int days) { 78 if (days < 0) 79 return 0; 80 return days; 81 } 82 83 // Calculates the value to use for the ping days parameter. 84 int CalculatePingDays(const Time& last_ping_day) { 85 int days = extensions::ManifestFetchData::kNeverPinged; 86 if (!last_ping_day.is_null()) { 87 days = SanitizeDays((Time::Now() - last_ping_day).InDays()); 88 } 89 return days; 90 } 91 92 int CalculateActivePingDays(const Time& last_active_ping_day, 93 bool hasActiveBit) { 94 if (!hasActiveBit) 95 return 0; 96 if (last_active_ping_day.is_null()) 97 return extensions::ManifestFetchData::kNeverPinged; 98 return SanitizeDays((Time::Now() - last_active_ping_day).InDays()); 99 } 100 101 void RespondWithForcedUpdates( 102 const base::Callback<void(const std::set<std::string>&)>& callback, 103 scoped_ptr<std::set<std::string> > forced_updates) { 104 callback.Run(*forced_updates.get()); 105 } 106 107 void DetermineForcedUpdatesOnBlockingPool( 108 scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions, 109 const base::Callback<void(const std::set<std::string>&)>& callback) { 110 scoped_ptr<std::set<std::string> > forced_updates( 111 new std::set<std::string>()); 112 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 113 for (std::vector<scoped_refptr<const Extension> >::const_iterator iter = 114 extensions->begin(); 115 iter != extensions->end(); 116 ++iter) { 117 scoped_refptr<const Extension> extension = *iter; 118 base::FilePath platform_specific_path = extension->path().Append( 119 extensions::kPlatformSpecificFolder); 120 if (base::PathExists(platform_specific_path)) { 121 bool force = true; 122 const base::ListValue* platforms; 123 if (extension->manifest()->GetList(extensions::manifest_keys::kPlatforms, 124 &platforms)) { 125 for (size_t i = 0; i < platforms->GetSize(); ++i) { 126 const base::DictionaryValue* p; 127 if (platforms->GetDictionary(i, &p)) { 128 std::string nacl_arch; 129 if (p->GetString(extensions::manifest_keys::kNaClArch, 130 &nacl_arch) && 131 nacl_arch == OmahaQueryParams::GetNaclArch()) { 132 std::string subpath; 133 if (p->GetString(extensions::manifest_keys::kSubPackagePath, 134 &subpath)) { 135 // _platform_specific is part of the sub_package_path entry. 136 base::FilePath platform_specific_subpath = 137 extension->path().AppendASCII(subpath); 138 if (base::PathExists(platform_specific_subpath)) { 139 force = false; 140 } 141 } 142 } 143 } 144 } 145 } 146 147 if (force) 148 forced_updates->insert(extension->id()); 149 } 150 } 151 BrowserThread::PostTask( 152 BrowserThread::UI, 153 FROM_HERE, 154 base::Bind(&RespondWithForcedUpdates, 155 callback, 156 base::Passed(&forced_updates))); 157 } 158 159 void CollectExtensionsFromSet( 160 const ExtensionSet& extensions, 161 std::vector<scoped_refptr<const Extension> >* paths) { 162 std::copy(extensions.begin(), extensions.end(), std::back_inserter(*paths)); 163 } 164 165 void DetermineForcedUpdates( 166 content::BrowserContext* browser_context, 167 const base::Callback<void(const std::set<std::string>&)>& callback) { 168 scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions( 169 new std::vector<scoped_refptr<const Extension> >()); 170 const extensions::ExtensionRegistry* registry = 171 extensions::ExtensionRegistry::Get(browser_context); 172 scoped_ptr<ExtensionSet> installed_extensions = 173 registry->GenerateInstalledExtensionsSet(); 174 CollectExtensionsFromSet(*installed_extensions.get(), extensions.get()); 175 BrowserThread::PostBlockingPoolTask( 176 FROM_HERE, 177 base::Bind(&DetermineForcedUpdatesOnBlockingPool, 178 base::Passed(&extensions), 179 callback)); 180 } 181 182 } // namespace 183 184 namespace extensions { 185 186 ExtensionUpdater::CheckParams::CheckParams() 187 : install_immediately(false) {} 188 189 ExtensionUpdater::CheckParams::~CheckParams() {} 190 191 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile( 192 const std::string& i, 193 const base::FilePath& p, 194 bool file_ownership_passed, 195 const std::set<int>& request_ids) 196 : extension_id(i), 197 path(p), 198 file_ownership_passed(file_ownership_passed), 199 request_ids(request_ids) {} 200 201 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile() 202 : path(), file_ownership_passed(true) {} 203 204 ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() {} 205 206 ExtensionUpdater::InProgressCheck::InProgressCheck() 207 : install_immediately(false) {} 208 209 ExtensionUpdater::InProgressCheck::~InProgressCheck() {} 210 211 struct ExtensionUpdater::ThrottleInfo { 212 ThrottleInfo() 213 : in_progress(true), 214 throttle_delay(kMinUpdateThrottleTime), 215 check_start(Time::Now()) {} 216 217 bool in_progress; 218 int throttle_delay; 219 Time check_start; 220 }; 221 222 ExtensionUpdater::ExtensionUpdater( 223 ExtensionServiceInterface* service, 224 ExtensionPrefs* extension_prefs, 225 PrefService* prefs, 226 Profile* profile, 227 int frequency_seconds, 228 ExtensionCache* cache, 229 const ExtensionDownloader::Factory& downloader_factory) 230 : alive_(false), 231 service_(service), 232 downloader_factory_(downloader_factory), 233 frequency_seconds_(frequency_seconds), 234 will_check_soon_(false), 235 extension_prefs_(extension_prefs), 236 prefs_(prefs), 237 profile_(profile), 238 next_request_id_(0), 239 extension_registry_observer_(this), 240 crx_install_is_running_(false), 241 extension_cache_(cache), 242 weak_ptr_factory_(this) { 243 DCHECK_GE(frequency_seconds_, 5); 244 DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds); 245 #if defined(NDEBUG) 246 // In Release mode we enforce that update checks don't happen too often. 247 frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds); 248 #endif 249 frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds); 250 251 extension_registry_observer_.Add(ExtensionRegistry::Get(profile)); 252 } 253 254 ExtensionUpdater::~ExtensionUpdater() { 255 Stop(); 256 } 257 258 void ExtensionUpdater::EnsureDownloaderCreated() { 259 if (!downloader_.get()) { 260 downloader_ = downloader_factory_.Run(this); 261 } 262 } 263 264 // The overall goal here is to balance keeping clients up to date while 265 // avoiding a thundering herd against update servers. 266 TimeDelta ExtensionUpdater::DetermineFirstCheckDelay() { 267 DCHECK(alive_); 268 // If someone's testing with a quick frequency, just allow it. 269 if (frequency_seconds_ < kStartupWaitSeconds) 270 return TimeDelta::FromSeconds(frequency_seconds_); 271 272 // If we've never scheduled a check before, start at frequency_seconds_. 273 if (!prefs_->HasPrefPath(pref_names::kNextUpdateCheck)) 274 return TimeDelta::FromSeconds(frequency_seconds_); 275 276 // If it's been a long time since our last actual check, we want to do one 277 // relatively soon. 278 Time now = Time::Now(); 279 Time last = Time::FromInternalValue(prefs_->GetInt64( 280 pref_names::kLastUpdateCheck)); 281 int days = (now - last).InDays(); 282 if (days >= 30) { 283 // Wait 5-10 minutes. 284 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds, 285 kStartupWaitSeconds * 2)); 286 } else if (days >= 14) { 287 // Wait 10-20 minutes. 288 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 2, 289 kStartupWaitSeconds * 4)); 290 } else if (days >= 3) { 291 // Wait 20-40 minutes. 292 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 4, 293 kStartupWaitSeconds * 8)); 294 } 295 296 // Read the persisted next check time, and use that if it isn't too soon 297 // or too late. Otherwise pick something random. 298 Time saved_next = Time::FromInternalValue(prefs_->GetInt64( 299 pref_names::kNextUpdateCheck)); 300 Time earliest = now + TimeDelta::FromSeconds(kStartupWaitSeconds); 301 Time latest = now + TimeDelta::FromSeconds(frequency_seconds_); 302 if (saved_next >= earliest && saved_next <= latest) { 303 return saved_next - now; 304 } else { 305 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds, 306 frequency_seconds_)); 307 } 308 } 309 310 void ExtensionUpdater::Start() { 311 DCHECK(!alive_); 312 // If these are NULL, then that means we've been called after Stop() 313 // has been called. 314 DCHECK(service_); 315 DCHECK(extension_prefs_); 316 DCHECK(prefs_); 317 DCHECK(profile_); 318 DCHECK(!weak_ptr_factory_.HasWeakPtrs()); 319 alive_ = true; 320 // Make sure our prefs are registered, then schedule the first check. 321 ScheduleNextCheck(DetermineFirstCheckDelay()); 322 } 323 324 void ExtensionUpdater::Stop() { 325 weak_ptr_factory_.InvalidateWeakPtrs(); 326 alive_ = false; 327 service_ = NULL; 328 extension_prefs_ = NULL; 329 prefs_ = NULL; 330 profile_ = NULL; 331 timer_.Stop(); 332 will_check_soon_ = false; 333 downloader_.reset(); 334 } 335 336 void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) { 337 DCHECK(alive_); 338 DCHECK(!timer_.IsRunning()); 339 DCHECK(target_delay >= TimeDelta::FromSeconds(1)); 340 341 // Add +/- 10% random jitter. 342 double delay_ms = target_delay.InMillisecondsF(); 343 double jitter_factor = (RandDouble() * .2) - 0.1; 344 delay_ms += delay_ms * jitter_factor; 345 TimeDelta actual_delay = TimeDelta::FromMilliseconds( 346 static_cast<int64>(delay_ms)); 347 348 // Save the time of next check. 349 Time next = Time::Now() + actual_delay; 350 prefs_->SetInt64(pref_names::kNextUpdateCheck, next.ToInternalValue()); 351 352 timer_.Start(FROM_HERE, actual_delay, this, &ExtensionUpdater::TimerFired); 353 } 354 355 void ExtensionUpdater::TimerFired() { 356 DCHECK(alive_); 357 CheckNow(default_params_); 358 359 // If the user has overridden the update frequency, don't bother reporting 360 // this. 361 if (frequency_seconds_ == extensions::kDefaultUpdateFrequencySeconds) { 362 Time last = Time::FromInternalValue(prefs_->GetInt64( 363 pref_names::kLastUpdateCheck)); 364 if (last.ToInternalValue() != 0) { 365 // Use counts rather than time so we can use minutes rather than millis. 366 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.UpdateCheckGap", 367 (Time::Now() - last).InMinutes(), 368 TimeDelta::FromSeconds(kStartupWaitSeconds).InMinutes(), 369 TimeDelta::FromDays(40).InMinutes(), 370 50); // 50 buckets seems to be the default. 371 } 372 } 373 374 // Save the last check time, and schedule the next check. 375 int64 now = Time::Now().ToInternalValue(); 376 prefs_->SetInt64(pref_names::kLastUpdateCheck, now); 377 ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_)); 378 } 379 380 void ExtensionUpdater::CheckSoon() { 381 DCHECK(alive_); 382 if (will_check_soon_) 383 return; 384 if (BrowserThread::PostTask( 385 BrowserThread::UI, FROM_HERE, 386 base::Bind(&ExtensionUpdater::DoCheckSoon, 387 weak_ptr_factory_.GetWeakPtr()))) { 388 will_check_soon_ = true; 389 } else { 390 NOTREACHED(); 391 } 392 } 393 394 bool ExtensionUpdater::WillCheckSoon() const { 395 return will_check_soon_; 396 } 397 398 void ExtensionUpdater::DoCheckSoon() { 399 DCHECK(will_check_soon_); 400 CheckNow(default_params_); 401 will_check_soon_ = false; 402 } 403 404 void ExtensionUpdater::AddToDownloader( 405 const ExtensionSet* extensions, 406 const std::list<std::string>& pending_ids, 407 int request_id) { 408 InProgressCheck& request = requests_in_progress_[request_id]; 409 for (ExtensionSet::const_iterator extension_iter = extensions->begin(); 410 extension_iter != extensions->end(); ++extension_iter) { 411 const Extension& extension = *extension_iter->get(); 412 if (!Manifest::IsAutoUpdateableLocation(extension.location())) { 413 VLOG(2) << "Extension " << extension.id() << " is not auto updateable"; 414 continue; 415 } 416 // An extension might be overwritten by policy, and have its update url 417 // changed. Make sure existing extensions aren't fetched again, if a 418 // pending fetch for an extension with the same id already exists. 419 std::list<std::string>::const_iterator pending_id_iter = std::find( 420 pending_ids.begin(), pending_ids.end(), extension.id()); 421 if (pending_id_iter == pending_ids.end()) { 422 if (downloader_->AddExtension(extension, request_id)) 423 request.in_progress_ids_.push_back(extension.id()); 424 } 425 } 426 } 427 428 void ExtensionUpdater::CheckNow(const CheckParams& params) { 429 DetermineForcedUpdates( 430 profile_, 431 base::Bind(&ExtensionUpdater::OnForcedUpdatesDetermined, 432 weak_ptr_factory_.GetWeakPtr(), 433 params)); 434 } 435 436 void ExtensionUpdater::OnForcedUpdatesDetermined( 437 const CheckParams& params, 438 const std::set<std::string>& forced_updates) { 439 int request_id = next_request_id_++; 440 441 VLOG(2) << "Starting update check " << request_id; 442 if (params.ids.empty()) 443 NotifyStarted(); 444 445 DCHECK(alive_); 446 447 InProgressCheck& request = requests_in_progress_[request_id]; 448 request.callback = params.callback; 449 request.install_immediately = params.install_immediately; 450 451 EnsureDownloaderCreated(); 452 453 forced_updates_ = forced_updates; 454 455 // Add fetch records for extensions that should be fetched by an update URL. 456 // These extensions are not yet installed. They come from group policy 457 // and external install sources. 458 const PendingExtensionManager* pending_extension_manager = 459 service_->pending_extension_manager(); 460 461 std::list<std::string> pending_ids; 462 463 if (params.ids.empty()) { 464 // If no extension ids are specified, check for updates for all extensions. 465 pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_ids); 466 467 std::list<std::string>::const_iterator iter; 468 for (iter = pending_ids.begin(); iter != pending_ids.end(); ++iter) { 469 const PendingExtensionInfo* info = pending_extension_manager->GetById( 470 *iter); 471 if (!Manifest::IsAutoUpdateableLocation(info->install_source())) { 472 VLOG(2) << "Extension " << *iter << " is not auto updateable"; 473 continue; 474 } 475 if (downloader_->AddPendingExtension(*iter, info->update_url(), 476 request_id)) 477 request.in_progress_ids_.push_back(*iter); 478 } 479 480 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); 481 AddToDownloader(®istry->enabled_extensions(), pending_ids, request_id); 482 AddToDownloader(®istry->disabled_extensions(), pending_ids, request_id); 483 } else { 484 for (std::list<std::string>::const_iterator it = params.ids.begin(); 485 it != params.ids.end(); ++it) { 486 const Extension* extension = service_->GetExtensionById(*it, true); 487 DCHECK(extension); 488 if (downloader_->AddExtension(*extension, request_id)) 489 request.in_progress_ids_.push_back(extension->id()); 490 } 491 } 492 493 // StartAllPending() might call OnExtensionDownloadFailed/Finished before 494 // it returns, which would cause NotifyIfFinished to incorrectly try to 495 // send out a notification. So check before we call StartAllPending if any 496 // extensions are going to be updated, and use that to figure out if 497 // NotifyIfFinished should be called. 498 bool noChecks = request.in_progress_ids_.empty(); 499 500 // StartAllPending() will call OnExtensionDownloadFailed or 501 // OnExtensionDownloadFinished for each extension that was checked. 502 downloader_->StartAllPending(extension_cache_); 503 504 if (noChecks) 505 NotifyIfFinished(request_id); 506 } 507 508 bool ExtensionUpdater::CheckExtensionSoon(const std::string& extension_id, 509 const FinishedCallback& callback) { 510 bool have_throttle_info = ContainsKey(throttle_info_, extension_id); 511 ThrottleInfo& info = throttle_info_[extension_id]; 512 if (have_throttle_info) { 513 // We already had a ThrottleInfo object for this extension, check if the 514 // update check request should be allowed. 515 516 // If another check is in progress, don't start a new check. 517 if (info.in_progress) 518 return false; 519 520 Time now = Time::Now(); 521 Time last = info.check_start; 522 // If somehow time moved back, we don't want to infinitely keep throttling. 523 if (now < last) { 524 last = now; 525 info.check_start = now; 526 } 527 Time earliest = last + TimeDelta::FromSeconds(info.throttle_delay); 528 // If check is too soon, throttle. 529 if (now < earliest) 530 return false; 531 532 // TODO(mek): Somehow increase time between allowing checks when checks 533 // are repeatedly throttled and don't result in updates being installed. 534 535 // It's okay to start a check, update values. 536 info.check_start = now; 537 info.in_progress = true; 538 } 539 540 CheckParams params; 541 params.ids.push_back(extension_id); 542 params.callback = base::Bind(&ExtensionUpdater::ExtensionCheckFinished, 543 weak_ptr_factory_.GetWeakPtr(), 544 extension_id, callback); 545 CheckNow(params); 546 return true; 547 } 548 549 void ExtensionUpdater::ExtensionCheckFinished( 550 const std::string& extension_id, 551 const FinishedCallback& callback) { 552 std::map<std::string, ThrottleInfo>::iterator it = 553 throttle_info_.find(extension_id); 554 if (it != throttle_info_.end()) { 555 it->second.in_progress = false; 556 } 557 callback.Run(); 558 } 559 560 void ExtensionUpdater::OnExtensionDownloadFailed( 561 const std::string& id, 562 Error error, 563 const PingResult& ping, 564 const std::set<int>& request_ids) { 565 DCHECK(alive_); 566 UpdatePingData(id, ping); 567 bool install_immediately = false; 568 for (std::set<int>::const_iterator it = request_ids.begin(); 569 it != request_ids.end(); ++it) { 570 InProgressCheck& request = requests_in_progress_[*it]; 571 install_immediately |= request.install_immediately; 572 request.in_progress_ids_.remove(id); 573 NotifyIfFinished(*it); 574 } 575 576 // This method is called if no updates were found. However a previous update 577 // check might have queued an update for this extension already. If a 578 // current update check has |install_immediately| set the previously 579 // queued update should be installed now. 580 if (install_immediately && service_->GetPendingExtensionUpdate(id)) 581 service_->FinishDelayedInstallation(id); 582 } 583 584 void ExtensionUpdater::OnExtensionDownloadFinished( 585 const std::string& id, 586 const base::FilePath& path, 587 bool file_ownership_passed, 588 const GURL& download_url, 589 const std::string& version, 590 const PingResult& ping, 591 const std::set<int>& request_ids) { 592 DCHECK(alive_); 593 UpdatePingData(id, ping); 594 595 VLOG(2) << download_url << " written to " << path.value(); 596 597 FetchedCRXFile fetched(id, path, file_ownership_passed, request_ids); 598 fetched_crx_files_.push(fetched); 599 600 // MaybeInstallCRXFile() removes extensions from |in_progress_ids_| after 601 // starting the crx installer. 602 MaybeInstallCRXFile(); 603 } 604 605 bool ExtensionUpdater::GetPingDataForExtension( 606 const std::string& id, 607 ManifestFetchData::PingData* ping_data) { 608 DCHECK(alive_); 609 ping_data->rollcall_days = CalculatePingDays( 610 extension_prefs_->LastPingDay(id)); 611 ping_data->is_enabled = service_->IsExtensionEnabled(id); 612 ping_data->active_days = 613 CalculateActivePingDays(extension_prefs_->LastActivePingDay(id), 614 extension_prefs_->GetActiveBit(id)); 615 return true; 616 } 617 618 std::string ExtensionUpdater::GetUpdateUrlData(const std::string& id) { 619 DCHECK(alive_); 620 return extension::GetUpdateURLData(extension_prefs_, id); 621 } 622 623 bool ExtensionUpdater::IsExtensionPending(const std::string& id) { 624 DCHECK(alive_); 625 return service_->pending_extension_manager()->IsIdPending(id); 626 } 627 628 bool ExtensionUpdater::GetExtensionExistingVersion(const std::string& id, 629 std::string* version) { 630 DCHECK(alive_); 631 const Extension* extension = service_->GetExtensionById(id, true); 632 if (!extension) 633 return false; 634 const Extension* update = service_->GetPendingExtensionUpdate(id); 635 if (update) 636 *version = update->VersionString(); 637 else 638 *version = extension->VersionString(); 639 return true; 640 } 641 642 bool ExtensionUpdater::ShouldForceUpdate( 643 const std::string& extension_id, 644 std::string* source) { 645 bool force = forced_updates_.find(extension_id) != forced_updates_.end(); 646 // Currently the only reason to force is a NaCl arch mismatch with the 647 // installed extension contents. 648 if (force) { 649 *source = kWrongMultiCrxInstallSource; 650 } 651 return force; 652 } 653 654 void ExtensionUpdater::UpdatePingData(const std::string& id, 655 const PingResult& ping_result) { 656 DCHECK(alive_); 657 if (ping_result.did_ping) 658 extension_prefs_->SetLastPingDay(id, ping_result.day_start); 659 if (extension_prefs_->GetActiveBit(id)) { 660 extension_prefs_->SetActiveBit(id, false); 661 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start); 662 } 663 } 664 665 void ExtensionUpdater::MaybeInstallCRXFile() { 666 if (crx_install_is_running_ || fetched_crx_files_.empty()) 667 return; 668 669 std::set<int> request_ids; 670 671 while (!fetched_crx_files_.empty() && !crx_install_is_running_) { 672 const FetchedCRXFile& crx_file = fetched_crx_files_.top(); 673 674 VLOG(2) << "updating " << crx_file.extension_id 675 << " with " << crx_file.path.value(); 676 677 // The ExtensionService is now responsible for cleaning up the temp file 678 // at |crx_file.path|. 679 CrxInstaller* installer = NULL; 680 if (service_->UpdateExtension(crx_file.extension_id, 681 crx_file.path, 682 crx_file.file_ownership_passed, 683 &installer)) { 684 crx_install_is_running_ = true; 685 current_crx_file_ = crx_file; 686 687 for (std::set<int>::const_iterator it = crx_file.request_ids.begin(); 688 it != crx_file.request_ids.end(); ++it) { 689 InProgressCheck& request = requests_in_progress_[*it]; 690 if (request.install_immediately) { 691 installer->set_install_immediately(true); 692 break; 693 } 694 } 695 696 // Source parameter ensures that we only see the completion event for the 697 // the installer we started. 698 registrar_.Add(this, 699 extensions::NOTIFICATION_CRX_INSTALLER_DONE, 700 content::Source<CrxInstaller>(installer)); 701 } else { 702 for (std::set<int>::const_iterator it = crx_file.request_ids.begin(); 703 it != crx_file.request_ids.end(); ++it) { 704 InProgressCheck& request = requests_in_progress_[*it]; 705 request.in_progress_ids_.remove(crx_file.extension_id); 706 } 707 request_ids.insert(crx_file.request_ids.begin(), 708 crx_file.request_ids.end()); 709 } 710 fetched_crx_files_.pop(); 711 } 712 713 for (std::set<int>::const_iterator it = request_ids.begin(); 714 it != request_ids.end(); ++it) { 715 NotifyIfFinished(*it); 716 } 717 } 718 719 void ExtensionUpdater::Observe(int type, 720 const content::NotificationSource& source, 721 const content::NotificationDetails& details) { 722 DCHECK_EQ(type, extensions::NOTIFICATION_CRX_INSTALLER_DONE); 723 724 registrar_.Remove(this, extensions::NOTIFICATION_CRX_INSTALLER_DONE, source); 725 crx_install_is_running_ = false; 726 727 const FetchedCRXFile& crx_file = current_crx_file_; 728 for (std::set<int>::const_iterator it = crx_file.request_ids.begin(); 729 it != crx_file.request_ids.end(); ++it) { 730 InProgressCheck& request = requests_in_progress_[*it]; 731 request.in_progress_ids_.remove(crx_file.extension_id); 732 NotifyIfFinished(*it); 733 } 734 735 // If any files are available to update, start one. 736 MaybeInstallCRXFile(); 737 } 738 739 void ExtensionUpdater::OnExtensionWillBeInstalled( 740 content::BrowserContext* browser_context, 741 const Extension* extension, 742 bool is_update, 743 bool from_ephemeral, 744 const std::string& old_name) { 745 throttle_info_.erase(extension->id()); 746 } 747 748 void ExtensionUpdater::NotifyStarted() { 749 content::NotificationService::current()->Notify( 750 extensions::NOTIFICATION_EXTENSION_UPDATING_STARTED, 751 content::Source<Profile>(profile_), 752 content::NotificationService::NoDetails()); 753 } 754 755 void ExtensionUpdater::NotifyIfFinished(int request_id) { 756 DCHECK(ContainsKey(requests_in_progress_, request_id)); 757 const InProgressCheck& request = requests_in_progress_[request_id]; 758 if (request.in_progress_ids_.empty()) { 759 VLOG(2) << "Finished update check " << request_id; 760 if (!request.callback.is_null()) 761 request.callback.Run(); 762 requests_in_progress_.erase(request_id); 763 } 764 } 765 766 } // namespace extensions 767