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/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "base/synchronization/cancellation_flag.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)); |
| 176 if (cancel_tasks_flag_.IsSet()) |
| 177 return; |
| 178 |
164 if (!error) | 179 if (!error) |
165 device_handle_ = device_handle; | 180 device_handle_ = device_handle; |
166 on_task_completed_event_->Signal(); | 181 on_task_completed_event_->Signal(); |
167 } | 182 } |
168 | 183 |
169 // Stores the storage name to open the device. | 184 // Stores the storage name to open the device. |
170 const std::string storage_name_; | 185 const std::string storage_name_; |
171 | 186 |
172 // Stores a reference to |media_task_runner_| to destruct this object on the | 187 // Stores a reference to |media_task_runner_| to destruct this object on the |
173 // correct thread. | 188 // correct thread. |
174 scoped_refptr<SequencedTaskRunner> media_task_runner_; | 189 scoped_refptr<SequencedTaskRunner> media_task_runner_; |
175 | 190 |
176 // |media_task_runner_| can wait on this event until the required operation | 191 // |media_task_runner_| can wait on this event until the required operation |
177 // is complete. | 192 // is complete. |
178 // TODO(kmadhusu): Remove this WaitableEvent after modifying the | 193 // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
179 // DeviceMediaFileUtil functions as asynchronous functions. | 194 // DeviceMediaFileUtil functions as asynchronous functions. |
180 WaitableEvent* on_task_completed_event_; | 195 WaitableEvent* on_task_completed_event_; |
181 | 196 |
182 // Stores a reference to waitable event associated with the shut down message. | 197 // Stores a reference to waitable event associated with the shut down message. |
183 WaitableEvent* on_shutdown_event_; | 198 WaitableEvent* on_shutdown_event_; |
184 | 199 |
185 // Stores the result of OpenStorage() request. | 200 // Stores the result of OpenStorage() request. |
186 std::string device_handle_; | 201 std::string device_handle_; |
187 | 202 |
| 203 // Set to ignore the request results. This will be set when |
| 204 // MTPDeviceDelegateImplLinux object is about to be deleted. |
| 205 // |on_task_completed_event_| and |on_shutdown_event_| should not be |
| 206 // dereferenced when this is set. |
| 207 base::CancellationFlag cancel_tasks_flag_; |
| 208 |
188 DISALLOW_COPY_AND_ASSIGN(OpenStorageWorker); | 209 DISALLOW_COPY_AND_ASSIGN(OpenStorageWorker); |
189 }; | 210 }; |
190 | 211 |
191 // Worker class to get media device file information given a |path|. | 212 // Worker class to get media device file information given a |path|. |
192 class GetFileInfoWorker | 213 class GetFileInfoWorker |
193 : public RefCountedThreadSafe<GetFileInfoWorker, GetFileInfoWorkerDeleter> { | 214 : public RefCountedThreadSafe<GetFileInfoWorker, GetFileInfoWorkerDeleter> { |
194 public: | 215 public: |
195 // Constructed on |media_task_runner_| thread. | 216 // Constructed on |media_task_runner_| thread. |
196 GetFileInfoWorker(const std::string& handle, | 217 GetFileInfoWorker(const std::string& handle, |
197 const std::string& path, | 218 const std::string& path, |
(...skipping 15 matching lines...) Expand all Loading... |
213 void Run() { | 234 void Run() { |
214 if (on_shutdown_event_->IsSignaled()) { | 235 if (on_shutdown_event_->IsSignaled()) { |
215 // Process is in shutdown mode. | 236 // Process is in shutdown mode. |
216 // Do not post any task on |media_task_runner_|. | 237 // Do not post any task on |media_task_runner_|. |
217 return; | 238 return; |
218 } | 239 } |
219 | 240 |
220 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 241 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
221 Bind(&GetFileInfoWorker::DoWorkOnUIThread, this)); | 242 Bind(&GetFileInfoWorker::DoWorkOnUIThread, this)); |
222 on_task_completed_event_->Wait(); | 243 on_task_completed_event_->Wait(); |
| 244 |
| 245 if (on_shutdown_event_->IsSignaled()) |
| 246 cancel_tasks_flag_.Set(); |
223 } | 247 } |
224 | 248 |
225 // Returns GetFileInfo() result and fills in |file_info| with requested file | 249 // Returns GetFileInfo() result and fills in |file_info| with requested file |
226 // entry details. | 250 // entry details. |
227 PlatformFileError get_file_info(PlatformFileInfo* file_info) const { | 251 PlatformFileError get_file_info(PlatformFileInfo* file_info) const { |
228 if (file_info) | 252 if (file_info) |
229 *file_info = file_entry_info_; | 253 *file_info = file_entry_info_; |
230 return error_; | 254 return error_; |
231 } | 255 } |
232 | 256 |
(...skipping 12 matching lines...) Expand all Loading... |
245 | 269 |
246 // Destructed via GetFileInfoWorkerDeleter. | 270 // Destructed via GetFileInfoWorkerDeleter. |
247 virtual ~GetFileInfoWorker() { | 271 virtual ~GetFileInfoWorker() { |
248 // This object must be destructed on |media_task_runner_|. | 272 // This object must be destructed on |media_task_runner_|. |
249 } | 273 } |
250 | 274 |
251 // Dispatches a request to MediaTransferProtocolManager to get file | 275 // Dispatches a request to MediaTransferProtocolManager to get file |
252 // information. | 276 // information. |
253 void DoWorkOnUIThread() { | 277 void DoWorkOnUIThread() { |
254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 279 if (cancel_tasks_flag_.IsSet()) { |
| 280 error_ = base::PLATFORM_FILE_ERROR_FAILED; |
| 281 return; |
| 282 } |
255 | 283 |
256 GetMediaTransferProtocolManager()->GetFileInfoByPath( | 284 GetMediaTransferProtocolManager()->GetFileInfoByPath( |
257 device_handle_, path_, | 285 device_handle_, path_, |
258 Bind(&GetFileInfoWorker::OnDidWorkOnUIThread, this)); | 286 Bind(&GetFileInfoWorker::OnDidWorkOnUIThread, this)); |
259 } | 287 } |
260 | 288 |
261 // Query callback for DoWorkOnUIThread(). On success, |file_entry| has media | 289 // Query callback for DoWorkOnUIThread(). On success, |file_entry| has media |
262 // file information. On failure, |error| is set to true. This function signals | 290 // file information. On failure, |error| is set to true. This function signals |
263 // to unblock |media_task_runner_|. | 291 // to unblock |media_task_runner_|. |
264 void OnDidWorkOnUIThread(const MtpFileEntry& file_entry, bool error) { | 292 void OnDidWorkOnUIThread(const MtpFileEntry& file_entry, bool error) { |
265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 294 if (cancel_tasks_flag_.IsSet()) { |
| 295 error_ = base::PLATFORM_FILE_ERROR_FAILED; |
| 296 return; |
| 297 } |
| 298 |
266 if (error) { | 299 if (error) { |
267 error_ = base::PLATFORM_FILE_ERROR_NOT_FOUND; | 300 error_ = base::PLATFORM_FILE_ERROR_NOT_FOUND; |
268 } else { | 301 } else { |
269 file_entry_info_.size = file_entry.file_size(); | 302 file_entry_info_.size = file_entry.file_size(); |
270 file_entry_info_.is_directory = | 303 file_entry_info_.is_directory = |
271 file_entry.file_type() == MtpFileEntry::FILE_TYPE_FOLDER; | 304 file_entry.file_type() == MtpFileEntry::FILE_TYPE_FOLDER; |
272 file_entry_info_.is_symbolic_link = false; | 305 file_entry_info_.is_symbolic_link = false; |
273 file_entry_info_.last_modified = | 306 file_entry_info_.last_modified = |
274 base::Time::FromTimeT(file_entry.modification_time()); | 307 base::Time::FromTimeT(file_entry.modification_time()); |
275 file_entry_info_.last_accessed = | 308 file_entry_info_.last_accessed = |
(...skipping 21 matching lines...) Expand all Loading... |
297 | 330 |
298 // |media_task_runner_| can wait on this event until the required operation | 331 // |media_task_runner_| can wait on this event until the required operation |
299 // is complete. | 332 // is complete. |
300 // TODO(kmadhusu): Remove this WaitableEvent after modifying the | 333 // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
301 // DeviceMediaFileUtil functions as asynchronous functions. | 334 // DeviceMediaFileUtil functions as asynchronous functions. |
302 WaitableEvent* on_task_completed_event_; | 335 WaitableEvent* on_task_completed_event_; |
303 | 336 |
304 // Stores a reference to waitable event associated with the shut down message. | 337 // Stores a reference to waitable event associated with the shut down message. |
305 WaitableEvent* on_shutdown_event_; | 338 WaitableEvent* on_shutdown_event_; |
306 | 339 |
| 340 // Set to ignore the request results. This will be set when |
| 341 // MTPDeviceDelegateImplLinux object is about to be deleted. |
| 342 // |on_task_completed_event_| and |on_shutdown_event_| should not be |
| 343 // dereferenced when this is set. |
| 344 base::CancellationFlag cancel_tasks_flag_; |
| 345 |
307 DISALLOW_COPY_AND_ASSIGN(GetFileInfoWorker); | 346 DISALLOW_COPY_AND_ASSIGN(GetFileInfoWorker); |
308 }; | 347 }; |
309 | 348 |
310 // Worker class to read media device file data given a file |path|. | 349 // Worker class to read media device file data given a file |path|. |
311 class ReadFileWorker | 350 class ReadFileWorker |
312 : public RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter> { | 351 : public RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter> { |
313 public: | 352 public: |
314 // Constructed on |media_task_runner_| thread. | 353 // Constructed on |media_task_runner_| thread. |
315 ReadFileWorker(const std::string& handle, | 354 ReadFileWorker(const std::string& handle, |
316 const std::string& path, | 355 const std::string& path, |
(...skipping 14 matching lines...) Expand all Loading... |
331 | 370 |
332 // This function is invoked on |media_task_runner_| to post the task on UI | 371 // This function is invoked on |media_task_runner_| to post the task on UI |
333 // thread. This blocks the |media_task_runner_| until the task is complete. | 372 // thread. This blocks the |media_task_runner_| until the task is complete. |
334 void Run() { | 373 void Run() { |
335 if (on_shutdown_event_->IsSignaled()) { | 374 if (on_shutdown_event_->IsSignaled()) { |
336 // Process is in shutdown mode. | 375 // Process is in shutdown mode. |
337 // Do not post any task on |media_task_runner_|. | 376 // Do not post any task on |media_task_runner_|. |
338 return; | 377 return; |
339 } | 378 } |
340 | 379 |
341 while (!error_occurred_ && (data_.size() < total_bytes_)) { | 380 while (!error_occurred_ && (data_.size() < total_bytes_) && |
| 381 !cancel_tasks_flag_.IsSet()) { |
342 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 382 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
343 Bind(&ReadFileWorker::DoWorkOnUIThread, this)); | 383 Bind(&ReadFileWorker::DoWorkOnUIThread, this)); |
344 on_task_completed_event_->Wait(); | 384 on_task_completed_event_->Wait(); |
| 385 if (on_shutdown_event_->IsSignaled()) |
| 386 cancel_tasks_flag_.Set(); |
345 } | 387 } |
346 } | 388 } |
347 | 389 |
348 // Returns the media file contents received from mtpd. | 390 // Returns the media file contents received from mtpd. |
349 const std::string& data() const { return data_; } | 391 const std::string& data() const { return data_; } |
350 | 392 |
351 // Returns the |media_task_runner_| associated with this worker object. | 393 // Returns the |media_task_runner_| associated with this worker object. |
352 // This function is exposed for WorkerDeleter struct to access the | 394 // This function is exposed for WorkerDeleter struct to access the |
353 // |media_task_runner_|. | 395 // |media_task_runner_|. |
354 SequencedTaskRunner* media_task_runner() const { | 396 SequencedTaskRunner* media_task_runner() const { |
355 return media_task_runner_.get(); | 397 return media_task_runner_.get(); |
356 } | 398 } |
357 | 399 |
358 private: | 400 private: |
359 friend struct WorkerDeleter<ReadFileWorker>; | 401 friend struct WorkerDeleter<ReadFileWorker>; |
360 friend class DeleteHelper<ReadFileWorker>; | 402 friend class DeleteHelper<ReadFileWorker>; |
361 friend class RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter>; | 403 friend class RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter>; |
362 | 404 |
363 // Destructed via ReadFileWorkerDeleter. | 405 // Destructed via ReadFileWorkerDeleter. |
364 virtual ~ReadFileWorker() { | 406 virtual ~ReadFileWorker() { |
365 // This object must be destructed on |media_task_runner_|. | 407 // This object must be destructed on |media_task_runner_|. |
366 } | 408 } |
367 | 409 |
368 // Dispatches a request to MediaTransferProtocolManager to get the media file | 410 // Dispatches a request to MediaTransferProtocolManager to get the media file |
369 // contents. | 411 // contents. |
370 void DoWorkOnUIThread() { | 412 void DoWorkOnUIThread() { |
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 414 if (cancel_tasks_flag_.IsSet()) |
| 415 return; |
| 416 |
372 GetMediaTransferProtocolManager()->ReadFileChunkByPath( | 417 GetMediaTransferProtocolManager()->ReadFileChunkByPath( |
373 device_handle_, path_, data_.size(), BytesToRead(), | 418 device_handle_, path_, data_.size(), BytesToRead(), |
374 Bind(&ReadFileWorker::OnDidWorkOnUIThread, this)); | 419 Bind(&ReadFileWorker::OnDidWorkOnUIThread, this)); |
375 } | 420 } |
376 | 421 |
377 // Query callback for DoWorkOnUIThread(). On success, |data| has the media | 422 // Query callback for DoWorkOnUIThread(). On success, |data| has the media |
378 // file contents. On failure, |error| is set to true. This function signals | 423 // file contents. On failure, |error| is set to true. This function signals |
379 // to unblock |media_task_runner_|. | 424 // to unblock |media_task_runner_|. |
380 void OnDidWorkOnUIThread(const std::string& data, bool error) { | 425 void OnDidWorkOnUIThread(const std::string& data, bool error) { |
381 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 427 if (cancel_tasks_flag_.IsSet()) |
| 428 return; |
| 429 |
382 error_occurred_ = error; | 430 error_occurred_ = error; |
383 if (!error) { | 431 if (!error) { |
384 if ((BytesToRead() == data.size())) { | 432 if ((BytesToRead() == data.size())) { |
385 // TODO(kmadhusu): Data could be really huge. Consider passing data by | 433 // TODO(kmadhusu): Data could be really huge. Consider passing data by |
386 // pointer/ref rather than by value here to avoid an extra data copy. | 434 // pointer/ref rather than by value here to avoid an extra data copy. |
387 data_.append(data); | 435 data_.append(data); |
388 } else { | 436 } else { |
389 NOTREACHED(); | 437 NOTREACHED(); |
390 error_occurred_ = true; | 438 error_occurred_ = true; |
391 } | 439 } |
(...skipping 29 matching lines...) Expand all Loading... |
421 | 469 |
422 // |media_task_runner_| can wait on this event until the required operation | 470 // |media_task_runner_| can wait on this event until the required operation |
423 // is complete. | 471 // is complete. |
424 // TODO(kmadhusu): Remove this WaitableEvent after modifying the | 472 // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
425 // DeviceMediaFileUtil functions as asynchronous functions. | 473 // DeviceMediaFileUtil functions as asynchronous functions. |
426 WaitableEvent* on_task_completed_event_; | 474 WaitableEvent* on_task_completed_event_; |
427 | 475 |
428 // Stores a reference to waitable event associated with the shut down message. | 476 // Stores a reference to waitable event associated with the shut down message. |
429 WaitableEvent* on_shutdown_event_; | 477 WaitableEvent* on_shutdown_event_; |
430 | 478 |
| 479 // Set to ignore the request results. This will be set when |
| 480 // MTPDeviceDelegateImplLinux object is about to be deleted. |
| 481 // |on_task_completed_event_| and |on_shutdown_event_| should not be |
| 482 // dereferenced when this is set. |
| 483 base::CancellationFlag cancel_tasks_flag_; |
| 484 |
431 DISALLOW_COPY_AND_ASSIGN(ReadFileWorker); | 485 DISALLOW_COPY_AND_ASSIGN(ReadFileWorker); |
432 }; | 486 }; |
433 | 487 |
434 // Worker class to read directory contents. Device is already opened for | 488 // Worker class to read directory contents. Device is already opened for |
435 // communication. | 489 // communication. |
436 class ReadDirectoryWorker | 490 class ReadDirectoryWorker |
437 : public RefCountedThreadSafe<ReadDirectoryWorker, | 491 : public RefCountedThreadSafe<ReadDirectoryWorker, |
438 ReadDirectoryWorkerDeleter> { | 492 ReadDirectoryWorkerDeleter> { |
439 public: | 493 public: |
440 // Construct a worker object given the directory |path|. This object is | 494 // Construct a worker object given the directory |path|. This object is |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 void Run() { | 530 void Run() { |
477 if (on_shutdown_event_->IsSignaled()) { | 531 if (on_shutdown_event_->IsSignaled()) { |
478 // Process is in shutdown mode. | 532 // Process is in shutdown mode. |
479 // Do not post any task on |media_task_runner_|. | 533 // Do not post any task on |media_task_runner_|. |
480 return; | 534 return; |
481 } | 535 } |
482 | 536 |
483 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 537 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
484 Bind(&ReadDirectoryWorker::DoWorkOnUIThread, this)); | 538 Bind(&ReadDirectoryWorker::DoWorkOnUIThread, this)); |
485 on_task_completed_event_->Wait(); | 539 on_task_completed_event_->Wait(); |
| 540 if (on_shutdown_event_->IsSignaled()) |
| 541 cancel_tasks_flag_.Set(); |
486 } | 542 } |
487 | 543 |
488 // Returns the directory entries for the given directory path. | 544 // Returns the directory entries for the given directory path. |
489 const std::vector<MtpFileEntry>& get_file_entries() const { | 545 const std::vector<MtpFileEntry>& get_file_entries() const { |
490 return file_entries_; | 546 return file_entries_; |
491 } | 547 } |
492 | 548 |
493 // Returns the |media_task_runner_| associated with this worker object. | 549 // Returns the |media_task_runner_| associated with this worker object. |
494 // This function is exposed for WorkerDeleter struct to access the | 550 // This function is exposed for WorkerDeleter struct to access the |
495 // |media_task_runner_|. | 551 // |media_task_runner_|. |
496 SequencedTaskRunner* media_task_runner() const { | 552 SequencedTaskRunner* media_task_runner() const { |
497 return media_task_runner_.get(); | 553 return media_task_runner_.get(); |
498 } | 554 } |
499 | 555 |
500 private: | 556 private: |
501 friend struct WorkerDeleter<ReadDirectoryWorker>; | 557 friend struct WorkerDeleter<ReadDirectoryWorker>; |
502 friend class DeleteHelper<ReadDirectoryWorker>; | 558 friend class DeleteHelper<ReadDirectoryWorker>; |
503 friend class RefCountedThreadSafe<ReadDirectoryWorker, | 559 friend class RefCountedThreadSafe<ReadDirectoryWorker, |
504 ReadDirectoryWorkerDeleter>; | 560 ReadDirectoryWorkerDeleter>; |
505 | 561 |
506 // Destructed via ReadDirectoryWorkerDeleter. | 562 // Destructed via ReadDirectoryWorkerDeleter. |
507 virtual ~ReadDirectoryWorker() { | 563 virtual ~ReadDirectoryWorker() { |
508 // This object must be destructed on |media_task_runner_|. | 564 // This object must be destructed on |media_task_runner_|. |
509 } | 565 } |
510 | 566 |
511 // Dispatches a request to MediaTransferProtocolManager to read the directory | 567 // Dispatches a request to MediaTransferProtocolManager to read the directory |
512 // entries. This is called on UI thread. | 568 // entries. This is called on UI thread. |
513 void DoWorkOnUIThread() { | 569 void DoWorkOnUIThread() { |
514 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 570 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 571 if (cancel_tasks_flag_.IsSet()) |
| 572 return; |
515 | 573 |
516 if (!dir_path_.empty()) { | 574 if (!dir_path_.empty()) { |
517 GetMediaTransferProtocolManager()->ReadDirectoryByPath( | 575 GetMediaTransferProtocolManager()->ReadDirectoryByPath( |
518 device_handle_, dir_path_, | 576 device_handle_, dir_path_, |
519 Bind(&ReadDirectoryWorker::OnDidWorkOnUIThread, this)); | 577 Bind(&ReadDirectoryWorker::OnDidWorkOnUIThread, this)); |
520 } else { | 578 } else { |
521 GetMediaTransferProtocolManager()->ReadDirectoryById( | 579 GetMediaTransferProtocolManager()->ReadDirectoryById( |
522 device_handle_, dir_entry_id_, | 580 device_handle_, dir_entry_id_, |
523 Bind(&ReadDirectoryWorker::OnDidWorkOnUIThread, this)); | 581 Bind(&ReadDirectoryWorker::OnDidWorkOnUIThread, this)); |
524 } | 582 } |
525 } | 583 } |
526 | 584 |
527 // Query callback for DoWorkOnUIThread(). On success, |file_entries| has the | 585 // Query callback for DoWorkOnUIThread(). On success, |file_entries| has the |
528 // directory file entries. |error| is true if there was an error. This | 586 // directory file entries. |error| is true if there was an error. This |
529 // function signals to unblock |media_task_runner_|. | 587 // function signals to unblock |media_task_runner_|. |
530 void OnDidWorkOnUIThread(const std::vector<MtpFileEntry>& file_entries, | 588 void OnDidWorkOnUIThread(const std::vector<MtpFileEntry>& file_entries, |
531 bool error) { | 589 bool error) { |
532 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 590 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 591 if (cancel_tasks_flag_.IsSet()) |
| 592 return; |
| 593 |
533 if (!error) | 594 if (!error) |
534 file_entries_ = file_entries; | 595 file_entries_ = file_entries; |
535 on_task_completed_event_->Signal(); | 596 on_task_completed_event_->Signal(); |
536 } | 597 } |
537 | 598 |
538 // Stores the device handle to communicate with storage device. | 599 // Stores the device handle to communicate with storage device. |
539 const std::string device_handle_; | 600 const std::string device_handle_; |
540 | 601 |
541 // Stores the directory path whose contents needs to be listed. | 602 // Stores the directory path whose contents needs to be listed. |
542 const std::string dir_path_; | 603 const std::string dir_path_; |
(...skipping 10 matching lines...) Expand all Loading... |
553 // TODO(kmadhusu): Remove this WaitableEvent after modifying the | 614 // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
554 // DeviceMediaFileUtil functions as asynchronous functions. | 615 // DeviceMediaFileUtil functions as asynchronous functions. |
555 WaitableEvent* on_task_completed_event_; | 616 WaitableEvent* on_task_completed_event_; |
556 | 617 |
557 // Stores a reference to waitable event associated with the shut down message. | 618 // Stores a reference to waitable event associated with the shut down message. |
558 WaitableEvent* on_shutdown_event_; | 619 WaitableEvent* on_shutdown_event_; |
559 | 620 |
560 // Stores the result of read directory request. | 621 // Stores the result of read directory request. |
561 std::vector<MtpFileEntry> file_entries_; | 622 std::vector<MtpFileEntry> file_entries_; |
562 | 623 |
| 624 // Set to ignore the request results. This will be set when |
| 625 // MTPDeviceDelegateImplLinux object is about to be deleted. |
| 626 // |on_task_completed_event_| and |on_shutdown_event_| should not be |
| 627 // dereferenced when this is set. |
| 628 base::CancellationFlag cancel_tasks_flag_; |
| 629 |
563 DISALLOW_COPY_AND_ASSIGN(ReadDirectoryWorker); | 630 DISALLOW_COPY_AND_ASSIGN(ReadDirectoryWorker); |
564 }; | 631 }; |
565 | 632 |
566 // Simply enumerate each files from a given file entry list. | 633 // Simply enumerate each files from a given file entry list. |
567 // Used to enumerate top-level files of an media file system. | 634 // Used to enumerate top-level files of an media file system. |
568 class MediaFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { | 635 class MediaFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { |
569 public: | 636 public: |
570 explicit MediaFileEnumerator(const std::vector<MtpFileEntry>& entries) | 637 explicit MediaFileEnumerator(const std::vector<MtpFileEntry>& entries) |
571 : file_entries_(entries), | 638 : file_entries_(entries), |
572 file_entry_iter_(file_entries_.begin()) { | 639 file_entry_iter_(file_entries_.begin()) { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
725 const std::string& device_location) | 792 const std::string& device_location) |
726 : device_path_(device_location), | 793 : device_path_(device_location), |
727 on_task_completed_event_(false, false), | 794 on_task_completed_event_(false, false), |
728 on_shutdown_event_(true, false) { | 795 on_shutdown_event_(true, false) { |
729 CHECK(!device_path_.empty()); | 796 CHECK(!device_path_.empty()); |
730 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 797 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
731 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); | 798 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); |
732 base::SequencedWorkerPool::SequenceToken media_sequence_token = | 799 base::SequencedWorkerPool::SequenceToken media_sequence_token = |
733 pool->GetNamedSequenceToken("media-task-runner"); | 800 pool->GetNamedSequenceToken("media-task-runner"); |
734 media_task_runner_ = pool->GetSequencedTaskRunner(media_sequence_token); | 801 media_task_runner_ = pool->GetSequencedTaskRunner(media_sequence_token); |
735 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, | |
736 content::NotificationService::AllSources()); | |
737 | |
738 DCHECK(media_task_runner_); | |
739 } | |
740 | |
741 MTPDeviceDelegateImplLinux::~MTPDeviceDelegateImplLinux() { | |
742 registrar_.RemoveAll(); | |
743 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
744 GetMediaTransferProtocolManager()->CloseStorage(device_handle_, | |
745 Bind(&DoNothing)); | |
746 } | 802 } |
747 | 803 |
748 PlatformFileError MTPDeviceDelegateImplLinux::GetFileInfo( | 804 PlatformFileError MTPDeviceDelegateImplLinux::GetFileInfo( |
749 const FilePath& file_path, | 805 const FilePath& file_path, |
750 PlatformFileInfo* file_info) { | 806 PlatformFileInfo* file_info) { |
751 if (!LazyInit()) | 807 if (!LazyInit()) |
752 return base::PLATFORM_FILE_ERROR_FAILED; | 808 return base::PLATFORM_FILE_ERROR_FAILED; |
753 | 809 |
754 scoped_refptr<GetFileInfoWorker> worker(new GetFileInfoWorker( | 810 scoped_refptr<GetFileInfoWorker> worker(new GetFileInfoWorker( |
755 device_handle_, GetDeviceRelativePath(device_path_, file_path.value()), | 811 device_handle_, GetDeviceRelativePath(device_path_, file_path.value()), |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
819 // Modify the last modified time to null. This prevents the time stamp | 875 // Modify the last modified time to null. This prevents the time stamp |
820 // verfication in LocalFileStreamReader. | 876 // verfication in LocalFileStreamReader. |
821 file_info->last_modified = base::Time(); | 877 file_info->last_modified = base::Time(); |
822 return error; | 878 return error; |
823 } | 879 } |
824 | 880 |
825 SequencedTaskRunner* MTPDeviceDelegateImplLinux::GetMediaTaskRunner() { | 881 SequencedTaskRunner* MTPDeviceDelegateImplLinux::GetMediaTaskRunner() { |
826 return media_task_runner_.get(); | 882 return media_task_runner_.get(); |
827 } | 883 } |
828 | 884 |
829 void MTPDeviceDelegateImplLinux::DeleteOnCorrectThread() const { | 885 void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() { |
830 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 886 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
831 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this); | 887 // Caution: This function is called on the IO thread. Access only the thread |
832 return; | 888 // safe member variables in this function. Do all the clean up operations in |
833 } | 889 // DeleteDelegateOnTaskRunner(). |
834 delete this; | 890 on_shutdown_event_.Signal(); |
| 891 on_task_completed_event_.Signal(); |
| 892 media_task_runner_->PostTask( |
| 893 FROM_HERE, |
| 894 base::Bind(&MTPDeviceDelegateImplLinux::DeleteDelegateOnTaskRunner, |
| 895 base::Unretained(this))); |
835 } | 896 } |
836 | 897 |
837 void MTPDeviceDelegateImplLinux::Observe( | 898 base::WeakPtr<fileapi::MTPDeviceDelegate> MTPDeviceDelegateImplLinux:: |
838 int type, | 899 GetAsWeakPtrOnIOThread() { |
839 const content::NotificationSource& source, | 900 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
840 const content::NotificationDetails& details) { | 901 base::WeakPtr<fileapi::MTPDeviceDelegate> delegate = AsWeakPtr(); |
841 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type); | 902 // The weak pointer is instantiated on the IO thread, but only accessed on |
842 on_shutdown_event_.Signal(); | 903 // |media_task_runner_|. Therefore, detach from the current thread. |
843 on_task_completed_event_.Signal(); | 904 DetachFromThread(); |
| 905 return delegate; |
| 906 } |
| 907 |
| 908 MTPDeviceDelegateImplLinux::~MTPDeviceDelegateImplLinux() { |
| 909 DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); |
| 910 // Do all the clean up operations on DeleteDelegateOnTaskRunner(). |
844 } | 911 } |
845 | 912 |
846 bool MTPDeviceDelegateImplLinux::LazyInit() { | 913 bool MTPDeviceDelegateImplLinux::LazyInit() { |
847 DCHECK(media_task_runner_); | 914 DCHECK(media_task_runner_); |
848 DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); | 915 DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); |
849 | 916 |
850 if (!device_handle_.empty()) | 917 if (!device_handle_.empty()) |
851 return true; // Already successfully initialized. | 918 return true; // Already successfully initialized. |
852 | 919 |
853 std::string storage_name; | 920 std::string storage_name; |
854 RemoveChars(device_path_, kRootPath, &storage_name); | 921 RemoveChars(device_path_, kRootPath, &storage_name); |
855 DCHECK(!storage_name.empty()); | 922 DCHECK(!storage_name.empty()); |
856 scoped_refptr<OpenStorageWorker> worker(new OpenStorageWorker( | 923 scoped_refptr<OpenStorageWorker> worker(new OpenStorageWorker( |
857 storage_name, media_task_runner_, &on_task_completed_event_, | 924 storage_name, media_task_runner_, &on_task_completed_event_, |
858 &on_shutdown_event_)); | 925 &on_shutdown_event_)); |
859 worker->Run(); | 926 worker->Run(); |
860 device_handle_ = worker->device_handle(); | 927 device_handle_ = worker->device_handle(); |
861 return !device_handle_.empty(); | 928 return !device_handle_.empty(); |
862 } | 929 } |
863 | 930 |
| 931 void MTPDeviceDelegateImplLinux::DeleteDelegateOnTaskRunner() { |
| 932 DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); |
| 933 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 934 Bind(&CloseStorageOnUIThread, device_handle_)); |
| 935 delete this; |
| 936 } |
| 937 |
864 } // namespace chrome | 938 } // namespace chrome |
OLD | NEW |