OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/media_galleries/media_scan_manager.h" | 5 #include "chrome/browser/media_galleries/media_scan_manager.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/files/file_enumerator.h" | 8 #include "base/files/file_enumerator.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
203 MediaGalleryPrefInfo::kScanResult, | 203 MediaGalleryPrefInfo::kScanResult, |
204 gallery.volume_label, gallery.vendor_name, | 204 gallery.volume_label, gallery.vendor_name, |
205 gallery.model_name, gallery.total_size_in_bytes, | 205 gallery.model_name, gallery.total_size_in_bytes, |
206 gallery.last_attach_time, file_counts.audio_count, | 206 gallery.last_attach_time, file_counts.audio_count, |
207 file_counts.image_count, file_counts.video_count); | 207 file_counts.image_count, file_counts.video_count); |
208 } | 208 } |
209 UMA_HISTOGRAM_COUNTS_10000("MediaGalleries.ScanGalleriesPopulated", | 209 UMA_HISTOGRAM_COUNTS_10000("MediaGalleries.ScanGalleriesPopulated", |
210 unique_found_folders.size() + to_update.size()); | 210 unique_found_folders.size() + to_update.size()); |
211 } | 211 } |
212 | 212 |
213 // A single directory may contain many folders with media in them, without | 213 struct ContainerCount { |
214 // containing any media itself. In fact, the primary purpose of that directory | 214 int seen_count, entries_count; |
215 // may be to contain media directories. This function tries to find those | 215 bool is_qualified; |
216 // immediate container directories. | |
217 MediaFolderFinder::MediaFolderFinderResults FindContainerScanResults( | |
218 const MediaFolderFinder::MediaFolderFinderResults& found_folders, | |
219 const std::vector<base::FilePath>& sensitive_locations) { | |
220 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); | |
221 std::vector<base::FilePath> abs_sensitive_locations; | |
222 for (size_t i = 0; i < sensitive_locations.size(); ++i) { | |
223 base::FilePath path = base::MakeAbsoluteFilePath(sensitive_locations[i]); | |
224 if (!path.empty()) | |
225 abs_sensitive_locations.push_back(path); | |
226 } | |
227 // Count the number of scan results with the same parent directory. | |
228 typedef std::map<base::FilePath, int /*count*/> ContainerCandidates; | |
229 ContainerCandidates candidates; | |
230 for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it = | |
231 found_folders.begin(); it != found_folders.end(); ++it) { | |
232 base::FilePath parent_directory = it->first.DirName(); | |
233 | 216 |
234 // Skip sensitive folders and their ancestors. | 217 ContainerCount() : seen_count(0), entries_count(-1), is_qualified(false) {} |
235 bool is_sensitive = false; | 218 }; |
236 base::FilePath abs_parent_directory = | |
237 base::MakeAbsoluteFilePath(parent_directory); | |
238 if (abs_parent_directory.empty()) | |
239 continue; | |
240 for (size_t i = 0; i < abs_sensitive_locations.size(); ++i) { | |
241 if (abs_parent_directory == abs_sensitive_locations[i] || | |
242 abs_parent_directory.IsParent(abs_sensitive_locations[i])) { | |
243 is_sensitive = true; | |
244 continue; | |
245 } | |
246 } | |
247 if (is_sensitive) | |
248 continue; | |
249 | |
250 ContainerCandidates::iterator existing = candidates.find(parent_directory); | |
251 if (existing == candidates.end()) { | |
252 candidates[parent_directory] = 1; | |
253 } else { | |
254 existing->second++; | |
255 } | |
256 } | |
257 | |
258 // If a parent directory has more than one scan result, consider it. | |
259 MediaFolderFinder::MediaFolderFinderResults result; | |
260 for (ContainerCandidates::const_iterator it = candidates.begin(); | |
261 it != candidates.end(); | |
262 ++it) { | |
263 if (it->second <= 1) | |
264 continue; | |
265 | |
266 base::FileEnumerator dir_counter(it->first, false /*recursive*/, | |
267 base::FileEnumerator::DIRECTORIES); | |
268 base::FileEnumerator::FileInfo info; | |
269 int count = 0; | |
270 for (base::FilePath name = dir_counter.Next(); | |
271 !name.empty(); | |
272 name = dir_counter.Next()) { | |
273 if (!base::IsLink(name)) | |
274 count++; | |
275 } | |
276 if (it->second * 100 / count >= kContainerDirectoryMinimumPercent) | |
277 result[it->first] = MediaGalleryScanResult(); | |
278 } | |
279 return result; | |
280 } | |
281 | 219 |
282 int CountScanResultsForExtension(MediaGalleriesPreferences* preferences, | 220 int CountScanResultsForExtension(MediaGalleriesPreferences* preferences, |
283 const extensions::Extension* extension, | 221 const extensions::Extension* extension, |
284 MediaGalleryScanResult* file_counts) { | 222 MediaGalleryScanResult* file_counts) { |
285 int gallery_count = 0; | 223 int gallery_count = 0; |
286 | 224 |
287 MediaGalleryPrefIdSet permitted_galleries = | 225 MediaGalleryPrefIdSet permitted_galleries = |
288 preferences->GalleriesForExtension(*extension); | 226 preferences->GalleriesForExtension(*extension); |
289 const MediaGalleriesPrefInfoMap& known_galleries = | 227 const MediaGalleriesPrefInfoMap& known_galleries = |
290 preferences->known_galleries(); | 228 preferences->known_galleries(); |
291 for (MediaGalleriesPrefInfoMap::const_iterator it = known_galleries.begin(); | 229 for (MediaGalleriesPrefInfoMap::const_iterator it = known_galleries.begin(); |
292 it != known_galleries.end(); | 230 it != known_galleries.end(); |
293 ++it) { | 231 ++it) { |
294 if (it->second.type == MediaGalleryPrefInfo::kScanResult && | 232 if (it->second.type == MediaGalleryPrefInfo::kScanResult && |
295 !ContainsKey(permitted_galleries, it->first)) { | 233 !ContainsKey(permitted_galleries, it->first)) { |
296 gallery_count++; | 234 gallery_count++; |
297 file_counts->audio_count += it->second.audio_count; | 235 file_counts->audio_count += it->second.audio_count; |
298 file_counts->image_count += it->second.image_count; | 236 file_counts->image_count += it->second.image_count; |
299 file_counts->video_count += it->second.video_count; | 237 file_counts->video_count += it->second.video_count; |
300 } | 238 } |
301 } | 239 } |
302 return gallery_count; | 240 return gallery_count; |
303 } | 241 } |
304 | 242 |
243 int CountDirectoryEntries(const base::FilePath& path) { | |
244 base::FileEnumerator dir_counter(path, false /*recursive*/, | |
245 base::FileEnumerator::DIRECTORIES); | |
246 int count = 0; | |
247 base::FileEnumerator::FileInfo info; | |
248 for (base::FilePath name = dir_counter.Next(); | |
249 !name.empty(); | |
250 name = dir_counter.Next()) { | |
251 if (!base::IsLink(name)) | |
252 ++count; | |
253 } | |
254 return count; | |
255 } | |
256 | |
305 } // namespace | 257 } // namespace |
306 | 258 |
307 MediaScanManager::MediaScanManager() | 259 MediaScanManager::MediaScanManager() |
308 : scoped_extension_registry_observer_(this), | 260 : scoped_extension_registry_observer_(this), |
309 weak_factory_(this) { | 261 weak_factory_(this) { |
310 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 262 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
311 } | 263 } |
312 | 264 |
313 MediaScanManager::~MediaScanManager() { | 265 MediaScanManager::~MediaScanManager() { |
314 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 266 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
416 base::Time::Now() - scan_start_time_); | 368 base::Time::Now() - scan_start_time_); |
417 scan_start_time_ = base::Time(); | 369 scan_start_time_ = base::Time(); |
418 } | 370 } |
419 } | 371 } |
420 | 372 |
421 void MediaScanManager::SetMediaFolderFinderFactory( | 373 void MediaScanManager::SetMediaFolderFinderFactory( |
422 const MediaFolderFinderFactory& factory) { | 374 const MediaFolderFinderFactory& factory) { |
423 testing_folder_finder_factory_ = factory; | 375 testing_folder_finder_factory_ = factory; |
424 } | 376 } |
425 | 377 |
378 // A single directory may contain many folders with media in them, without | |
379 // containing any media itself. In fact, the primary purpose of that directory | |
380 // may be to contain media directories. This function tries to find those | |
381 // container directories. | |
382 MediaFolderFinder::MediaFolderFinderResults | |
383 MediaScanManager::FindContainerScanResults( | |
384 const MediaFolderFinder::MediaFolderFinderResults& found_folders, | |
385 const std::vector<base::FilePath>& sensitive_locations) { | |
386 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); | |
387 std::vector<base::FilePath> abs_sensitive_locations; | |
388 for (size_t i = 0; i < sensitive_locations.size(); ++i) { | |
389 base::FilePath path = base::MakeAbsoluteFilePath(sensitive_locations[i]); | |
390 if (!path.empty()) | |
391 abs_sensitive_locations.push_back(path); | |
392 } | |
393 // Find parent directories with majority of media directories, | |
vandebo (ex-Chrome)
2014/06/02 16:29:25
Recursively find... ?
Kevin Bailey
2014/06/02 21:03:43
Done.
| |
394 // or container directories. | |
395 // |candidates| keeps track of directories which might have enough | |
396 // media directories to have us return them. | |
397 typedef std::map<base::FilePath, ContainerCount> ContainerCandidates; | |
398 ContainerCandidates candidates; | |
399 for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it = | |
400 found_folders.begin(); it != found_folders.end(); ++it) { | |
401 base::FilePath candidate = it->first; | |
vandebo (ex-Chrome)
2014/06/02 16:29:25
nit: it->first is already in, it's the parent that
Kevin Bailey
2014/06/02 21:03:43
Indeed, I reused the name. But since it follows |p
| |
402 base::FilePath parent_directory = candidate.DirName(); | |
403 | |
404 // Parent of root is root. | |
405 while (!parent_directory.empty() && candidate != parent_directory) { | |
406 // Skip sensitive folders and their ancestors. | |
407 base::FilePath abs_parent_directory = | |
408 base::MakeAbsoluteFilePath(parent_directory); | |
409 if (abs_parent_directory.empty()) | |
410 break; | |
411 bool is_sensitive = false; | |
412 for (size_t i = 0; i < abs_sensitive_locations.size(); ++i) { | |
413 if (abs_parent_directory == abs_sensitive_locations[i] || | |
414 abs_parent_directory.IsParent(abs_sensitive_locations[i])) { | |
415 is_sensitive = true; | |
416 break; | |
417 } | |
418 } | |
419 if (is_sensitive) | |
420 break; | |
421 | |
422 // Don't bother with ones we already have. | |
423 if (found_folders.find(parent_directory) != found_folders.end()) | |
424 continue; | |
425 | |
426 ContainerCandidates::iterator parent_it = | |
427 candidates.find(parent_directory); | |
428 if (parent_it == candidates.end()) { | |
429 ContainerCount count; | |
430 count.seen_count = 1; | |
431 count.entries_count = CountDirectoryEntries(parent_directory); | |
432 parent_it = candidates.insert(std::make_pair(parent_directory, | |
433 count)).first; | |
434 } else { | |
435 ++candidates[parent_directory].seen_count; | |
436 } | |
437 // If was insufficient, but is now sufficient, mark qualified and | |
438 // check parent. | |
439 if ((parent_it->second.seen_count - 1) * 100 / | |
vandebo (ex-Chrome)
2014/06/02 16:29:25
Instead of doing the extra math, just check that i
Kevin Bailey
2014/06/02 21:03:43
Done. For some reason, I thought it wouldn't work
vandebo (ex-Chrome)
2014/06/03 16:27:21
You didn't do the early exit, which makes things e
Kevin Bailey
2014/06/03 18:01:20
Done.
| |
440 parent_it->second.entries_count < kContainerDirectoryMinimumPercent && | |
441 parent_it->second.seen_count * 100 / parent_it->second.entries_count | |
442 >= kContainerDirectoryMinimumPercent) { | |
443 parent_it->second.is_qualified = true; | |
444 } else { | |
445 break; | |
446 } | |
447 candidate = parent_directory; | |
448 parent_directory = candidate.DirName(); | |
449 } | |
450 } | |
451 MediaFolderFinder::MediaFolderFinderResults result; | |
452 // Copy and return worthy results. | |
453 for (ContainerCandidates::const_iterator it = candidates.begin(); | |
454 it != candidates.end(); ++it) { | |
455 if (it->second.is_qualified && it->second.seen_count >= 2) | |
vandebo (ex-Chrome)
2014/06/02 16:29:25
Are you sure this is sufficient? It seems that you
Kevin Bailey
2014/06/02 21:03:43
Neither X nor Y will be qualified, due to 80% rule
vandebo (ex-Chrome)
2014/06/03 16:27:21
Hmm, indeed. SG then.
| |
456 result[it->first] = MediaGalleryScanResult(); | |
457 } | |
458 return result; | |
459 } | |
460 | |
426 MediaScanManager::ScanObservers::ScanObservers() : observer(NULL) {} | 461 MediaScanManager::ScanObservers::ScanObservers() : observer(NULL) {} |
427 MediaScanManager::ScanObservers::~ScanObservers() {} | 462 MediaScanManager::ScanObservers::~ScanObservers() {} |
428 | 463 |
429 void MediaScanManager::OnExtensionUnloaded( | 464 void MediaScanManager::OnExtensionUnloaded( |
430 content::BrowserContext* browser_context, | 465 content::BrowserContext* browser_context, |
431 const extensions::Extension* extension, | 466 const extensions::Extension* extension, |
432 extensions::UnloadedExtensionInfo::Reason reason) { | 467 extensions::UnloadedExtensionInfo::Reason reason) { |
433 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 468 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
434 CancelScan(Profile::FromBrowserContext(browser_context), extension); | 469 CancelScan(Profile::FromBrowserContext(browser_context), extension); |
435 } | 470 } |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
508 gallery_count, | 543 gallery_count, |
509 file_counts); | 544 file_counts); |
510 } | 545 } |
511 } | 546 } |
512 scanning_extensions->clear(); | 547 scanning_extensions->clear(); |
513 preferences->SetLastScanCompletionTime(base::Time::Now()); | 548 preferences->SetLastScanCompletionTime(base::Time::Now()); |
514 } | 549 } |
515 scoped_extension_registry_observer_.RemoveAll(); | 550 scoped_extension_registry_observer_.RemoveAll(); |
516 folder_finder_.reset(); | 551 folder_finder_.reset(); |
517 } | 552 } |
OLD | NEW |