| 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 |