Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/updater/extension_updater.h" | 5 #include "chrome/browser/extensions/updater/extension_updater.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/files/file_enumerator.h" | |
| 12 #include "base/files/file_util.h" | |
| 11 #include "base/logging.h" | 13 #include "base/logging.h" |
| 12 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 13 #include "base/prefs/pref_service.h" | 15 #include "base/prefs/pref_service.h" |
| 14 #include "base/rand_util.h" | 16 #include "base/rand_util.h" |
| 15 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
| 16 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
| 17 #include "base/strings/string_split.h" | 19 #include "base/strings/string_split.h" |
| 18 #include "chrome/browser/chrome_notification_types.h" | 20 #include "chrome/browser/chrome_notification_types.h" |
| 19 #include "chrome/browser/extensions/api/module/module.h" | 21 #include "chrome/browser/extensions/api/module/module.h" |
| 20 #include "chrome/browser/extensions/crx_installer.h" | 22 #include "chrome/browser/extensions/crx_installer.h" |
| 21 #include "chrome/browser/extensions/extension_service.h" | 23 #include "chrome/browser/extensions/extension_service.h" |
| 22 #include "chrome/browser/extensions/pending_extension_manager.h" | 24 #include "chrome/browser/extensions/pending_extension_manager.h" |
| 23 #include "chrome/browser/profiles/profile.h" | 25 #include "chrome/browser/profiles/profile.h" |
| 24 #include "chrome/common/pref_names.h" | 26 #include "chrome/common/pref_names.h" |
| 27 #include "components/omaha_query_params/omaha_query_params.h" | |
| 25 #include "content/public/browser/browser_thread.h" | 28 #include "content/public/browser/browser_thread.h" |
| 26 #include "content/public/browser/notification_details.h" | 29 #include "content/public/browser/notification_details.h" |
| 27 #include "content/public/browser/notification_service.h" | 30 #include "content/public/browser/notification_service.h" |
| 28 #include "content/public/browser/notification_source.h" | 31 #include "content/public/browser/notification_source.h" |
| 29 #include "crypto/sha2.h" | 32 #include "crypto/sha2.h" |
| 30 #include "extensions/browser/extension_prefs.h" | 33 #include "extensions/browser/extension_prefs.h" |
| 31 #include "extensions/browser/extension_registry.h" | 34 #include "extensions/browser/extension_registry.h" |
| 32 #include "extensions/browser/pref_names.h" | 35 #include "extensions/browser/pref_names.h" |
| 33 #include "extensions/common/constants.h" | 36 #include "extensions/common/constants.h" |
| 34 #include "extensions/common/extension.h" | 37 #include "extensions/common/extension.h" |
| 35 #include "extensions/common/extension_set.h" | 38 #include "extensions/common/extension_set.h" |
| 36 #include "extensions/common/manifest.h" | 39 #include "extensions/common/manifest.h" |
| 37 | 40 |
| 38 using base::RandDouble; | 41 using base::RandDouble; |
| 39 using base::RandInt; | 42 using base::RandInt; |
| 40 using base::Time; | 43 using base::Time; |
| 41 using base::TimeDelta; | 44 using base::TimeDelta; |
| 42 using content::BrowserThread; | 45 using content::BrowserThread; |
| 46 using extensions::Extension; | |
| 47 using extensions::ExtensionSet; | |
| 48 using omaha_query_params::OmahaQueryParams; | |
| 43 | 49 |
| 44 typedef extensions::ExtensionDownloaderDelegate::Error Error; | 50 typedef extensions::ExtensionDownloaderDelegate::Error Error; |
| 45 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult; | 51 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult; |
| 46 | 52 |
| 47 namespace { | 53 namespace { |
| 48 | 54 |
| 49 // Wait at least 5 minutes after browser startup before we do any checks. If you | 55 // Wait at least 5 minutes after browser startup before we do any checks. If you |
| 50 // change this value, make sure to update comments where it is used. | 56 // change this value, make sure to update comments where it is used. |
| 51 const int kStartupWaitSeconds = 60 * 5; | 57 const int kStartupWaitSeconds = 60 * 5; |
| 52 | 58 |
| 53 // For sanity checking on update frequency - enforced in release mode only. | 59 // For sanity checking on update frequency - enforced in release mode only. |
| 54 #if defined(NDEBUG) | 60 #if defined(NDEBUG) |
| 55 const int kMinUpdateFrequencySeconds = 30; | 61 const int kMinUpdateFrequencySeconds = 30; |
| 56 #endif | 62 #endif |
| 57 const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days | 63 const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days |
| 58 | 64 |
| 59 // Require at least 5 seconds between consecutive non-succesful extension update | 65 // Require at least 5 seconds between consecutive non-succesful extension update |
| 60 // checks. | 66 // checks. |
| 61 const int kMinUpdateThrottleTime = 5; | 67 const int kMinUpdateThrottleTime = 5; |
| 62 | 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 | |
| 63 // When we've computed a days value, we want to make sure we don't send a | 73 // When we've computed a days value, we want to make sure we don't send a |
| 64 // negative value (due to the system clock being set backwards, etc.), since -1 | 74 // negative value (due to the system clock being set backwards, etc.), since -1 |
| 65 // is a special sentinel value that means "never pinged", and other negative | 75 // is a special sentinel value that means "never pinged", and other negative |
| 66 // values don't make sense. | 76 // values don't make sense. |
| 67 int SanitizeDays(int days) { | 77 int SanitizeDays(int days) { |
| 68 if (days < 0) | 78 if (days < 0) |
| 69 return 0; | 79 return 0; |
| 70 return days; | 80 return days; |
| 71 } | 81 } |
| 72 | 82 |
| 73 // Calculates the value to use for the ping days parameter. | 83 // Calculates the value to use for the ping days parameter. |
| 74 int CalculatePingDays(const Time& last_ping_day) { | 84 int CalculatePingDays(const Time& last_ping_day) { |
| 75 int days = extensions::ManifestFetchData::kNeverPinged; | 85 int days = extensions::ManifestFetchData::kNeverPinged; |
| 76 if (!last_ping_day.is_null()) { | 86 if (!last_ping_day.is_null()) { |
| 77 days = SanitizeDays((Time::Now() - last_ping_day).InDays()); | 87 days = SanitizeDays((Time::Now() - last_ping_day).InDays()); |
| 78 } | 88 } |
| 79 return days; | 89 return days; |
| 80 } | 90 } |
| 81 | 91 |
| 82 int CalculateActivePingDays(const Time& last_active_ping_day, | 92 int CalculateActivePingDays(const Time& last_active_ping_day, |
| 83 bool hasActiveBit) { | 93 bool hasActiveBit) { |
| 84 if (!hasActiveBit) | 94 if (!hasActiveBit) |
| 85 return 0; | 95 return 0; |
| 86 if (last_active_ping_day.is_null()) | 96 if (last_active_ping_day.is_null()) |
| 87 return extensions::ManifestFetchData::kNeverPinged; | 97 return extensions::ManifestFetchData::kNeverPinged; |
| 88 return SanitizeDays((Time::Now() - last_active_ping_day).InDays()); | 98 return SanitizeDays((Time::Now() - last_active_ping_day).InDays()); |
| 89 } | 99 } |
| 90 | 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) { | |
|
Yoyo Zhou
2014/09/04 22:41:26
Consider DCHECKing that we're on a non-UI thread.
Ken Rockot(use gerrit already)
2014/09/05 01:41:34
Done.
| |
| 110 scoped_ptr<std::set<std::string> > forced_updates( | |
| 111 new std::set<std::string>()); | |
| 112 for (std::vector<scoped_refptr<const Extension> >::const_iterator iter = | |
| 113 extensions->begin(); | |
| 114 iter != extensions->end(); | |
| 115 ++iter) { | |
| 116 scoped_refptr<const Extension> extension = *iter; | |
| 117 base::FilePath platform_specific_path = extension->path().Append( | |
| 118 extensions::kPlatformSpecificFolder); | |
| 119 if (base::PathExists(platform_specific_path)) { | |
| 120 bool force = true; | |
| 121 base::FileEnumerator all_archs(platform_specific_path, | |
| 122 false, | |
| 123 base::FileEnumerator::DIRECTORIES); | |
| 124 base::FilePath arch; | |
| 125 while (!(arch = all_archs.Next()).empty()) { | |
| 126 std::string arch_name = arch.BaseName().AsUTF8Unsafe(); | |
| 127 std::replace(arch_name.begin(), arch_name.end(), '_', '-'); | |
| 128 if (arch_name == OmahaQueryParams::GetNaclArch()) | |
| 129 force = false; | |
| 130 } | |
| 131 | |
| 132 if (force) | |
| 133 forced_updates->insert(extension->id()); | |
| 134 } | |
| 135 } | |
| 136 BrowserThread::PostTask( | |
| 137 BrowserThread::UI, | |
| 138 FROM_HERE, | |
| 139 base::Bind(&RespondWithForcedUpdates, | |
| 140 callback, | |
| 141 base::Passed(&forced_updates))); | |
| 142 } | |
| 143 | |
| 144 void CollectExtensionsFromSet( | |
| 145 const ExtensionSet& extensions, | |
| 146 std::vector<scoped_refptr<const Extension> >* paths) { | |
| 147 std::copy(extensions.begin(), extensions.end(), std::back_inserter(*paths)); | |
| 148 } | |
| 149 | |
| 150 void DetermineForcedUpdates( | |
| 151 content::BrowserContext* browser_context, | |
| 152 const base::Callback<void(const std::set<std::string>&)>& callback) { | |
| 153 scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions( | |
| 154 new std::vector<scoped_refptr<const Extension> >()); | |
| 155 const extensions::ExtensionRegistry* registry = | |
| 156 extensions::ExtensionRegistry::Get(browser_context); | |
| 157 CollectExtensionsFromSet(registry->enabled_extensions(), extensions.get()); | |
|
Yoyo Zhou
2014/09/04 22:41:26
Why not use registry->GenerateInstalledExtensionsS
Ken Rockot(use gerrit already)
2014/09/05 01:41:34
Because I totally missed it when looking over the
| |
| 158 CollectExtensionsFromSet(registry->disabled_extensions(), extensions.get()); | |
| 159 BrowserThread::PostBlockingPoolTask( | |
| 160 FROM_HERE, | |
| 161 base::Bind(&DetermineForcedUpdatesOnBlockingPool, | |
| 162 base::Passed(&extensions), | |
| 163 callback)); | |
| 164 } | |
| 165 | |
| 91 } // namespace | 166 } // namespace |
| 92 | 167 |
| 93 namespace extensions { | 168 namespace extensions { |
| 94 | 169 |
| 95 ExtensionUpdater::CheckParams::CheckParams() | 170 ExtensionUpdater::CheckParams::CheckParams() |
| 96 : install_immediately(false) {} | 171 : install_immediately(false) {} |
| 97 | 172 |
| 98 ExtensionUpdater::CheckParams::~CheckParams() {} | 173 ExtensionUpdater::CheckParams::~CheckParams() {} |
| 99 | 174 |
| 100 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile( | 175 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile( |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 328 std::list<std::string>::const_iterator pending_id_iter = std::find( | 403 std::list<std::string>::const_iterator pending_id_iter = std::find( |
| 329 pending_ids.begin(), pending_ids.end(), extension.id()); | 404 pending_ids.begin(), pending_ids.end(), extension.id()); |
| 330 if (pending_id_iter == pending_ids.end()) { | 405 if (pending_id_iter == pending_ids.end()) { |
| 331 if (downloader_->AddExtension(extension, request_id)) | 406 if (downloader_->AddExtension(extension, request_id)) |
| 332 request.in_progress_ids_.push_back(extension.id()); | 407 request.in_progress_ids_.push_back(extension.id()); |
| 333 } | 408 } |
| 334 } | 409 } |
| 335 } | 410 } |
| 336 | 411 |
| 337 void ExtensionUpdater::CheckNow(const CheckParams& params) { | 412 void ExtensionUpdater::CheckNow(const CheckParams& params) { |
| 413 DetermineForcedUpdates( | |
| 414 profile_, | |
| 415 base::Bind(&ExtensionUpdater::OnForcedUpdatesDetermined, | |
| 416 weak_ptr_factory_.GetWeakPtr(), | |
| 417 params)); | |
| 418 } | |
| 419 | |
| 420 void ExtensionUpdater::OnForcedUpdatesDetermined( | |
| 421 const CheckParams& params, | |
| 422 const std::set<std::string>& forced_updates) { | |
| 338 int request_id = next_request_id_++; | 423 int request_id = next_request_id_++; |
| 339 | 424 |
| 340 VLOG(2) << "Starting update check " << request_id; | 425 VLOG(2) << "Starting update check " << request_id; |
| 341 if (params.ids.empty()) | 426 if (params.ids.empty()) |
| 342 NotifyStarted(); | 427 NotifyStarted(); |
| 343 | 428 |
| 344 DCHECK(alive_); | 429 DCHECK(alive_); |
| 345 | 430 |
| 346 InProgressCheck& request = requests_in_progress_[request_id]; | 431 InProgressCheck& request = requests_in_progress_[request_id]; |
| 347 request.callback = params.callback; | 432 request.callback = params.callback; |
| 348 request.install_immediately = params.install_immediately; | 433 request.install_immediately = params.install_immediately; |
| 349 | 434 |
| 350 EnsureDownloaderCreated(); | 435 EnsureDownloaderCreated(); |
| 351 | 436 |
| 437 forced_updates_ = forced_updates; | |
| 438 | |
| 352 // Add fetch records for extensions that should be fetched by an update URL. | 439 // Add fetch records for extensions that should be fetched by an update URL. |
| 353 // These extensions are not yet installed. They come from group policy | 440 // These extensions are not yet installed. They come from group policy |
| 354 // and external install sources. | 441 // and external install sources. |
| 355 const PendingExtensionManager* pending_extension_manager = | 442 const PendingExtensionManager* pending_extension_manager = |
| 356 service_->pending_extension_manager(); | 443 service_->pending_extension_manager(); |
| 357 | 444 |
| 358 std::list<std::string> pending_ids; | 445 std::list<std::string> pending_ids; |
| 359 | 446 |
| 360 if (params.ids.empty()) { | 447 if (params.ids.empty()) { |
| 361 // If no extension ids are specified, check for updates for all extensions. | 448 // If no extension ids are specified, check for updates for all extensions. |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 529 if (!extension) | 616 if (!extension) |
| 530 return false; | 617 return false; |
| 531 const Extension* update = service_->GetPendingExtensionUpdate(id); | 618 const Extension* update = service_->GetPendingExtensionUpdate(id); |
| 532 if (update) | 619 if (update) |
| 533 *version = update->VersionString(); | 620 *version = update->VersionString(); |
| 534 else | 621 else |
| 535 *version = extension->VersionString(); | 622 *version = extension->VersionString(); |
| 536 return true; | 623 return true; |
| 537 } | 624 } |
| 538 | 625 |
| 626 bool ExtensionUpdater::ShouldForceUpdate( | |
| 627 const std::string& extension_id, | |
| 628 std::string* source) { | |
| 629 bool force = forced_updates_.find(extension_id) != forced_updates_.end(); | |
| 630 // Currently the only reason to force is a NaCl arch mismatch with the | |
| 631 // installed extension contents. | |
| 632 if (force) { | |
| 633 *source = kWrongMultiCrxInstallSource; | |
| 634 } | |
| 635 return force; | |
| 636 } | |
| 637 | |
| 539 void ExtensionUpdater::UpdatePingData(const std::string& id, | 638 void ExtensionUpdater::UpdatePingData(const std::string& id, |
| 540 const PingResult& ping_result) { | 639 const PingResult& ping_result) { |
| 541 DCHECK(alive_); | 640 DCHECK(alive_); |
| 542 if (ping_result.did_ping) | 641 if (ping_result.did_ping) |
| 543 extension_prefs_->SetLastPingDay(id, ping_result.day_start); | 642 extension_prefs_->SetLastPingDay(id, ping_result.day_start); |
| 544 if (extension_prefs_->GetActiveBit(id)) { | 643 if (extension_prefs_->GetActiveBit(id)) { |
| 545 extension_prefs_->SetActiveBit(id, false); | 644 extension_prefs_->SetActiveBit(id, false); |
| 546 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start); | 645 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start); |
| 547 } | 646 } |
| 548 } | 647 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 642 const InProgressCheck& request = requests_in_progress_[request_id]; | 741 const InProgressCheck& request = requests_in_progress_[request_id]; |
| 643 if (request.in_progress_ids_.empty()) { | 742 if (request.in_progress_ids_.empty()) { |
| 644 VLOG(2) << "Finished update check " << request_id; | 743 VLOG(2) << "Finished update check " << request_id; |
| 645 if (!request.callback.is_null()) | 744 if (!request.callback.is_null()) |
| 646 request.callback.Run(); | 745 request.callback.Run(); |
| 647 requests_in_progress_.erase(request_id); | 746 requests_in_progress_.erase(request_id); |
| 648 } | 747 } |
| 649 } | 748 } |
| 650 | 749 |
| 651 } // namespace extensions | 750 } // namespace extensions |
| OLD | NEW |