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