Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(240)

Side by Side Diff: chrome/browser/extensions/extension_updater.cc

Issue 6965018: Install CRX updates one at a time. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Polish Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/extension_updater.h" 5 #include "chrome/browser/extensions/extension_updater.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 9
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/file_util.h" 12 #include "base/file_util.h"
13 #include "base/memory/scoped_handle.h" 13 #include "base/memory/scoped_handle.h"
14 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
15 #include "base/rand_util.h" 15 #include "base/rand_util.h"
16 #include "base/stl_util-inl.h" 16 #include "base/stl_util-inl.h"
17 #include "base/string_number_conversions.h" 17 #include "base/string_number_conversions.h"
18 #include "base/string_split.h" 18 #include "base/string_split.h"
19 #include "base/string_util.h" 19 #include "base/string_util.h"
20 #include "base/time.h" 20 #include "base/time.h"
21 #include "base/threading/thread.h" 21 #include "base/threading/thread.h"
22 #include "base/version.h" 22 #include "base/version.h"
23 #include "crypto/sha2.h" 23 #include "crypto/sha2.h"
24 #include "content/common/notification_service.h" 24 #include "content/common/notification_service.h"
25 #include "content/common/notification_source.h"
25 #include "chrome/browser/browser_process.h" 26 #include "chrome/browser/browser_process.h"
27 #include "chrome/browser/extensions/crx_installer.h"
26 #include "chrome/browser/extensions/extension_error_reporter.h" 28 #include "chrome/browser/extensions/extension_error_reporter.h"
27 #include "chrome/browser/extensions/extension_service.h" 29 #include "chrome/browser/extensions/extension_service.h"
28 #include "chrome/browser/prefs/pref_service.h" 30 #include "chrome/browser/prefs/pref_service.h"
29 #include "chrome/browser/profiles/profile.h" 31 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/browser/utility_process_host.h" 32 #include "chrome/browser/utility_process_host.h"
31 #include "chrome/common/chrome_switches.h" 33 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/chrome_version_info.h" 34 #include "chrome/common/chrome_version_info.h"
33 #include "chrome/common/extensions/extension.h" 35 #include "chrome/common/extensions/extension.h"
34 #include "chrome/common/extensions/extension_constants.h" 36 #include "chrome/common/extensions/extension_constants.h"
35 #include "chrome/common/extensions/extension_file_util.h" 37 #include "chrome/common/extensions/extension_file_util.h"
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 // happens when creating a temp file or when writing to it. Knowing this 76 // happens when creating a temp file or when writing to it. Knowing this
75 // will require changes to URLFetcher. 77 // will require changes to URLFetcher.
76 enum FileWriteResult { 78 enum FileWriteResult {
77 SUCCESS = 0, 79 SUCCESS = 0,
78 CANT_CREATE_OR_WRITE_TEMP_CRX, 80 CANT_CREATE_OR_WRITE_TEMP_CRX,
79 CANT_READ_CRX_FILE, 81 CANT_READ_CRX_FILE,
80 NUM_FILE_WRITE_RESULTS 82 NUM_FILE_WRITE_RESULTS
81 }; 83 };
82 84
83 // Prototypes allow the functions to be defined in the order they run. 85 // Prototypes allow the functions to be defined in the order they run.
84 void CheckThatCrxIsReadable(const FilePath& crx_path); 86 void CheckThatCRXIsReadable(const FilePath& crx_path);
85 void RecordFileUpdateHistogram(FileWriteResult file_write_result); 87 void RecordFileUpdateHistogram(FileWriteResult file_write_result);
86 88
87 // Record the result of writing a CRX file. Will be used to understand 89 // Record the result of writing a CRX file. Will be used to understand
88 // high failure rates of CRX installs in the field. If |success| is 90 // high failure rates of CRX installs in the field. If |success| is
89 // true, |crx_path| should be set to the path to the CRX file. 91 // true, |crx_path| should be set to the path to the CRX file.
90 void RecordCrxWriteHistogram(bool success, const FilePath& crx_path) { 92 void RecordCRXWriteHistogram(bool success, const FilePath& crx_path) {
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
92 94
93 if (!success) { 95 if (!success) {
94 // We know there was an error writing the file. 96 // We know there was an error writing the file.
95 RecordFileUpdateHistogram(CANT_CREATE_OR_WRITE_TEMP_CRX); 97 RecordFileUpdateHistogram(CANT_CREATE_OR_WRITE_TEMP_CRX);
96 98
97 } else { 99 } else {
98 // Test that the file can be read. Based on histograms in 100 // Test that the file can be read. Based on histograms in
99 // SandboxExtensionUnpacker, we know that many CRX files 101 // SandboxExtensionUnpacker, we know that many CRX files
100 // can not be read. Try reading. 102 // can not be read. Try reading.
101 BrowserThread::PostTask( 103 BrowserThread::PostTask(
102 BrowserThread::FILE, FROM_HERE, 104 BrowserThread::FILE, FROM_HERE,
103 NewRunnableFunction(CheckThatCrxIsReadable, crx_path)); 105 NewRunnableFunction(CheckThatCRXIsReadable, crx_path));
104 } 106 }
105 } 107 }
106 108
107 void CheckThatCrxIsReadable(const FilePath& crx_path) { 109 void CheckThatCRXIsReadable(const FilePath& crx_path) {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
109 111
110 FileWriteResult file_write_result = SUCCESS; 112 FileWriteResult file_write_result = SUCCESS;
111 113
112 // Open the file in the same way 114 // Open the file in the same way
113 // SandboxExtensionUnpacker::ValidateSigniture() will. 115 // SandboxExtensionUnpacker::ValidateSigniture() will.
114 ScopedStdioHandle file(file_util::OpenFile(crx_path, "rb")); 116 ScopedStdioHandle file(file_util::OpenFile(crx_path, "rb"));
115 if (!file.get()) { 117 if (!file.get()) {
116 LOG(ERROR) << "Can't read CRX file written for update at path " 118 LOG(ERROR) << "Can't read CRX file written for update at path "
117 << crx_path.value().c_str(); 119 << crx_path.value().c_str();
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
437 version("") {} 439 version("") {}
438 440
439 ExtensionUpdater::ExtensionFetch::ExtensionFetch(const std::string& i, 441 ExtensionUpdater::ExtensionFetch::ExtensionFetch(const std::string& i,
440 const GURL& u, 442 const GURL& u,
441 const std::string& h, 443 const std::string& h,
442 const std::string& v) 444 const std::string& v)
443 : id(i), url(u), package_hash(h), version(v) {} 445 : id(i), url(u), package_hash(h), version(v) {}
444 446
445 ExtensionUpdater::ExtensionFetch::~ExtensionFetch() {} 447 ExtensionUpdater::ExtensionFetch::~ExtensionFetch() {}
446 448
449 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile(const std::string& i,
450 const FilePath& p,
451 const GURL& u)
452 : id(i),
453 path(p),
454 download_url(u) {}
455
456 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile()
457 : id(""),
458 path(),
459 download_url() {}
460
461 ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() {}
462
447 ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service, 463 ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service,
448 ExtensionPrefs* extension_prefs, 464 ExtensionPrefs* extension_prefs,
449 PrefService* prefs, 465 PrefService* prefs,
450 Profile* profile, 466 Profile* profile,
451 int frequency_seconds) 467 int frequency_seconds)
452 : alive_(false), 468 : alive_(false),
453 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), 469 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
454 service_(service), frequency_seconds_(frequency_seconds), 470 service_(service), frequency_seconds_(frequency_seconds),
455 method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), 471 method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
456 will_check_soon_(false), extension_prefs_(extension_prefs), 472 will_check_soon_(false), extension_prefs_(extension_prefs),
457 prefs_(prefs), profile_(profile), blacklist_checks_enabled_(true) { 473 prefs_(prefs), profile_(profile), blacklist_checks_enabled_(true),
474 crx_install_is_running_(false) {
458 Init(); 475 Init();
459 } 476 }
460 477
461 void ExtensionUpdater::Init() { 478 void ExtensionUpdater::Init() {
462 DCHECK_GE(frequency_seconds_, 5); 479 DCHECK_GE(frequency_seconds_, 5);
463 DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds); 480 DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds);
464 #ifdef NDEBUG 481 #ifdef NDEBUG
465 // In Release mode we enforce that update checks don't happen too often. 482 // In Release mode we enforce that update checks don't happen too often.
466 frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds); 483 frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds);
467 #endif 484 #endif
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
793 const GURL& url, 810 const GURL& url,
794 const net::URLRequestStatus& status, 811 const net::URLRequestStatus& status,
795 int response_code) { 812 int response_code) {
796 813
797 base::PlatformFileError error_code = base::PLATFORM_FILE_OK; 814 base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
798 if (source->FileErrorOccurred(&error_code)) { 815 if (source->FileErrorOccurred(&error_code)) {
799 LOG(ERROR) << "Failed to write update CRX with id " 816 LOG(ERROR) << "Failed to write update CRX with id "
800 << current_extension_fetch_.id << ". " 817 << current_extension_fetch_.id << ". "
801 << "Error code is "<< error_code; 818 << "Error code is "<< error_code;
802 819
803 RecordCrxWriteHistogram(false, FilePath()); 820 RecordCRXWriteHistogram(false, FilePath());
804 OnCRXFileWriteError(current_extension_fetch_.id); 821 OnCRXFileWriteError(current_extension_fetch_.id);
805 822
806 } else if (status.status() == net::URLRequestStatus::SUCCESS && 823 } else if (status.status() == net::URLRequestStatus::SUCCESS &&
807 (response_code == 200 || url.SchemeIsFile())) { 824 (response_code == 200 || url.SchemeIsFile())) {
808 if (current_extension_fetch_.id == kBlacklistAppID) { 825 if (current_extension_fetch_.id == kBlacklistAppID) {
809 std::string data; 826 std::string data;
810 CHECK(source->GetResponseAsString(&data)); 827 CHECK(source->GetResponseAsString(&data));
811 ProcessBlacklist(data); 828 ProcessBlacklist(data);
812 in_progress_ids_.erase(current_extension_fetch_.id); 829 in_progress_ids_.erase(current_extension_fetch_.id);
813 } else { 830 } else {
814 FilePath crx_path; 831 FilePath crx_path;
815 // Take ownership of the file at |crx_path|. 832 // Take ownership of the file at |crx_path|.
816 CHECK(source->GetResponseAsFilePath(true, &crx_path)); 833 CHECK(source->GetResponseAsFilePath(true, &crx_path));
817 RecordCrxWriteHistogram(true, crx_path); 834 RecordCRXWriteHistogram(true, crx_path);
818 OnCRXFileWritten(current_extension_fetch_.id, crx_path, url); 835 OnCRXFileWritten(current_extension_fetch_.id, crx_path, url);
819 } 836 }
820 } else { 837 } else {
821 // TODO(asargent) do things like exponential backoff, handling 838 // TODO(asargent) do things like exponential backoff, handling
822 // 503 Service Unavailable / Retry-After headers, etc. here. 839 // 503 Service Unavailable / Retry-After headers, etc. here.
823 // (http://crbug.com/12546). 840 // (http://crbug.com/12546).
824 VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec() 841 VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec()
825 << "' response code:" << response_code; 842 << "' response code:" << response_code;
826 } 843 }
827 extension_fetcher_.reset(); 844 extension_fetcher_.reset();
828 current_extension_fetch_ = ExtensionFetch(); 845 current_extension_fetch_ = ExtensionFetch();
829 846
830 // If there are any pending downloads left, start the next one. 847 // If there are any pending downloads left, start the next one.
831 if (!extensions_pending_.empty()) { 848 if (!extensions_pending_.empty()) {
832 ExtensionFetch next = extensions_pending_.front(); 849 ExtensionFetch next = extensions_pending_.front();
833 extensions_pending_.pop_front(); 850 extensions_pending_.pop_front();
834 FetchUpdatedExtension(next.id, next.url, next.package_hash, next.version); 851 FetchUpdatedExtension(next.id, next.url, next.package_hash, next.version);
835 } 852 }
836 } 853 }
837 854
838 void ExtensionUpdater::OnCRXFileWritten(const std::string& id, 855 void ExtensionUpdater::OnCRXFileWritten(const std::string& id,
839 const FilePath& path, 856 const FilePath& path,
840 const GURL& download_url) { 857 const GURL& download_url) {
841 DCHECK(alive_); 858 DCHECK(alive_);
842 // The ExtensionService is now responsible for cleaning up the temp file 859
843 // at |path|. 860 FetchedCRXFile fetched(id, path, download_url);
844 service_->UpdateExtension(id, path, download_url); 861 fetched_crx_files_.push(fetched);
845 in_progress_ids_.erase(id); 862
863 MaybeInstallCRXFile();
864 }
865
866 bool ExtensionUpdater::MaybeInstallCRXFile() {
867 if (crx_install_is_running_)
868 return false;
869
870 while (!fetched_crx_files_.empty() && !crx_install_is_running_) {
871 const FetchedCRXFile& crx_file = fetched_crx_files_.top();
872
873 // The ExtensionService is now responsible for cleaning up the temp file
874 // at |extension_file.path|.
875 CrxInstaller* installer = NULL;
876 if (service_->UpdateExtension(crx_file.id,
877 crx_file.path,
878 crx_file.download_url,
879 &installer)) {
880 crx_install_is_running_ = true;
881
882 // Source parameter ensures that we only see the completion event for the
883 // the installer we started.
884 registrar_.Add(this,
885 NotificationType::CRX_INSTALLER_DONE,
886 Source<CrxInstaller>(installer));
887 }
888 in_progress_ids_.erase(crx_file.id);
889 fetched_crx_files_.pop();
890 }
891
892 // If an updater is running, it was started above.
893 return crx_install_is_running_;
894 }
895
896 void ExtensionUpdater::Observe(NotificationType type,
897 const NotificationSource& source,
898 const NotificationDetails& details) {
899 DCHECK(type == NotificationType::CRX_INSTALLER_DONE);
900
901 // No need to listen for CRX_INSTALLER_DONE anymore.
902 registrar_.Remove(this,
903 NotificationType::CRX_INSTALLER_DONE,
904 source);
905 crx_install_is_running_ = false;
906 // If any files are available to update, start one.
907 MaybeInstallCRXFile();
846 } 908 }
847 909
848 void ExtensionUpdater::OnCRXFileWriteError(const std::string& id) { 910 void ExtensionUpdater::OnCRXFileWriteError(const std::string& id) {
849 DCHECK(alive_); 911 DCHECK(alive_);
850 in_progress_ids_.erase(id); 912 in_progress_ids_.erase(id);
851 } 913 }
852 914
853 void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) { 915 void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) {
854 DCHECK(alive_); 916 DCHECK(alive_);
855 DCHECK(!timer_.IsRunning()); 917 DCHECK(!timer_.IsRunning());
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
1159 std::set<std::string>::const_iterator i; 1221 std::set<std::string>::const_iterator i;
1160 for (i = ids.begin(); i != ids.end(); ++i) 1222 for (i = ids.begin(); i != ids.end(); ++i)
1161 in_progress_ids_.insert(*i); 1223 in_progress_ids_.insert(*i);
1162 } 1224 }
1163 1225
1164 void ExtensionUpdater::RemoveFromInProgress(const std::set<std::string>& ids) { 1226 void ExtensionUpdater::RemoveFromInProgress(const std::set<std::string>& ids) {
1165 std::set<std::string>::const_iterator i; 1227 std::set<std::string>::const_iterator i;
1166 for (i = ids.begin(); i != ids.end(); ++i) 1228 for (i = ids.begin(); i != ids.end(); ++i)
1167 in_progress_ids_.erase(*i); 1229 in_progress_ids_.erase(*i);
1168 } 1230 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_updater.h ('k') | chrome/browser/extensions/extension_updater_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698