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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
63 ++iter_a; | 63 ++iter_a; |
64 } | 64 } |
65 while (iter_b != timestamp_map_b.end()) { | 65 while (iter_b != timestamp_map_b.end()) { |
66 changed_paths.emplace_back(iter_b->first); | 66 changed_paths.emplace_back(iter_b->first); |
67 ++iter_b; | 67 ++iter_b; |
68 } | 68 } |
69 | 69 |
70 return changed_paths; | 70 return changed_paths; |
71 } | 71 } |
72 | 72 |
73 // Scans files under |downloads_dir| recursively and builds a map from file | |
74 // paths (in Android filesystem) to last modified timestamps. | |
75 TimestampMap BuildTimestampMap(base::FilePath downloads_dir) { | |
76 DCHECK(!downloads_dir.EndsWithSeparator()); | |
77 TimestampMap timestamp_map; | |
78 | |
79 // Enumerate normal files only; directories and symlinks are skipped. | |
80 base::FileEnumerator enumerator(downloads_dir, true, | |
81 base::FileEnumerator::FILES); | |
82 for (base::FilePath cros_path = enumerator.Next(); !cros_path.empty(); | |
83 cros_path = enumerator.Next()) { | |
84 // Android file path can be obtained by replacing |downloads_dir| prefix | |
85 // with |kAndroidDownloadDir|. | |
86 const base::FilePath& android_path = | |
87 base::FilePath(kAndroidDownloadDir) | |
88 .Append( | |
89 cros_path.value().substr(downloads_dir.value().length() + 1)); | |
90 const base::FileEnumerator::FileInfo& info = enumerator.GetInfo(); | |
91 timestamp_map[android_path] = info.GetLastModifiedTime(); | |
92 } | |
93 return timestamp_map; | |
94 } | |
95 | |
96 std::pair<base::Time, TimestampMap> BuildTimestampMapCallback( | |
97 base::FilePath downloads_dir) { | |
98 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.
| |
99 TimestampMap current_timestamp_map = BuildTimestampMap(downloads_dir); | |
100 return std::make_pair(update_time, std::move(current_timestamp_map)); | |
101 } | |
102 | |
73 } // namespace | 103 } // namespace |
74 | 104 |
75 // The core part of ArcDownloadsWatcherService to watch for file changes in | 105 // The core part of ArcDownloadsWatcherService to watch for file changes in |
76 // Downloads directory. | 106 // Downloads directory. |
77 class ArcDownloadsWatcherService::DownloadsWatcher { | 107 class ArcDownloadsWatcherService::DownloadsWatcher { |
78 public: | 108 public: |
79 using Callback = base::Callback<void(mojo::Array<mojo::String> paths)>; | 109 using Callback = base::Callback<void(mojo::Array<mojo::String> paths)>; |
80 | 110 |
81 explicit DownloadsWatcher(const Callback& callback); | 111 explicit DownloadsWatcher(const Callback& callback); |
82 ~DownloadsWatcher(); | 112 ~DownloadsWatcher(); |
83 | 113 |
84 // Starts watching Downloads directory. | 114 // Starts watching Downloads directory. |
85 void Start(); | 115 void Start(); |
86 | 116 |
87 private: | 117 private: |
88 // Called by base::FilePathWatcher to notify file changes. | 118 // Called by base::FilePathWatcher to notify file changes. |
119 // Kicks off the update of last_timestamp_map_ if one is not already in | |
120 // progress. | |
89 void OnFilePathChanged(const base::FilePath& path, bool error); | 121 void OnFilePathChanged(const base::FilePath& path, bool error); |
90 | 122 |
91 // Scans files under |downloads_dir_| recursively and builds a map from file | 123 void OnBuildTimestampMap( |
92 // paths (in Android filesystem) to last modified timestamps. | 124 std::pair<base::Time, TimestampMap> timestamp_and_map); |
93 TimestampMap BuildTimestampMap() const; | |
94 | 125 |
95 Callback callback_; | 126 Callback callback_; |
96 base::FilePath downloads_dir_; | 127 base::FilePath downloads_dir_; |
97 std::unique_ptr<base::FilePathWatcher> watcher_; | 128 std::unique_ptr<base::FilePathWatcher> watcher_; |
98 TimestampMap last_timestamp_map_; | 129 TimestampMap last_timestamp_map_; |
130 // The timestamp of the last OnFilePathChanged callback received. | |
131 base::Time last_update_time_; | |
132 // Whether or not there is an outstanding task to update last_timestamp_map_. | |
133 bool outstanding_task_; | |
99 | 134 |
100 // Note: This should remain the last member so it'll be destroyed and | 135 // Note: This should remain the last member so it'll be destroyed and |
101 // invalidate the weak pointers before any other members are destroyed. | 136 // invalidate the weak pointers before any other members are destroyed. |
102 base::WeakPtrFactory<DownloadsWatcher> weak_ptr_factory_; | 137 base::WeakPtrFactory<DownloadsWatcher> weak_ptr_factory_; |
103 | 138 |
104 DISALLOW_COPY_AND_ASSIGN(DownloadsWatcher); | 139 DISALLOW_COPY_AND_ASSIGN(DownloadsWatcher); |
105 }; | 140 }; |
106 | 141 |
107 ArcDownloadsWatcherService::DownloadsWatcher::DownloadsWatcher( | 142 ArcDownloadsWatcherService::DownloadsWatcher::DownloadsWatcher( |
108 const Callback& callback) | 143 const Callback& callback) |
109 : callback_(callback), weak_ptr_factory_(this) { | 144 : callback_(callback), |
145 last_update_time_(base::Time()), | |
146 outstanding_task_(false), | |
147 weak_ptr_factory_(this) { | |
110 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 148 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
111 | 149 |
112 downloads_dir_ = DownloadPrefs(ProfileManager::GetActiveUserProfile()) | 150 downloads_dir_ = DownloadPrefs(ProfileManager::GetActiveUserProfile()) |
113 .GetDefaultDownloadDirectoryForProfile() | 151 .GetDefaultDownloadDirectoryForProfile() |
114 .StripTrailingSeparators(); | 152 .StripTrailingSeparators(); |
115 } | 153 } |
116 | 154 |
117 ArcDownloadsWatcherService::DownloadsWatcher::~DownloadsWatcher() { | 155 ArcDownloadsWatcherService::DownloadsWatcher::~DownloadsWatcher() { |
118 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 156 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
119 } | 157 } |
120 | 158 |
121 void ArcDownloadsWatcherService::DownloadsWatcher::Start() { | 159 void ArcDownloadsWatcherService::DownloadsWatcher::Start() { |
122 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 160 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
123 | 161 |
124 // Initialize with the current timestamp map and avoid initial notification. | 162 // Initialize with the current timestamp map and avoid initial notification. |
125 // It is not needed since MediaProvider scans whole storage area on boot. | 163 // It is not needed since MediaProvider scans whole storage area on boot. |
126 last_timestamp_map_ = BuildTimestampMap(); | 164 last_update_time_ = base::Time::Now(); |
165 last_timestamp_map_ = BuildTimestampMap(downloads_dir_); | |
166 | |
167 outstanding_task_ = false; | |
127 | 168 |
128 watcher_ = base::MakeUnique<base::FilePathWatcher>(); | 169 watcher_ = base::MakeUnique<base::FilePathWatcher>(); |
129 // On Linux, base::FilePathWatcher::Watch() always returns true. | 170 // On Linux, base::FilePathWatcher::Watch() always returns true. |
130 watcher_->Watch(downloads_dir_, true, | 171 watcher_->Watch(downloads_dir_, true, |
131 base::Bind(&DownloadsWatcher::OnFilePathChanged, | 172 base::Bind(&DownloadsWatcher::OnFilePathChanged, |
132 weak_ptr_factory_.GetWeakPtr())); | 173 weak_ptr_factory_.GetWeakPtr())); |
133 } | 174 } |
134 | 175 |
135 void ArcDownloadsWatcherService::DownloadsWatcher::OnFilePathChanged( | 176 void ArcDownloadsWatcherService::DownloadsWatcher::OnFilePathChanged( |
136 const base::FilePath& path, | 177 const base::FilePath& path, |
137 bool error) { | 178 bool error) { |
138 // On Linux, |error| is always false. Also, |path| is always the same path | 179 // On Linux, |error| is always false. Also, |path| is always the same path |
139 // as one given to FilePathWatcher::Watch(). | 180 // as one given to FilePathWatcher::Watch(). |
140 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 181 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
182 if (!outstanding_task_) { | |
183 base::PostTaskAndReplyWithResult( | |
184 BrowserThread::GetBlockingPool(), FROM_HERE, | |
185 base::Bind(&BuildTimestampMapCallback, downloads_dir_), | |
186 base::Bind(&DownloadsWatcher::OnBuildTimestampMap, | |
187 weak_ptr_factory_.GetWeakPtr())); | |
188 outstanding_task_ = true; | |
189 } else { | |
190 last_update_time_ = base::Time::Now(); | |
191 } | |
192 } | |
141 | 193 |
142 TimestampMap current_timestamp_map = BuildTimestampMap(); | 194 void ArcDownloadsWatcherService::DownloadsWatcher::OnBuildTimestampMap( |
143 | 195 std::pair<base::Time, TimestampMap> timestamp_and_map) { |
196 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
197 DCHECK(outstanding_task_); | |
198 TimestampMap current_timestamp_map = timestamp_and_map.second; | |
144 std::vector<base::FilePath> changed_paths = | 199 std::vector<base::FilePath> changed_paths = |
145 CollectChangedPaths(last_timestamp_map_, current_timestamp_map); | 200 CollectChangedPaths(last_timestamp_map_, current_timestamp_map); |
146 | 201 |
147 last_timestamp_map_ = std::move(current_timestamp_map); | 202 last_timestamp_map_ = std::move(current_timestamp_map); |
148 | 203 |
149 mojo::Array<mojo::String> mojo_paths(changed_paths.size()); | 204 mojo::Array<mojo::String> mojo_paths(changed_paths.size()); |
150 for (size_t i = 0; i < changed_paths.size(); ++i) { | 205 for (size_t i = 0; i < changed_paths.size(); ++i) { |
151 mojo_paths[i] = changed_paths[i].value(); | 206 mojo_paths[i] = changed_paths[i].value(); |
152 } | 207 } |
153 BrowserThread::PostTask( | 208 BrowserThread::PostTask( |
154 BrowserThread::UI, FROM_HERE, | 209 BrowserThread::UI, FROM_HERE, |
155 base::Bind(callback_, base::Passed(std::move(mojo_paths)))); | 210 base::Bind(callback_, base::Passed(std::move(mojo_paths)))); |
156 } | 211 if (last_update_time_ > timestamp_and_map.first) { |
157 | 212 base::PostTaskAndReplyWithResult( |
158 TimestampMap ArcDownloadsWatcherService::DownloadsWatcher::BuildTimestampMap() | 213 BrowserThread::GetBlockingPool(), FROM_HERE, |
159 const { | 214 base::Bind(&BuildTimestampMapCallback, downloads_dir_), |
160 DCHECK(!downloads_dir_.EndsWithSeparator()); | 215 base::Bind(&DownloadsWatcher::OnBuildTimestampMap, |
161 TimestampMap timestamp_map; | 216 weak_ptr_factory_.GetWeakPtr())); |
162 | 217 } else { |
163 // Enumerate normal files only; directories and symlinks are skipped. | 218 outstanding_task_ = false; |
164 base::FileEnumerator enumerator(downloads_dir_, true, | |
165 base::FileEnumerator::FILES); | |
166 for (base::FilePath cros_path = enumerator.Next(); !cros_path.empty(); | |
167 cros_path = enumerator.Next()) { | |
168 // Android file path can be obtained by replacing |downloads_dir_| prefix | |
169 // with |kAndroidDownloadDir|. | |
170 const base::FilePath& android_path = | |
171 base::FilePath(kAndroidDownloadDir) | |
172 .Append( | |
173 cros_path.value().substr(downloads_dir_.value().length() + 1)); | |
174 const base::FileEnumerator::FileInfo& info = enumerator.GetInfo(); | |
175 timestamp_map[android_path] = info.GetLastModifiedTime(); | |
176 } | 219 } |
177 return timestamp_map; | |
178 } | 220 } |
179 | 221 |
180 ArcDownloadsWatcherService::ArcDownloadsWatcherService( | 222 ArcDownloadsWatcherService::ArcDownloadsWatcherService( |
181 ArcBridgeService* bridge_service) | 223 ArcBridgeService* bridge_service) |
182 : ArcService(bridge_service), weak_ptr_factory_(this) { | 224 : ArcService(bridge_service), weak_ptr_factory_(this) { |
183 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 225 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
184 arc_bridge_service()->file_system()->AddObserver(this); | 226 arc_bridge_service()->file_system()->AddObserver(this); |
185 } | 227 } |
186 | 228 |
187 ArcDownloadsWatcherService::~ArcDownloadsWatcherService() { | 229 ArcDownloadsWatcherService::~ArcDownloadsWatcherService() { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
225 mojo::Array<mojo::String> paths) { | 267 mojo::Array<mojo::String> paths) { |
226 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 268 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
227 | 269 |
228 auto* instance = arc_bridge_service()->file_system()->instance(); | 270 auto* instance = arc_bridge_service()->file_system()->instance(); |
229 if (!instance) | 271 if (!instance) |
230 return; | 272 return; |
231 instance->RequestMediaScan(std::move(paths)); | 273 instance->RequestMediaScan(std::move(paths)); |
232 } | 274 } |
233 | 275 |
234 } // namespace arc | 276 } // namespace arc |
OLD | NEW |