summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkmadhusu@chromium.org <kmadhusu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-18 21:39:38 +0000
committerkmadhusu@chromium.org <kmadhusu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-18 21:39:38 +0000
commit09b0ec2edd2fae3fc75811bc9363045686e75341 (patch)
treef20b7eff76e4bc74dec0b1d6b09121aca0c31c20
parent946937cc9998b1abdab95ff69976589d2b0d10ad (diff)
downloadchromium_src-09b0ec2edd2fae3fc75811bc9363045686e75341.zip
chromium_src-09b0ec2edd2fae3fc75811bc9363045686e75341.tar.gz
chromium_src-09b0ec2edd2fae3fc75811bc9363045686e75341.tar.bz2
[Media Gallery] When a NOTIFICATION_APP_TERMINATING notification is received, signal the |media_task_runner_| about the shutdown sequence.
BUG=154758 TEST=none Review URL: https://chromiumcodereview.appspot.com/11154014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@162800 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/media_gallery/mtp_device_delegate_impl_linux.cc162
-rw-r--r--chrome/browser/media_gallery/mtp_device_delegate_impl_linux.h23
2 files changed, 152 insertions, 33 deletions
diff --git a/chrome/browser/media_gallery/mtp_device_delegate_impl_linux.cc b/chrome/browser/media_gallery/mtp_device_delegate_impl_linux.cc
index 68dae4f..69e6f0d 100644
--- a/chrome/browser/media_gallery/mtp_device_delegate_impl_linux.cc
+++ b/chrome/browser/media_gallery/mtp_device_delegate_impl_linux.cc
@@ -10,11 +10,12 @@
#include "base/sequenced_task_runner.h"
#include "base/sequenced_task_runner_helpers.h"
#include "base/string_util.h"
-#include "base/synchronization/waitable_event.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/media_transfer_protocol/media_transfer_protocol_manager.h"
#include "chrome/browser/media_transfer_protocol/mtp_file_entry.pb.h"
+#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
using base::Bind;
@@ -97,19 +98,30 @@ class OpenStorageWorker
: public RefCountedThreadSafe<OpenStorageWorker, OpenStorageWorkerDeleter> {
public:
// Constructed on |media_task_runner_| thread.
- OpenStorageWorker(const std::string& name, SequencedTaskRunner* task_runner)
+ OpenStorageWorker(const std::string& name, SequencedTaskRunner* task_runner,
+ WaitableEvent* task_completed_event,
+ WaitableEvent* shutdown_event)
: storage_name_(name),
media_task_runner_(task_runner),
- event_(false, false) {
+ on_task_completed_event_(task_completed_event),
+ on_shutdown_event_(shutdown_event) {
+ DCHECK(on_task_completed_event_);
+ DCHECK(on_shutdown_event_);
}
// This function is invoked on |media_task_runner_| to post the task on UI
// thread. This blocks the |media_task_runner_| until the task is complete.
void Run() {
+ if (on_shutdown_event_->IsSignaled()) {
+ // Process is in shutdown mode.
+ // Do not post any task on |media_task_runner_|.
+ return;
+ }
+
DCHECK(media_task_runner_->RunsTasksOnCurrentThread());
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
Bind(&OpenStorageWorker::DoWorkOnUIThread, this));
- event_.Wait();
+ on_task_completed_event_->Wait();
}
// Returns a device handle string if the OpenStorage() request was
@@ -151,7 +163,7 @@ class OpenStorageWorker
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!error)
device_handle_ = device_handle;
- event_.Signal();
+ on_task_completed_event_->Signal();
}
// Stores the storage name to open the device.
@@ -165,7 +177,10 @@ class OpenStorageWorker
// is complete.
// TODO(kmadhusu): Remove this WaitableEvent after modifying the
// DeviceMediaFileUtil functions as asynchronous functions.
- WaitableEvent event_;
+ WaitableEvent* on_task_completed_event_;
+
+ // Stores a reference to waitable event associated with the shut down message.
+ WaitableEvent* on_shutdown_event_;
// Stores the result of OpenStorage() request.
std::string device_handle_;
@@ -180,20 +195,31 @@ class GetFileInfoWorker
// Constructed on |media_task_runner_| thread.
GetFileInfoWorker(const std::string& handle,
const std::string& path,
- SequencedTaskRunner* task_runner)
+ SequencedTaskRunner* task_runner,
+ WaitableEvent* task_completed_event,
+ WaitableEvent* shutdown_event)
: device_handle_(handle),
path_(path),
media_task_runner_(task_runner),
error_(base::PLATFORM_FILE_OK),
- event_(false, false) {
+ on_task_completed_event_(task_completed_event),
+ on_shutdown_event_(shutdown_event) {
+ DCHECK(on_task_completed_event_);
+ DCHECK(on_shutdown_event_);
}
// This function is invoked on |media_task_runner_| to post the task on UI
// thread. This blocks the |media_task_runner_| until the task is complete.
void Run() {
+ if (on_shutdown_event_->IsSignaled()) {
+ // Process is in shutdown mode.
+ // Do not post any task on |media_task_runner_|.
+ return;
+ }
+
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
Bind(&GetFileInfoWorker::DoWorkOnUIThread, this));
- event_.Wait();
+ on_task_completed_event_->Wait();
}
// Returns GetFileInfo() result and fills in |file_info| with requested file
@@ -250,7 +276,7 @@ class GetFileInfoWorker
base::Time::FromTimeT(file_entry.modification_time());
file_entry_info_.creation_time = base::Time();
}
- event_.Signal();
+ on_task_completed_event_->Signal();
}
// Stores the device handle to query the device.
@@ -273,7 +299,10 @@ class GetFileInfoWorker
// is complete.
// TODO(kmadhusu): Remove this WaitableEvent after modifying the
// DeviceMediaFileUtil functions as asynchronous functions.
- WaitableEvent event_;
+ WaitableEvent* on_task_completed_event_;
+
+ // Stores a reference to waitable event associated with the shut down message.
+ WaitableEvent* on_shutdown_event_;
DISALLOW_COPY_AND_ASSIGN(GetFileInfoWorker);
};
@@ -285,19 +314,30 @@ class ReadFileWorker
// Constructed on |media_task_runner_| thread.
ReadFileWorker(const std::string& handle,
const std::string& path,
- SequencedTaskRunner* task_runner)
+ SequencedTaskRunner* task_runner,
+ WaitableEvent* task_completed_event,
+ WaitableEvent* shutdown_event)
: device_handle_(handle),
path_(path),
media_task_runner_(task_runner),
- event_(false, false) {
+ on_task_completed_event_(task_completed_event),
+ on_shutdown_event_(shutdown_event) {
+ DCHECK(on_task_completed_event_);
+ DCHECK(on_shutdown_event_);
}
// This function is invoked on |media_task_runner_| to post the task on UI
// thread. This blocks the |media_task_runner_| until the task is complete.
void Run() {
+ if (on_shutdown_event_->IsSignaled()) {
+ // Process is in shutdown mode.
+ // Do not post any task on |media_task_runner_|.
+ return;
+ }
+
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
Bind(&ReadFileWorker::DoWorkOnUIThread, this));
- event_.Wait();
+ on_task_completed_event_->Wait();
}
// Returns the media file contents received by ReadFileByPath() callback
@@ -339,7 +379,7 @@ class ReadFileWorker
// pointer/ref rather than by value here to avoid an extra data copy.
data_ = data;
}
- event_.Signal();
+ on_task_completed_event_->Signal();
}
// Stores the device unique identifier to query the device.
@@ -359,7 +399,10 @@ class ReadFileWorker
// is complete.
// TODO(kmadhusu): Remove this WaitableEvent after modifying the
// DeviceMediaFileUtil functions as asynchronous functions.
- WaitableEvent event_;
+ WaitableEvent* on_task_completed_event_;
+
+ // Stores a reference to waitable event associated with the shut down message.
+ WaitableEvent* on_shutdown_event_;
DISALLOW_COPY_AND_ASSIGN(ReadFileWorker);
};
@@ -374,32 +417,48 @@ class ReadDirectoryWorker
// constructed on |media_task_runner_| thread.
ReadDirectoryWorker(const std::string& handle,
const std::string& path,
- SequencedTaskRunner* task_runner)
+ SequencedTaskRunner* task_runner,
+ WaitableEvent* task_completed_event,
+ WaitableEvent* shutdown_event)
: device_handle_(handle),
dir_path_(path),
dir_entry_id_(0),
media_task_runner_(task_runner),
- event_(false, false) {
+ on_task_completed_event_(task_completed_event),
+ on_shutdown_event_(shutdown_event) {
DCHECK(!dir_path_.empty());
+ DCHECK(on_task_completed_event_);
+ DCHECK(on_shutdown_event_);
}
// Construct a worker object given the directory |entry_id|. This object is
// constructed on |media_task_runner_| thread.
ReadDirectoryWorker(const std::string& storage_name,
const uint32_t entry_id,
- SequencedTaskRunner* task_runner)
+ SequencedTaskRunner* task_runner,
+ WaitableEvent* task_completed_event,
+ WaitableEvent* shutdown_event)
: device_handle_(storage_name),
dir_entry_id_(entry_id),
media_task_runner_(task_runner),
- event_(false, false) {
+ on_task_completed_event_(task_completed_event),
+ on_shutdown_event_(shutdown_event) {
+ DCHECK(on_task_completed_event_);
+ DCHECK(on_shutdown_event_);
}
// This function is invoked on |media_task_runner_| to post the task on UI
// thread. This blocks the |media_task_runner_| until the task is complete.
void Run() {
+ if (on_shutdown_event_->IsSignaled()) {
+ // Process is in shutdown mode.
+ // Do not post any task on |media_task_runner_|.
+ return;
+ }
+
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
Bind(&ReadDirectoryWorker::DoWorkOnUIThread, this));
- event_.Wait();
+ on_task_completed_event_->Wait();
}
// Returns the directory entries for the given directory path.
@@ -449,7 +508,7 @@ class ReadDirectoryWorker
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!error)
file_entries_ = file_entries;
- event_.Signal();
+ on_task_completed_event_->Signal();
}
// Stores the device handle to communicate with storage device.
@@ -469,7 +528,10 @@ class ReadDirectoryWorker
// is complete.
// TODO(kmadhusu): Remove this WaitableEvent after modifying the
// DeviceMediaFileUtil functions as asynchronous functions.
- WaitableEvent event_;
+ WaitableEvent* on_task_completed_event_;
+
+ // Stores a reference to waitable event associated with the shut down message.
+ WaitableEvent* on_shutdown_event_;
// Stores the result of read directory request.
std::vector<MtpFileEntry> file_entries_;
@@ -537,11 +599,17 @@ class RecursiveMediaFileEnumerator
public:
RecursiveMediaFileEnumerator(const std::string& handle,
SequencedTaskRunner* task_runner,
- const std::vector<MtpFileEntry>& entries)
+ const std::vector<MtpFileEntry>& entries,
+ WaitableEvent* task_completed_event,
+ WaitableEvent* shutdown_event)
: device_handle_(handle),
media_task_runner_(task_runner),
file_entries_(entries),
- file_entry_iter_(file_entries_.begin()) {
+ file_entry_iter_(file_entries_.begin()),
+ on_task_completed_event_(task_completed_event),
+ on_shutdown_event_(shutdown_event) {
+ DCHECK(on_task_completed_event_);
+ DCHECK(on_shutdown_event_);
current_enumerator_.reset(new MediaFileEnumerator(entries));
}
@@ -551,6 +619,11 @@ class RecursiveMediaFileEnumerator
// Returns the next file entry path on success and empty file path on
// failure or when it reaches the end.
virtual FilePath Next() OVERRIDE {
+ if (on_shutdown_event_->IsSignaled()) {
+ // Process is in shut down mode.
+ return FilePath();
+ }
+
FilePath path = current_enumerator_->Next();
if (!path.empty())
return path;
@@ -565,7 +638,8 @@ class RecursiveMediaFileEnumerator
// Create a ReadDirectoryWorker object to enumerate sub directories.
scoped_refptr<ReadDirectoryWorker> worker(new ReadDirectoryWorker(
- device_handle_, next_file_entry.item_id(), media_task_runner_));
+ device_handle_, next_file_entry.item_id(), media_task_runner_,
+ on_task_completed_event_, on_shutdown_event_));
worker->Run();
if (!worker->get_file_entries().empty()) {
current_enumerator_.reset(
@@ -611,6 +685,13 @@ class RecursiveMediaFileEnumerator
// Enumerator to access current directory Id/path entries.
scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> current_enumerator_;
+ // |media_task_runner_| can wait on this event until the requested operation
+ // is complete.
+ WaitableEvent* on_task_completed_event_;
+
+ // Stores a reference to waitable event associated with the shut down message.
+ WaitableEvent* on_shutdown_event_;
+
DISALLOW_COPY_AND_ASSIGN(RecursiveMediaFileEnumerator);
};
@@ -618,17 +699,23 @@ class RecursiveMediaFileEnumerator
MtpDeviceDelegateImplLinux::MtpDeviceDelegateImplLinux(
const std::string& device_location)
- : device_path_(device_location) {
+ : device_path_(device_location),
+ on_task_completed_event_(false, false),
+ on_shutdown_event_(true, false) {
CHECK(!device_path_.empty());
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
base::SequencedWorkerPool::SequenceToken media_sequence_token =
pool->GetNamedSequenceToken("media-task-runner");
media_task_runner_ = pool->GetSequencedTaskRunner(media_sequence_token);
+ registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
+ content::NotificationService::AllSources());
+
DCHECK(media_task_runner_);
}
MtpDeviceDelegateImplLinux::~MtpDeviceDelegateImplLinux() {
+ registrar_.RemoveAll();
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
GetMediaTransferProtocolManager()->CloseStorage(device_handle_,
Bind(&DoNothing));
@@ -642,7 +729,7 @@ PlatformFileError MtpDeviceDelegateImplLinux::GetFileInfo(
scoped_refptr<GetFileInfoWorker> worker(new GetFileInfoWorker(
device_handle_, GetDeviceRelativePath(device_path_, file_path.value()),
- media_task_runner_));
+ media_task_runner_, &on_task_completed_event_, &on_shutdown_event_));
worker->Run();
return worker->get_file_info(file_info);
}
@@ -656,7 +743,7 @@ MtpDeviceDelegateImplLinux::CreateFileEnumerator(
scoped_refptr<ReadDirectoryWorker> worker(new ReadDirectoryWorker(
device_handle_, GetDeviceRelativePath(device_path_, root.value()),
- media_task_runner_));
+ media_task_runner_, &on_task_completed_event_, &on_shutdown_event_));
worker->Run();
if (worker->get_file_entries().empty())
@@ -664,7 +751,8 @@ MtpDeviceDelegateImplLinux::CreateFileEnumerator(
if (recursive) {
return new RecursiveMediaFileEnumerator(
- device_handle_, media_task_runner_, worker->get_file_entries());
+ device_handle_, media_task_runner_, worker->get_file_entries(),
+ &on_task_completed_event_, &on_shutdown_event_);
}
return new MediaFileEnumerator(worker->get_file_entries());
}
@@ -679,7 +767,7 @@ PlatformFileError MtpDeviceDelegateImplLinux::CreateSnapshotFile(
scoped_refptr<ReadFileWorker> worker(new ReadFileWorker(
device_handle_,
GetDeviceRelativePath(device_path_, device_file_path.value()),
- media_task_runner_));
+ media_task_runner_, &on_task_completed_event_, &on_shutdown_event_));
worker->Run();
const std::string& file_data = worker->data();
@@ -710,6 +798,15 @@ void MtpDeviceDelegateImplLinux::DeleteOnCorrectThread() const {
delete this;
}
+void MtpDeviceDelegateImplLinux::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
+ on_shutdown_event_.Signal();
+ on_task_completed_event_.Signal();
+}
+
bool MtpDeviceDelegateImplLinux::LazyInit() {
DCHECK(media_task_runner_);
DCHECK(media_task_runner_->RunsTasksOnCurrentThread());
@@ -721,7 +818,8 @@ bool MtpDeviceDelegateImplLinux::LazyInit() {
RemoveChars(device_path_, kRootPath, &storage_name);
DCHECK(!storage_name.empty());
scoped_refptr<OpenStorageWorker> worker(new OpenStorageWorker(
- storage_name, media_task_runner_));
+ storage_name, media_task_runner_, &on_task_completed_event_,
+ &on_shutdown_event_));
worker->Run();
device_handle_ = worker->device_handle();
return !device_handle_.empty();
diff --git a/chrome/browser/media_gallery/mtp_device_delegate_impl_linux.h b/chrome/browser/media_gallery/mtp_device_delegate_impl_linux.h
index c1f0e3e..eb21b30 100644
--- a/chrome/browser/media_gallery/mtp_device_delegate_impl_linux.h
+++ b/chrome/browser/media_gallery/mtp_device_delegate_impl_linux.h
@@ -7,6 +7,9 @@
#include "base/memory/ref_counted.h"
#include "base/platform_file.h"
+#include "base/synchronization/waitable_event.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
#include "webkit/fileapi/file_system_file_util.h"
#include "webkit/fileapi/media/mtp_device_delegate.h"
@@ -22,7 +25,8 @@ namespace chrome {
// operations. This class contains platform specific code to communicate with
// the attached MTP storage. Instantiate this class per MTP storage.
// This class is ref-counted, because MtpDeviceDelegate is ref-counted.
-class MtpDeviceDelegateImplLinux : public fileapi::MtpDeviceDelegate {
+class MtpDeviceDelegateImplLinux : public fileapi::MtpDeviceDelegate,
+ public content::NotificationObserver {
public:
// Constructed on UI thread. Defer the device initializations until the first
// file operation request. Do all the initializations in LazyInit() function.
@@ -49,6 +53,11 @@ class MtpDeviceDelegateImplLinux : public fileapi::MtpDeviceDelegate {
// Private because this class is ref-counted.
virtual ~MtpDeviceDelegateImplLinux();
+ // content::NotificationObserver implementation.
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
// Opens the device for communication. This function is called on
// |media_task_runner_|. Returns true if the device is ready for
// communication, else false.
@@ -66,6 +75,18 @@ class MtpDeviceDelegateImplLinux : public fileapi::MtpDeviceDelegate {
// operations are posted on |media_task_runner_|.
scoped_refptr<base::SequencedTaskRunner> media_task_runner_;
+ // |media_task_runner_| can wait on this event until the requested task is
+ // complete.
+ base::WaitableEvent on_task_completed_event_;
+
+ // Used to notify |media_task_runner_| pending tasks about the shutdown
+ // sequence.
+ base::WaitableEvent on_shutdown_event_;
+
+ // Handles registering notifications with the NotificationService.
+ // Used to listen for application termination message.
+ content::NotificationRegistrar registrar_;
+
DISALLOW_COPY_AND_ASSIGN(MtpDeviceDelegateImplLinux);
};