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

Unified Diff: chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc

Issue 2310833002: Don't block FILE thread for media scanning (Closed)
Patch Set: Addressed Comments Created 4 years, 3 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 | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc
diff --git a/chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc b/chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc
index cb43c4c445b344f5b02f3a5048cf2c070f51d20c..961125edc4704aeb4915126a8d3b790fa412a252 100644
--- a/chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc
+++ b/chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc
@@ -33,6 +33,11 @@ namespace {
const base::FilePath::CharType kAndroidDownloadDir[] =
FILE_PATH_LITERAL("/storage/emulated/0/Download");
+// How long to wait for new inotify events before building the updated timestamp
+// map.
+const base::TimeDelta kBuildTimestampMapDelay =
+ base::TimeDelta::FromMilliseconds(1000);
+
// Compares two TimestampMaps and returns the list of file paths added/removed
// or whose timestamp have changed.
std::vector<base::FilePath> CollectChangedPaths(
@@ -70,6 +75,39 @@ std::vector<base::FilePath> CollectChangedPaths(
return changed_paths;
}
+// Scans files under |downloads_dir| recursively and builds a map from file
+// paths (in Android filesystem) to last modified timestamps.
+TimestampMap BuildTimestampMap(base::FilePath downloads_dir) {
+ DCHECK(!downloads_dir.EndsWithSeparator());
+ TimestampMap timestamp_map;
+
+ // Enumerate normal files only; directories and symlinks are skipped.
+ base::FileEnumerator enumerator(downloads_dir, true,
+ base::FileEnumerator::FILES);
+ for (base::FilePath cros_path = enumerator.Next(); !cros_path.empty();
+ cros_path = enumerator.Next()) {
+ // Android file path can be obtained by replacing |downloads_dir| prefix
+ // with |kAndroidDownloadDir|.
+ const base::FilePath& android_path =
+ base::FilePath(kAndroidDownloadDir)
+ .AppendRelativePath(
+ cros_path.value().substr(downloads_dir.value().length() + 1));
hidehiko 2016/09/13 07:33:56 Something went wrong here, I think?
dspaid 2016/09/15 01:58:12 Not sure what you're thinking of, but the previous
hidehiko 2016/09/15 02:26:18 Sorry for poor explanation. I meant; FilePath and
+ const base::FileEnumerator::FileInfo& info = enumerator.GetInfo();
+ timestamp_map[android_path] = info.GetLastModifiedTime();
+ }
+ return timestamp_map;
+}
+
+std::pair<base::TimeTicks, TimestampMap> BuildTimestampMapCallback(
+ base::FilePath downloads_dir) {
+ // The TimestampMap may include chnages form after snapshot_time.
hidehiko 2016/09/13 07:33:56 nit: changes
dspaid 2016/09/15 01:58:12 Done.
+ // We must take the snapshot_time before we build the TimestampMap since
+ // changes that occur while building the map may not be captured.
+ base::TimeTicks snapshot_time = base::TimeTicks::Now();
+ TimestampMap current_timestamp_map = BuildTimestampMap(downloads_dir);
+ return std::make_pair(snapshot_time, std::move(current_timestamp_map));
+}
+
} // namespace
// The core part of ArcDownloadsWatcherService to watch for file changes in
@@ -86,16 +124,27 @@ class ArcDownloadsWatcherService::DownloadsWatcher {
private:
// Called by base::FilePathWatcher to notify file changes.
+ // Kicks off the update of last_timestamp_map_ if one is not already in
+ // progress.
void OnFilePathChanged(const base::FilePath& path, bool error);
- // Scans files under |downloads_dir_| recursively and builds a map from file
- // paths (in Android filesystem) to last modified timestamps.
- TimestampMap BuildTimestampMap() const;
+ // Called with a delay to allow additional inotify events for the same user
+ // action to queue up so that they can be dealt with in batch.
+ void DelayBuildTimestampMap();
+
+ // Called after a new timestamp map has been created and causes any recently
+ // modified files to be sent to the media scanner.
+ void OnBuildTimestampMap(
+ std::pair<base::TimeTicks, TimestampMap> timestamp_and_map);
Callback callback_;
base::FilePath downloads_dir_;
std::unique_ptr<base::FilePathWatcher> watcher_;
TimestampMap last_timestamp_map_;
+ // The timestamp of the last OnFilePathChanged callback received.
+ base::TimeTicks last_notify_time_;
+ // Whether or not there is an outstanding task to update last_timestamp_map_.
+ bool outstanding_task_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate the weak pointers before any other members are destroyed.
@@ -106,7 +155,10 @@ class ArcDownloadsWatcherService::DownloadsWatcher {
ArcDownloadsWatcherService::DownloadsWatcher::DownloadsWatcher(
const Callback& callback)
- : callback_(callback), weak_ptr_factory_(this) {
+ : callback_(callback),
+ last_notify_time_(base::TimeTicks()),
+ outstanding_task_(false),
+ weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
downloads_dir_ = DownloadPrefs(ProfileManager::GetActiveUserProfile())
@@ -123,7 +175,8 @@ void ArcDownloadsWatcherService::DownloadsWatcher::Start() {
// Initialize with the current timestamp map and avoid initial notification.
// It is not needed since MediaProvider scans whole storage area on boot.
- last_timestamp_map_ = BuildTimestampMap();
+ last_notify_time_ = base::TimeTicks::Now();
+ last_timestamp_map_ = BuildTimestampMap(downloads_dir_);
watcher_ = base::MakeUnique<base::FilePathWatcher>();
// On Linux, base::FilePathWatcher::Watch() always returns true.
@@ -138,9 +191,34 @@ void ArcDownloadsWatcherService::DownloadsWatcher::OnFilePathChanged(
// On Linux, |error| is always false. Also, |path| is always the same path
// as one given to FilePathWatcher::Watch().
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ if (!outstanding_task_) {
+ outstanding_task_ = true;
+ BrowserThread::PostDelayedTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&DownloadsWatcher::DelayBuildTimestampMap,
+ weak_ptr_factory_.GetWeakPtr()),
+ kBuildTimestampMapDelay);
+ } else {
+ last_notify_time_ = base::TimeTicks::Now();
+ }
+}
- TimestampMap current_timestamp_map = BuildTimestampMap();
+void ArcDownloadsWatcherService::DownloadsWatcher::DelayBuildTimestampMap() {
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ DCHECK(outstanding_task_);
+ base::PostTaskAndReplyWithResult(
+ BrowserThread::GetBlockingPool(), FROM_HERE,
+ base::Bind(&BuildTimestampMapCallback, downloads_dir_),
+ base::Bind(&DownloadsWatcher::OnBuildTimestampMap,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+void ArcDownloadsWatcherService::DownloadsWatcher::OnBuildTimestampMap(
+ std::pair<base::TimeTicks, TimestampMap> timestamp_and_map) {
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ DCHECK(outstanding_task_);
+ base::TimeTicks snapshot_time = timestamp_and_map.first;
+ TimestampMap current_timestamp_map = std::move(timestamp_and_map.second);
std::vector<base::FilePath> changed_paths =
CollectChangedPaths(last_timestamp_map_, current_timestamp_map);
@@ -153,28 +231,15 @@ void ArcDownloadsWatcherService::DownloadsWatcher::OnFilePathChanged(
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(callback_, base::Passed(std::move(mojo_paths))));
-}
-
-TimestampMap ArcDownloadsWatcherService::DownloadsWatcher::BuildTimestampMap()
- const {
- DCHECK(!downloads_dir_.EndsWithSeparator());
- TimestampMap timestamp_map;
-
- // Enumerate normal files only; directories and symlinks are skipped.
- base::FileEnumerator enumerator(downloads_dir_, true,
- base::FileEnumerator::FILES);
- for (base::FilePath cros_path = enumerator.Next(); !cros_path.empty();
- cros_path = enumerator.Next()) {
- // Android file path can be obtained by replacing |downloads_dir_| prefix
- // with |kAndroidDownloadDir|.
- const base::FilePath& android_path =
- base::FilePath(kAndroidDownloadDir)
- .Append(
- cros_path.value().substr(downloads_dir_.value().length() + 1));
- const base::FileEnumerator::FileInfo& info = enumerator.GetInfo();
- timestamp_map[android_path] = info.GetLastModifiedTime();
+ if (last_notify_time_ > snapshot_time) {
+ base::PostTaskAndReplyWithResult(
+ BrowserThread::GetBlockingPool(), FROM_HERE,
+ base::Bind(&BuildTimestampMapCallback, downloads_dir_),
+ base::Bind(&DownloadsWatcher::OnBuildTimestampMap,
+ weak_ptr_factory_.GetWeakPtr()));
+ } else {
+ outstanding_task_ = false;
}
- return timestamp_map;
}
ArcDownloadsWatcherService::ArcDownloadsWatcherService(
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698