Chromium Code Reviews| 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( |