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 |