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

Unified Diff: chrome/browser/win/enumerate_modules_model.cc

Issue 2420133002: Make module enumeration a low priority background task. (Closed)
Patch Set: Fix small bug. Created 4 years, 2 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/win/enumerate_modules_model.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/win/enumerate_modules_model.cc
diff --git a/chrome/browser/win/enumerate_modules_model.cc b/chrome/browser/win/enumerate_modules_model.cc
index 376e6b08bf18de878278b889079182c067c39854..7d301ca42caf3f6ba0e4b28c6f3cddc371491014 100644
--- a/chrome/browser/win/enumerate_modules_model.cc
+++ b/chrome/browser/win/enumerate_modules_model.cc
@@ -60,6 +60,12 @@ static bool ModuleSort(const ModuleEnumerator::Module& a,
namespace {
+// The default amount of time between module inspections. This prevents
+// certificate inspection and validation from using a large amount of CPU and
+// battery immediately after startup.
+constexpr base::TimeDelta kDefaultPerModuleDelay =
+ base::TimeDelta::FromSeconds(1);
+
// A struct to help de-duping modules before adding them to the enumerated
// modules vector.
struct FindModule {
@@ -393,7 +399,8 @@ void ModuleEnumerator::NormalizeModule(Module* module) {
ModuleEnumerator::ModuleEnumerator(EnumerateModulesModel* observer)
: enumerated_modules_(nullptr),
- observer_(observer) {
+ observer_(observer),
+ per_module_delay_(kDefaultPerModuleDelay) {
}
ModuleEnumerator::~ModuleEnumerator() {
@@ -408,12 +415,17 @@ void ModuleEnumerator::ScanNow(ModulesVector* list) {
// scanning has not been finished before shutdown.
BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior(
FROM_HERE,
- base::Bind(&ModuleEnumerator::ScanImpl,
+ base::Bind(&ModuleEnumerator::ScanImplStart,
base::Unretained(this)),
base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
}
-void ModuleEnumerator::ScanImpl() {
+void ModuleEnumerator::SetPerModuleDelayToZero() {
+ // Set the delay to zero so the modules enumerate as quickly as possible.
+ per_module_delay_ = base::TimeDelta::FromSeconds(0);
+}
+
+void ModuleEnumerator::ScanImplStart() {
base::TimeTicks start_time = base::TimeTicks::Now();
// The provided destination for the enumerated modules should be empty, as it
@@ -444,6 +456,61 @@ void ModuleEnumerator::ScanImpl() {
UMA_HISTOGRAM_TIMES("Conflicts.EnumerateWinsockModules",
checkpoint2 - checkpoint);
+ enumeration_total_time_ = base::TimeTicks::Now() - start_time;
+
+ // Post a delayed task to scan the first module. This forwards directly to
+ // ScanImplFinish if there are no modules to scan.
+ BrowserThread::GetBlockingPool()->PostDelayedWorkerTask(
+ FROM_HERE,
+ base::Bind(&ModuleEnumerator::ScanImplModule,
+ base::Unretained(this),
+ 0),
+ per_module_delay_);
+}
+
+void ModuleEnumerator::ScanImplDelay(size_t index) {
+ // Bounce this over to a CONTINUE_ON_SHUTDOWN task in the same pool. This is
+ // necessary to prevent shutdown hangs while inspecting a module.
+ BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior(
+ FROM_HERE,
+ base::Bind(&ModuleEnumerator::ScanImplModule,
+ base::Unretained(this),
+ index),
+ base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+}
+
+void ModuleEnumerator::ScanImplModule(size_t index) {
+ while (index < enumerated_modules_->size()) {
+ base::TimeTicks start_time = base::TimeTicks::Now();
+ Module& entry = enumerated_modules_->at(index);
+ PopulateModuleInformation(&entry);
+ CollapsePath(&entry);
+ base::TimeDelta elapsed = base::TimeTicks::Now() - start_time;
+ enumeration_inspection_time_ += elapsed;
+ enumeration_total_time_ += elapsed;
+
+ // With a non-zero delay, bounce back over to ScanImplDelay, which will
+ // bounce back to this function and inspect the next module.
+ if (!per_module_delay_.is_zero()) {
+ BrowserThread::GetBlockingPool()->PostDelayedWorkerTask(
+ FROM_HERE,
+ base::Bind(&ModuleEnumerator::ScanImplDelay,
+ base::Unretained(this),
+ index + 1),
+ per_module_delay_);
+ return;
+ }
+
+ // If the delay has been set to zero then simply finish the rest of the
+ // enumeration in this already started task.
+ ++index;
+ }
+
+ // Getting here means that all of the modules have been inspected.
+ return ScanImplFinish();
+}
+
+void ModuleEnumerator::ScanImplFinish() {
// TODO(chrisha): Annotate any modules that are suspicious/bad.
ReportThirdPartyMetrics();
@@ -451,8 +518,10 @@ void ModuleEnumerator::ScanImpl() {
std::sort(enumerated_modules_->begin(),
enumerated_modules_->end(), ModuleSort);
+ UMA_HISTOGRAM_TIMES("Conflicts.EnumerationInspectionTime",
+ enumeration_inspection_time_);
UMA_HISTOGRAM_TIMES("Conflicts.EnumerationTotalTime",
- base::TimeTicks::Now() - start_time);
+ enumeration_total_time_);
// Send a reply back on the UI thread. The |observer_| outlives this
// enumerator, so posting a raw pointer is safe. This is done last as
@@ -482,10 +551,7 @@ void ModuleEnumerator::EnumerateLoadedModules() {
Module entry;
entry.type = LOADED_MODULE;
entry.location = module.szExePath;
- PopulateModuleInformation(&entry);
-
NormalizeModule(&entry);
- CollapsePath(&entry);
enumerated_modules_->push_back(entry);
} while (::Module32Next(snap.Get(), &module));
}
@@ -515,10 +581,7 @@ void ModuleEnumerator::ReadShellExtensions(HKEY parent) {
Module entry;
entry.type = SHELL_EXTENSION;
entry.location = dll;
- PopulateModuleInformation(&entry);
-
NormalizeModule(&entry);
- CollapsePath(&entry);
AddToListWithoutDuplicating(entry);
++registration;
@@ -542,12 +605,9 @@ void ModuleEnumerator::EnumerateWinsockModules() {
wchar_t expanded[MAX_PATH];
DWORD size = ExpandEnvironmentStrings(
entry.location.c_str(), expanded, MAX_PATH);
- if (size != 0 && size <= MAX_PATH) {
- GetCertificateInfo(base::FilePath(expanded), &entry.cert_info);
- }
+ if (size != 0 && size <= MAX_PATH)
+ entry.location = expanded;
entry.version = base::IntToString16(layered_providers[i].version);
-
- // Paths have already been collapsed.
NormalizeModule(&entry);
AddToListWithoutDuplicating(entry);
}
@@ -756,20 +816,29 @@ void EnumerateModulesModel::MaybePostScanningTask() {
BrowserThread::PostAfterStartupTask(
FROM_HERE,
BrowserThread::GetTaskRunnerForThread(BrowserThread::UI),
- base::Bind(&EnumerateModulesModel::ScanNow, base::Unretained(this)));
+ base::Bind(&EnumerateModulesModel::ScanNow,
+ base::Unretained(this),
+ true));
done = true;
}
}
-void EnumerateModulesModel::ScanNow() {
+void EnumerateModulesModel::ScanNow(bool background_mode) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// |module_enumerator_| is used as a lock to know whether or not there are
// active/pending blocking pool tasks. If a module enumerator exists then a
// scan is already underway. Otherwise, either no scan has been completed or
// a scan has terminated.
- if (module_enumerator_)
+ if (module_enumerator_) {
+ // If a scan is in progress and this request is for immediate results, then
+ // inform the background scan. This is done without any locks because the
+ // other thread only reads from the value that is being modified, and on
+ // Windows its an atomic write.
+ if (!background_mode)
+ module_enumerator_->SetPerModuleDelayToZero();
return;
+ }
// Only allow a single scan per process lifetime. Immediately notify any
// observers that the scan is complete. At this point |enumerated_modules_| is
@@ -781,6 +850,8 @@ void EnumerateModulesModel::ScanNow() {
// ScanNow does not block, rather it simply schedules a task.
module_enumerator_.reset(new ModuleEnumerator(this));
+ if (!background_mode)
+ module_enumerator_->SetPerModuleDelayToZero();
module_enumerator_->ScanNow(&enumerated_modules_);
}
« no previous file with comments | « chrome/browser/win/enumerate_modules_model.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698