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..689a627b9288f64378edcb5c4fc74fd44e63a7ef 100644 |
--- a/chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc |
+++ b/chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc |
@@ -70,6 +70,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 update_time = base::Time::Now(); |
Shuhei Takahashi
2016/09/08 04:25:48
|last_update_time_| and |update_time| sounds a bit
dspaid
2016/09/09 02:10:45
Done.
|
+ TimestampMap current_timestamp_map = BuildTimestampMap(downloads_dir); |
+ return std::make_pair(update_time, std::move(current_timestamp_map)); |
+} |
+ |
} // namespace |
// The core part of ArcDownloadsWatcherService to watch for file changes in |
@@ -86,16 +116,21 @@ 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; |
+ void OnBuildTimestampMap( |
+ std::pair<base::Time, 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::Time last_update_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 +141,10 @@ class ArcDownloadsWatcherService::DownloadsWatcher { |
ArcDownloadsWatcherService::DownloadsWatcher::DownloadsWatcher( |
const Callback& callback) |
- : callback_(callback), weak_ptr_factory_(this) { |
+ : callback_(callback), |
+ last_update_time_(base::Time()), |
+ outstanding_task_(false), |
+ weak_ptr_factory_(this) { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
downloads_dir_ = DownloadPrefs(ProfileManager::GetActiveUserProfile()) |
@@ -123,7 +161,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_update_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 +179,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_) { |
+ base::PostTaskAndReplyWithResult( |
+ BrowserThread::GetBlockingPool(), FROM_HERE, |
+ base::Bind(&BuildTimestampMapCallback, downloads_dir_), |
+ base::Bind(&DownloadsWatcher::OnBuildTimestampMap, |
+ weak_ptr_factory_.GetWeakPtr())); |
+ outstanding_task_ = true; |
+ } else { |
+ last_update_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; |
std::vector<base::FilePath> changed_paths = |
CollectChangedPaths(last_timestamp_map_, current_timestamp_map); |
@@ -153,28 +208,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_update_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; |
} |
- return timestamp_map; |
} |
ArcDownloadsWatcherService::ArcDownloadsWatcherService( |