| Index: chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc
|
| diff --git a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc
|
| index 6c8b936f1260af4f699518db8174efbc2b458cc8..6a65157662e298959d35312d7104c49e454c5527 100644
|
| --- a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc
|
| +++ b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc
|
| @@ -26,6 +26,15 @@ namespace arc {
|
|
|
| namespace {
|
|
|
| +// A special watcher ID indicating this watcher is orphaned.
|
| +// Though we have an entry in ArcDocumentsProviderRoot, the remote
|
| +// ArcFileSystemService does not have a corresponding watcher. This happens
|
| +// when, for example, AddWatcher() is called for non-existent files or the
|
| +// remote service crashes.
|
| +// We use this value to allow RemoveWatcher() to succeed even after the remote
|
| +// service forgets watchers.
|
| +constexpr int64_t kOrphanWatcherId = -1;
|
| +
|
| // Computes a file name for a document.
|
| // TODO(crbug.com/675868): Consolidate with the similar logic for Drive.
|
| base::FilePath::StringType GetFileNameForDocument(
|
| @@ -102,20 +111,35 @@ void ArcDocumentsProviderRoot::AddWatcher(
|
| const WatcherCallback& watcher_callback,
|
| const StatusCallback& callback) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - if (path_to_watcher_id_.count(path)) {
|
| + if (path_to_watcher_id_.count(path) ||
|
| + path_to_watcher_request_id_.count(path)) {
|
| callback.Run(base::File::FILE_ERROR_FAILED);
|
| return;
|
| }
|
| + uint64_t watcher_request_id = next_watcher_request_id_++;
|
| + path_to_watcher_request_id_.insert(std::make_pair(path, watcher_request_id));
|
| ResolveToDocumentId(
|
| - path,
|
| - base::Bind(&ArcDocumentsProviderRoot::AddWatcherWithDocumentId,
|
| - weak_ptr_factory_.GetWeakPtr(), path, watcher_callback,
|
| - callback));
|
| + path, base::Bind(&ArcDocumentsProviderRoot::AddWatcherWithDocumentId,
|
| + weak_ptr_factory_.GetWeakPtr(), path, watcher_request_id,
|
| + watcher_callback));
|
| +
|
| + // HACK: Invoke |callback| immediately.
|
| + //
|
| + // TODO(crbug.com/698624): Remove this hack. It was introduced because Files
|
| + // app freezes until AddWatcher() finishes, but it should be handled in Files
|
| + // app rather than here.
|
| + callback.Run(base::File::FILE_OK);
|
| }
|
|
|
| void ArcDocumentsProviderRoot::RemoveWatcher(const base::FilePath& path,
|
| const StatusCallback& callback) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + auto iter_request = path_to_watcher_request_id_.find(path);
|
| + if (iter_request != path_to_watcher_request_id_.end()) {
|
| + path_to_watcher_request_id_.erase(iter_request);
|
| + callback.Run(base::File::FILE_OK);
|
| + return;
|
| + }
|
| auto iter = path_to_watcher_id_.find(path);
|
| if (iter == path_to_watcher_id_.end()) {
|
| callback.Run(base::File::FILE_ERROR_FAILED);
|
| @@ -149,7 +173,7 @@ void ArcDocumentsProviderRoot::OnWatchersCleared() {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| // Mark all watchers orphan.
|
| for (auto& entry : path_to_watcher_id_)
|
| - entry.second = -1;
|
| + entry.second = kOrphanWatcherId;
|
| }
|
|
|
| void ArcDocumentsProviderRoot::GetFileInfoWithDocumentId(
|
| @@ -232,52 +256,56 @@ void ArcDocumentsProviderRoot::ReadDirectoryWithNameToThinDocumentMap(
|
|
|
| void ArcDocumentsProviderRoot::AddWatcherWithDocumentId(
|
| const base::FilePath& path,
|
| + uint64_t watcher_request_id,
|
| const WatcherCallback& watcher_callback,
|
| - const StatusCallback& callback,
|
| const std::string& document_id) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (IsWatcherRequestCanceled(path, watcher_request_id))
|
| + return;
|
| +
|
| if (document_id.empty()) {
|
| - callback.Run(base::File::FILE_ERROR_NOT_FOUND);
|
| + DCHECK(!path_to_watcher_id_.count(path));
|
| + path_to_watcher_id_.insert(std::make_pair(path, kOrphanWatcherId));
|
| + path_to_watcher_request_id_.erase(path);
|
| return;
|
| }
|
| +
|
| // Start observing ArcFileSystemOperationRunner if we have not.
|
| if (!observer_wrapper_) {
|
| observer_wrapper_ =
|
| new file_system_operation_runner_util::ObserverIOThreadWrapper(this);
|
| file_system_operation_runner_util::AddObserverOnIOThread(observer_wrapper_);
|
| }
|
| +
|
| file_system_operation_runner_util::AddWatcherOnIOThread(
|
| authority_, document_id, watcher_callback,
|
| base::Bind(&ArcDocumentsProviderRoot::OnWatcherAdded,
|
| - weak_ptr_factory_.GetWeakPtr(), path, callback));
|
| + weak_ptr_factory_.GetWeakPtr(), path, watcher_request_id));
|
| }
|
|
|
| void ArcDocumentsProviderRoot::OnWatcherAdded(const base::FilePath& path,
|
| - const StatusCallback& callback,
|
| + uint64_t watcher_request_id,
|
| int64_t watcher_id) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - if (watcher_id < 0) {
|
| - callback.Run(base::File::FILE_ERROR_FAILED);
|
| - return;
|
| - }
|
| - if (path_to_watcher_id_.count(path)) {
|
| - // Multiple watchers have been installed on the same file path in a race.
|
| - // Following the contract of WatcherManager, we reject all except the first.
|
| +
|
| + if (IsWatcherRequestCanceled(path, watcher_request_id)) {
|
| file_system_operation_runner_util::RemoveWatcherOnIOThread(
|
| watcher_id,
|
| base::Bind(&ArcDocumentsProviderRoot::OnWatcherAddedButRemoved,
|
| - weak_ptr_factory_.GetWeakPtr(), callback));
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| return;
|
| }
|
| - path_to_watcher_id_.insert(std::make_pair(path, watcher_id));
|
| - callback.Run(base::File::FILE_OK);
|
| +
|
| + DCHECK(!path_to_watcher_id_.count(path));
|
| + path_to_watcher_id_.insert(
|
| + std::make_pair(path, watcher_id < 0 ? kOrphanWatcherId : watcher_id));
|
| + path_to_watcher_request_id_.erase(path);
|
| }
|
|
|
| -void ArcDocumentsProviderRoot::OnWatcherAddedButRemoved(
|
| - const StatusCallback& callback,
|
| - bool success) {
|
| +void ArcDocumentsProviderRoot::OnWatcherAddedButRemoved(bool success) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - callback.Run(base::File::FILE_ERROR_FAILED);
|
| + // Ignore |success|.
|
| }
|
|
|
| void ArcDocumentsProviderRoot::OnWatcherRemoved(const StatusCallback& callback,
|
| @@ -286,6 +314,14 @@ void ArcDocumentsProviderRoot::OnWatcherRemoved(const StatusCallback& callback,
|
| callback.Run(success ? base::File::FILE_OK : base::File::FILE_ERROR_FAILED);
|
| }
|
|
|
| +bool ArcDocumentsProviderRoot::IsWatcherRequestCanceled(
|
| + const base::FilePath& path,
|
| + uint64_t watcher_request_id) {
|
| + auto iter = path_to_watcher_request_id_.find(path);
|
| + return (iter == path_to_watcher_request_id_.end() ||
|
| + iter->second != watcher_request_id);
|
| +}
|
| +
|
| void ArcDocumentsProviderRoot::ResolveToContentUrlWithDocumentId(
|
| const ResolveToContentUrlCallback& callback,
|
| const std::string& document_id) {
|
|
|