1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/memory/singleton.h"
13 #include "base/optional.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "chrome/browser/chromeos/arc/arc_util.h"
16 #include "chrome/browser/chromeos/arc/fileapi/arc_file_system_bridge.h"
17 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
20 #include "components/arc/session/arc_bridge_service.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "url/gurl.h"
23 
24 using content::BrowserThread;
25 
26 namespace arc {
27 namespace {
28 
29 // Singleton factory for ArcFileSystemOperationRunner.
30 class ArcFileSystemOperationRunnerFactory
31     : public internal::ArcBrowserContextKeyedServiceFactoryBase<
32           ArcFileSystemOperationRunner,
33           ArcFileSystemOperationRunnerFactory> {
34  public:
35   // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
36   static constexpr const char* kName = "ArcFileSystemOperationRunnerFactory";
37 
GetInstance()38   static ArcFileSystemOperationRunnerFactory* GetInstance() {
39     return base::Singleton<ArcFileSystemOperationRunnerFactory>::get();
40   }
41 
42  private:
43   friend base::DefaultSingletonTraits<ArcFileSystemOperationRunnerFactory>;
ArcFileSystemOperationRunnerFactory()44   ArcFileSystemOperationRunnerFactory() {
45     DependsOn(ArcFileSystemBridge::GetFactory());
46   }
47   ~ArcFileSystemOperationRunnerFactory() override = default;
48 };
49 
50 }  // namespace
51 
52 // static
53 ArcFileSystemOperationRunner*
GetForBrowserContext(content::BrowserContext * context)54 ArcFileSystemOperationRunner::GetForBrowserContext(
55     content::BrowserContext* context) {
56   return ArcFileSystemOperationRunnerFactory::GetForBrowserContext(context);
57 }
58 
59 // static
GetFactory()60 BrowserContextKeyedServiceFactory* ArcFileSystemOperationRunner::GetFactory() {
61   return ArcFileSystemOperationRunnerFactory::GetInstance();
62 }
63 
64 // static
65 std::unique_ptr<ArcFileSystemOperationRunner>
CreateForTesting(content::BrowserContext * context,ArcBridgeService * bridge_service)66 ArcFileSystemOperationRunner::CreateForTesting(
67     content::BrowserContext* context,
68     ArcBridgeService* bridge_service) {
69   // We can't use std::make_unique() here because we are calling a private
70   // constructor.
71   return base::WrapUnique<ArcFileSystemOperationRunner>(
72       new ArcFileSystemOperationRunner(context, bridge_service, false));
73 }
74 
ArcFileSystemOperationRunner(content::BrowserContext * context,ArcBridgeService * bridge_service)75 ArcFileSystemOperationRunner::ArcFileSystemOperationRunner(
76     content::BrowserContext* context,
77     ArcBridgeService* bridge_service)
78     : ArcFileSystemOperationRunner(Profile::FromBrowserContext(context),
79                                    bridge_service,
80                                    true) {
81   DCHECK(context);
82 }
83 
ArcFileSystemOperationRunner(content::BrowserContext * context,ArcBridgeService * bridge_service,bool set_should_defer_by_events)84 ArcFileSystemOperationRunner::ArcFileSystemOperationRunner(
85     content::BrowserContext* context,
86     ArcBridgeService* bridge_service,
87     bool set_should_defer_by_events)
88     : context_(context),
89       arc_bridge_service_(bridge_service),
90       set_should_defer_by_events_(set_should_defer_by_events) {
91   DCHECK_CURRENTLY_ON(BrowserThread::UI);
92 
93   arc_bridge_service_->file_system()->AddObserver(this);
94 
95   // ArcSessionManager may not exist in unit tests.
96   auto* arc_session_manager = ArcSessionManager::Get();
97   if (arc_session_manager)
98     arc_session_manager->AddObserver(this);
99 
100   ArcFileSystemBridge::GetForBrowserContext(context_)->AddObserver(this);
101 
102   OnStateChanged();
103 }
104 
~ArcFileSystemOperationRunner()105 ArcFileSystemOperationRunner::~ArcFileSystemOperationRunner() {
106   DCHECK_CURRENTLY_ON(BrowserThread::UI);
107   // On destruction, deferred operations are discarded.
108 }
109 
AddObserver(Observer * observer)110 void ArcFileSystemOperationRunner::AddObserver(Observer* observer) {
111   DCHECK_CURRENTLY_ON(BrowserThread::UI);
112   observer_list_.AddObserver(observer);
113 }
114 
RemoveObserver(Observer * observer)115 void ArcFileSystemOperationRunner::RemoveObserver(Observer* observer) {
116   DCHECK_CURRENTLY_ON(BrowserThread::UI);
117   observer_list_.RemoveObserver(observer);
118 }
119 
GetFileSize(const GURL & url,GetFileSizeCallback callback)120 void ArcFileSystemOperationRunner::GetFileSize(const GURL& url,
121                                                GetFileSizeCallback callback) {
122   DCHECK_CURRENTLY_ON(BrowserThread::UI);
123   if (should_defer_) {
124     deferred_operations_.emplace_back(base::BindOnce(
125         &ArcFileSystemOperationRunner::GetFileSize,
126         weak_ptr_factory_.GetWeakPtr(), url, std::move(callback)));
127     return;
128   }
129   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
130       arc_bridge_service_->file_system(), GetFileSize);
131   if (!file_system_instance) {
132     base::ThreadTaskRunnerHandle::Get()->PostTask(
133         FROM_HERE, base::BindOnce(std::move(callback), -1));
134     return;
135   }
136   file_system_instance->GetFileSize(url.spec(), std::move(callback));
137 }
138 
GetMimeType(const GURL & url,GetMimeTypeCallback callback)139 void ArcFileSystemOperationRunner::GetMimeType(const GURL& url,
140                                                GetMimeTypeCallback callback) {
141   DCHECK_CURRENTLY_ON(BrowserThread::UI);
142   if (should_defer_) {
143     deferred_operations_.emplace_back(base::BindOnce(
144         &ArcFileSystemOperationRunner::GetMimeType,
145         weak_ptr_factory_.GetWeakPtr(), url, std::move(callback)));
146     return;
147   }
148   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
149       arc_bridge_service_->file_system(), GetMimeType);
150   if (!file_system_instance) {
151     base::ThreadTaskRunnerHandle::Get()->PostTask(
152         FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
153     return;
154   }
155   file_system_instance->GetMimeType(url.spec(), std::move(callback));
156 }
157 
OpenFileToRead(const GURL & url,OpenFileToReadCallback callback)158 void ArcFileSystemOperationRunner::OpenFileToRead(
159     const GURL& url,
160     OpenFileToReadCallback callback) {
161   DCHECK_CURRENTLY_ON(BrowserThread::UI);
162   if (should_defer_) {
163     deferred_operations_.emplace_back(base::BindOnce(
164         &ArcFileSystemOperationRunner::OpenFileToRead,
165         weak_ptr_factory_.GetWeakPtr(), url, std::move(callback)));
166     return;
167   }
168   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
169       arc_bridge_service_->file_system(), OpenFileToRead);
170   if (!file_system_instance) {
171     base::ThreadTaskRunnerHandle::Get()->PostTask(
172         FROM_HERE, base::BindOnce(std::move(callback), mojo::ScopedHandle()));
173     return;
174   }
175   file_system_instance->OpenFileToRead(url.spec(), std::move(callback));
176 }
177 
OpenThumbnail(const GURL & url,const gfx::Size & size,OpenThumbnailCallback callback)178 void ArcFileSystemOperationRunner::OpenThumbnail(
179     const GURL& url,
180     const gfx::Size& size,
181     OpenThumbnailCallback callback) {
182   DCHECK_CURRENTLY_ON(BrowserThread::UI);
183   if (should_defer_) {
184     deferred_operations_.emplace_back(base::BindOnce(
185         &ArcFileSystemOperationRunner::OpenThumbnail,
186         weak_ptr_factory_.GetWeakPtr(), url, size, std::move(callback)));
187     return;
188   }
189   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
190       arc_bridge_service_->file_system(), OpenThumbnail);
191   if (!file_system_instance) {
192     base::ThreadTaskRunnerHandle::Get()->PostTask(
193         FROM_HERE, base::BindOnce(std::move(callback), mojo::ScopedHandle()));
194     return;
195   }
196   file_system_instance->OpenThumbnail(url.spec(), size, std::move(callback));
197 }
198 
OpenFileToWrite(const GURL & url,OpenFileToWriteCallback callback)199 void ArcFileSystemOperationRunner::OpenFileToWrite(
200     const GURL& url,
201     OpenFileToWriteCallback callback) {
202   DCHECK_CURRENTLY_ON(BrowserThread::UI);
203   if (should_defer_) {
204     deferred_operations_.emplace_back(base::BindOnce(
205         &ArcFileSystemOperationRunner::OpenFileToWrite,
206         weak_ptr_factory_.GetWeakPtr(), url, std::move(callback)));
207     return;
208   }
209   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
210       arc_bridge_service_->file_system(), OpenFileToWrite);
211   if (!file_system_instance) {
212     base::ThreadTaskRunnerHandle::Get()->PostTask(
213         FROM_HERE, base::BindOnce(std::move(callback), mojo::ScopedHandle()));
214     return;
215   }
216   file_system_instance->OpenFileToWrite(url.spec(), std::move(callback));
217 }
218 
GetDocument(const std::string & authority,const std::string & document_id,GetDocumentCallback callback)219 void ArcFileSystemOperationRunner::GetDocument(const std::string& authority,
220                                                const std::string& document_id,
221                                                GetDocumentCallback callback) {
222   DCHECK_CURRENTLY_ON(BrowserThread::UI);
223   if (should_defer_) {
224     deferred_operations_.emplace_back(
225         base::BindOnce(&ArcFileSystemOperationRunner::GetDocument,
226                        weak_ptr_factory_.GetWeakPtr(), authority, document_id,
227                        std::move(callback)));
228     return;
229   }
230   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
231       arc_bridge_service_->file_system(), GetDocument);
232   if (!file_system_instance) {
233     base::ThreadTaskRunnerHandle::Get()->PostTask(
234         FROM_HERE, base::BindOnce(std::move(callback), mojom::DocumentPtr()));
235     return;
236   }
237   file_system_instance->GetDocument(authority, document_id,
238                                     std::move(callback));
239 }
240 
GetChildDocuments(const std::string & authority,const std::string & parent_document_id,GetChildDocumentsCallback callback)241 void ArcFileSystemOperationRunner::GetChildDocuments(
242     const std::string& authority,
243     const std::string& parent_document_id,
244     GetChildDocumentsCallback callback) {
245   DCHECK_CURRENTLY_ON(BrowserThread::UI);
246   if (should_defer_) {
247     deferred_operations_.emplace_back(
248         base::BindOnce(&ArcFileSystemOperationRunner::GetChildDocuments,
249                        weak_ptr_factory_.GetWeakPtr(), authority,
250                        parent_document_id, std::move(callback)));
251     return;
252   }
253   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
254       arc_bridge_service_->file_system(), GetChildDocuments);
255   if (!file_system_instance) {
256     base::ThreadTaskRunnerHandle::Get()->PostTask(
257         FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
258     return;
259   }
260   file_system_instance->GetChildDocuments(authority, parent_document_id,
261                                           std::move(callback));
262 }
263 
GetRecentDocuments(const std::string & authority,const std::string & root_id,GetRecentDocumentsCallback callback)264 void ArcFileSystemOperationRunner::GetRecentDocuments(
265     const std::string& authority,
266     const std::string& root_id,
267     GetRecentDocumentsCallback callback) {
268   DCHECK_CURRENTLY_ON(BrowserThread::UI);
269   if (should_defer_) {
270     deferred_operations_.emplace_back(
271         base::BindOnce(&ArcFileSystemOperationRunner::GetRecentDocuments,
272                        weak_ptr_factory_.GetWeakPtr(), authority, root_id,
273                        std::move(callback)));
274     return;
275   }
276   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
277       arc_bridge_service_->file_system(), GetRecentDocuments);
278   if (!file_system_instance) {
279     base::ThreadTaskRunnerHandle::Get()->PostTask(
280         FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
281     return;
282   }
283   file_system_instance->GetRecentDocuments(authority, root_id,
284                                            std::move(callback));
285 }
286 
GetRoots(GetRootsCallback callback)287 void ArcFileSystemOperationRunner::GetRoots(GetRootsCallback callback) {
288   DCHECK_CURRENTLY_ON(BrowserThread::UI);
289   if (should_defer_) {
290     deferred_operations_.emplace_back(
291         base::BindOnce(&ArcFileSystemOperationRunner::GetRoots,
292                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
293     return;
294   }
295   auto* file_system_instance =
296       ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->file_system(), GetRoots);
297   if (!file_system_instance) {
298     base::ThreadTaskRunnerHandle::Get()->PostTask(
299         FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
300     return;
301   }
302   file_system_instance->GetRoots(std::move(callback));
303 }
304 
DeleteDocument(const std::string & authority,const std::string & document_id,DeleteDocumentCallback callback)305 void ArcFileSystemOperationRunner::DeleteDocument(
306     const std::string& authority,
307     const std::string& document_id,
308     DeleteDocumentCallback callback) {
309   if (should_defer_) {
310     deferred_operations_.emplace_back(
311         base::BindOnce(&ArcFileSystemOperationRunner::DeleteDocument,
312                        weak_ptr_factory_.GetWeakPtr(), authority, document_id,
313                        std::move(callback)));
314     return;
315   }
316   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
317       arc_bridge_service_->file_system(), DeleteDocument);
318   if (!file_system_instance) {
319     base::ThreadTaskRunnerHandle::Get()->PostTask(
320         FROM_HERE, base::BindOnce(std::move(callback), false));
321     return;
322   }
323   file_system_instance->DeleteDocument(authority, document_id,
324                                        std::move(callback));
325 }
326 
RenameDocument(const std::string & authority,const std::string & document_id,const std::string & display_name,RenameDocumentCallback callback)327 void ArcFileSystemOperationRunner::RenameDocument(
328     const std::string& authority,
329     const std::string& document_id,
330     const std::string& display_name,
331     RenameDocumentCallback callback) {
332   if (should_defer_) {
333     deferred_operations_.emplace_back(
334         base::BindOnce(&ArcFileSystemOperationRunner::RenameDocument,
335                        weak_ptr_factory_.GetWeakPtr(), authority, document_id,
336                        display_name, std::move(callback)));
337     return;
338   }
339   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
340       arc_bridge_service_->file_system(), RenameDocument);
341   if (!file_system_instance) {
342     base::ThreadTaskRunnerHandle::Get()->PostTask(
343         FROM_HERE, base::BindOnce(std::move(callback), mojom::DocumentPtr()));
344     return;
345   }
346   file_system_instance->RenameDocument(authority, document_id, display_name,
347                                        std::move(callback));
348 }
349 
CreateDocument(const std::string & authority,const std::string & parent_document_id,const std::string & mime_type,const std::string & display_name,CreateDocumentCallback callback)350 void ArcFileSystemOperationRunner::CreateDocument(
351     const std::string& authority,
352     const std::string& parent_document_id,
353     const std::string& mime_type,
354     const std::string& display_name,
355     CreateDocumentCallback callback) {
356   if (should_defer_) {
357     deferred_operations_.emplace_back(base::BindOnce(
358         &ArcFileSystemOperationRunner::CreateDocument,
359         weak_ptr_factory_.GetWeakPtr(), authority, parent_document_id,
360         mime_type, display_name, std::move(callback)));
361     return;
362   }
363   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
364       arc_bridge_service_->file_system(), CreateDocument);
365   if (!file_system_instance) {
366     base::ThreadTaskRunnerHandle::Get()->PostTask(
367         FROM_HERE, base::BindOnce(std::move(callback), mojom::DocumentPtr()));
368     return;
369   }
370   file_system_instance->CreateDocument(authority, parent_document_id, mime_type,
371                                        display_name, std::move(callback));
372 }
373 
CopyDocument(const std::string & authority,const std::string & source_document_id,const std::string & target_parent_document_id,CopyDocumentCallback callback)374 void ArcFileSystemOperationRunner::CopyDocument(
375     const std::string& authority,
376     const std::string& source_document_id,
377     const std::string& target_parent_document_id,
378     CopyDocumentCallback callback) {
379   if (should_defer_) {
380     deferred_operations_.emplace_back(base::BindOnce(
381         &ArcFileSystemOperationRunner::CopyDocument,
382         weak_ptr_factory_.GetWeakPtr(), authority, source_document_id,
383         target_parent_document_id, std::move(callback)));
384     return;
385   }
386   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
387       arc_bridge_service_->file_system(), CopyDocument);
388   if (!file_system_instance) {
389     base::ThreadTaskRunnerHandle::Get()->PostTask(
390         FROM_HERE, base::BindOnce(std::move(callback), mojom::DocumentPtr()));
391     return;
392   }
393   file_system_instance->CopyDocument(authority, source_document_id,
394                                      target_parent_document_id,
395                                      std::move(callback));
396 }
397 
MoveDocument(const std::string & authority,const std::string & source_document_id,const std::string & source_parent_document_id,const std::string & target_parent_document_id,MoveDocumentCallback callback)398 void ArcFileSystemOperationRunner::MoveDocument(
399     const std::string& authority,
400     const std::string& source_document_id,
401     const std::string& source_parent_document_id,
402     const std::string& target_parent_document_id,
403     MoveDocumentCallback callback) {
404   if (should_defer_) {
405     deferred_operations_.emplace_back(
406         base::BindOnce(&ArcFileSystemOperationRunner::MoveDocument,
407                        weak_ptr_factory_.GetWeakPtr(), authority,
408                        source_document_id, source_parent_document_id,
409                        target_parent_document_id, std::move(callback)));
410     return;
411   }
412   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
413       arc_bridge_service_->file_system(), MoveDocument);
414   if (!file_system_instance) {
415     base::ThreadTaskRunnerHandle::Get()->PostTask(
416         FROM_HERE, base::BindOnce(std::move(callback), mojom::DocumentPtr()));
417     return;
418   }
419   file_system_instance->MoveDocument(
420       authority, source_document_id, source_parent_document_id,
421       target_parent_document_id, std::move(callback));
422 }
423 
AddWatcher(const std::string & authority,const std::string & document_id,const WatcherCallback & watcher_callback,AddWatcherCallback callback)424 void ArcFileSystemOperationRunner::AddWatcher(
425     const std::string& authority,
426     const std::string& document_id,
427     const WatcherCallback& watcher_callback,
428     AddWatcherCallback callback) {
429   DCHECK_CURRENTLY_ON(BrowserThread::UI);
430   if (should_defer_) {
431     deferred_operations_.emplace_back(
432         base::BindOnce(&ArcFileSystemOperationRunner::AddWatcher,
433                        weak_ptr_factory_.GetWeakPtr(), authority, document_id,
434                        watcher_callback, std::move(callback)));
435     return;
436   }
437   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
438       arc_bridge_service_->file_system(), AddWatcher);
439   if (!file_system_instance) {
440     base::ThreadTaskRunnerHandle::Get()->PostTask(
441         FROM_HERE, base::BindOnce(std::move(callback), -1));
442     return;
443   }
444   file_system_instance->AddWatcher(
445       authority, document_id,
446       base::BindOnce(&ArcFileSystemOperationRunner::OnWatcherAdded,
447                      weak_ptr_factory_.GetWeakPtr(), watcher_callback,
448                      std::move(callback)));
449 }
450 
RemoveWatcher(int64_t watcher_id,RemoveWatcherCallback callback)451 void ArcFileSystemOperationRunner::RemoveWatcher(
452     int64_t watcher_id,
453     RemoveWatcherCallback callback) {
454   DCHECK_CURRENTLY_ON(BrowserThread::UI);
455   // RemoveWatcher() is never deferred since watchers do not persist across
456   // container reboots.
457   if (should_defer_) {
458     base::ThreadTaskRunnerHandle::Get()->PostTask(
459         FROM_HERE, base::BindOnce(std::move(callback), false));
460     return;
461   }
462 
463   // Unregister from |watcher_callbacks_| now because we will do it even if
464   // the remote method fails anyway. This is an implementation detail, so
465   // users must not assume registered callbacks are immediately invalidated.
466   auto iter = watcher_callbacks_.find(watcher_id);
467   if (iter == watcher_callbacks_.end()) {
468     base::ThreadTaskRunnerHandle::Get()->PostTask(
469         FROM_HERE, base::BindOnce(std::move(callback), false));
470     return;
471   }
472   watcher_callbacks_.erase(iter);
473 
474   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
475       arc_bridge_service_->file_system(), RemoveWatcher);
476   if (!file_system_instance) {
477     base::ThreadTaskRunnerHandle::Get()->PostTask(
478         FROM_HERE, base::BindOnce(std::move(callback), false));
479     return;
480   }
481   file_system_instance->RemoveWatcher(watcher_id, std::move(callback));
482 }
483 
Shutdown()484 void ArcFileSystemOperationRunner::Shutdown() {
485   DCHECK_CURRENTLY_ON(BrowserThread::UI);
486   ArcFileSystemBridge::GetForBrowserContext(context_)->RemoveObserver(this);
487 
488   // ArcSessionManager may not exist in unit tests.
489   auto* arc_session_manager = ArcSessionManager::Get();
490   if (arc_session_manager)
491     arc_session_manager->RemoveObserver(this);
492 
493   arc_bridge_service_->file_system()->RemoveObserver(this);
494 }
495 
OnDocumentChanged(int64_t watcher_id,ChangeType type)496 void ArcFileSystemOperationRunner::OnDocumentChanged(int64_t watcher_id,
497                                                      ChangeType type) {
498   DCHECK_CURRENTLY_ON(BrowserThread::UI);
499   auto iter = watcher_callbacks_.find(watcher_id);
500   if (iter == watcher_callbacks_.end()) {
501     // This may happen in a race condition with documents changes and
502     // RemoveWatcher().
503     return;
504   }
505   WatcherCallback watcher_callback = iter->second;
506   watcher_callback.Run(type);
507 }
508 
OnArcPlayStoreEnabledChanged(bool enabled)509 void ArcFileSystemOperationRunner::OnArcPlayStoreEnabledChanged(bool enabled) {
510   DCHECK_CURRENTLY_ON(BrowserThread::UI);
511   OnStateChanged();
512 }
513 
OnConnectionReady()514 void ArcFileSystemOperationRunner::OnConnectionReady() {
515   DCHECK_CURRENTLY_ON(BrowserThread::UI);
516   OnStateChanged();
517 }
518 
OnConnectionClosed()519 void ArcFileSystemOperationRunner::OnConnectionClosed() {
520   DCHECK_CURRENTLY_ON(BrowserThread::UI);
521   // ArcFileSystemService and watchers are gone.
522   watcher_callbacks_.clear();
523   for (auto& observer : observer_list_)
524     observer.OnWatchersCleared();
525   OnStateChanged();
526 }
527 
OnWatcherAdded(const WatcherCallback & watcher_callback,AddWatcherCallback callback,int64_t watcher_id)528 void ArcFileSystemOperationRunner::OnWatcherAdded(
529     const WatcherCallback& watcher_callback,
530     AddWatcherCallback callback,
531     int64_t watcher_id) {
532   DCHECK_CURRENTLY_ON(BrowserThread::UI);
533   if (watcher_id < 0) {
534     std::move(callback).Run(-1);
535     return;
536   }
537   if (watcher_callbacks_.count(watcher_id)) {
538     NOTREACHED();
539     std::move(callback).Run(-1);
540     return;
541   }
542   watcher_callbacks_.insert(std::make_pair(watcher_id, watcher_callback));
543   std::move(callback).Run(watcher_id);
544 }
545 
OnStateChanged()546 void ArcFileSystemOperationRunner::OnStateChanged() {
547   DCHECK_CURRENTLY_ON(BrowserThread::UI);
548   if (set_should_defer_by_events_) {
549     SetShouldDefer(IsArcPlayStoreEnabledForProfile(
550                        Profile::FromBrowserContext(context_)) &&
551                    !arc_bridge_service_->file_system()->IsConnected());
552   }
553 }
554 
SetShouldDefer(bool should_defer)555 void ArcFileSystemOperationRunner::SetShouldDefer(bool should_defer) {
556   DCHECK_CURRENTLY_ON(BrowserThread::UI);
557 
558   should_defer_ = should_defer;
559 
560   if (should_defer_)
561     return;
562 
563   // Run deferred operations.
564   std::vector<base::OnceClosure> deferred_operations;
565   deferred_operations.swap(deferred_operations_);
566   for (base::OnceClosure& operation : deferred_operations)
567     std::move(operation).Run();
568 
569   // No deferred operations should be left at this point.
570   DCHECK(deferred_operations_.empty());
571 }
572 
573 }  // namespace arc
574