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