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