Chromium Code Reviews| 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 | |
| 214 // containing any media itself. In fact, the primary purpose of that directory | |
| 215 // may be to contain media directories. This function tries to find those | |
| 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 | |
| 234 // Skip sensitive folders and their ancestors. | |
| 235 bool is_sensitive = false; | |
| 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 | |
| 282 int CountScanResultsForExtension(MediaGalleriesPreferences* preferences, | 213 int CountScanResultsForExtension(MediaGalleriesPreferences* preferences, |
| 283 const extensions::Extension* extension, | 214 const extensions::Extension* extension, |
| 284 MediaGalleryScanResult* file_counts) { | 215 MediaGalleryScanResult* file_counts) { |
| 285 int gallery_count = 0; | 216 int gallery_count = 0; |
| 286 | 217 |
| 287 MediaGalleryPrefIdSet permitted_galleries = | 218 MediaGalleryPrefIdSet permitted_galleries = |
| 288 preferences->GalleriesForExtension(*extension); | 219 preferences->GalleriesForExtension(*extension); |
| 289 const MediaGalleriesPrefInfoMap& known_galleries = | 220 const MediaGalleriesPrefInfoMap& known_galleries = |
| 290 preferences->known_galleries(); | 221 preferences->known_galleries(); |
| 291 for (MediaGalleriesPrefInfoMap::const_iterator it = known_galleries.begin(); | 222 for (MediaGalleriesPrefInfoMap::const_iterator it = known_galleries.begin(); |
| 292 it != known_galleries.end(); | 223 it != known_galleries.end(); |
| 293 ++it) { | 224 ++it) { |
| 294 if (it->second.type == MediaGalleryPrefInfo::kScanResult && | 225 if (it->second.type == MediaGalleryPrefInfo::kScanResult && |
| 295 !ContainsKey(permitted_galleries, it->first)) { | 226 !ContainsKey(permitted_galleries, it->first)) { |
| 296 gallery_count++; | 227 gallery_count++; |
| 297 file_counts->audio_count += it->second.audio_count; | 228 file_counts->audio_count += it->second.audio_count; |
| 298 file_counts->image_count += it->second.image_count; | 229 file_counts->image_count += it->second.image_count; |
| 299 file_counts->video_count += it->second.video_count; | 230 file_counts->video_count += it->second.video_count; |
| 300 } | 231 } |
| 301 } | 232 } |
| 302 return gallery_count; | 233 return gallery_count; |
| 303 } | 234 } |
| 304 | 235 |
| 236 int CountDirectoryEntries(const base::FilePath& path) { | |
| 237 base::FileEnumerator dir_counter(path, false /*recursive*/, | |
| 238 base::FileEnumerator::DIRECTORIES); | |
| 239 int count = 0; | |
| 240 base::FileEnumerator::FileInfo info; | |
| 241 for (base::FilePath name = dir_counter.Next(); | |
| 242 !name.empty(); | |
| 243 name = dir_counter.Next()) { | |
| 244 if (!base::IsLink(name)) | |
| 245 ++count; | |
| 246 } | |
| 247 return count; | |
| 248 } | |
| 249 | |
| 250 struct ContainerCount { | |
| 251 int seen_count, entries_count; | |
| 252 bool is_qualified; | |
| 253 | |
| 254 ContainerCount() : seen_count(0), entries_count(-1), is_qualified(false) {} | |
| 255 }; | |
| 256 | |
| 257 typedef std::map<base::FilePath, ContainerCount> ContainerCandidates; | |
| 258 | |
| 305 } // namespace | 259 } // namespace |
| 306 | 260 |
| 307 MediaScanManager::MediaScanManager() | 261 MediaScanManager::MediaScanManager() |
| 308 : scoped_extension_registry_observer_(this), | 262 : scoped_extension_registry_observer_(this), |
| 309 weak_factory_(this) { | 263 weak_factory_(this) { |
| 310 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 264 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 311 } | 265 } |
| 312 | 266 |
| 313 MediaScanManager::~MediaScanManager() { | 267 MediaScanManager::~MediaScanManager() { |
| 314 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 268 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_); | 370 base::Time::Now() - scan_start_time_); |
| 417 scan_start_time_ = base::Time(); | 371 scan_start_time_ = base::Time(); |
| 418 } | 372 } |
| 419 } | 373 } |
| 420 | 374 |
| 421 void MediaScanManager::SetMediaFolderFinderFactory( | 375 void MediaScanManager::SetMediaFolderFinderFactory( |
| 422 const MediaFolderFinderFactory& factory) { | 376 const MediaFolderFinderFactory& factory) { |
| 423 testing_folder_finder_factory_ = factory; | 377 testing_folder_finder_factory_ = factory; |
| 424 } | 378 } |
| 425 | 379 |
| 380 // A single directory may contain many folders with media in them, without | |
| 381 // containing any media itself. In fact, the primary purpose of that directory | |
| 382 // may be to contain media directories. This function tries to find those | |
| 383 // container directories. | |
| 384 MediaFolderFinder::MediaFolderFinderResults | |
| 385 MediaScanManager::FindContainerScanResults( | |
| 386 const MediaFolderFinder::MediaFolderFinderResults& found_folders, | |
| 387 const std::vector<base::FilePath>& sensitive_locations) { | |
| 388 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); | |
| 389 std::vector<base::FilePath> abs_sensitive_locations; | |
| 390 for (size_t i = 0; i < sensitive_locations.size(); ++i) { | |
| 391 base::FilePath path = base::MakeAbsoluteFilePath(sensitive_locations[i]); | |
| 392 if (!path.empty()) | |
| 393 abs_sensitive_locations.push_back(path); | |
| 394 } | |
| 395 // Recursively find parent directories with majority of media directories, | |
| 396 // or container directories. | |
| 397 // |candidates| keeps track of directories which might have enough | |
| 398 // such directories to have us return them. | |
| 399 typedef std::map<base::FilePath, ContainerCount> ContainerCandidates; | |
| 400 ContainerCandidates candidates; | |
| 401 for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it = | |
| 402 found_folders.begin(); it != found_folders.end(); ++it) { | |
| 403 base::FilePath child_directory = it->first; | |
| 404 base::FilePath parent_directory = child_directory.DirName(); | |
| 405 | |
| 406 // Parent of root is root. | |
| 407 while (!parent_directory.empty() && child_directory != parent_directory) { | |
| 408 // Skip sensitive folders and their ancestors. | |
| 409 base::FilePath abs_parent_directory = | |
| 410 base::MakeAbsoluteFilePath(parent_directory); | |
| 411 if (abs_parent_directory.empty()) | |
| 412 break; | |
| 413 bool is_sensitive = false; | |
| 414 for (size_t i = 0; i < abs_sensitive_locations.size(); ++i) { | |
| 415 if (abs_parent_directory == abs_sensitive_locations[i] || | |
| 416 abs_parent_directory.IsParent(abs_sensitive_locations[i])) { | |
| 417 is_sensitive = true; | |
| 418 break; | |
| 419 } | |
| 420 } | |
| 421 if (is_sensitive) | |
| 422 break; | |
| 423 | |
| 424 // Don't bother with ones we already have. | |
| 425 if (found_folders.find(parent_directory) != found_folders.end()) | |
| 426 continue; | |
| 427 | |
| 428 ContainerCandidates::iterator parent_it = | |
| 429 candidates.find(parent_directory); | |
| 430 if (parent_it == candidates.end()) { | |
| 431 ContainerCount count; | |
| 432 count.seen_count = 1; | |
| 433 count.entries_count = CountDirectoryEntries(parent_directory); | |
| 434 parent_it = candidates.insert(std::make_pair(parent_directory, | |
| 435 count)).first; | |
| 436 } else { | |
| 437 ++candidates[parent_directory].seen_count; | |
| 438 } | |
| 439 // If already sufficient, bail. | |
| 440 if (parent_it->second.is_qualified) | |
| 441 break; | |
| 442 // If now sufficient, mark qualified and check parent. | |
| 443 if (parent_it->second.seen_count * 100 / parent_it->second.entries_count | |
| 444 >= kContainerDirectoryMinimumPercent) { | |
| 445 parent_it->second.is_qualified = true; | |
| 446 } else { | |
| 447 break; | |
|
vandebo (ex-Chrome)
2014/06/03 18:08:31
nit: This else break construct is kind of hard to
Kevin Bailey
2014/06/03 18:31:25
Couldn't make it *exactly* the same due to line le
vandebo (ex-Chrome)
2014/06/03 18:42:31
Assumed... as is, it violated style guide. I'd sug
| |
| 448 } | |
| 449 child_directory = parent_directory; | |
| 450 parent_directory = child_directory.DirName(); | |
| 451 } | |
| 452 } | |
| 453 MediaFolderFinder::MediaFolderFinderResults result; | |
| 454 // Copy and return worthy results. | |
| 455 for (ContainerCandidates::const_iterator it = candidates.begin(); | |
| 456 it != candidates.end(); ++it) { | |
| 457 if (it->second.is_qualified && it->second.seen_count >= 2) | |
| 458 result[it->first] = MediaGalleryScanResult(); | |
| 459 } | |
| 460 return result; | |
| 461 } | |
| 462 | |
| 426 MediaScanManager::ScanObservers::ScanObservers() : observer(NULL) {} | 463 MediaScanManager::ScanObservers::ScanObservers() : observer(NULL) {} |
| 427 MediaScanManager::ScanObservers::~ScanObservers() {} | 464 MediaScanManager::ScanObservers::~ScanObservers() {} |
| 428 | 465 |
| 429 void MediaScanManager::OnExtensionUnloaded( | 466 void MediaScanManager::OnExtensionUnloaded( |
| 430 content::BrowserContext* browser_context, | 467 content::BrowserContext* browser_context, |
| 431 const extensions::Extension* extension, | 468 const extensions::Extension* extension, |
| 432 extensions::UnloadedExtensionInfo::Reason reason) { | 469 extensions::UnloadedExtensionInfo::Reason reason) { |
| 433 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 470 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 434 CancelScan(Profile::FromBrowserContext(browser_context), extension); | 471 CancelScan(Profile::FromBrowserContext(browser_context), extension); |
| 435 } | 472 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 508 gallery_count, | 545 gallery_count, |
| 509 file_counts); | 546 file_counts); |
| 510 } | 547 } |
| 511 } | 548 } |
| 512 scanning_extensions->clear(); | 549 scanning_extensions->clear(); |
| 513 preferences->SetLastScanCompletionTime(base::Time::Now()); | 550 preferences->SetLastScanCompletionTime(base::Time::Now()); |
| 514 } | 551 } |
| 515 scoped_extension_registry_observer_.RemoveAll(); | 552 scoped_extension_registry_observer_.RemoveAll(); |
| 516 folder_finder_.reset(); | 553 folder_finder_.reset(); |
| 517 } | 554 } |
| OLD | NEW |