Commit 340ba206 authored by mtomasz's avatar mtomasz Committed by Commit bot

[fsp] Implement storage::WatcherManager for FSP.

This patch implements the storage::WatcherManager interface, which simply calls
the Add/RemoveWatcher methods on ProvidedFileSystemInterface implementations.

An additional callback has been added to AddWatcher, so it's easy to notify
WatcherManager about changes. Without that, we would have to observe provided
file system objects and store callbacks passed to WatcherManager::AddWatcher,
which would make the code complex.

Along the way the storage::WatcherManager interface has been refactored to have
consistent naming with FSP watching methods.

TEST=unit_tests: *ProvidedFileSystem*
BUG=248427

Review URL: https://codereview.chromium.org/689603002

Cr-Commit-Position: refs/heads/master@{#302229}
parent 55ef2cde
......@@ -17,6 +17,7 @@
#include "chrome/browser/chromeos/file_system_provider/service.h"
#include "chrome/common/extensions/api/file_system_provider.h"
#include "chrome/common/extensions/api/file_system_provider_internal.h"
#include "storage/browser/fileapi/watcher_manager.h"
using chromeos::file_system_provider::MountOptions;
using chromeos::file_system_provider::ProvidedFileSystemInfo;
......@@ -36,18 +37,18 @@ const char kInvalidNotificationErrorMessage[] = "The notification is invalid.";
// Converts the change type from the IDL type to a native type. |changed_type|
// must be specified (not CHANGE_TYPE_NONE).
ProvidedFileSystemObserver::ChangeType ParseChangeType(
storage::WatcherManager::ChangeType ParseChangeType(
const api::file_system_provider::ChangeType& change_type) {
switch (change_type) {
case api::file_system_provider::CHANGE_TYPE_CHANGED:
return ProvidedFileSystemObserver::CHANGED;
return storage::WatcherManager::CHANGED;
case api::file_system_provider::CHANGE_TYPE_DELETED:
return ProvidedFileSystemObserver::DELETED;
return storage::WatcherManager::DELETED;
default:
break;
}
NOTREACHED();
return ProvidedFileSystemObserver::CHANGED;
return storage::WatcherManager::CHANGED;
}
// Convert the change from the IDL type to a native type. The reason IDL types
......
......@@ -326,7 +326,9 @@ ProvidedFileSystemInterface::AbortCallback FakeProvidedFileSystem::AddWatcher(
const base::FilePath& entry_watcher,
bool recursive,
bool persistent,
const storage::AsyncFileUtil::StatusCallback& callback) {
const storage::AsyncFileUtil::StatusCallback& callback,
const storage::WatcherManager::NotificationCallback&
notification_callback) {
// TODO(mtomasz): Implement it once needed.
return PostAbortableTask(base::Bind(callback, base::File::FILE_OK));
}
......@@ -368,7 +370,7 @@ void FakeProvidedFileSystem::RemoveObserver(
bool FakeProvidedFileSystem::Notify(
const base::FilePath& entry_path,
bool recursive,
ProvidedFileSystemObserver::ChangeType change_type,
storage::WatcherManager::ChangeType change_type,
scoped_ptr<ProvidedFileSystemObserver::Changes> changes,
const std::string& tag) {
NOTREACHED();
......
......@@ -18,6 +18,8 @@
#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
#include "chrome/browser/chromeos/file_system_provider/provided_file_system_observer.h"
#include "chrome/browser/chromeos/file_system_provider/watcher.h"
#include "storage/browser/fileapi/async_file_util.h"
#include "storage/browser/fileapi/watcher_manager.h"
#include "url/gurl.h"
class Profile;
......@@ -131,7 +133,9 @@ class FakeProvidedFileSystem : public ProvidedFileSystemInterface {
const base::FilePath& entry_path,
bool recursive,
bool persistent,
const storage::AsyncFileUtil::StatusCallback& callback) override;
const storage::AsyncFileUtil::StatusCallback& callback,
const storage::WatcherManager::NotificationCallback&
notification_callback) override;
virtual void RemoveWatcher(
const GURL& origin,
const base::FilePath& entry_path,
......@@ -144,7 +148,7 @@ class FakeProvidedFileSystem : public ProvidedFileSystemInterface {
virtual void RemoveObserver(ProvidedFileSystemObserver* observer) override;
virtual bool Notify(const base::FilePath& entry_path,
bool recursive,
ProvidedFileSystemObserver::ChangeType change_type,
storage::WatcherManager::ChangeType change_type,
scoped_ptr<ProvidedFileSystemObserver::Changes> changes,
const std::string& tag) override;
virtual base::WeakPtr<ProvidedFileSystemInterface> GetWeakPtr() override;
......
......@@ -10,6 +10,7 @@
#include "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.h"
#include "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer.h"
#include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h"
#include "chrome/browser/chromeos/file_system_provider/fileapi/watcher_manager.h"
#include "content/public/browser/browser_thread.h"
#include "storage/browser/blob/file_stream_reader.h"
#include "storage/browser/fileapi/file_stream_writer.h"
......@@ -32,7 +33,9 @@ const int kWriterBufferSize = 512 * 1024; // 512KB.
} // namespace
BackendDelegate::BackendDelegate()
: async_file_util_(new internal::ProviderAsyncFileUtil) {}
: async_file_util_(new internal::ProviderAsyncFileUtil),
watcher_manager_(new WatcherManager) {
}
BackendDelegate::~BackendDelegate() {}
......@@ -73,8 +76,9 @@ scoped_ptr<storage::FileStreamWriter> BackendDelegate::CreateFileStreamWriter(
storage::WatcherManager* BackendDelegate::GetWatcherManager(
const storage::FileSystemURL& url) {
NOTIMPLEMENTED();
return NULL;
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(storage::kFileSystemTypeProvided, url.type());
return watcher_manager_.get();
}
void BackendDelegate::GetRedirectURLForContents(
......
......@@ -50,6 +50,7 @@ class BackendDelegate : public chromeos::FileSystemBackendDelegate {
private:
scoped_ptr<storage::AsyncFileUtil> async_file_util_;
scoped_ptr<storage::WatcherManager> watcher_manager_;
DISALLOW_COPY_AND_ASSIGN(BackendDelegate);
};
......
......@@ -14,6 +14,7 @@ namespace file_system_provider {
class FileSystemInterface;
// TODO(mtomasz): Remove this namespace.
namespace internal {
// The implementation of storage::AsyncFileUtil for provided file systems. It is
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/file_system_provider/fileapi/watcher_manager.h"
#include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
#include "content/public/browser/browser_thread.h"
#include "storage/browser/fileapi/file_system_url.h"
using content::BrowserThread;
namespace chromeos {
namespace file_system_provider {
WatcherManager::WatcherManager() {
}
WatcherManager::~WatcherManager() {
}
void WatcherManager::AddWatcher(
const storage::FileSystemURL& url,
bool recursive,
const StatusCallback& callback,
const NotificationCallback& notification_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
util::FileSystemURLParser parser(url);
if (!parser.Parse()) {
callback.Run(base::File::FILE_ERROR_SECURITY);
return;
}
parser.file_system()->AddWatcher(url.origin(),
parser.file_path(),
recursive,
false /* persistent */,
callback,
notification_callback);
}
void WatcherManager::RemoveWatcher(const storage::FileSystemURL& url,
bool recursive,
const StatusCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
util::FileSystemURLParser parser(url);
if (!parser.Parse()) {
callback.Run(base::File::FILE_ERROR_SECURITY);
return;
}
parser.file_system()->RemoveWatcher(
url.origin(), parser.file_path(), recursive, callback);
}
} // namespace file_system_provider
} // namespace chromeos
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_FILEAPI_WATCHER_MANAGER_H_
#define CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_FILEAPI_WATCHER_MANAGER_H_
#include "storage/browser/fileapi/watcher_manager.h"
namespace storage {
class FileSystemURL;
} // namespace storage
namespace chromeos {
namespace file_system_provider {
// Exposes entry watching capability to fileapi.
class WatcherManager : public storage::WatcherManager {
public:
WatcherManager();
virtual ~WatcherManager();
// storage::WatcherManager overrides.
virtual void AddWatcher(
const storage::FileSystemURL& url,
bool recursive,
const StatusCallback& callback,
const NotificationCallback& notification_callback) override;
virtual void RemoveWatcher(const storage::FileSystemURL& url,
bool recursive,
const StatusCallback& callback) override;
};
} // namespace file_system_provider
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_FILEAPI_WATCHER_MANAGER_H_
......@@ -369,29 +369,37 @@ ProvidedFileSystem::AbortCallback ProvidedFileSystem::AddWatcher(
const base::FilePath& entry_path,
bool recursive,
bool persistent,
const storage::AsyncFileUtil::StatusCallback& callback) {
const storage::AsyncFileUtil::StatusCallback& callback,
const storage::WatcherManager::NotificationCallback&
notification_callback) {
// TODO(mtomasz): Wrap the entire method body with an asynchronous queue to
// avoid races.
if (persistent && !file_system_info_.supports_notify_tag()) {
OnAddWatcherCompleted(origin,
entry_path,
if (persistent && (!file_system_info_.supports_notify_tag() ||
!notification_callback.is_null())) {
OnAddWatcherCompleted(entry_path,
recursive,
persistent,
Subscriber(),
callback,
base::File::FILE_ERROR_INVALID_OPERATION);
return AbortCallback();
}
// Create a candidate subscriber. This could be done in OnAddWatcherCompleted,
// but base::Bind supports only up to 7 arguments.
Subscriber subscriber;
subscriber.origin = origin;
subscriber.persistent = persistent;
subscriber.notification_callback = notification_callback;
const WatcherKey key(entry_path, recursive);
const Watchers::const_iterator it = watchers_.find(key);
if (it != watchers_.end()) {
const bool exists =
it->second.subscribers.find(origin) != it->second.subscribers.end();
OnAddWatcherCompleted(
origin,
entry_path,
recursive,
persistent,
subscriber,
callback,
exists ? base::File::FILE_ERROR_EXISTS : base::File::FILE_OK);
return AbortCallback();
......@@ -406,17 +414,15 @@ ProvidedFileSystem::AbortCallback ProvidedFileSystem::AddWatcher(
recursive,
base::Bind(&ProvidedFileSystem::OnAddWatcherCompleted,
weak_ptr_factory_.GetWeakPtr(),
origin,
entry_path,
recursive,
persistent,
subscriber,
callback))));
if (!request_id) {
OnAddWatcherCompleted(origin,
entry_path,
OnAddWatcherCompleted(entry_path,
recursive,
persistent,
subscriber,
callback,
base::File::FILE_ERROR_SECURITY);
return AbortCallback();
......@@ -498,12 +504,12 @@ void ProvidedFileSystem::RemoveObserver(ProvidedFileSystemObserver* observer) {
bool ProvidedFileSystem::Notify(
const base::FilePath& entry_path,
bool recursive,
ProvidedFileSystemObserver::ChangeType change_type,
storage::WatcherManager::ChangeType change_type,
scoped_ptr<ProvidedFileSystemObserver::Changes> changes,
const std::string& tag) {
const WatcherKey key(entry_path, recursive);
const Watchers::iterator it = watchers_.find(key);
if (it == watchers_.end())
const auto& watcher_it = watchers_.find(key);
if (watcher_it == watchers_.end())
return false;
// The tag must be provided if and only if it's explicitly supported.
......@@ -521,13 +527,22 @@ bool ProvidedFileSystem::Notify(
recursive,
change_type,
base::Passed(&changes),
it->second.last_tag,
watcher_it->second.last_tag,
tag)));
// Call all notification callbacks (if any).
for (const auto& subscriber_it : watcher_it->second.subscribers) {
const storage::WatcherManager::NotificationCallback& notification_callback =
subscriber_it.second.notification_callback;
if (!notification_callback.is_null())
notification_callback.Run(change_type);
}
// Notify all observers.
FOR_EACH_OBSERVER(ProvidedFileSystemObserver,
observers_,
OnWatcherChanged(file_system_info_,
it->second,
watcher_it->second,
change_type,
changes_ref,
auto_updater->CreateCallback()));
......@@ -557,10 +572,9 @@ void ProvidedFileSystem::Abort(
}
void ProvidedFileSystem::OnAddWatcherCompleted(
const GURL& origin,
const base::FilePath& entry_path,
bool recursive,
bool persistent,
const Subscriber& subscriber,
const storage::AsyncFileUtil::StatusCallback& callback,
base::File::Error result) {
if (result != base::File::FILE_OK) {
......@@ -575,11 +589,11 @@ void ProvidedFileSystem::OnAddWatcherCompleted(
return;
}
// TODO(mtomasz): Add a queue to prevent races.
Watcher* const watcher = &watchers_[key];
watcher->entry_path = entry_path;
watcher->recursive = recursive;
watcher->subscribers[origin].origin = origin;
watcher->subscribers[origin].persistent |= persistent;
watcher->subscribers[subscriber.origin] = subscriber;
FOR_EACH_OBSERVER(ProvidedFileSystemObserver,
observers_,
......@@ -591,7 +605,7 @@ void ProvidedFileSystem::OnAddWatcherCompleted(
void ProvidedFileSystem::OnNotifyCompleted(
const base::FilePath& entry_path,
bool recursive,
ProvidedFileSystemObserver::ChangeType change_type,
storage::WatcherManager::ChangeType change_type,
scoped_ptr<ProvidedFileSystemObserver::Changes> /* changes */,
const std::string& last_tag,
const std::string& tag) {
......@@ -618,7 +632,7 @@ void ProvidedFileSystem::OnNotifyCompleted(
OnWatcherTagUpdated(file_system_info_, it->second));
// If the watched entry is deleted, then remove the watcher.
if (change_type == ProvidedFileSystemObserver::DELETED) {
if (change_type == storage::WatcherManager::DELETED) {
// Make a copy, since the |it| iterator will get invalidated on the last
// subscriber.
Subscribers subscribers = it->second.subscribers;
......
......@@ -16,6 +16,7 @@
#include "chrome/browser/chromeos/file_system_provider/provided_file_system_observer.h"
#include "chrome/browser/chromeos/file_system_provider/request_manager.h"
#include "storage/browser/fileapi/async_file_util.h"
#include "storage/browser/fileapi/watcher_manager.h"
#include "url/gurl.h"
class Profile;
......@@ -142,7 +143,9 @@ class ProvidedFileSystem : public ProvidedFileSystemInterface {
const base::FilePath& entry_path,
bool recursive,
bool persistent,
const storage::AsyncFileUtil::StatusCallback& callback) override;
const storage::AsyncFileUtil::StatusCallback& callback,
const storage::WatcherManager::NotificationCallback&
notification_callback) override;
virtual void RemoveWatcher(
const GURL& origin,
const base::FilePath& entry_path,
......@@ -155,7 +158,7 @@ class ProvidedFileSystem : public ProvidedFileSystemInterface {
virtual void RemoveObserver(ProvidedFileSystemObserver* observer) override;
virtual bool Notify(const base::FilePath& entry_path,
bool recursive,
ProvidedFileSystemObserver::ChangeType change_type,
storage::WatcherManager::ChangeType change_type,
scoped_ptr<ProvidedFileSystemObserver::Changes> changes,
const std::string& tag) override;
virtual base::WeakPtr<ProvidedFileSystemInterface> GetWeakPtr() override;
......@@ -169,10 +172,9 @@ class ProvidedFileSystem : public ProvidedFileSystemInterface {
// Called when adding a watcher is completed with either success or en error.
void OnAddWatcherCompleted(
const GURL& origin,
const base::FilePath& entry_path,
bool recursive,
bool persistent,
const Subscriber& subscriber,
const storage::AsyncFileUtil::StatusCallback& callback,
base::File::Error result);
......@@ -181,7 +183,7 @@ class ProvidedFileSystem : public ProvidedFileSystemInterface {
void OnNotifyCompleted(
const base::FilePath& entry_path,
bool recursive,
ProvidedFileSystemObserver::ChangeType change_type,
storage::WatcherManager::ChangeType change_type,
scoped_ptr<ProvidedFileSystemObserver::Changes> changes,
const std::string& last_tag,
const std::string& tag);
......
......@@ -17,6 +17,7 @@
#include "chrome/browser/chromeos/file_system_provider/provided_file_system_observer.h"
#include "chrome/browser/chromeos/file_system_provider/watcher.h"
#include "storage/browser/fileapi/async_file_util.h"
#include "storage/browser/fileapi/watcher_manager.h"
#include "url/gurl.h"
class EventRouter;
......@@ -177,13 +178,16 @@ class ProvidedFileSystemInterface {
const storage::AsyncFileUtil::StatusCallback& callback) = 0;
// Requests adding a watcher on an entry. |recursive| must not be true for
// files.
// files. |callback| is optional, but it can't be used for persistent
// watchers.
virtual AbortCallback AddWatcher(
const GURL& origin,
const base::FilePath& entry_path,
bool recursive,
bool persistent,
const storage::AsyncFileUtil::StatusCallback& callback) = 0;
const storage::AsyncFileUtil::StatusCallback& callback,
const storage::WatcherManager::NotificationCallback&
notification_callback) = 0;
// Requests removing a watcher, which is immediately deleted from the internal
// list, hence the operation is not abortable.
......@@ -199,7 +203,7 @@ class ProvidedFileSystemInterface {
// TODO(mtomasz): Replace [entry_path, recursive] with a watcher id.
virtual bool Notify(const base::FilePath& entry_path,
bool recursive,
ProvidedFileSystemObserver::ChangeType change_type,
storage::WatcherManager::ChangeType change_type,
scoped_ptr<ProvidedFileSystemObserver::Changes> changes,
const std::string& tag) = 0;
......
......@@ -7,7 +7,8 @@
namespace chromeos {
namespace file_system_provider {
ProvidedFileSystemObserver::Change::Change() : change_type(CHANGED) {
ProvidedFileSystemObserver::Change::Change()
: change_type(storage::WatcherManager::CHANGED) {
}
ProvidedFileSystemObserver::Change::~Change() {
......
......@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/files/file_path.h"
#include "chrome/browser/chromeos/file_system_provider/watcher.h"
#include "storage/browser/fileapi/watcher_manager.h"
namespace chromeos {
namespace file_system_provider {
......@@ -24,9 +25,6 @@ class ProvidedFileSystemObserver {
public:
struct Change;
// Type of a change to a watched entry.
enum ChangeType { CHANGED, DELETED };
// Lust of changes.
typedef std::vector<Change> Changes;
......@@ -36,7 +34,7 @@ class ProvidedFileSystemObserver {
~Change();
base::FilePath entry_path;
ChangeType change_type;
storage::WatcherManager::ChangeType change_type;
};
// Called when a watched entry is changed, including removals. |callback|
......@@ -45,7 +43,7 @@ class ProvidedFileSystemObserver {
// called. The reference to |changes| is valid at least as long as |callback|.
virtual void OnWatcherChanged(const ProvidedFileSystemInfo& file_system_info,
const Watcher& watcher,
ChangeType change_type,
storage::WatcherManager::ChangeType change_type,
const Changes& changes,
const base::Closure& callback) = 0;
......
......@@ -347,7 +347,7 @@ void Service::OnRequestUnmountStatus(
void Service::OnWatcherChanged(const ProvidedFileSystemInfo& file_system_info,
const Watcher& watcher,
ChangeType change_type,
storage::WatcherManager::ChangeType change_type,
const Changes& changes,
const base::Closure& callback) {
callback.Run();
......
......@@ -27,6 +27,7 @@
#include "content/public/browser/browser_context.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/common/extension.h"
#include "storage/browser/fileapi/watcher_manager.h"
namespace extensions {
class ExtensionRegistry;
......@@ -132,7 +133,7 @@ class Service : public KeyedService,
virtual void OnWatcherChanged(
const ProvidedFileSystemInfo& file_system_info,
const Watcher& watcher,
ProvidedFileSystemObserver::ChangeType change_type,
storage::WatcherManager::ChangeType change_type,
const ProvidedFileSystemObserver::Changes& changes,
const base::Closure& callback) override;
virtual void OnWatcherTagUpdated(
......
......@@ -9,7 +9,9 @@
#include <set>
#include <string>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "storage/browser/fileapi/watcher_manager.h"
#include "url/gurl.h"
namespace chromeos {
......@@ -49,6 +51,12 @@ struct Subscriber {
// Whether the subscriber should be restored after shutdown or not.
bool persistent;
// Callback to be called for each watcher notification. It's optional, but
// not allowed for persistent watchers. In case of persistent subscribers,
// the notification should be handled using observers, as the callback can't
// be restored after shutdown.
storage::WatcherManager::NotificationCallback notification_callback;
};
// Represents a watcher on a file system.
......
......@@ -269,6 +269,8 @@
'browser/chromeos/file_system_provider/fileapi/file_stream_writer.h',
'browser/chromeos/file_system_provider/fileapi/provider_async_file_util.cc',
'browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h',
'browser/chromeos/file_system_provider/fileapi/watcher_manager.cc',
'browser/chromeos/file_system_provider/fileapi/watcher_manager.h',
'browser/chromeos/file_system_provider/mount_path_util.cc',
'browser/chromeos/file_system_provider/mount_path_util.h',
'browser/chromeos/file_system_provider/notification_manager.cc',
......
......@@ -11,10 +11,6 @@
#include "base/callback_forward.h"
#include "base/files/file.h"
namespace base {
class Time;
}
namespace storage {
class FileSystemOperationContext;
......@@ -27,28 +23,34 @@ class FileSystemURL;
// can assume that they don't get any null callbacks.
class WatcherManager {
public:
enum Action { CHANGED, REMOVED };
enum ChangeType { CHANGED, DELETED };
typedef base::Callback<void(base::File::Error result)> StatusCallback;
typedef base::Callback<void(Action action)> NotificationCallback;
typedef base::Callback<void(ChangeType change_type)> NotificationCallback;
virtual ~WatcherManager() {}
// Observes a directory entry. If the |recursive| mode is not supported then
// Adds an entry watcher. If the |recursive| mode is not supported then
// FILE_ERROR_INVALID_OPERATION must be returned as an error. If the |url| is
// already watched, or setting up the watcher fails, then |callback|
// must be called with a specific error code. Otherwise |callback| must be
// called with the FILE_OK error code. |notification_callback| is called for
// every change related to the watched directory.
virtual void WatchDirectory(
// already watched with the same |recursive|, or setting up the watcher fails,
// then |callback| must be called with a specific error code.
//
// There may be up to two watchers for the same |url| as well as one of them
// is recursive, and the other one is not.
//
// In case of a success |callback| must be called with the FILE_OK error code.
// |notification_callback| is called for every change related to the watched
// directory.
virtual void AddWatcher(
const FileSystemURL& url,
bool recursive,
const StatusCallback& callback,
const NotificationCallback& notification_callback) = 0;
// Stops observing an entry represented by |url|.
virtual void UnwatchEntry(const FileSystemURL& url,
const StatusCallback& callback) = 0;
// Removes a watcher represented by |url| in |recursive| mode.
virtual void RemoveWatcher(const FileSystemURL& url,
bool recursive,
const StatusCallback& callback) = 0;
};
} // namespace storage
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment