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

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

Issue 2310833002: Don't block FILE thread for media scanning (Closed)
Patch Set: 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..c043a895a5bc56256d899e75404d5e32cc772bbd 100644
--- a/chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc
+++ b/chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc
@@ -33,6 +33,9 @@ namespace {
const base::FilePath::CharType kAndroidDownloadDir[] =
FILE_PATH_LITERAL("/storage/emulated/0/Download");
+const base::TimeDelta kBuildTimestampMapDelay =
+ base::TimeDelta::FromMilliseconds(5);
Shuhei Takahashi 2016/09/09 06:32:40 Hmm, 5ms sounds too short when threads are busy. W
dspaid 2016/09/09 07:20:12 Experimental testing showed 5ms covered all inotif
+
// Compares two TimestampMaps and returns the list of file paths added/removed
// or whose timestamp have changed.
std::vector<base::FilePath> CollectChangedPaths(
@@ -70,6 +73,36 @@ 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)
+ .Append(
+ cros_path.value().substr(downloads_dir.value().length() + 1));
+ const base::FileEnumerator::FileInfo& info = enumerator.GetInfo();
+ timestamp_map[android_path] = info.GetLastModifiedTime();
+ }
+ return timestamp_map;
+}
+
+std::pair<base::Time, TimestampMap> BuildTimestampMapCallback(
+ base::FilePath downloads_dir) {
+ base::Time snapshot_time = base::Time::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 +119,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 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::Time, TimestampMap> timestamp_and_map);
+
+ // 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();
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::Time last_notify_time_;
Shuhei Takahashi 2016/09/09 06:32:41 Oh, BTW, base::Time is not guaranteed to be monoto
dspaid 2016/09/09 07:20:12 Done.
+ // 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 +150,10 @@ class ArcDownloadsWatcherService::DownloadsWatcher {
ArcDownloadsWatcherService::DownloadsWatcher::DownloadsWatcher(
const Callback& callback)
- : callback_(callback), weak_ptr_factory_(this) {
+ : callback_(callback),
+ last_notify_time_(base::Time()),
+ outstanding_task_(false),
+ weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
downloads_dir_ = DownloadPrefs(ProfileManager::GetActiveUserProfile())
@@ -123,7 +170,10 @@ 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::Time::Now();
+ last_timestamp_map_ = BuildTimestampMap(downloads_dir_);
+
+ outstanding_task_ = false;
watcher_ = base::MakeUnique<base::FilePathWatcher>();
// On Linux, base::FilePathWatcher::Watch() always returns true.
@@ -138,9 +188,23 @@ 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::Time::Now();
+ }
+}
- TimestampMap current_timestamp_map = BuildTimestampMap();
-
+void ArcDownloadsWatcherService::DownloadsWatcher::OnBuildTimestampMap(
+ std::pair<base::Time, TimestampMap> timestamp_and_map) {
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ DCHECK(outstanding_task_);
+ TimestampMap current_timestamp_map = timestamp_and_map.second;
Shuhei Takahashi 2016/09/09 06:32:41 Nit: Could you also destructure |snapshot_time|? T
dspaid 2016/09/09 07:20:13 Done.
std::vector<base::FilePath> changed_paths =
CollectChangedPaths(last_timestamp_map_, current_timestamp_map);
@@ -153,28 +217,25 @@ void ArcDownloadsWatcherService::DownloadsWatcher::OnFilePathChanged(
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(callback_, base::Passed(std::move(mojo_paths))));
+ if (last_notify_time_ > timestamp_and_map.first) {
+ base::PostTaskAndReplyWithResult(
+ BrowserThread::GetBlockingPool(), FROM_HERE,
+ base::Bind(&BuildTimestampMapCallback, downloads_dir_),
+ base::Bind(&DownloadsWatcher::OnBuildTimestampMap,
+ weak_ptr_factory_.GetWeakPtr()));
+ } else {
+ outstanding_task_ = false;
+ }
}
-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();
- }
- return timestamp_map;
+void ArcDownloadsWatcherService::DownloadsWatcher::DelayBuildTimestampMap() {
Shuhei Takahashi 2016/09/09 06:32:40 nit: Could you move this function to before OnBuil
dspaid 2016/09/09 07:20:12 Done.
+ 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()));
}
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