Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/arc/arc_downloads_watcher_service.h" | 5 #include "chrome/browser/chromeos/arc/arc_downloads_watcher_service.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 | 23 |
| 24 using content::BrowserThread; | 24 using content::BrowserThread; |
| 25 | 25 |
| 26 // Mapping from Android file paths to last modified timestamps. | 26 // Mapping from Android file paths to last modified timestamps. |
| 27 using TimestampMap = std::map<base::FilePath, base::Time>; | 27 using TimestampMap = std::map<base::FilePath, base::Time>; |
| 28 | 28 |
| 29 namespace arc { | 29 namespace arc { |
| 30 | 30 |
| 31 namespace { | 31 namespace { |
| 32 | 32 |
| 33 // ID used to ensure sequential execution of HandleFilePathChanged. | |
| 34 // This is sequential to prevent two instances from updating last_update_time_. | |
| 35 const char kSequenceId[] = "arc_downloads_watcher"; | |
| 36 | |
| 33 const base::FilePath::CharType kAndroidDownloadDir[] = | 37 const base::FilePath::CharType kAndroidDownloadDir[] = |
| 34 FILE_PATH_LITERAL("/storage/emulated/0/Download"); | 38 FILE_PATH_LITERAL("/storage/emulated/0/Download"); |
| 35 | 39 |
| 36 // Compares two TimestampMaps and returns the list of file paths added/removed | 40 // Compares two TimestampMaps and returns the list of file paths added/removed |
| 37 // or whose timestamp have changed. | 41 // or whose timestamp have changed. |
| 38 std::vector<base::FilePath> CollectChangedPaths( | 42 std::vector<base::FilePath> CollectChangedPaths( |
| 39 const TimestampMap& timestamp_map_a, | 43 const TimestampMap& timestamp_map_a, |
| 40 const TimestampMap& timestamp_map_b) { | 44 const TimestampMap& timestamp_map_b) { |
| 41 std::vector<base::FilePath> changed_paths; | 45 std::vector<base::FilePath> changed_paths; |
| 42 | 46 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 80 base::Callback<void(const std::vector<base::FilePath>& paths)>; | 84 base::Callback<void(const std::vector<base::FilePath>& paths)>; |
| 81 | 85 |
| 82 explicit DownloadsWatcher(const Callback& callback); | 86 explicit DownloadsWatcher(const Callback& callback); |
| 83 ~DownloadsWatcher(); | 87 ~DownloadsWatcher(); |
| 84 | 88 |
| 85 // Starts watching Downloads directory. | 89 // Starts watching Downloads directory. |
| 86 void Start(); | 90 void Start(); |
| 87 | 91 |
| 88 private: | 92 private: |
| 89 // Called by base::FilePathWatcher to notify file changes. | 93 // Called by base::FilePathWatcher to notify file changes. |
| 94 // Wrapper around HandleFilePathChanged to pass the notification timestamp | |
| 95 // and move the work off the FILE thread. | |
| 90 void OnFilePathChanged(const base::FilePath& path, bool error); | 96 void OnFilePathChanged(const base::FilePath& path, bool error); |
| 91 | 97 |
| 98 // If there has not been a full scan of updated files since notify_time, | |
| 99 // update the last_timestamp_map_ and send any new/changed files to the | |
| 100 // android media scanner. | |
| 101 void HandleFilePathChanged(base::Time notify_time); | |
| 102 | |
| 92 // Scans files under |downloads_dir_| recursively and builds a map from file | 103 // Scans files under |downloads_dir_| recursively and builds a map from file |
| 93 // paths (in Android filesystem) to last modified timestamps. | 104 // paths (in Android filesystem) to last modified timestamps. |
| 94 TimestampMap BuildTimestampMap() const; | 105 TimestampMap BuildTimestampMap() const; |
| 95 | 106 |
| 96 Callback callback_; | 107 Callback callback_; |
| 97 base::FilePath downloads_dir_; | 108 base::FilePath downloads_dir_; |
| 98 std::unique_ptr<base::FilePathWatcher> watcher_; | 109 std::unique_ptr<base::FilePathWatcher> watcher_; |
| 99 TimestampMap last_timestamp_map_; | 110 TimestampMap last_timestamp_map_; |
| 111 base::Time last_update_time_; | |
| 100 | 112 |
| 101 // Note: This should remain the last member so it'll be destroyed and | 113 // Note: This should remain the last member so it'll be destroyed and |
| 102 // invalidate the weak pointers before any other members are destroyed. | 114 // invalidate the weak pointers before any other members are destroyed. |
| 103 base::WeakPtrFactory<DownloadsWatcher> weak_ptr_factory_; | 115 base::WeakPtrFactory<DownloadsWatcher> weak_ptr_factory_; |
| 104 | 116 |
| 105 DISALLOW_COPY_AND_ASSIGN(DownloadsWatcher); | 117 DISALLOW_COPY_AND_ASSIGN(DownloadsWatcher); |
| 106 }; | 118 }; |
| 107 | 119 |
| 108 ArcDownloadsWatcherService::DownloadsWatcher::DownloadsWatcher( | 120 ArcDownloadsWatcherService::DownloadsWatcher::DownloadsWatcher( |
| 109 const Callback& callback) | 121 const Callback& callback) |
| 110 : callback_(callback), weak_ptr_factory_(this) { | 122 : callback_(callback), |
| 123 last_update_time_(base::Time()), | |
| 124 weak_ptr_factory_(this) { | |
| 111 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 125 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 112 | 126 |
| 113 downloads_dir_ = DownloadPrefs(ProfileManager::GetActiveUserProfile()) | 127 downloads_dir_ = DownloadPrefs(ProfileManager::GetActiveUserProfile()) |
| 114 .GetDefaultDownloadDirectoryForProfile() | 128 .GetDefaultDownloadDirectoryForProfile() |
| 115 .StripTrailingSeparators(); | 129 .StripTrailingSeparators(); |
| 116 } | 130 } |
| 117 | 131 |
| 118 ArcDownloadsWatcherService::DownloadsWatcher::~DownloadsWatcher() { | 132 ArcDownloadsWatcherService::DownloadsWatcher::~DownloadsWatcher() { |
| 119 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 133 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 120 } | 134 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 132 base::Bind(&DownloadsWatcher::OnFilePathChanged, | 146 base::Bind(&DownloadsWatcher::OnFilePathChanged, |
| 133 weak_ptr_factory_.GetWeakPtr())); | 147 weak_ptr_factory_.GetWeakPtr())); |
| 134 } | 148 } |
| 135 | 149 |
| 136 void ArcDownloadsWatcherService::DownloadsWatcher::OnFilePathChanged( | 150 void ArcDownloadsWatcherService::DownloadsWatcher::OnFilePathChanged( |
| 137 const base::FilePath& path, | 151 const base::FilePath& path, |
| 138 bool error) { | 152 bool error) { |
| 139 // On Linux, |error| is always false. Also, |path| is always the same path | 153 // On Linux, |error| is always false. Also, |path| is always the same path |
| 140 // as one given to FilePathWatcher::Watch(). | 154 // as one given to FilePathWatcher::Watch(). |
| 141 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 155 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 156 BrowserThread::PostBlockingPoolSequencedTask( | |
| 157 kSequenceId, FROM_HERE, | |
| 158 base::Bind(&DownloadsWatcher::HandleFilePathChanged, | |
| 159 weak_ptr_factory_.GetWeakPtr(), base::Time::Now())); | |
|
Shuhei Takahashi
2016/09/05 09:28:23
Weak pointers can be dereferenced only on FILE thr
dspaid
2016/09/07 01:16:56
Thanks for the reminder. I couldn't really find a
| |
| 160 } | |
| 161 | |
| 162 void ArcDownloadsWatcherService::DownloadsWatcher::HandleFilePathChanged( | |
| 163 base::Time notify_time) { | |
| 164 if (notify_time < last_update_time_) { | |
|
Shuhei Takahashi
2016/09/05 09:28:23
Please add a comment about the purpose of this che
dspaid
2016/09/07 01:16:56
Done.
| |
| 165 return; | |
| 166 } | |
| 167 last_update_time_ = base::Time::Now(); | |
| 142 | 168 |
| 143 TimestampMap current_timestamp_map = BuildTimestampMap(); | 169 TimestampMap current_timestamp_map = BuildTimestampMap(); |
| 144 | 170 |
| 145 std::vector<base::FilePath> changed_paths = | 171 std::vector<base::FilePath> changed_paths = |
| 146 CollectChangedPaths(last_timestamp_map_, current_timestamp_map); | 172 CollectChangedPaths(last_timestamp_map_, current_timestamp_map); |
| 147 | 173 |
| 148 last_timestamp_map_ = std::move(current_timestamp_map); | 174 last_timestamp_map_ = std::move(current_timestamp_map); |
| 149 | 175 |
| 150 callback_.Run(changed_paths); | 176 callback_.Run(changed_paths); |
|
Shuhei Takahashi
2016/09/05 09:28:23
|callback_| should be run on FILE thread.
dspaid
2016/09/07 01:16:56
Looks like this was fixed in a recent CL by hashim
| |
| 151 } | 177 } |
| 152 | 178 |
| 153 TimestampMap ArcDownloadsWatcherService::DownloadsWatcher::BuildTimestampMap() | 179 TimestampMap ArcDownloadsWatcherService::DownloadsWatcher::BuildTimestampMap() |
| 154 const { | 180 const { |
| 155 DCHECK(!downloads_dir_.EndsWithSeparator()); | 181 DCHECK(!downloads_dir_.EndsWithSeparator()); |
| 156 TimestampMap timestamp_map; | 182 TimestampMap timestamp_map; |
| 157 | 183 |
| 158 // Enumerate normal files only; directories and symlinks are skipped. | 184 // Enumerate normal files only; directories and symlinks are skipped. |
| 159 base::FileEnumerator enumerator(downloads_dir_, true, | 185 base::FileEnumerator enumerator(downloads_dir_, true, |
| 160 base::FileEnumerator::FILES); | 186 base::FileEnumerator::FILES); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 225 return; | 251 return; |
| 226 | 252 |
| 227 mojo::Array<mojo::String> mojo_paths(paths.size()); | 253 mojo::Array<mojo::String> mojo_paths(paths.size()); |
| 228 for (size_t i = 0; i < paths.size(); ++i) { | 254 for (size_t i = 0; i < paths.size(); ++i) { |
| 229 mojo_paths[i] = paths[i].value(); | 255 mojo_paths[i] = paths[i].value(); |
| 230 } | 256 } |
| 231 instance->RequestMediaScan(std::move(mojo_paths)); | 257 instance->RequestMediaScan(std::move(mojo_paths)); |
| 232 } | 258 } |
| 233 | 259 |
| 234 } // namespace arc | 260 } // namespace arc |
| OLD | NEW |