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/win/enumerate_modules_model.h" | 5 #include "chrome/browser/win/enumerate_modules_model.h" |
6 | 6 |
7 #include <softpub.h> | 7 #include <softpub.h> |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 #include <tlhelp32.h> | 10 #include <tlhelp32.h> |
(...skipping 10 matching lines...) Expand all Loading... | |
21 #include "base/debug/leak_annotations.h" | 21 #include "base/debug/leak_annotations.h" |
22 #include "base/environment.h" | 22 #include "base/environment.h" |
23 #include "base/file_version_info.h" | 23 #include "base/file_version_info.h" |
24 #include "base/i18n/case_conversion.h" | 24 #include "base/i18n/case_conversion.h" |
25 #include "base/macros.h" | 25 #include "base/macros.h" |
26 #include "base/metrics/histogram_macros.h" | 26 #include "base/metrics/histogram_macros.h" |
27 #include "base/scoped_generic.h" | 27 #include "base/scoped_generic.h" |
28 #include "base/strings/string_number_conversions.h" | 28 #include "base/strings/string_number_conversions.h" |
29 #include "base/strings/string_util.h" | 29 #include "base/strings/string_util.h" |
30 #include "base/strings/utf_string_conversions.h" | 30 #include "base/strings/utf_string_conversions.h" |
31 #include "base/threading/sequenced_worker_pool.h" | 31 #include "base/task_scheduler/post_task.h" |
32 #include "base/time/time.h" | 32 #include "base/time/time.h" |
33 #include "base/values.h" | 33 #include "base/values.h" |
34 #include "base/version.h" | 34 #include "base/version.h" |
35 #include "base/win/registry.h" | 35 #include "base/win/registry.h" |
36 #include "base/win/scoped_handle.h" | 36 #include "base/win/scoped_handle.h" |
37 #include "base/win/windows_version.h" | 37 #include "base/win/windows_version.h" |
38 #include "chrome/browser/net/service_providers_win.h" | 38 #include "chrome/browser/net/service_providers_win.h" |
39 #include "chrome/common/chrome_constants.h" | 39 #include "chrome/common/chrome_constants.h" |
40 #include "chrome/common/crash_keys.h" | 40 #include "chrome/common/crash_keys.h" |
41 #include "chrome/grit/generated_resources.h" | 41 #include "chrome/grit/generated_resources.h" |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
156 if (first_space != base::string16::npos) | 156 if (first_space != base::string16::npos) |
157 module->version = module->version.substr(0, first_space); | 157 module->version = module->version.substr(0, first_space); |
158 | 158 |
159 // The signer may be returned with trailing nulls. | 159 // The signer may be returned with trailing nulls. |
160 size_t first_null = module->cert_info.subject.find(L'\0'); | 160 size_t first_null = module->cert_info.subject.find(L'\0'); |
161 if (first_null != base::string16::npos) | 161 if (first_null != base::string16::npos) |
162 module->cert_info.subject.resize(first_null); | 162 module->cert_info.subject.resize(first_null); |
163 } | 163 } |
164 | 164 |
165 ModuleEnumerator::ModuleEnumerator(EnumerateModulesModel* observer) | 165 ModuleEnumerator::ModuleEnumerator(EnumerateModulesModel* observer) |
166 : enumerated_modules_(nullptr), | 166 : background_task_runner_(base::CreateTaskRunnerWithTraits( |
167 base::TaskTraits() | |
168 .MayBlock() | |
169 .WithPriority(base::TaskPriority::BACKGROUND) | |
170 .WithShutdownBehavior( | |
171 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN))), | |
Finnur
2017/02/21 10:45:55
Speaking out loud here -- I really don't like the
fdoray
2017/02/22 18:53:06
I agree with you. I'll show your comment to my tea
| |
172 enumerated_modules_(nullptr), | |
167 observer_(observer), | 173 observer_(observer), |
168 per_module_delay_(kDefaultPerModuleDelay) { | 174 per_module_delay_(kDefaultPerModuleDelay) {} |
169 } | |
170 | 175 |
171 ModuleEnumerator::~ModuleEnumerator() { | 176 ModuleEnumerator::~ModuleEnumerator() { |
172 } | 177 } |
173 | 178 |
174 void ModuleEnumerator::ScanNow(ModulesVector* list) { | 179 void ModuleEnumerator::ScanNow(ModulesVector* list) { |
175 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 180 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
176 enumerated_modules_ = list; | 181 enumerated_modules_ = list; |
177 | 182 |
178 // This object can't be reaped until it has finished scanning, so its safe | 183 // This object can't be reaped until it has finished scanning, so its safe |
179 // to post a raw pointer to another thread. It will simply be leaked if the | 184 // to post a raw pointer to another thread. It will simply be leaked if the |
180 // scanning has not been finished before shutdown. | 185 // scanning has not been finished before shutdown. |
181 BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( | 186 background_task_runner_->PostTask( |
182 FROM_HERE, | 187 FROM_HERE, |
183 base::Bind(&ModuleEnumerator::ScanImplStart, | 188 base::Bind(&ModuleEnumerator::ScanImplStart, base::Unretained(this))); |
184 base::Unretained(this)), | |
185 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); | |
186 } | 189 } |
187 | 190 |
188 void ModuleEnumerator::SetPerModuleDelayToZero() { | 191 void ModuleEnumerator::SetPerModuleDelayToZero() { |
189 // Set the delay to zero so the modules enumerate as quickly as possible. | 192 // Set the delay to zero so the modules enumerate as quickly as possible. |
190 per_module_delay_ = base::TimeDelta::FromSeconds(0); | 193 per_module_delay_ = base::TimeDelta::FromSeconds(0); |
191 } | 194 } |
192 | 195 |
193 void ModuleEnumerator::ScanImplStart() { | 196 void ModuleEnumerator::ScanImplStart() { |
194 base::TimeTicks start_time = base::TimeTicks::Now(); | 197 base::TimeTicks start_time = base::TimeTicks::Now(); |
195 | 198 |
(...skipping 22 matching lines...) Expand all Loading... | |
218 checkpoint = checkpoint2; | 221 checkpoint = checkpoint2; |
219 EnumerateWinsockModules(); | 222 EnumerateWinsockModules(); |
220 checkpoint2 = base::TimeTicks::Now(); | 223 checkpoint2 = base::TimeTicks::Now(); |
221 UMA_HISTOGRAM_TIMES("Conflicts.EnumerateWinsockModules", | 224 UMA_HISTOGRAM_TIMES("Conflicts.EnumerateWinsockModules", |
222 checkpoint2 - checkpoint); | 225 checkpoint2 - checkpoint); |
223 | 226 |
224 enumeration_total_time_ = base::TimeTicks::Now() - start_time; | 227 enumeration_total_time_ = base::TimeTicks::Now() - start_time; |
225 | 228 |
226 // Post a delayed task to scan the first module. This forwards directly to | 229 // Post a delayed task to scan the first module. This forwards directly to |
227 // ScanImplFinish if there are no modules to scan. | 230 // ScanImplFinish if there are no modules to scan. |
228 BrowserThread::GetBlockingPool()->PostDelayedWorkerTask( | 231 background_task_runner_->PostDelayedTask( |
229 FROM_HERE, | 232 FROM_HERE, |
230 base::Bind(&ModuleEnumerator::ScanImplModule, | 233 base::Bind(&ModuleEnumerator::ScanImplModule, base::Unretained(this), 0), |
231 base::Unretained(this), | |
232 0), | |
233 per_module_delay_); | 234 per_module_delay_); |
234 } | 235 } |
235 | 236 |
236 void ModuleEnumerator::ScanImplDelay(size_t index) { | |
237 // Bounce this over to a CONTINUE_ON_SHUTDOWN task in the same pool. This is | |
238 // necessary to prevent shutdown hangs while inspecting a module. | |
239 BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( | |
240 FROM_HERE, | |
241 base::Bind(&ModuleEnumerator::ScanImplModule, | |
242 base::Unretained(this), | |
243 index), | |
244 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); | |
245 } | |
246 | |
247 void ModuleEnumerator::ScanImplModule(size_t index) { | 237 void ModuleEnumerator::ScanImplModule(size_t index) { |
248 while (index < enumerated_modules_->size()) { | 238 while (index < enumerated_modules_->size()) { |
249 base::TimeTicks start_time = base::TimeTicks::Now(); | 239 base::TimeTicks start_time = base::TimeTicks::Now(); |
250 Module& entry = enumerated_modules_->at(index); | 240 Module& entry = enumerated_modules_->at(index); |
251 PopulateModuleInformation(&entry); | 241 PopulateModuleInformation(&entry); |
252 NormalizeModule(&entry); | 242 NormalizeModule(&entry); |
253 CollapsePath(&entry); | 243 CollapsePath(&entry); |
254 base::TimeDelta elapsed = base::TimeTicks::Now() - start_time; | 244 base::TimeDelta elapsed = base::TimeTicks::Now() - start_time; |
255 enumeration_inspection_time_ += elapsed; | 245 enumeration_inspection_time_ += elapsed; |
256 enumeration_total_time_ += elapsed; | 246 enumeration_total_time_ += elapsed; |
257 | 247 |
258 // With a non-zero delay, bounce back over to ScanImplDelay, which will | 248 // If |per_module_delay_| is non-zero, post a task to scan the next module |
259 // bounce back to this function and inspect the next module. | 249 // when the delay expires. |
260 if (!per_module_delay_.is_zero()) { | 250 if (!per_module_delay_.is_zero()) { |
261 BrowserThread::GetBlockingPool()->PostDelayedWorkerTask( | 251 background_task_runner_->PostDelayedTask( |
262 FROM_HERE, | 252 FROM_HERE, base::Bind(&ModuleEnumerator::ScanImplModule, |
263 base::Bind(&ModuleEnumerator::ScanImplDelay, | 253 base::Unretained(this), index + 1), |
264 base::Unretained(this), | |
265 index + 1), | |
266 per_module_delay_); | 254 per_module_delay_); |
267 return; | 255 return; |
268 } | 256 } |
269 | 257 |
270 // If the delay has been set to zero then simply finish the rest of the | 258 // If the delay has been set to zero then simply finish the rest of the |
271 // enumeration in this already started task. | 259 // enumeration in this already started task. |
272 ++index; | 260 ++index; |
273 } | 261 } |
274 | 262 |
275 // Getting here means that all of the modules have been inspected. | 263 // Getting here means that all of the modules have been inspected. |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
606 base::Unretained(this), | 594 base::Unretained(this), |
607 true)); | 595 true)); |
608 done = true; | 596 done = true; |
609 } | 597 } |
610 } | 598 } |
611 | 599 |
612 void EnumerateModulesModel::ScanNow(bool background_mode) { | 600 void EnumerateModulesModel::ScanNow(bool background_mode) { |
613 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 601 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
614 | 602 |
615 // |module_enumerator_| is used as a lock to know whether or not there are | 603 // |module_enumerator_| is used as a lock to know whether or not there are |
616 // active/pending blocking pool tasks. If a module enumerator exists then a | 604 // active/pending background tasks. If a module enumerator exists then a scan |
617 // scan is already underway. Otherwise, either no scan has been completed or | 605 // is already underway. Otherwise, either no scan has been completed or a scan |
618 // a scan has terminated. | 606 // has terminated. |
619 if (module_enumerator_) { | 607 if (module_enumerator_) { |
620 // If a scan is in progress and this request is for immediate results, then | 608 // If a scan is in progress and this request is for immediate results, then |
621 // inform the background scan. This is done without any locks because the | 609 // inform the background scan. This is done without any locks because the |
622 // other thread only reads from the value that is being modified, and on | 610 // other thread only reads from the value that is being modified, and on |
623 // Windows its an atomic write. | 611 // Windows its an atomic write. |
624 if (!background_mode) | 612 if (!background_mode) |
625 module_enumerator_->SetPerModuleDelayToZero(); | 613 module_enumerator_->SetPerModuleDelayToZero(); |
626 return; | 614 return; |
627 } | 615 } |
628 | 616 |
629 // Only allow a single scan per process lifetime. Immediately notify any | 617 // Only allow a single scan per process lifetime. Immediately notify any |
630 // observers that the scan is complete. At this point |enumerated_modules_| is | 618 // observers that the scan is complete. At this point |enumerated_modules_| is |
631 // safe to access as no potentially racing blocking pool task can exist. | 619 // safe to access as no potentially racing background task can exist. |
632 if (!enumerated_modules_.empty()) { | 620 if (!enumerated_modules_.empty()) { |
633 for (Observer& observer : observers_) | 621 for (Observer& observer : observers_) |
634 observer.OnScanCompleted(); | 622 observer.OnScanCompleted(); |
635 return; | 623 return; |
636 } | 624 } |
637 | 625 |
638 // ScanNow does not block, rather it simply schedules a task. | 626 // ScanNow does not block, rather it simply schedules a task. |
639 module_enumerator_.reset(new ModuleEnumerator(this)); | 627 module_enumerator_.reset(new ModuleEnumerator(this)); |
640 if (!background_mode) | 628 if (!background_mode) |
641 module_enumerator_->SetPerModuleDelayToZero(); | 629 module_enumerator_->SetPerModuleDelayToZero(); |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
771 | 759 |
772 UMA_HISTOGRAM_COUNTS_100("Conflicts.SuspectedBadModules", | 760 UMA_HISTOGRAM_COUNTS_100("Conflicts.SuspectedBadModules", |
773 suspected_bad_modules_detected_); | 761 suspected_bad_modules_detected_); |
774 UMA_HISTOGRAM_COUNTS_100("Conflicts.ConfirmedBadModules", | 762 UMA_HISTOGRAM_COUNTS_100("Conflicts.ConfirmedBadModules", |
775 confirmed_bad_modules_detected_); | 763 confirmed_bad_modules_detected_); |
776 | 764 |
777 // Forward the callback to any registered observers. | 765 // Forward the callback to any registered observers. |
778 for (Observer& observer : observers_) | 766 for (Observer& observer : observers_) |
779 observer.OnScanCompleted(); | 767 observer.OnScanCompleted(); |
780 } | 768 } |
OLD | NEW |