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..06f715d5c36a5086b6618189a976c5b1d6718f45 100644 |
--- a/chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc |
+++ b/chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc |
@@ -70,6 +70,37 @@ 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(); |
+ TimestampMap current_timestamp_map = BuildTimestampMap(downloads_dir); |
+ return std::pair<base::Time, TimestampMap>(update_time, |
Shuhei Takahashi
2016/09/08 03:43:48
FYI, std::make_pair is useful to avoid explicit te
dspaid
2016/09/08 03:59:56
Done.
|
+ current_timestamp_map); |
Shuhei Takahashi
2016/09/08 03:43:48
IIUC you need std::move() here to avoid copy.
dspaid
2016/09/08 03:59:56
Done.
|
+} |
+ |
} // namespace |
// The core part of ArcDownloadsWatcherService to watch for file changes in |
@@ -86,16 +117,25 @@ class ArcDownloadsWatcherService::DownloadsWatcher { |
private: |
// Called by base::FilePathWatcher to notify file changes. |
+ // Wrapper around HandleFilePathChanged to pass the notification timestamp. |
Shuhei Takahashi
2016/09/08 03:43:48
This line is outdated.
dspaid
2016/09/08 03:59:56
Done.
|
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; |
+ // If there has not been a full scan of updated files since notify_time, |
+ // update the last_timestamp_map_ and send any new/changed files to the |
+ // android media scanner. |
+ void HandleFilePathChanged(base::Time notify_time); |
Shuhei Takahashi
2016/09/08 03:43:48
This function is no longer defined.
dspaid
2016/09/08 03:59:56
Done.
|
+ |
+ 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_; |
Shuhei Takahashi
2016/09/08 03:43:48
How about using "bool pending_task_" instead? Thou
dspaid
2016/09/08 03:59:56
The small timing difference actually has a reasona
Shuhei Takahashi
2016/09/08 04:25:48
I see. But then I think it's a bit optimistic to a
dspaid
2016/09/09 02:10:45
Experimentally I'm seeing a reasonable success rat
Shuhei Takahashi
2016/09/09 03:18:51
It is best if we have PostDelayedTaskAndReplyWithR
|
+ // 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 +146,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 +166,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 +184,21 @@ 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) { |
+ TimestampMap current_timestamp_map = timestamp_and_map.second; |
Shuhei Takahashi
2016/09/08 03:43:48
Could you insert DCHECK_CURRENTLY_ON?
Shuhei Takahashi
2016/09/08 03:43:48
Also, could you insert DCHECK(outstanding_task_)?
dspaid
2016/09/08 03:59:56
Done.
dspaid
2016/09/08 03:59:57
Done.
|
std::vector<base::FilePath> changed_paths = |
CollectChangedPaths(last_timestamp_map_, current_timestamp_map); |
@@ -153,28 +211,14 @@ 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())); |
} |
- return timestamp_map; |
+ outstanding_task_ = false; |
Shuhei Takahashi
2016/09/08 03:43:48
We must keep |outstanding_task_| true when there w
dspaid
2016/09/08 03:59:56
Done.
|
} |
ArcDownloadsWatcherService::ArcDownloadsWatcherService( |