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

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

Issue 6969067: Allow URLFetcher to save results in a file. Have CRX updates use this capability. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase for commit Created 9 years, 7 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"
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 const int kStartupWaitSeconds = 60 * 5; 63 const int kStartupWaitSeconds = 60 * 5;
64 64
65 // For sanity checking on update frequency - enforced in release mode only. 65 // For sanity checking on update frequency - enforced in release mode only.
66 static const int kMinUpdateFrequencySeconds = 30; 66 static const int kMinUpdateFrequencySeconds = 30;
67 static const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days 67 static const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days
68 68
69 // Maximum length of an extension manifest update check url, since it is a GET 69 // Maximum length of an extension manifest update check url, since it is a GET
70 // request. We want to stay under 2K because of proxies, etc. 70 // request. We want to stay under 2K because of proxies, etc.
71 static const int kExtensionsManifestMaxURLSize = 2000; 71 static const int kExtensionsManifestMaxURLSize = 2000;
72 72
73 // TODO(skerner): It would be nice to know if the file system failure
74 // happens when creating a temp file or when writing to it. Knowing this
75 // will require changes to URLFetcher.
73 enum FileWriteResult { 76 enum FileWriteResult {
74 SUCCESS = 0, 77 SUCCESS = 0,
75 CANT_CREATE_TEMP_CRX, 78 CANT_CREATE_OR_WRITE_TEMP_CRX,
76 CANT_WRITE_CRX_DATA,
77 CANT_READ_CRX_FILE, 79 CANT_READ_CRX_FILE,
78 NUM_FILE_WRITE_RESULTS 80 NUM_FILE_WRITE_RESULTS
79 }; 81 };
80 82
83 // Prototypes allow the functions to be defined in the order they run.
84 void CheckThatCrxIsReadable(const FilePath& crx_path);
85 void RecordFileUpdateHistogram(FileWriteResult file_write_result);
86
87 // 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
89 // true, |crx_path| should be set to the path to the CRX file.
90 void RecordCrxWriteHistogram(bool success, const FilePath& crx_path) {
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
92
93 if (!success) {
94 // We know there was an error writing the file.
95 RecordFileUpdateHistogram(CANT_CREATE_OR_WRITE_TEMP_CRX);
96
97 } else {
98 // Test that the file can be read. Based on histograms in
99 // SandboxExtensionUnpacker, we know that many CRX files
100 // can not be read. Try reading.
101 BrowserThread::PostTask(
102 BrowserThread::FILE, FROM_HERE,
103 NewRunnableFunction(CheckThatCrxIsReadable, crx_path));
104 }
105 }
106
107 void CheckThatCrxIsReadable(const FilePath& crx_path) {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
109
110 FileWriteResult file_write_result = SUCCESS;
111
112 // Open the file in the same way
113 // SandboxExtensionUnpacker::ValidateSigniture() will.
114 ScopedStdioHandle file(file_util::OpenFile(crx_path, "rb"));
115 if (!file.get()) {
116 LOG(ERROR) << "Can't read CRX file written for update at path "
117 << crx_path.value().c_str();
118 file_write_result = CANT_READ_CRX_FILE;
119 }
120
121 BrowserThread::PostTask(
122 BrowserThread::UI, FROM_HERE,
123 NewRunnableFunction(RecordFileUpdateHistogram, file_write_result));
124 }
125
126 void RecordFileUpdateHistogram(FileWriteResult file_write_result) {
127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
128 UMA_HISTOGRAM_ENUMERATION("Extensions.UpdaterWriteCrxAsFile",
129 file_write_result,
130 NUM_FILE_WRITE_RESULTS);
131 }
132
81 } // namespace 133 } // namespace
82 134
83 ManifestFetchData::ManifestFetchData(const GURL& update_url) 135 ManifestFetchData::ManifestFetchData(const GURL& update_url)
84 : base_url_(update_url), 136 : base_url_(update_url),
85 full_url_(update_url) { 137 full_url_(update_url) {
86 } 138 }
87 139
88 ManifestFetchData::~ManifestFetchData() {} 140 ManifestFetchData::~ManifestFetchData() {}
89 141
90 // The format for request parameters in update checks is: 142 // The format for request parameters in update checks is:
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 } 423 }
372 if (!fetch) { 424 if (!fetch) {
373 fetch = new ManifestFetchData(update_url); 425 fetch = new ManifestFetchData(update_url);
374 fetches_.insert(std::pair<GURL, ManifestFetchData*>(update_url, fetch)); 426 fetches_.insert(std::pair<GURL, ManifestFetchData*>(update_url, fetch));
375 bool added = fetch->AddExtension(id, version.GetString(), ping_data, 427 bool added = fetch->AddExtension(id, version.GetString(), ping_data,
376 update_url_data); 428 update_url_data);
377 DCHECK(added); 429 DCHECK(added);
378 } 430 }
379 } 431 }
380 432
381 // A utility class to do file handling on the file I/O thread.
382 class ExtensionUpdaterFileHandler
383 : public base::RefCountedThreadSafe<ExtensionUpdaterFileHandler> {
384 public:
385 explicit ExtensionUpdaterFileHandler(
386 base::WeakPtr<ExtensionUpdater> updater)
387 : updater_(updater) {
388 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
389 }
390
391 // Writes crx file data into a tempfile, and calls back the updater.
392 void WriteTempFile(const std::string& extension_id, const std::string& data,
393 const GURL& download_url) {
394 // Make sure we're running in the right thread.
395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
396
397 FileWriteResult file_write_result = SUCCESS;
398 FilePath path;
399 if (!file_util::CreateTemporaryFile(&path)) {
400 LOG(WARNING) << "Failed to create temporary file path";
401 file_write_result = CANT_CREATE_TEMP_CRX;
402 } else if (file_util::WriteFile(path, data.c_str(), data.length()) !=
403 static_cast<int>(data.length())) {
404 // TODO(asargent) - It would be nice to back off updating altogether if
405 // the disk is full. (http://crbug.com/12763).
406 LOG(ERROR) << "Failed to write temporary file";
407 file_util::Delete(path, false);
408 file_write_result = CANT_WRITE_CRX_DATA;
409 } else {
410 // We are seeing a high failure rate unpacking extensions, where
411 // the crx file can not be read. See if the file we wrote is readable.
412 // See crbug.com/81687 .
413 ScopedStdioHandle file(file_util::OpenFile(path, "rb"));
414 if (!file.get()) {
415 LOG(ERROR) << "Can't read CRX file written for update at path "
416 << path.value().c_str();
417 file_util::Delete(path, false);
418 file_write_result = CANT_READ_CRX_FILE;
419 }
420 }
421
422 UMA_HISTOGRAM_ENUMERATION("Extensions.UpdaterWriteCrx", file_write_result,
423 NUM_FILE_WRITE_RESULTS);
424
425 if (file_write_result != SUCCESS) {
426 if (!BrowserThread::PostTask(
427 BrowserThread::UI, FROM_HERE,
428 NewRunnableMethod(
429 this, &ExtensionUpdaterFileHandler::OnCRXFileWriteError,
430 extension_id))) {
431 NOTREACHED();
432 }
433 } else {
434 if (!BrowserThread::PostTask(
435 BrowserThread::UI, FROM_HERE,
436 NewRunnableMethod(
437 this, &ExtensionUpdaterFileHandler::OnCRXFileWritten,
438 extension_id, path, download_url))) {
439 NOTREACHED();
440 // Delete |path| since we couldn't post.
441 extension_file_util::DeleteFile(path, false);
442 }
443 }
444 }
445
446 private:
447 friend class base::RefCountedThreadSafe<ExtensionUpdaterFileHandler>;
448
449 ~ExtensionUpdaterFileHandler() {
450 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
451 BrowserThread::CurrentlyOn(BrowserThread::FILE));
452 }
453
454 void OnCRXFileWritten(const std::string& id,
455 const FilePath& path,
456 const GURL& download_url) {
457 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
458 if (!updater_) {
459 // Delete |path| since we don't have an updater anymore.
460 if (!BrowserThread::PostTask(
461 BrowserThread::FILE, FROM_HERE,
462 NewRunnableFunction(
463 extension_file_util::DeleteFile, path, false))) {
464 NOTREACHED();
465 }
466 return;
467 }
468 // The ExtensionUpdater now owns the temp file.
469 updater_->OnCRXFileWritten(id, path, download_url);
470 }
471
472 void OnCRXFileWriteError(const std::string& id) {
473 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
474 if (!updater_) {
475 return;
476 }
477 updater_->OnCRXFileWriteError(id);
478 }
479
480 // Should be accessed only on UI thread.
481 base::WeakPtr<ExtensionUpdater> updater_;
482 };
483
484 ExtensionUpdater::ExtensionFetch::ExtensionFetch() 433 ExtensionUpdater::ExtensionFetch::ExtensionFetch()
485 : id(""), 434 : id(""),
486 url(), 435 url(),
487 package_hash(""), 436 package_hash(""),
488 version("") {} 437 version("") {}
489 438
490 ExtensionUpdater::ExtensionFetch::ExtensionFetch(const std::string& i, 439 ExtensionUpdater::ExtensionFetch::ExtensionFetch(const std::string& i,
491 const GURL& u, 440 const GURL& u,
492 const std::string& h, 441 const std::string& h,
493 const std::string& v) 442 const std::string& v)
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
584 533
585 void ExtensionUpdater::Start() { 534 void ExtensionUpdater::Start() {
586 DCHECK(!alive_); 535 DCHECK(!alive_);
587 // If these are NULL, then that means we've been called after Stop() 536 // If these are NULL, then that means we've been called after Stop()
588 // has been called. 537 // has been called.
589 DCHECK(service_); 538 DCHECK(service_);
590 DCHECK(extension_prefs_); 539 DCHECK(extension_prefs_);
591 DCHECK(prefs_); 540 DCHECK(prefs_);
592 DCHECK(profile_); 541 DCHECK(profile_);
593 DCHECK(!weak_ptr_factory_.HasWeakPtrs()); 542 DCHECK(!weak_ptr_factory_.HasWeakPtrs());
594 file_handler_ =
595 new ExtensionUpdaterFileHandler(weak_ptr_factory_.GetWeakPtr());
596 alive_ = true; 543 alive_ = true;
597 // Make sure our prefs are registered, then schedule the first check. 544 // Make sure our prefs are registered, then schedule the first check.
598 EnsureInt64PrefRegistered(prefs_, kLastExtensionsUpdateCheck); 545 EnsureInt64PrefRegistered(prefs_, kLastExtensionsUpdateCheck);
599 EnsureInt64PrefRegistered(prefs_, kNextExtensionsUpdateCheck); 546 EnsureInt64PrefRegistered(prefs_, kNextExtensionsUpdateCheck);
600 EnsureBlacklistVersionPrefRegistered(prefs_); 547 EnsureBlacklistVersionPrefRegistered(prefs_);
601 ScheduleNextCheck(DetermineFirstCheckDelay()); 548 ScheduleNextCheck(DetermineFirstCheckDelay());
602 } 549 }
603 550
604 void ExtensionUpdater::Stop() { 551 void ExtensionUpdater::Stop() {
605 weak_ptr_factory_.InvalidateWeakPtrs(); 552 weak_ptr_factory_.InvalidateWeakPtrs();
606 alive_ = false; 553 alive_ = false;
607 file_handler_ = NULL;
608 service_ = NULL; 554 service_ = NULL;
609 extension_prefs_ = NULL; 555 extension_prefs_ = NULL;
610 prefs_ = NULL; 556 prefs_ = NULL;
611 profile_ = NULL; 557 profile_ = NULL;
612 timer_.Stop(); 558 timer_.Stop();
613 will_check_soon_ = false; 559 will_check_soon_ = false;
614 method_factory_.RevokeAll(); 560 method_factory_.RevokeAll();
615 manifest_fetcher_.reset(); 561 manifest_fetcher_.reset();
616 extension_fetcher_.reset(); 562 extension_fetcher_.reset();
617 STLDeleteElements(&manifests_pending_); 563 STLDeleteElements(&manifests_pending_);
618 manifests_pending_.clear(); 564 manifests_pending_.clear();
619 extensions_pending_.clear(); 565 extensions_pending_.clear();
620 } 566 }
621 567
622 void ExtensionUpdater::OnURLFetchComplete( 568 void ExtensionUpdater::OnURLFetchComplete(const URLFetcher* source) {
623 const URLFetcher* source,
624 const GURL& url,
625 const net::URLRequestStatus& status,
626 int response_code,
627 const net::ResponseCookies& cookies,
628 const std::string& data) {
629 // Stop() destroys all our URLFetchers, which means we shouldn't be 569 // Stop() destroys all our URLFetchers, which means we shouldn't be
630 // called after Stop() is called. 570 // called after Stop() is called.
631 DCHECK(alive_); 571 DCHECK(alive_);
632 572
633 if (source == manifest_fetcher_.get()) { 573 if (source == manifest_fetcher_.get()) {
634 OnManifestFetchComplete(url, status, response_code, data); 574 std::string data;
575 CHECK(source->GetResponseAsString(&data));
576 OnManifestFetchComplete(source->url(),
577 source->status(),
578 source->response_code(),
579 data);
635 } else if (source == extension_fetcher_.get()) { 580 } else if (source == extension_fetcher_.get()) {
636 OnCRXFetchComplete(url, status, response_code, data); 581 OnCRXFetchComplete(source,
582 source->url(),
583 source->status(),
584 source->response_code());
637 } else { 585 } else {
638 NOTREACHED(); 586 NOTREACHED();
639 } 587 }
640 NotifyIfFinished(); 588 NotifyIfFinished();
641 } 589 }
642 590
643 // Utility class to handle doing xml parsing in a sandboxed utility process. 591 // Utility class to handle doing xml parsing in a sandboxed utility process.
644 class SafeManifestParser : public UtilityProcessHost::Client { 592 class SafeManifestParser : public UtilityProcessHost::Client {
645 public: 593 public:
646 // Takes ownership of |fetch_data|. 594 // Takes ownership of |fetch_data|.
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
833 781
834 // Tell ExtensionService to update prefs. 782 // Tell ExtensionService to update prefs.
835 service_->UpdateExtensionBlacklist(blacklist); 783 service_->UpdateExtensionBlacklist(blacklist);
836 784
837 // Update the pref value for blacklist version 785 // Update the pref value for blacklist version
838 prefs_->SetString(kExtensionBlacklistUpdateVersion, 786 prefs_->SetString(kExtensionBlacklistUpdateVersion,
839 current_extension_fetch_.version); 787 current_extension_fetch_.version);
840 prefs_->ScheduleSavePersistentPrefs(); 788 prefs_->ScheduleSavePersistentPrefs();
841 } 789 }
842 790
843 void ExtensionUpdater::OnCRXFetchComplete(const GURL& url, 791 void ExtensionUpdater::OnCRXFetchComplete(
844 const net::URLRequestStatus& status, 792 const URLFetcher* source,
845 int response_code, 793 const GURL& url,
846 const std::string& data) { 794 const net::URLRequestStatus& status,
847 if (status.status() == net::URLRequestStatus::SUCCESS && 795 int response_code) {
848 (response_code == 200 || (url.SchemeIsFile() && data.length() > 0))) { 796
797 base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
798 if (source->FileErrorOccurred(&error_code)) {
799 LOG(ERROR) << "Failed to write update CRX with id "
800 << current_extension_fetch_.id << ". "
801 << "Error code is "<< error_code;
802
803 RecordCrxWriteHistogram(false, FilePath());
804 OnCRXFileWriteError(current_extension_fetch_.id);
805
806 } else if (status.status() == net::URLRequestStatus::SUCCESS &&
807 (response_code == 200 || url.SchemeIsFile())) {
849 if (current_extension_fetch_.id == kBlacklistAppID) { 808 if (current_extension_fetch_.id == kBlacklistAppID) {
809 std::string data;
810 CHECK(source->GetResponseAsString(&data));
850 ProcessBlacklist(data); 811 ProcessBlacklist(data);
851 in_progress_ids_.erase(current_extension_fetch_.id); 812 in_progress_ids_.erase(current_extension_fetch_.id);
852 } else { 813 } else {
853 // Successfully fetched - now write crx to a file so we can have the 814 FilePath crx_path;
854 // ExtensionService install it. 815 // Take ownership of the file at |crx_path|.
855 if (!BrowserThread::PostTask( 816 CHECK(source->GetResponseAsFilePath(true, &crx_path));
856 BrowserThread::FILE, FROM_HERE, 817 RecordCrxWriteHistogram(true, crx_path);
857 NewRunnableMethod( 818 OnCRXFileWritten(current_extension_fetch_.id, crx_path, url);
858 file_handler_.get(),
859 &ExtensionUpdaterFileHandler::WriteTempFile,
860 current_extension_fetch_.id, data, url))) {
861 NOTREACHED();
862 }
863 } 819 }
864 } else { 820 } else {
865 // TODO(asargent) do things like exponential backoff, handling 821 // TODO(asargent) do things like exponential backoff, handling
866 // 503 Service Unavailable / Retry-After headers, etc. here. 822 // 503 Service Unavailable / Retry-After headers, etc. here.
867 // (http://crbug.com/12546). 823 // (http://crbug.com/12546).
868 VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec() 824 VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec()
869 << "' response code:" << response_code; 825 << "' response code:" << response_code;
870 } 826 }
871 extension_fetcher_.reset(); 827 extension_fetcher_.reset();
872 current_extension_fetch_ = ExtensionFetch(); 828 current_extension_fetch_ = ExtensionFetch();
873 829
874 // If there are any pending downloads left, start one. 830 // If there are any pending downloads left, start the next one.
875 if (!extensions_pending_.empty()) { 831 if (!extensions_pending_.empty()) {
876 ExtensionFetch next = extensions_pending_.front(); 832 ExtensionFetch next = extensions_pending_.front();
877 extensions_pending_.pop_front(); 833 extensions_pending_.pop_front();
878 FetchUpdatedExtension(next.id, next.url, next.package_hash, next.version); 834 FetchUpdatedExtension(next.id, next.url, next.package_hash, next.version);
879 } 835 }
880 } 836 }
881 837
882 void ExtensionUpdater::OnCRXFileWritten(const std::string& id, 838 void ExtensionUpdater::OnCRXFileWritten(const std::string& id,
883 const FilePath& path, 839 const FilePath& path,
884 const GURL& download_url) { 840 const GURL& download_url) {
885 DCHECK(alive_); 841 DCHECK(alive_);
886 // The ExtensionService is now responsible for cleaning up the temp file 842 // The ExtensionService is now responsible for cleaning up the temp file
887 // at |path|. 843 // at |path|.
888 service_->UpdateExtension(id, path, download_url); 844 service_->UpdateExtension(id, path, download_url);
889 in_progress_ids_.erase(id); 845 in_progress_ids_.erase(id);
890 NotifyIfFinished();
891 } 846 }
892 847
893 void ExtensionUpdater::OnCRXFileWriteError(const std::string& id) { 848 void ExtensionUpdater::OnCRXFileWriteError(const std::string& id) {
894 DCHECK(alive_); 849 DCHECK(alive_);
895 in_progress_ids_.erase(id); 850 in_progress_ids_.erase(id);
896 NotifyIfFinished();
897 } 851 }
898 852
899 void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) { 853 void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) {
900 DCHECK(alive_); 854 DCHECK(alive_);
901 DCHECK(!timer_.IsRunning()); 855 DCHECK(!timer_.IsRunning());
902 DCHECK(target_delay >= TimeDelta::FromSeconds(1)); 856 DCHECK(target_delay >= TimeDelta::FromSeconds(1));
903 857
904 // Add +/- 10% random jitter. 858 // Add +/- 10% random jitter.
905 double delay_ms = target_delay.InMillisecondsF(); 859 double delay_ms = target_delay.InMillisecondsF();
906 double jitter_factor = (RandDouble() * .2) - 0.1; 860 double jitter_factor = (RandDouble() * .2) - 0.1;
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after
1158 extensions_pending_.push_back(ExtensionFetch(id, url, hash, version)); 1112 extensions_pending_.push_back(ExtensionFetch(id, url, hash, version));
1159 } 1113 }
1160 } else { 1114 } else {
1161 extension_fetcher_.reset( 1115 extension_fetcher_.reset(
1162 URLFetcher::Create(kExtensionFetcherId, url, URLFetcher::GET, this)); 1116 URLFetcher::Create(kExtensionFetcherId, url, URLFetcher::GET, this));
1163 extension_fetcher_->set_request_context( 1117 extension_fetcher_->set_request_context(
1164 profile_->GetRequestContext()); 1118 profile_->GetRequestContext());
1165 extension_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES | 1119 extension_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES |
1166 net::LOAD_DO_NOT_SAVE_COOKIES | 1120 net::LOAD_DO_NOT_SAVE_COOKIES |
1167 net::LOAD_DISABLE_CACHE); 1121 net::LOAD_DISABLE_CACHE);
1122 // Download CRX files to a temp file. The blacklist is small and will be
1123 // processed in memory, so it is fetched into a string.
1124 if (id != ExtensionUpdater::kBlacklistAppID) {
1125 extension_fetcher_->SaveResponseToTemporaryFile(
1126 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
1127 }
1128
1168 extension_fetcher_->Start(); 1129 extension_fetcher_->Start();
1169 current_extension_fetch_ = ExtensionFetch(id, url, hash, version); 1130 current_extension_fetch_ = ExtensionFetch(id, url, hash, version);
1170 } 1131 }
1171 } 1132 }
1172 1133
1173 void ExtensionUpdater::NotifyStarted() { 1134 void ExtensionUpdater::NotifyStarted() {
1174 NotificationService::current()->Notify( 1135 NotificationService::current()->Notify(
1175 NotificationType::EXTENSION_UPDATING_STARTED, 1136 NotificationType::EXTENSION_UPDATING_STARTED,
1176 Source<Profile>(profile_), 1137 Source<Profile>(profile_),
1177 NotificationService::NoDetails()); 1138 NotificationService::NoDetails());
(...skipping 20 matching lines...) Expand all
1198 std::set<std::string>::const_iterator i; 1159 std::set<std::string>::const_iterator i;
1199 for (i = ids.begin(); i != ids.end(); ++i) 1160 for (i = ids.begin(); i != ids.end(); ++i)
1200 in_progress_ids_.insert(*i); 1161 in_progress_ids_.insert(*i);
1201 } 1162 }
1202 1163
1203 void ExtensionUpdater::RemoveFromInProgress(const std::set<std::string>& ids) { 1164 void ExtensionUpdater::RemoveFromInProgress(const std::set<std::string>& ids) {
1204 std::set<std::string>::const_iterator i; 1165 std::set<std::string>::const_iterator i;
1205 for (i = ids.begin(); i != ids.end(); ++i) 1166 for (i = ids.begin(); i != ids.end(); ++i)
1206 in_progress_ids_.erase(*i); 1167 in_progress_ids_.erase(*i);
1207 } 1168 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698