OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/media_gallery/mtp_device_delegate_impl_linux.h" | 5 #include "chrome/browser/media_gallery/mtp_device_delegate_impl_linux.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/file_path.h" | 8 #include "base/file_path.h" |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/sequenced_task_runner.h" | 10 #include "base/sequenced_task_runner.h" |
11 #include "base/sequenced_task_runner_helpers.h" | 11 #include "base/sequenced_task_runner_helpers.h" |
| 12 #include "base/synchronization/cancellation_flag.h" |
12 #include "base/string_util.h" | 13 #include "base/string_util.h" |
13 #include "base/threading/sequenced_worker_pool.h" | 14 #include "base/threading/sequenced_worker_pool.h" |
14 #include "chrome/browser/media_transfer_protocol/media_transfer_protocol_manager
.h" | 15 #include "chrome/browser/media_transfer_protocol/media_transfer_protocol_manager
.h" |
15 #include "chrome/browser/media_transfer_protocol/mtp_file_entry.pb.h" | 16 #include "chrome/browser/media_transfer_protocol/mtp_file_entry.pb.h" |
16 #include "chrome/common/chrome_notification_types.h" | |
17 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
18 #include "content/public/browser/notification_service.h" | |
19 #include "third_party/cros_system_api/dbus/service_constants.h" | 18 #include "third_party/cros_system_api/dbus/service_constants.h" |
20 | 19 |
21 using base::Bind; | 20 using base::Bind; |
22 using base::PlatformFileError; | 21 using base::PlatformFileError; |
23 using base::PlatformFileInfo; | 22 using base::PlatformFileInfo; |
24 using base::SequencedTaskRunner; | 23 using base::SequencedTaskRunner; |
25 using base::Time; | 24 using base::Time; |
26 using content::BrowserThread; | 25 using content::BrowserThread; |
27 using fileapi::FileSystemFileUtil; | 26 using fileapi::FileSystemFileUtil; |
28 | 27 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 DCHECK(mtp_device_mgr); | 60 DCHECK(mtp_device_mgr); |
62 return mtp_device_mgr; | 61 return mtp_device_mgr; |
63 } | 62 } |
64 | 63 |
65 // Does nothing. | 64 // Does nothing. |
66 // This method is used to handle the results of | 65 // This method is used to handle the results of |
67 // MediaTransferProtocolManager::CloseStorage method call. | 66 // MediaTransferProtocolManager::CloseStorage method call. |
68 void DoNothing(bool error) { | 67 void DoNothing(bool error) { |
69 } | 68 } |
70 | 69 |
| 70 // Closes the device storage on the UI thread. |
| 71 void CloseStorageOnUIThread(const std::string& device_handle) { |
| 72 DCHECK(!device_handle.empty()); |
| 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 74 GetMediaTransferProtocolManager()->CloseStorage(device_handle, |
| 75 Bind(&DoNothing)); |
| 76 } |
| 77 |
71 // Returns the device relative file path given |file_path|. | 78 // Returns the device relative file path given |file_path|. |
72 // E.g.: If the |file_path| is "/usb:2,2:12345/DCIM" and |registered_dev_path| | 79 // E.g.: If the |file_path| is "/usb:2,2:12345/DCIM" and |registered_dev_path| |
73 // is "/usb:2,2:12345", this function returns the device relative path which is | 80 // is "/usb:2,2:12345", this function returns the device relative path which is |
74 // "/DCIM". | 81 // "/DCIM". |
75 std::string GetDeviceRelativePath(const std::string& registered_dev_path, | 82 std::string GetDeviceRelativePath(const std::string& registered_dev_path, |
76 const std::string& file_path) { | 83 const std::string& file_path) { |
77 DCHECK(!registered_dev_path.empty()); | 84 DCHECK(!registered_dev_path.empty()); |
78 DCHECK(!file_path.empty()); | 85 DCHECK(!file_path.empty()); |
79 | 86 |
80 std::string actual_file_path; | 87 std::string actual_file_path; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 if (on_shutdown_event_->IsSignaled()) { | 122 if (on_shutdown_event_->IsSignaled()) { |
116 // Process is in shutdown mode. | 123 // Process is in shutdown mode. |
117 // Do not post any task on |media_task_runner_|. | 124 // Do not post any task on |media_task_runner_|. |
118 return; | 125 return; |
119 } | 126 } |
120 | 127 |
121 DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); | 128 DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); |
122 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 129 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
123 Bind(&OpenStorageWorker::DoWorkOnUIThread, this)); | 130 Bind(&OpenStorageWorker::DoWorkOnUIThread, this)); |
124 on_task_completed_event_->Wait(); | 131 on_task_completed_event_->Wait(); |
| 132 |
| 133 if (on_shutdown_event_->IsSignaled()) |
| 134 cancel_tasks_flag_.Set(); |
125 } | 135 } |
126 | 136 |
127 // Returns a device handle string if the OpenStorage() request was | 137 // Returns a device handle string if the OpenStorage() request was |
128 // successfully completed or an empty string otherwise. | 138 // successfully completed or an empty string otherwise. |
129 const std::string& device_handle() const { return device_handle_; } | 139 const std::string& device_handle() const { return device_handle_; } |
130 | 140 |
131 // Returns the |media_task_runner_| associated with this worker object. | 141 // Returns the |media_task_runner_| associated with this worker object. |
132 // This function is exposed for WorkerDeleter struct to access the | 142 // This function is exposed for WorkerDeleter struct to access the |
133 // |media_task_runner_|. | 143 // |media_task_runner_|. |
134 SequencedTaskRunner* media_task_runner() const { | 144 SequencedTaskRunner* media_task_runner() const { |
135 return media_task_runner_.get(); | 145 return media_task_runner_.get(); |
136 } | 146 } |
137 | 147 |
138 private: | 148 private: |
139 friend struct WorkerDeleter<OpenStorageWorker>; | 149 friend struct WorkerDeleter<OpenStorageWorker>; |
140 friend class DeleteHelper<OpenStorageWorker>; | 150 friend class DeleteHelper<OpenStorageWorker>; |
141 friend class RefCountedThreadSafe<OpenStorageWorker, | 151 friend class RefCountedThreadSafe<OpenStorageWorker, |
142 OpenStorageWorkerDeleter>; | 152 OpenStorageWorkerDeleter>; |
143 | 153 |
144 // Destructed via OpenStorageWorkerDeleter struct. | 154 // Destructed via OpenStorageWorkerDeleter struct. |
145 virtual ~OpenStorageWorker() { | 155 virtual ~OpenStorageWorker() { |
146 // This object must be destructed on |media_task_runner_|. | 156 // This object must be destructed on |media_task_runner_|. |
147 } | 157 } |
148 | 158 |
149 // Dispatches a request to MediaTransferProtocolManager to open the MTP | 159 // Dispatches a request to MediaTransferProtocolManager to open the MTP |
150 // storage for communication. This is called on UI thread. | 160 // storage for communication. This is called on UI thread. |
151 void DoWorkOnUIThread() { | 161 void DoWorkOnUIThread() { |
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 163 if (cancel_tasks_flag_.IsSet()) |
| 164 return; |
153 | 165 |
154 GetMediaTransferProtocolManager()->OpenStorage( | 166 GetMediaTransferProtocolManager()->OpenStorage( |
155 storage_name_, mtpd::kReadOnlyMode, | 167 storage_name_, mtpd::kReadOnlyMode, |
156 Bind(&OpenStorageWorker::OnDidWorkOnUIThread, this)); | 168 Bind(&OpenStorageWorker::OnDidWorkOnUIThread, this)); |
157 } | 169 } |
158 | 170 |
159 // Query callback for DoWorkOnUIThread(). |error| is set to true if the device | 171 // Query callback for DoWorkOnUIThread(). |error| is set to true if the device |
160 // did not open successfully. This function signals to unblock | 172 // did not open successfully. This function signals to unblock |
161 // |media_task_runner_|. | 173 // |media_task_runner_|. |
162 void OnDidWorkOnUIThread(const std::string& device_handle, bool error) { | 174 void OnDidWorkOnUIThread(const std::string& device_handle, bool error) { |
163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 175 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
164 if (!error) | 176 if (!error) |
165 device_handle_ = device_handle; | 177 device_handle_ = device_handle; |
166 on_task_completed_event_->Signal(); | 178 if (!cancel_tasks_flag_.IsSet()) |
| 179 on_task_completed_event_->Signal(); |
167 } | 180 } |
168 | 181 |
169 // Stores the storage name to open the device. | 182 // Stores the storage name to open the device. |
170 const std::string storage_name_; | 183 const std::string storage_name_; |
171 | 184 |
172 // Stores a reference to |media_task_runner_| to destruct this object on the | 185 // Stores a reference to |media_task_runner_| to destruct this object on the |
173 // correct thread. | 186 // correct thread. |
174 scoped_refptr<SequencedTaskRunner> media_task_runner_; | 187 scoped_refptr<SequencedTaskRunner> media_task_runner_; |
175 | 188 |
176 // |media_task_runner_| can wait on this event until the required operation | 189 // |media_task_runner_| can wait on this event until the required operation |
177 // is complete. | 190 // is complete. |
178 // TODO(kmadhusu): Remove this WaitableEvent after modifying the | 191 // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
179 // DeviceMediaFileUtil functions as asynchronous functions. | 192 // DeviceMediaFileUtil functions as asynchronous functions. |
180 WaitableEvent* on_task_completed_event_; | 193 WaitableEvent* on_task_completed_event_; |
181 | 194 |
182 // Stores a reference to waitable event associated with the shut down message. | 195 // Stores a reference to waitable event associated with the shut down message. |
183 WaitableEvent* on_shutdown_event_; | 196 WaitableEvent* on_shutdown_event_; |
184 | 197 |
185 // Stores the result of OpenStorage() request. | 198 // Stores the result of OpenStorage() request. |
186 std::string device_handle_; | 199 std::string device_handle_; |
187 | 200 |
| 201 // Set to ignore the request results. This will be set when |
| 202 // MTPDeviceDelegateImplLinux object is about to be deleted. |
| 203 // |on_task_completed_event_| and |on_shutdown_event_| should not be |
| 204 // dereferenced when this is set. |
| 205 base::CancellationFlag cancel_tasks_flag_; |
| 206 |
188 DISALLOW_COPY_AND_ASSIGN(OpenStorageWorker); | 207 DISALLOW_COPY_AND_ASSIGN(OpenStorageWorker); |
189 }; | 208 }; |
190 | 209 |
191 // Worker class to get media device file information given a |path|. | 210 // Worker class to get media device file information given a |path|. |
192 class GetFileInfoWorker | 211 class GetFileInfoWorker |
193 : public RefCountedThreadSafe<GetFileInfoWorker, GetFileInfoWorkerDeleter> { | 212 : public RefCountedThreadSafe<GetFileInfoWorker, GetFileInfoWorkerDeleter> { |
194 public: | 213 public: |
195 // Constructed on |media_task_runner_| thread. | 214 // Constructed on |media_task_runner_| thread. |
196 GetFileInfoWorker(const std::string& handle, | 215 GetFileInfoWorker(const std::string& handle, |
197 const std::string& path, | 216 const std::string& path, |
(...skipping 15 matching lines...) Expand all Loading... |
213 void Run() { | 232 void Run() { |
214 if (on_shutdown_event_->IsSignaled()) { | 233 if (on_shutdown_event_->IsSignaled()) { |
215 // Process is in shutdown mode. | 234 // Process is in shutdown mode. |
216 // Do not post any task on |media_task_runner_|. | 235 // Do not post any task on |media_task_runner_|. |
217 return; | 236 return; |
218 } | 237 } |
219 | 238 |
220 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 239 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
221 Bind(&GetFileInfoWorker::DoWorkOnUIThread, this)); | 240 Bind(&GetFileInfoWorker::DoWorkOnUIThread, this)); |
222 on_task_completed_event_->Wait(); | 241 on_task_completed_event_->Wait(); |
| 242 |
| 243 if (on_shutdown_event_->IsSignaled()) |
| 244 cancel_tasks_flag_.Set(); |
223 } | 245 } |
224 | 246 |
225 // Returns GetFileInfo() result and fills in |file_info| with requested file | 247 // Returns GetFileInfo() result and fills in |file_info| with requested file |
226 // entry details. | 248 // entry details. |
227 PlatformFileError get_file_info(PlatformFileInfo* file_info) const { | 249 PlatformFileError get_file_info(PlatformFileInfo* file_info) const { |
228 if (file_info) | 250 if (file_info) |
229 *file_info = file_entry_info_; | 251 *file_info = file_entry_info_; |
230 return error_; | 252 return error_; |
231 } | 253 } |
232 | 254 |
(...skipping 12 matching lines...) Expand all Loading... |
245 | 267 |
246 // Destructed via GetFileInfoWorkerDeleter. | 268 // Destructed via GetFileInfoWorkerDeleter. |
247 virtual ~GetFileInfoWorker() { | 269 virtual ~GetFileInfoWorker() { |
248 // This object must be destructed on |media_task_runner_|. | 270 // This object must be destructed on |media_task_runner_|. |
249 } | 271 } |
250 | 272 |
251 // Dispatches a request to MediaTransferProtocolManager to get file | 273 // Dispatches a request to MediaTransferProtocolManager to get file |
252 // information. | 274 // information. |
253 void DoWorkOnUIThread() { | 275 void DoWorkOnUIThread() { |
254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 277 if (cancel_tasks_flag_.IsSet()) |
| 278 return; |
255 | 279 |
256 GetMediaTransferProtocolManager()->GetFileInfoByPath( | 280 GetMediaTransferProtocolManager()->GetFileInfoByPath( |
257 device_handle_, path_, | 281 device_handle_, path_, |
258 Bind(&GetFileInfoWorker::OnDidWorkOnUIThread, this)); | 282 Bind(&GetFileInfoWorker::OnDidWorkOnUIThread, this)); |
259 } | 283 } |
260 | 284 |
261 // Query callback for DoWorkOnUIThread(). On success, |file_entry| has media | 285 // Query callback for DoWorkOnUIThread(). On success, |file_entry| has media |
262 // file information. On failure, |error| is set to true. This function signals | 286 // file information. On failure, |error| is set to true. This function signals |
263 // to unblock |media_task_runner_|. | 287 // to unblock |media_task_runner_|. |
264 void OnDidWorkOnUIThread(const MtpFileEntry& file_entry, bool error) { | 288 void OnDidWorkOnUIThread(const MtpFileEntry& file_entry, bool error) { |
265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 289 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
266 if (error) { | 290 if (error) { |
267 error_ = base::PLATFORM_FILE_ERROR_NOT_FOUND; | 291 error_ = base::PLATFORM_FILE_ERROR_NOT_FOUND; |
268 } else { | 292 } else { |
269 file_entry_info_.size = file_entry.file_size(); | 293 file_entry_info_.size = file_entry.file_size(); |
270 file_entry_info_.is_directory = | 294 file_entry_info_.is_directory = |
271 file_entry.file_type() == MtpFileEntry::FILE_TYPE_FOLDER; | 295 file_entry.file_type() == MtpFileEntry::FILE_TYPE_FOLDER; |
272 file_entry_info_.is_symbolic_link = false; | 296 file_entry_info_.is_symbolic_link = false; |
273 file_entry_info_.last_modified = | 297 file_entry_info_.last_modified = |
274 base::Time::FromTimeT(file_entry.modification_time()); | 298 base::Time::FromTimeT(file_entry.modification_time()); |
275 file_entry_info_.last_accessed = | 299 file_entry_info_.last_accessed = |
276 base::Time::FromTimeT(file_entry.modification_time()); | 300 base::Time::FromTimeT(file_entry.modification_time()); |
277 file_entry_info_.creation_time = base::Time(); | 301 file_entry_info_.creation_time = base::Time(); |
278 } | 302 } |
279 on_task_completed_event_->Signal(); | 303 if (!cancel_tasks_flag_.IsSet()) |
| 304 on_task_completed_event_->Signal(); |
280 } | 305 } |
281 | 306 |
282 // Stores the device handle to query the device. | 307 // Stores the device handle to query the device. |
283 const std::string device_handle_; | 308 const std::string device_handle_; |
284 | 309 |
285 // Stores the requested media device file path. | 310 // Stores the requested media device file path. |
286 const std::string path_; | 311 const std::string path_; |
287 | 312 |
288 // Stores a reference to |media_task_runner_| to destruct this object on the | 313 // Stores a reference to |media_task_runner_| to destruct this object on the |
289 // correct thread. | 314 // correct thread. |
290 scoped_refptr<SequencedTaskRunner> media_task_runner_; | 315 scoped_refptr<SequencedTaskRunner> media_task_runner_; |
291 | 316 |
292 // Stores the result of GetFileInfo(). | 317 // Stores the result of GetFileInfo(). |
293 PlatformFileError error_; | 318 PlatformFileError error_; |
294 | 319 |
295 // Stores the media file entry information. | 320 // Stores the media file entry information. |
296 PlatformFileInfo file_entry_info_; | 321 PlatformFileInfo file_entry_info_; |
297 | 322 |
298 // |media_task_runner_| can wait on this event until the required operation | 323 // |media_task_runner_| can wait on this event until the required operation |
299 // is complete. | 324 // is complete. |
300 // TODO(kmadhusu): Remove this WaitableEvent after modifying the | 325 // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
301 // DeviceMediaFileUtil functions as asynchronous functions. | 326 // DeviceMediaFileUtil functions as asynchronous functions. |
302 WaitableEvent* on_task_completed_event_; | 327 WaitableEvent* on_task_completed_event_; |
303 | 328 |
304 // Stores a reference to waitable event associated with the shut down message. | 329 // Stores a reference to waitable event associated with the shut down message. |
305 WaitableEvent* on_shutdown_event_; | 330 WaitableEvent* on_shutdown_event_; |
306 | 331 |
| 332 // Set to ignore the request results. This will be set when |
| 333 // MTPDeviceDelegateImplLinux object is about to be deleted. |
| 334 // |on_task_completed_event_| and |on_shutdown_event_| should not be |
| 335 // dereferenced when this is set. |
| 336 base::CancellationFlag cancel_tasks_flag_; |
| 337 |
307 DISALLOW_COPY_AND_ASSIGN(GetFileInfoWorker); | 338 DISALLOW_COPY_AND_ASSIGN(GetFileInfoWorker); |
308 }; | 339 }; |
309 | 340 |
310 // Worker class to read media device file data given a file |path|. | 341 // Worker class to read media device file data given a file |path|. |
311 class ReadFileWorker | 342 class ReadFileWorker |
312 : public RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter> { | 343 : public RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter> { |
313 public: | 344 public: |
314 // Constructed on |media_task_runner_| thread. | 345 // Constructed on |media_task_runner_| thread. |
315 ReadFileWorker(const std::string& handle, | 346 ReadFileWorker(const std::string& handle, |
316 const std::string& path, | 347 const std::string& path, |
(...skipping 14 matching lines...) Expand all Loading... |
331 void Run() { | 362 void Run() { |
332 if (on_shutdown_event_->IsSignaled()) { | 363 if (on_shutdown_event_->IsSignaled()) { |
333 // Process is in shutdown mode. | 364 // Process is in shutdown mode. |
334 // Do not post any task on |media_task_runner_|. | 365 // Do not post any task on |media_task_runner_|. |
335 return; | 366 return; |
336 } | 367 } |
337 | 368 |
338 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 369 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
339 Bind(&ReadFileWorker::DoWorkOnUIThread, this)); | 370 Bind(&ReadFileWorker::DoWorkOnUIThread, this)); |
340 on_task_completed_event_->Wait(); | 371 on_task_completed_event_->Wait(); |
| 372 if (on_shutdown_event_->IsSignaled()) |
| 373 cancel_tasks_flag_.Set(); |
341 } | 374 } |
342 | 375 |
343 // Returns the media file contents received by ReadFileByPath() callback | 376 // Returns the media file contents received by ReadFileByPath() callback |
344 // function. | 377 // function. |
345 const std::string& data() const { return data_; } | 378 const std::string& data() const { return data_; } |
346 | 379 |
347 // Returns the |media_task_runner_| associated with this worker object. | 380 // Returns the |media_task_runner_| associated with this worker object. |
348 // This function is exposed for WorkerDeleter struct to access the | 381 // This function is exposed for WorkerDeleter struct to access the |
349 // |media_task_runner_|. | 382 // |media_task_runner_|. |
350 SequencedTaskRunner* media_task_runner() const { | 383 SequencedTaskRunner* media_task_runner() const { |
351 return media_task_runner_.get(); | 384 return media_task_runner_.get(); |
352 } | 385 } |
353 | 386 |
354 private: | 387 private: |
355 friend struct WorkerDeleter<ReadFileWorker>; | 388 friend struct WorkerDeleter<ReadFileWorker>; |
356 friend class DeleteHelper<ReadFileWorker>; | 389 friend class DeleteHelper<ReadFileWorker>; |
357 friend class RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter>; | 390 friend class RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter>; |
358 | 391 |
359 // Destructed via ReadFileWorkerDeleter. | 392 // Destructed via ReadFileWorkerDeleter. |
360 virtual ~ReadFileWorker() { | 393 virtual ~ReadFileWorker() { |
361 // This object must be destructed on |media_task_runner_|. | 394 // This object must be destructed on |media_task_runner_|. |
362 } | 395 } |
363 | 396 |
364 // Dispatches a request to MediaTransferProtocolManager to get the media file | 397 // Dispatches a request to MediaTransferProtocolManager to get the media file |
365 // contents. | 398 // contents. |
366 void DoWorkOnUIThread() { | 399 void DoWorkOnUIThread() { |
367 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 401 if (cancel_tasks_flag_.IsSet()) |
| 402 return; |
| 403 |
368 GetMediaTransferProtocolManager()->ReadFileByPath( | 404 GetMediaTransferProtocolManager()->ReadFileByPath( |
369 device_handle_, path_, Bind(&ReadFileWorker::OnDidWorkOnUIThread, this)); | 405 device_handle_, path_, Bind(&ReadFileWorker::OnDidWorkOnUIThread, this)); |
370 } | 406 } |
371 | 407 |
372 // Query callback for DoWorkOnUIThread(). On success, |data| has the media | 408 // Query callback for DoWorkOnUIThread(). On success, |data| has the media |
373 // file contents. On failure, |error| is set to true. This function signals | 409 // file contents. On failure, |error| is set to true. This function signals |
374 // to unblock |media_task_runner_|. | 410 // to unblock |media_task_runner_|. |
375 void OnDidWorkOnUIThread(const std::string& data, bool error) { | 411 void OnDidWorkOnUIThread(const std::string& data, bool error) { |
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
377 if (!error) { | 413 if (!error) { |
378 // TODO(kmadhusu): Data could be really huge. Consider passing data by | 414 // TODO(kmadhusu): Data could be really huge. Consider passing data by |
379 // pointer/ref rather than by value here to avoid an extra data copy. | 415 // pointer/ref rather than by value here to avoid an extra data copy. |
380 data_ = data; | 416 data_ = data; |
381 } | 417 } |
382 on_task_completed_event_->Signal(); | 418 if (!cancel_tasks_flag_.IsSet()) |
| 419 on_task_completed_event_->Signal(); |
383 } | 420 } |
384 | 421 |
385 // Stores the device unique identifier to query the device. | 422 // Stores the device unique identifier to query the device. |
386 const std::string device_handle_; | 423 const std::string device_handle_; |
387 | 424 |
388 // Stores the media device file path. | 425 // Stores the media device file path. |
389 const std::string path_; | 426 const std::string path_; |
390 | 427 |
391 // Stores a reference to |media_task_runner_| to destruct this object on the | 428 // Stores a reference to |media_task_runner_| to destruct this object on the |
392 // correct thread. | 429 // correct thread. |
393 scoped_refptr<SequencedTaskRunner> media_task_runner_; | 430 scoped_refptr<SequencedTaskRunner> media_task_runner_; |
394 | 431 |
395 // Stores the result of ReadFileByPath() callback. | 432 // Stores the result of ReadFileByPath() callback. |
396 std::string data_; | 433 std::string data_; |
397 | 434 |
398 // |media_task_runner_| can wait on this event until the required operation | 435 // |media_task_runner_| can wait on this event until the required operation |
399 // is complete. | 436 // is complete. |
400 // TODO(kmadhusu): Remove this WaitableEvent after modifying the | 437 // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
401 // DeviceMediaFileUtil functions as asynchronous functions. | 438 // DeviceMediaFileUtil functions as asynchronous functions. |
402 WaitableEvent* on_task_completed_event_; | 439 WaitableEvent* on_task_completed_event_; |
403 | 440 |
404 // Stores a reference to waitable event associated with the shut down message. | 441 // Stores a reference to waitable event associated with the shut down message. |
405 WaitableEvent* on_shutdown_event_; | 442 WaitableEvent* on_shutdown_event_; |
406 | 443 |
| 444 // Set to ignore the request results. This will be set when |
| 445 // MTPDeviceDelegateImplLinux object is about to be deleted. |
| 446 // |on_task_completed_event_| and |on_shutdown_event_| should not be |
| 447 // dereferenced when this is set. |
| 448 base::CancellationFlag cancel_tasks_flag_; |
| 449 |
407 DISALLOW_COPY_AND_ASSIGN(ReadFileWorker); | 450 DISALLOW_COPY_AND_ASSIGN(ReadFileWorker); |
408 }; | 451 }; |
409 | 452 |
410 // Worker class to read directory contents. Device is already opened for | 453 // Worker class to read directory contents. Device is already opened for |
411 // communication. | 454 // communication. |
412 class ReadDirectoryWorker | 455 class ReadDirectoryWorker |
413 : public RefCountedThreadSafe<ReadDirectoryWorker, | 456 : public RefCountedThreadSafe<ReadDirectoryWorker, |
414 ReadDirectoryWorkerDeleter> { | 457 ReadDirectoryWorkerDeleter> { |
415 public: | 458 public: |
416 // Construct a worker object given the directory |path|. This object is | 459 // Construct a worker object given the directory |path|. This object is |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
452 void Run() { | 495 void Run() { |
453 if (on_shutdown_event_->IsSignaled()) { | 496 if (on_shutdown_event_->IsSignaled()) { |
454 // Process is in shutdown mode. | 497 // Process is in shutdown mode. |
455 // Do not post any task on |media_task_runner_|. | 498 // Do not post any task on |media_task_runner_|. |
456 return; | 499 return; |
457 } | 500 } |
458 | 501 |
459 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 502 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
460 Bind(&ReadDirectoryWorker::DoWorkOnUIThread, this)); | 503 Bind(&ReadDirectoryWorker::DoWorkOnUIThread, this)); |
461 on_task_completed_event_->Wait(); | 504 on_task_completed_event_->Wait(); |
| 505 if (on_shutdown_event_->IsSignaled()) |
| 506 cancel_tasks_flag_.Set(); |
462 } | 507 } |
463 | 508 |
464 // Returns the directory entries for the given directory path. | 509 // Returns the directory entries for the given directory path. |
465 const std::vector<MtpFileEntry>& get_file_entries() const { | 510 const std::vector<MtpFileEntry>& get_file_entries() const { |
466 return file_entries_; | 511 return file_entries_; |
467 } | 512 } |
468 | 513 |
469 // Returns the |media_task_runner_| associated with this worker object. | 514 // Returns the |media_task_runner_| associated with this worker object. |
470 // This function is exposed for WorkerDeleter struct to access the | 515 // This function is exposed for WorkerDeleter struct to access the |
471 // |media_task_runner_|. | 516 // |media_task_runner_|. |
472 SequencedTaskRunner* media_task_runner() const { | 517 SequencedTaskRunner* media_task_runner() const { |
473 return media_task_runner_.get(); | 518 return media_task_runner_.get(); |
474 } | 519 } |
475 | 520 |
476 private: | 521 private: |
477 friend struct WorkerDeleter<ReadDirectoryWorker>; | 522 friend struct WorkerDeleter<ReadDirectoryWorker>; |
478 friend class DeleteHelper<ReadDirectoryWorker>; | 523 friend class DeleteHelper<ReadDirectoryWorker>; |
479 friend class RefCountedThreadSafe<ReadDirectoryWorker, | 524 friend class RefCountedThreadSafe<ReadDirectoryWorker, |
480 ReadDirectoryWorkerDeleter>; | 525 ReadDirectoryWorkerDeleter>; |
481 | 526 |
482 // Destructed via ReadDirectoryWorkerDeleter. | 527 // Destructed via ReadDirectoryWorkerDeleter. |
483 virtual ~ReadDirectoryWorker() { | 528 virtual ~ReadDirectoryWorker() { |
484 // This object must be destructed on |media_task_runner_|. | 529 // This object must be destructed on |media_task_runner_|. |
485 } | 530 } |
486 | 531 |
487 // Dispatches a request to MediaTransferProtocolManager to read the directory | 532 // Dispatches a request to MediaTransferProtocolManager to read the directory |
488 // entries. This is called on UI thread. | 533 // entries. This is called on UI thread. |
489 void DoWorkOnUIThread() { | 534 void DoWorkOnUIThread() { |
490 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 535 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 536 if (cancel_tasks_flag_.IsSet()) |
| 537 return; |
491 | 538 |
492 if (!dir_path_.empty()) { | 539 if (!dir_path_.empty()) { |
493 GetMediaTransferProtocolManager()->ReadDirectoryByPath( | 540 GetMediaTransferProtocolManager()->ReadDirectoryByPath( |
494 device_handle_, dir_path_, | 541 device_handle_, dir_path_, |
495 Bind(&ReadDirectoryWorker::OnDidWorkOnUIThread, this)); | 542 Bind(&ReadDirectoryWorker::OnDidWorkOnUIThread, this)); |
496 } else { | 543 } else { |
497 GetMediaTransferProtocolManager()->ReadDirectoryById( | 544 GetMediaTransferProtocolManager()->ReadDirectoryById( |
498 device_handle_, dir_entry_id_, | 545 device_handle_, dir_entry_id_, |
499 Bind(&ReadDirectoryWorker::OnDidWorkOnUIThread, this)); | 546 Bind(&ReadDirectoryWorker::OnDidWorkOnUIThread, this)); |
500 } | 547 } |
501 } | 548 } |
502 | 549 |
503 // Query callback for DoWorkOnUIThread(). On success, |file_entries| has the | 550 // Query callback for DoWorkOnUIThread(). On success, |file_entries| has the |
504 // directory file entries. |error| is true if there was an error. This | 551 // directory file entries. |error| is true if there was an error. This |
505 // function signals to unblock |media_task_runner_|. | 552 // function signals to unblock |media_task_runner_|. |
506 void OnDidWorkOnUIThread(const std::vector<MtpFileEntry>& file_entries, | 553 void OnDidWorkOnUIThread(const std::vector<MtpFileEntry>& file_entries, |
507 bool error) { | 554 bool error) { |
508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 555 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
509 if (!error) | 556 if (!error) |
510 file_entries_ = file_entries; | 557 file_entries_ = file_entries; |
511 on_task_completed_event_->Signal(); | 558 if (!cancel_tasks_flag_.IsSet()) |
| 559 on_task_completed_event_->Signal(); |
512 } | 560 } |
513 | 561 |
514 // Stores the device handle to communicate with storage device. | 562 // Stores the device handle to communicate with storage device. |
515 const std::string device_handle_; | 563 const std::string device_handle_; |
516 | 564 |
517 // Stores the directory path whose contents needs to be listed. | 565 // Stores the directory path whose contents needs to be listed. |
518 const std::string dir_path_; | 566 const std::string dir_path_; |
519 | 567 |
520 // Stores the directory entry id whose contents needs to be listed. | 568 // Stores the directory entry id whose contents needs to be listed. |
521 const uint32_t dir_entry_id_; | 569 const uint32_t dir_entry_id_; |
522 | 570 |
523 // Stores a reference to |media_task_runner_| to destruct this object on the | 571 // Stores a reference to |media_task_runner_| to destruct this object on the |
524 // correct thread. | 572 // correct thread. |
525 scoped_refptr<SequencedTaskRunner> media_task_runner_; | 573 scoped_refptr<SequencedTaskRunner> media_task_runner_; |
526 | 574 |
527 // |media_task_runner_| can wait on this event until the required operation | 575 // |media_task_runner_| can wait on this event until the required operation |
528 // is complete. | 576 // is complete. |
529 // TODO(kmadhusu): Remove this WaitableEvent after modifying the | 577 // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
530 // DeviceMediaFileUtil functions as asynchronous functions. | 578 // DeviceMediaFileUtil functions as asynchronous functions. |
531 WaitableEvent* on_task_completed_event_; | 579 WaitableEvent* on_task_completed_event_; |
532 | 580 |
533 // Stores a reference to waitable event associated with the shut down message. | 581 // Stores a reference to waitable event associated with the shut down message. |
534 WaitableEvent* on_shutdown_event_; | 582 WaitableEvent* on_shutdown_event_; |
535 | 583 |
536 // Stores the result of read directory request. | 584 // Stores the result of read directory request. |
537 std::vector<MtpFileEntry> file_entries_; | 585 std::vector<MtpFileEntry> file_entries_; |
538 | 586 |
| 587 // Set to ignore the request results. This will be set when |
| 588 // MTPDeviceDelegateImplLinux object is about to be deleted. |
| 589 // |on_task_completed_event_| and |on_shutdown_event_| should not be |
| 590 // dereferenced when this is set. |
| 591 base::CancellationFlag cancel_tasks_flag_; |
| 592 |
539 DISALLOW_COPY_AND_ASSIGN(ReadDirectoryWorker); | 593 DISALLOW_COPY_AND_ASSIGN(ReadDirectoryWorker); |
540 }; | 594 }; |
541 | 595 |
542 // Simply enumerate each files from a given file entry list. | 596 // Simply enumerate each files from a given file entry list. |
543 // Used to enumerate top-level files of an media file system. | 597 // Used to enumerate top-level files of an media file system. |
544 class MediaFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { | 598 class MediaFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { |
545 public: | 599 public: |
546 explicit MediaFileEnumerator(const std::vector<MtpFileEntry>& entries) | 600 explicit MediaFileEnumerator(const std::vector<MtpFileEntry>& entries) |
547 : file_entries_(entries), | 601 : file_entries_(entries), |
548 file_entry_iter_(file_entries_.begin()) { | 602 file_entry_iter_(file_entries_.begin()) { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
701 const std::string& device_location) | 755 const std::string& device_location) |
702 : device_path_(device_location), | 756 : device_path_(device_location), |
703 on_task_completed_event_(false, false), | 757 on_task_completed_event_(false, false), |
704 on_shutdown_event_(true, false) { | 758 on_shutdown_event_(true, false) { |
705 CHECK(!device_path_.empty()); | 759 CHECK(!device_path_.empty()); |
706 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 760 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
707 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); | 761 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); |
708 base::SequencedWorkerPool::SequenceToken media_sequence_token = | 762 base::SequencedWorkerPool::SequenceToken media_sequence_token = |
709 pool->GetNamedSequenceToken("media-task-runner"); | 763 pool->GetNamedSequenceToken("media-task-runner"); |
710 media_task_runner_ = pool->GetSequencedTaskRunner(media_sequence_token); | 764 media_task_runner_ = pool->GetSequencedTaskRunner(media_sequence_token); |
711 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, | |
712 content::NotificationService::AllSources()); | |
713 | |
714 DCHECK(media_task_runner_); | |
715 } | |
716 | |
717 MTPDeviceDelegateImplLinux::~MTPDeviceDelegateImplLinux() { | |
718 registrar_.RemoveAll(); | |
719 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
720 GetMediaTransferProtocolManager()->CloseStorage(device_handle_, | |
721 Bind(&DoNothing)); | |
722 } | 765 } |
723 | 766 |
724 PlatformFileError MTPDeviceDelegateImplLinux::GetFileInfo( | 767 PlatformFileError MTPDeviceDelegateImplLinux::GetFileInfo( |
725 const FilePath& file_path, | 768 const FilePath& file_path, |
726 PlatformFileInfo* file_info) { | 769 PlatformFileInfo* file_info) { |
727 if (!LazyInit()) | 770 if (!LazyInit()) |
728 return base::PLATFORM_FILE_ERROR_FAILED; | 771 return base::PLATFORM_FILE_ERROR_FAILED; |
729 | 772 |
730 scoped_refptr<GetFileInfoWorker> worker(new GetFileInfoWorker( | 773 scoped_refptr<GetFileInfoWorker> worker(new GetFileInfoWorker( |
731 device_handle_, GetDeviceRelativePath(device_path_, file_path.value()), | 774 device_handle_, GetDeviceRelativePath(device_path_, file_path.value()), |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
789 // Modify the last modified time to null. This prevents the time stamp | 832 // Modify the last modified time to null. This prevents the time stamp |
790 // verfication in LocalFileStreamReader. | 833 // verfication in LocalFileStreamReader. |
791 file_info->last_modified = base::Time(); | 834 file_info->last_modified = base::Time(); |
792 return error; | 835 return error; |
793 } | 836 } |
794 | 837 |
795 SequencedTaskRunner* MTPDeviceDelegateImplLinux::GetMediaTaskRunner() { | 838 SequencedTaskRunner* MTPDeviceDelegateImplLinux::GetMediaTaskRunner() { |
796 return media_task_runner_.get(); | 839 return media_task_runner_.get(); |
797 } | 840 } |
798 | 841 |
799 void MTPDeviceDelegateImplLinux::DeleteOnCorrectThread() const { | 842 void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() { |
800 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 843 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
801 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this); | 844 // Caution: This function is called on the IO thread. Access only the thread |
802 return; | 845 // safe member variables in this function. Do all the clean up operations in |
803 } | 846 // DeleteDelegateOnTaskRunner(). |
804 delete this; | 847 on_shutdown_event_.Signal(); |
| 848 on_task_completed_event_.Signal(); |
| 849 media_task_runner_->PostTask( |
| 850 FROM_HERE, |
| 851 base::Bind(&MTPDeviceDelegateImplLinux::DeleteDelegateOnTaskRunner, |
| 852 base::Unretained(this))); |
805 } | 853 } |
806 | 854 |
807 void MTPDeviceDelegateImplLinux::Observe( | 855 base::WeakPtr<fileapi::MTPDeviceDelegate> MTPDeviceDelegateImplLinux:: |
808 int type, | 856 GetAsWeakPtrOnIOThread() { |
809 const content::NotificationSource& source, | 857 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
810 const content::NotificationDetails& details) { | 858 base::WeakPtr<fileapi::MTPDeviceDelegate> delegate = AsWeakPtr(); |
811 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type); | 859 // This function is called on the IO thread but the member functions are |
812 on_shutdown_event_.Signal(); | 860 // accessed on |media_task_runner_|. Therefore, detach from the the current |
813 on_task_completed_event_.Signal(); | 861 // thread. |
| 862 DetachFromThread(); |
| 863 return delegate; |
| 864 } |
| 865 |
| 866 MTPDeviceDelegateImplLinux::~MTPDeviceDelegateImplLinux() { |
| 867 DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); |
| 868 // Do all the clean up operations on DeleteDelegateOnTaskRunner(). |
814 } | 869 } |
815 | 870 |
816 bool MTPDeviceDelegateImplLinux::LazyInit() { | 871 bool MTPDeviceDelegateImplLinux::LazyInit() { |
817 DCHECK(media_task_runner_); | 872 DCHECK(media_task_runner_); |
818 DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); | 873 DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); |
819 | 874 |
820 if (!device_handle_.empty()) | 875 if (!device_handle_.empty()) |
821 return true; // Already successfully initialized. | 876 return true; // Already successfully initialized. |
822 | 877 |
823 std::string storage_name; | 878 std::string storage_name; |
824 RemoveChars(device_path_, kRootPath, &storage_name); | 879 RemoveChars(device_path_, kRootPath, &storage_name); |
825 DCHECK(!storage_name.empty()); | 880 DCHECK(!storage_name.empty()); |
826 scoped_refptr<OpenStorageWorker> worker(new OpenStorageWorker( | 881 scoped_refptr<OpenStorageWorker> worker(new OpenStorageWorker( |
827 storage_name, media_task_runner_, &on_task_completed_event_, | 882 storage_name, media_task_runner_, &on_task_completed_event_, |
828 &on_shutdown_event_)); | 883 &on_shutdown_event_)); |
829 worker->Run(); | 884 worker->Run(); |
830 device_handle_ = worker->device_handle(); | 885 device_handle_ = worker->device_handle(); |
831 return !device_handle_.empty(); | 886 return !device_handle_.empty(); |
832 } | 887 } |
833 | 888 |
| 889 void MTPDeviceDelegateImplLinux::DeleteDelegateOnTaskRunner() { |
| 890 DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); |
| 891 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 892 Bind(&CloseStorageOnUIThread, device_handle_)); |
| 893 delete this; |
| 894 } |
| 895 |
834 } // namespace chrome | 896 } // namespace chrome |
OLD | NEW |