Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(597)

Side by Side Diff: chrome/browser/media_gallery/mtp_device_delegate_impl_linux.cc

Issue 11358243: Redesigned and refactored ScopedMTPDeviceMapEntry, MTPDeviceMapService & MTPDeviceDelegate classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix unit test Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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_;
Lei Zhang 2012/11/21 01:33:30 Do you need both |cancel_tasks_flag_| and |on_shut
kmadhusu 2012/11/21 04:09:53 Yes, we need both |cancel_tasks_flag_| and |on_shu
Lei Zhang 2012/11/21 06:46:39 Can you explain how we can dereference an invalid
kmadhusu 2012/11/22 00:49:07 We can signal the MTR from MTPDeviceDelegateImplLi
Lei Zhang 2012/11/22 03:09:41 So what if we make |cancel_tasks_flag_| a WeakPtr.
kmadhusu 2012/11/26 23:23:51 WeakPtr's created from a WeakPtrFactory should be
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
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
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
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
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
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
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
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();
Lei Zhang 2012/11/21 01:33:30 How does this work? The comment in weak_ptr.h says
kmadhusu 2012/11/21 04:09:53 DetachFromThread() does not nullify the |delegate|
Lei Zhang 2012/11/21 06:46:39 How about we remove GetAsWeakPtrOnIOThread() altog
kmadhusu 2012/11/22 00:49:07 I don't want to store a raw pointer in FileSystemO
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698