Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync_file_system / sync_file_system_service.cc
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/format_macros.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/metrics/histogram.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/stl_util.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
18 #include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/sync/profile_sync_service.h"
21 #include "chrome/browser/sync/profile_sync_service_factory.h"
22 #include "chrome/browser/sync_file_system/local/local_file_sync_service.h"
23 #include "chrome/browser/sync_file_system/logger.h"
24 #include "chrome/browser/sync_file_system/sync_direction.h"
25 #include "chrome/browser/sync_file_system/sync_event_observer.h"
26 #include "chrome/browser/sync_file_system/sync_file_metadata.h"
27 #include "chrome/browser/sync_file_system/sync_process_runner.h"
28 #include "chrome/browser/sync_file_system/sync_status_code.h"
29 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
30 #include "components/keyed_service/content/browser_context_dependency_manager.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/storage_partition.h"
33 #include "extensions/browser/extension_prefs.h"
34 #include "extensions/browser/extension_registry.h"
35 #include "extensions/common/extension.h"
36 #include "extensions/common/manifest_constants.h"
37 #include "storage/browser/fileapi/file_system_context.h"
38 #include "url/gurl.h"
39
40 using content::BrowserThread;
41 using extensions::Extension;
42 using extensions::ExtensionPrefs;
43 using extensions::ExtensionRegistry;
44 using storage::FileSystemURL;
45 using storage::FileSystemURLSet;
46
47 namespace sync_file_system {
48
49 namespace {
50
51 const char kLocalSyncName[] = "Local sync";
52 const char kRemoteSyncName[] = "Remote sync";
53
54 SyncServiceState RemoteStateToSyncServiceState(
55     RemoteServiceState state) {
56   switch (state) {
57     case REMOTE_SERVICE_OK:
58       return SYNC_SERVICE_RUNNING;
59     case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
60       return SYNC_SERVICE_TEMPORARY_UNAVAILABLE;
61     case REMOTE_SERVICE_AUTHENTICATION_REQUIRED:
62       return SYNC_SERVICE_AUTHENTICATION_REQUIRED;
63     case REMOTE_SERVICE_ACCESS_FORBIDDEN:
64       return SYNC_SERVICE_TEMPORARY_UNAVAILABLE;
65     case REMOTE_SERVICE_DISABLED:
66       return SYNC_SERVICE_DISABLED;
67     case REMOTE_SERVICE_STATE_MAX:
68       NOTREACHED();
69   }
70   NOTREACHED() << "Unknown remote service state: " << state;
71   return SYNC_SERVICE_DISABLED;
72 }
73
74 void DidHandleUninstalledEvent(const GURL& origin, SyncStatusCode code) {
75   if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) {
76     util::Log(logging::LOG_WARNING, FROM_HERE,
77               "Failed to uninstall origin for uninstall event: %s",
78               origin.spec().c_str());
79   }
80 }
81
82 void DidHandleUnloadedEvent(const GURL& origin, SyncStatusCode code) {
83   if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) {
84     util::Log(logging::LOG_WARNING, FROM_HERE,
85               "Failed to disable origin for unload event: %s",
86               origin.spec().c_str());
87   }
88 }
89
90 void DidHandleLoadEvent(
91     const GURL& origin,
92     SyncStatusCode code) {
93   if (code != SYNC_STATUS_OK) {
94     util::Log(logging::LOG_WARNING, FROM_HERE,
95               "Failed to enable origin for load event: %s",
96               origin.spec().c_str());
97   }
98 }
99
100 std::string SyncFileStatusToString(SyncFileStatus sync_file_status) {
101   return extensions::api::sync_file_system::ToString(
102       extensions::SyncFileStatusToExtensionEnum(sync_file_status));
103 }
104
105 // Gets called repeatedly until every SyncFileStatus has been mapped.
106 void DidGetFileSyncStatusForDump(
107     base::ListValue* files,
108     size_t* num_results,
109     const SyncFileSystemService::DumpFilesCallback& callback,
110     base::DictionaryValue* file,
111     SyncStatusCode sync_status_code,
112     SyncFileStatus sync_file_status) {
113   DCHECK(files);
114   DCHECK(num_results);
115
116   if (file)
117     file->SetString("status", SyncFileStatusToString(sync_file_status));
118
119   // Once all results have been received, run the callback to signal end.
120   DCHECK_LE(*num_results, files->GetSize());
121   if (++*num_results < files->GetSize())
122     return;
123
124   callback.Run(*files);
125 }
126
127 // We need this indirection because WeakPtr can only be bound to methods
128 // without a return value.
129 LocalChangeProcessor* GetLocalChangeProcessorAdapter(
130     base::WeakPtr<SyncFileSystemService> service,
131     const GURL& origin) {
132   if (!service)
133     return nullptr;
134   return service->GetLocalChangeProcessor(origin);
135 }
136
137 }  // namespace
138
139 //---------------------------------------------------------------------------
140 // SyncProcessRunner's.
141
142 // SyncProcessRunner implementation for LocalSync.
143 class LocalSyncRunner : public SyncProcessRunner,
144                         public LocalFileSyncService::Observer {
145  public:
146   LocalSyncRunner(const std::string& name,
147                   SyncFileSystemService* sync_service)
148       : SyncProcessRunner(name, sync_service,
149                           nullptr,  /* timer_helper */
150                           1  /* max_parallel_task */),
151         factory_(this) {}
152
153   void StartSync(const SyncStatusCallback& callback) override {
154     GetSyncService()->local_service_->ProcessLocalChange(
155         base::Bind(&LocalSyncRunner::DidProcessLocalChange,
156                    factory_.GetWeakPtr(), callback));
157   }
158
159   // LocalFileSyncService::Observer overrides.
160   void OnLocalChangeAvailable(int64 pending_changes) override {
161     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
162
163     OnChangesUpdated(pending_changes);
164
165     // Kick other sync runners just in case they're not running.
166     GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule);
167   }
168
169  private:
170   void DidProcessLocalChange(
171       const SyncStatusCallback& callback,
172       SyncStatusCode status,
173       const FileSystemURL& url) {
174     util::Log(logging::LOG_VERBOSE, FROM_HERE,
175               "ProcessLocalChange finished with status=%d (%s) for url=%s",
176               status, SyncStatusCodeToString(status),
177               url.DebugString().c_str());
178     callback.Run(status);
179   }
180
181   base::WeakPtrFactory<LocalSyncRunner> factory_;
182   DISALLOW_COPY_AND_ASSIGN(LocalSyncRunner);
183 };
184
185 // SyncProcessRunner implementation for RemoteSync.
186 class RemoteSyncRunner : public SyncProcessRunner,
187                          public RemoteFileSyncService::Observer {
188  public:
189   RemoteSyncRunner(const std::string& name,
190                    SyncFileSystemService* sync_service,
191                    RemoteFileSyncService* remote_service)
192       : SyncProcessRunner(name, sync_service,
193                           nullptr,  /* timer_helper */
194                           1  /* max_parallel_task */),
195         remote_service_(remote_service),
196         last_state_(REMOTE_SERVICE_OK),
197         factory_(this) {}
198
199   void StartSync(const SyncStatusCallback& callback) override {
200     remote_service_->ProcessRemoteChange(
201         base::Bind(&RemoteSyncRunner::DidProcessRemoteChange,
202                    factory_.GetWeakPtr(), callback));
203   }
204
205   SyncServiceState GetServiceState() override {
206     return RemoteStateToSyncServiceState(last_state_);
207   }
208
209   // RemoteFileSyncService::Observer overrides.
210   void OnRemoteChangeQueueUpdated(int64 pending_changes) override {
211     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
212
213     OnChangesUpdated(pending_changes);
214
215     // Kick other sync runners just in case they're not running.
216     GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule);
217   }
218
219   void OnRemoteServiceStateUpdated(RemoteServiceState state,
220                                    const std::string& description) override {
221     // Just forward to SyncFileSystemService.
222     GetSyncService()->OnRemoteServiceStateUpdated(state, description);
223     last_state_ = state;
224   }
225
226  private:
227   void DidProcessRemoteChange(
228       const SyncStatusCallback& callback,
229       SyncStatusCode status,
230       const FileSystemURL& url) {
231     util::Log(logging::LOG_VERBOSE, FROM_HERE,
232               "ProcessRemoteChange finished with status=%d (%s) for url=%s",
233               status, SyncStatusCodeToString(status),
234               url.DebugString().c_str());
235
236     if (status == SYNC_STATUS_FILE_BUSY) {
237       GetSyncService()->local_service_->RegisterURLForWaitingSync(
238           url, base::Bind(&RemoteSyncRunner::Schedule,
239                           factory_.GetWeakPtr()));
240     }
241     callback.Run(status);
242   }
243
244   RemoteFileSyncService* remote_service_;
245   RemoteServiceState last_state_;
246   base::WeakPtrFactory<RemoteSyncRunner> factory_;
247   DISALLOW_COPY_AND_ASSIGN(RemoteSyncRunner);
248 };
249
250 //-----------------------------------------------------------------------------
251 // SyncFileSystemService
252
253 void SyncFileSystemService::Shutdown() {
254   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
255
256   local_sync_runners_.clear();
257   remote_sync_runners_.clear();
258
259   local_service_->Shutdown();
260   local_service_.reset();
261
262   remote_service_.reset();
263
264   ProfileSyncServiceBase* profile_sync_service =
265       ProfileSyncServiceFactory::GetForProfile(profile_);
266   if (profile_sync_service)
267     profile_sync_service->RemoveObserver(this);
268
269   ExtensionRegistry::Get(profile_)->RemoveObserver(this);
270
271   profile_ = nullptr;
272 }
273
274 SyncFileSystemService::~SyncFileSystemService() {
275   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
276   DCHECK(!profile_);
277 }
278
279 void SyncFileSystemService::InitializeForApp(
280     storage::FileSystemContext* file_system_context,
281     const GURL& app_origin,
282     const SyncStatusCallback& callback) {
283   DCHECK(local_service_);
284   DCHECK(remote_service_);
285   DCHECK(app_origin == app_origin.GetOrigin());
286
287   util::Log(logging::LOG_VERBOSE, FROM_HERE,
288             "Initializing for App: %s", app_origin.spec().c_str());
289
290   local_service_->MaybeInitializeFileSystemContext(
291       app_origin, file_system_context,
292       base::Bind(&SyncFileSystemService::DidInitializeFileSystem,
293                  AsWeakPtr(), app_origin, callback));
294 }
295
296 void SyncFileSystemService::GetExtensionStatusMap(
297     const ExtensionStatusMapCallback& callback) {
298   remote_service_->GetOriginStatusMap(
299       base::Bind(&SyncFileSystemService::DidGetExtensionStatusMap,
300                  AsWeakPtr(), callback));
301 }
302
303 void SyncFileSystemService::DumpFiles(const GURL& origin,
304                                       const DumpFilesCallback& callback) {
305   DCHECK(!origin.is_empty());
306
307   content::StoragePartition* storage_partition =
308       content::BrowserContext::GetStoragePartitionForSite(profile_, origin);
309   storage::FileSystemContext* file_system_context =
310       storage_partition->GetFileSystemContext();
311   local_service_->MaybeInitializeFileSystemContext(
312       origin, file_system_context,
313       base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump,
314                  AsWeakPtr(), origin, callback));
315 }
316
317 void SyncFileSystemService::DumpDatabase(const DumpFilesCallback& callback) {
318   remote_service_->DumpDatabase(
319       base::Bind(&SyncFileSystemService::DidDumpDatabase,
320                  AsWeakPtr(), callback));
321 }
322
323 void SyncFileSystemService::GetFileSyncStatus(
324     const FileSystemURL& url, const SyncFileStatusCallback& callback) {
325   DCHECK(local_service_);
326   DCHECK(GetRemoteService(url.origin()));
327
328   // It's possible to get an invalid FileEntry.
329   if (!url.is_valid()) {
330     base::ThreadTaskRunnerHandle::Get()->PostTask(
331         FROM_HERE,
332         base::Bind(callback,
333                    SYNC_FILE_ERROR_INVALID_URL,
334                    SYNC_FILE_STATUS_UNKNOWN));
335     return;
336   }
337
338   local_service_->HasPendingLocalChanges(
339       url,
340       base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus,
341                  AsWeakPtr(), callback));
342 }
343
344 void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) {
345   observers_.AddObserver(observer);
346 }
347
348 void SyncFileSystemService::RemoveSyncEventObserver(
349     SyncEventObserver* observer) {
350   observers_.RemoveObserver(observer);
351 }
352
353 LocalChangeProcessor* SyncFileSystemService::GetLocalChangeProcessor(
354     const GURL& origin) {
355   return GetRemoteService(origin)->GetLocalChangeProcessor();
356 }
357
358 void SyncFileSystemService::OnSyncIdle() {
359   if (promoting_demoted_changes_)
360     return;
361   promoting_demoted_changes_ = true;
362
363   int* job_count = new int(1);
364   base::Closure promote_completion_callback =
365       base::Bind(&SyncFileSystemService::OnPromotionCompleted,
366                  AsWeakPtr(), base::Owned(job_count));
367
368   int64 remote_changes = 0;
369   for (size_t i = 0; i < remote_sync_runners_.size(); ++i)
370     remote_changes += remote_sync_runners_[i]->pending_changes();
371   if (remote_changes == 0) {
372     ++*job_count;
373     local_service_->PromoteDemotedChanges(promote_completion_callback);
374   }
375
376   int64 local_changes = 0;
377   for (size_t i = 0; i < local_sync_runners_.size(); ++i)
378     local_changes += local_sync_runners_[i]->pending_changes();
379   if (local_changes == 0) {
380     ++*job_count;
381     remote_service_->PromoteDemotedChanges(promote_completion_callback);
382   }
383
384   promote_completion_callback.Run();
385 }
386
387 void SyncFileSystemService::OnPromotionCompleted(int* count) {
388   if (--*count != 0)
389     return;
390   promoting_demoted_changes_ = false;
391   CheckIfIdle();
392 }
393
394 void SyncFileSystemService::CheckIfIdle() {
395   if (promoting_demoted_changes_)
396     return;
397
398   for (size_t i = 0; i < remote_sync_runners_.size(); ++i) {
399     SyncServiceState service_state = remote_sync_runners_[i]->GetServiceState();
400     if (service_state != SYNC_SERVICE_RUNNING)
401       continue;
402
403     if (remote_sync_runners_[i]->pending_changes())
404       return;
405   }
406
407   for (size_t i = 0; i < local_sync_runners_.size(); ++i) {
408     SyncServiceState service_state = local_sync_runners_[i]->GetServiceState();
409     if (service_state != SYNC_SERVICE_RUNNING)
410       continue;
411
412     if (local_sync_runners_[i]->pending_changes())
413       return;
414   }
415
416   if (idle_callback_.is_null())
417     return;
418
419   base::Closure callback = idle_callback_;
420   idle_callback_.Reset();
421   callback.Run();
422 }
423
424 SyncServiceState SyncFileSystemService::GetSyncServiceState() {
425   // For now we always query the state from the main RemoteFileSyncService.
426   return RemoteStateToSyncServiceState(remote_service_->GetCurrentState());
427 }
428
429 SyncFileSystemService* SyncFileSystemService::GetSyncService() {
430   return this;
431 }
432
433 void SyncFileSystemService::CallOnIdleForTesting(
434     const base::Closure& callback) {
435   DCHECK(idle_callback_.is_null());
436   idle_callback_ = callback;
437   CheckIfIdle();
438 }
439
440 SyncFileSystemService::SyncFileSystemService(Profile* profile)
441     : profile_(profile),
442       sync_enabled_(true),
443       promoting_demoted_changes_(false) {
444 }
445
446 void SyncFileSystemService::Initialize(
447     scoped_ptr<LocalFileSyncService> local_service,
448     scoped_ptr<RemoteFileSyncService> remote_service) {
449   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
450   DCHECK(local_service);
451   DCHECK(remote_service);
452   DCHECK(profile_);
453
454   local_service_ = local_service.Pass();
455   remote_service_ = remote_service.Pass();
456
457   scoped_ptr<LocalSyncRunner> local_syncer(
458       new LocalSyncRunner(kLocalSyncName, this));
459   scoped_ptr<RemoteSyncRunner> remote_syncer(
460       new RemoteSyncRunner(kRemoteSyncName, this, remote_service_.get()));
461
462   local_service_->AddChangeObserver(local_syncer.get());
463   local_service_->SetLocalChangeProcessorCallback(
464       base::Bind(&GetLocalChangeProcessorAdapter, AsWeakPtr()));
465
466   remote_service_->AddServiceObserver(remote_syncer.get());
467   remote_service_->AddFileStatusObserver(this);
468   remote_service_->SetRemoteChangeProcessor(local_service_.get());
469
470   local_sync_runners_.push_back(local_syncer.release());
471   remote_sync_runners_.push_back(remote_syncer.release());
472
473   ProfileSyncServiceBase* profile_sync_service =
474       ProfileSyncServiceFactory::GetForProfile(profile_);
475   if (profile_sync_service) {
476     UpdateSyncEnabledStatus(profile_sync_service);
477     profile_sync_service->AddObserver(this);
478   }
479
480   ExtensionRegistry::Get(profile_)->AddObserver(this);
481 }
482
483 void SyncFileSystemService::DidInitializeFileSystem(
484     const GURL& app_origin,
485     const SyncStatusCallback& callback,
486     SyncStatusCode status) {
487   DVLOG(1) << "DidInitializeFileSystem: "
488            << app_origin.spec() << " " << status;
489
490   if (status != SYNC_STATUS_OK) {
491     callback.Run(status);
492     return;
493   }
494
495   // Local side of initialization for the app is done.
496   // Continue on initializing the remote side.
497   GetRemoteService(app_origin)->RegisterOrigin(
498       app_origin,
499       base::Bind(&SyncFileSystemService::DidRegisterOrigin,
500                  AsWeakPtr(), app_origin, callback));
501 }
502
503 void SyncFileSystemService::DidRegisterOrigin(
504     const GURL& app_origin,
505     const SyncStatusCallback& callback,
506     SyncStatusCode status) {
507   util::Log(logging::LOG_VERBOSE, FROM_HERE,
508             "DidInitializeForApp (registered the origin): %s: %s",
509             app_origin.spec().c_str(),
510             SyncStatusCodeToString(status));
511
512   UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.RegisterOriginResult",
513                             GetRemoteService(app_origin)->GetCurrentState(),
514                             REMOTE_SERVICE_STATE_MAX);
515
516   if (status == SYNC_STATUS_FAILED) {
517     // If we got generic error return the service status information.
518     switch (GetRemoteService(app_origin)->GetCurrentState()) {
519       case REMOTE_SERVICE_AUTHENTICATION_REQUIRED:
520         callback.Run(SYNC_STATUS_AUTHENTICATION_FAILED);
521         return;
522       case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
523         callback.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE);
524         return;
525       default:
526         break;
527     }
528   }
529
530   callback.Run(status);
531 }
532
533 void SyncFileSystemService::DidInitializeFileSystemForDump(
534     const GURL& origin,
535     const DumpFilesCallback& callback,
536     SyncStatusCode status) {
537   DCHECK(!origin.is_empty());
538
539   if (status != SYNC_STATUS_OK) {
540     callback.Run(base::ListValue());
541     return;
542   }
543
544   GetRemoteService(origin)->DumpFiles(
545       origin,
546       base::Bind(
547           &SyncFileSystemService::DidDumpFiles,
548           AsWeakPtr(),
549           origin,
550           callback));
551 }
552
553 void SyncFileSystemService::DidDumpFiles(
554     const GURL& origin,
555     const DumpFilesCallback& callback,
556     scoped_ptr<base::ListValue> dump_files) {
557   if (!dump_files || !dump_files->GetSize()) {
558     callback.Run(base::ListValue());
559     return;
560   }
561
562   base::ListValue* files = dump_files.get();
563   base::Callback<void(base::DictionaryValue*,
564                       SyncStatusCode,
565                       SyncFileStatus)> completion_callback =
566       base::Bind(&DidGetFileSyncStatusForDump,
567                  base::Owned(dump_files.release()),
568                  base::Owned(new size_t(0)),
569                  callback);
570
571   // After all metadata loaded, sync status can be added to each entry.
572   for (size_t i = 0; i < files->GetSize(); ++i) {
573     base::DictionaryValue* file = nullptr;
574     std::string path_string;
575     if (!files->GetDictionary(i, &file) ||
576         !file->GetString("path", &path_string)) {
577       NOTREACHED();
578       completion_callback.Run(
579           nullptr, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN);
580       continue;
581     }
582
583     base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path_string);
584     FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path);
585     GetFileSyncStatus(url, base::Bind(completion_callback, file));
586   }
587 }
588
589 void SyncFileSystemService::DidDumpDatabase(const DumpFilesCallback& callback,
590                                             scoped_ptr<base::ListValue> list) {
591   if (!list)
592     list = make_scoped_ptr(new base::ListValue);
593   callback.Run(*list);
594 }
595
596 void SyncFileSystemService::DidGetExtensionStatusMap(
597     const ExtensionStatusMapCallback& callback,
598     scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map) {
599   if (!status_map)
600     status_map = make_scoped_ptr(new RemoteFileSyncService::OriginStatusMap);
601   callback.Run(*status_map);
602 }
603
604 void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) {
605   sync_enabled_ = enabled;
606   remote_service_->SetSyncEnabled(sync_enabled_);
607 }
608
609 void SyncFileSystemService::DidGetLocalChangeStatus(
610     const SyncFileStatusCallback& callback,
611     SyncStatusCode status,
612     bool has_pending_local_changes) {
613   callback.Run(
614       status,
615       has_pending_local_changes ?
616           SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED);
617 }
618
619 void SyncFileSystemService::OnRemoteServiceStateUpdated(
620     RemoteServiceState state,
621     const std::string& description) {
622   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
623   util::Log(logging::LOG_VERBOSE, FROM_HERE,
624             "OnRemoteServiceStateChanged: %d %s", state, description.c_str());
625
626   FOR_EACH_OBSERVER(
627       SyncEventObserver, observers_,
628       OnSyncStateUpdated(GURL(),
629                          RemoteStateToSyncServiceState(state),
630                          description));
631
632   RunForEachSyncRunners(&SyncProcessRunner::Schedule);
633 }
634
635 void SyncFileSystemService::OnExtensionInstalled(
636     content::BrowserContext* browser_context,
637     const Extension* extension,
638     bool is_update) {
639   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
640   DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin;
641   // NOTE: When an app is uninstalled and re-installed in a sequence,
642   // |local_service_| may still keeps |app_origin| as disabled origin.
643   local_service_->SetOriginEnabled(app_origin, true);
644 }
645
646 void SyncFileSystemService::OnExtensionUnloaded(
647     content::BrowserContext* browser_context,
648     const Extension* extension,
649     extensions::UnloadedExtensionInfo::Reason reason) {
650   if (reason != extensions::UnloadedExtensionInfo::REASON_DISABLE)
651     return;
652
653   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
654   int disable_reasons =
655       ExtensionPrefs::Get(profile_)->GetDisableReasons(extension->id());
656   if (disable_reasons & Extension::DISABLE_RELOAD) {
657     // Bypass disabling the origin since the app will be re-enabled soon.
658     // NOTE: If re-enabling the app fails, the app is disabled while it is
659     // handled as enabled origin in the SyncFS. This should be safe and will be
660     // recovered when the user re-enables the app manually or the sync service
661     // restarts.
662     DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): "
663              << app_origin;
664     return;
665   }
666
667   DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
668            << app_origin;
669   GetRemoteService(app_origin)->DisableOrigin(
670       app_origin,
671       base::Bind(&DidHandleUnloadedEvent, app_origin));
672   local_service_->SetOriginEnabled(app_origin, false);
673 }
674
675 void SyncFileSystemService::OnExtensionUninstalled(
676     content::BrowserContext* browser_context,
677     const Extension* extension,
678     extensions::UninstallReason reason) {
679   RemoteFileSyncService::UninstallFlag flag =
680       RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE;
681   // If it's loaded from an unpacked package and with key: field,
682   // the uninstall will not be sync'ed and the user might be using the
683   // same app key in other installs, so avoid purging the remote folder.
684   if (extensions::Manifest::IsUnpackedLocation(extension->location()) &&
685       extension->manifest()->HasKey(extensions::manifest_keys::kKey)) {
686     flag = RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE;
687   }
688
689   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
690   DVLOG(1) << "Handle extension notification for UNINSTALLED: "
691            << app_origin;
692   GetRemoteService(app_origin)->UninstallOrigin(
693       app_origin, flag,
694       base::Bind(&DidHandleUninstalledEvent, app_origin));
695   local_service_->SetOriginEnabled(app_origin, false);
696 }
697
698 void SyncFileSystemService::OnExtensionLoaded(
699     content::BrowserContext* browser_context,
700     const Extension* extension) {
701   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
702   DVLOG(1) << "Handle extension notification for LOADED: " << app_origin;
703   GetRemoteService(app_origin)->EnableOrigin(
704       app_origin,
705       base::Bind(&DidHandleLoadEvent, app_origin));
706   local_service_->SetOriginEnabled(app_origin, true);
707 }
708
709 void SyncFileSystemService::OnStateChanged() {
710   ProfileSyncServiceBase* profile_sync_service =
711       ProfileSyncServiceFactory::GetForProfile(profile_);
712   if (profile_sync_service)
713     UpdateSyncEnabledStatus(profile_sync_service);
714 }
715
716 void SyncFileSystemService::OnFileStatusChanged(
717     const FileSystemURL& url,
718     SyncFileType file_type,
719     SyncFileStatus sync_status,
720     SyncAction action_taken,
721     SyncDirection direction) {
722   FOR_EACH_OBSERVER(
723       SyncEventObserver, observers_,
724       OnFileSynced(url, file_type, sync_status, action_taken, direction));
725 }
726
727 void SyncFileSystemService::UpdateSyncEnabledStatus(
728     ProfileSyncServiceBase* profile_sync_service) {
729   if (!profile_sync_service->HasSyncSetupCompleted())
730     return;
731   bool old_sync_enabled = sync_enabled_;
732   sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has(
733       syncer::APPS);
734   remote_service_->SetSyncEnabled(sync_enabled_);
735   if (!old_sync_enabled && sync_enabled_)
736     RunForEachSyncRunners(&SyncProcessRunner::Schedule);
737 }
738
739 void SyncFileSystemService::RunForEachSyncRunners(
740     void(SyncProcessRunner::*method)()) {
741   for (ScopedVector<SyncProcessRunner>::iterator iter =
742            local_sync_runners_.begin();
743        iter != local_sync_runners_.end(); ++iter)
744     ((*iter)->*method)();
745   for (ScopedVector<SyncProcessRunner>::iterator iter =
746            remote_sync_runners_.begin();
747        iter != remote_sync_runners_.end(); ++iter)
748     ((*iter)->*method)();
749 }
750
751 RemoteFileSyncService* SyncFileSystemService::GetRemoteService(
752     const GURL& origin) {
753   return remote_service_.get();
754 }
755
756 }  // namespace sync_file_system