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.
5 #include "chrome/browser/sync_file_system/sync_file_system_service.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"
38 #include "webkit/browser/fileapi/file_system_context.h"
40 using content::BrowserThread;
41 using extensions::Extension;
42 using extensions::ExtensionPrefs;
43 using extensions::ExtensionRegistry;
44 using fileapi::FileSystemURL;
45 using fileapi::FileSystemURLSet;
47 namespace sync_file_system {
51 const char kLocalSyncName[] = "Local sync";
52 const char kRemoteSyncName[] = "Remote sync";
53 const char kRemoteSyncNameV2[] = "Remote sync (v2)";
55 SyncServiceState RemoteStateToSyncServiceState(
56 RemoteServiceState 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:
71 NOTREACHED() << "Unknown remote service state: " << state;
72 return SYNC_SERVICE_DISABLED;
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());
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());
91 void DidHandleLoadEvent(
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());
101 std::string SyncFileStatusToString(SyncFileStatus sync_file_status) {
102 return extensions::api::sync_file_system::ToString(
103 extensions::SyncFileStatusToExtensionEnum(sync_file_status));
106 // Gets called repeatedly until every SyncFileStatus has been mapped.
107 void DidGetFileSyncStatusForDump(
108 base::ListValue* files,
110 const SyncFileSystemService::DumpFilesCallback& callback,
111 base::DictionaryValue* file,
112 SyncStatusCode sync_status_code,
113 SyncFileStatus sync_file_status) {
118 file->SetString("status", SyncFileStatusToString(sync_file_status));
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())
125 callback.Run(*files);
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) {
135 return service->GetLocalChangeProcessor(origin);
140 //---------------------------------------------------------------------------
141 // SyncProcessRunner's.
143 // SyncProcessRunner implementation for LocalSync.
144 class LocalSyncRunner : public SyncProcessRunner,
145 public LocalFileSyncService::Observer {
147 LocalSyncRunner(const std::string& name,
148 SyncFileSystemService* sync_service)
149 : SyncProcessRunner(name, sync_service,
150 scoped_ptr<SyncProcessRunner::TimerHelper>(), 1),
153 virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE {
154 GetSyncService()->local_service_->ProcessLocalChange(
155 base::Bind(&LocalSyncRunner::DidProcessLocalChange,
156 factory_.GetWeakPtr(), callback));
159 // LocalFileSyncService::Observer overrides.
160 virtual void OnLocalChangeAvailable(int64 pending_changes) OVERRIDE {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
163 OnChangesUpdated(pending_changes);
165 // Kick other sync runners just in case they're not running.
166 GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule);
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);
181 base::WeakPtrFactory<LocalSyncRunner> factory_;
182 DISALLOW_COPY_AND_ASSIGN(LocalSyncRunner);
185 // SyncProcessRunner implementation for RemoteSync.
186 class RemoteSyncRunner : public SyncProcessRunner,
187 public RemoteFileSyncService::Observer {
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),
198 virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE {
199 remote_service_->ProcessRemoteChange(
200 base::Bind(&RemoteSyncRunner::DidProcessRemoteChange,
201 factory_.GetWeakPtr(), callback));
204 virtual SyncServiceState GetServiceState() OVERRIDE {
205 return RemoteStateToSyncServiceState(last_state_);
208 // RemoteFileSyncService::Observer overrides.
209 virtual void OnRemoteChangeQueueUpdated(int64 pending_changes) OVERRIDE {
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
212 OnChangesUpdated(pending_changes);
214 // Kick other sync runners just in case they're not running.
215 GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule);
218 virtual void OnRemoteServiceStateUpdated(
219 RemoteServiceState state,
220 const std::string& description) OVERRIDE {
221 // Just forward to SyncFileSystemService.
222 GetSyncService()->OnRemoteServiceStateUpdated(state, description);
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());
236 if (status == SYNC_STATUS_FILE_BUSY) {
237 GetSyncService()->local_service_->RegisterURLForWaitingSync(
238 url, base::Bind(&RemoteSyncRunner::Schedule,
239 factory_.GetWeakPtr()));
241 callback.Run(status);
244 RemoteFileSyncService* remote_service_;
245 RemoteServiceState last_state_;
246 base::WeakPtrFactory<RemoteSyncRunner> factory_;
247 DISALLOW_COPY_AND_ASSIGN(RemoteSyncRunner);
250 //-----------------------------------------------------------------------------
251 // SyncFileSystemService
253 void SyncFileSystemService::Shutdown() {
254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
256 local_sync_runners_.clear();
257 remote_sync_runners_.clear();
259 local_service_->Shutdown();
260 local_service_.reset();
262 remote_service_.reset();
263 v2_remote_service_.reset();
265 ProfileSyncServiceBase* profile_sync_service =
266 ProfileSyncServiceFactory::GetForProfile(profile_);
267 if (profile_sync_service)
268 profile_sync_service->RemoveObserver(this);
270 ExtensionRegistry::Get(profile_)->RemoveObserver(this);
275 SyncFileSystemService::~SyncFileSystemService() {
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
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());
288 util::Log(logging::LOG_VERBOSE, FROM_HERE,
289 "Initializing for App: %s", app_origin.spec().c_str());
291 local_service_->MaybeInitializeFileSystemContext(
292 app_origin, file_system_context,
293 base::Bind(&SyncFileSystemService::DidInitializeFileSystem,
294 AsWeakPtr(), app_origin, callback));
297 void SyncFileSystemService::GetExtensionStatusMap(
298 const ExtensionStatusMapCallback& callback) {
299 remote_service_->GetOriginStatusMap(
300 base::Bind(&SyncFileSystemService::DidGetExtensionStatusMap,
301 AsWeakPtr(), callback));
304 void SyncFileSystemService::DumpFiles(const GURL& origin,
305 const DumpFilesCallback& callback) {
306 DCHECK(!origin.is_empty());
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));
318 void SyncFileSystemService::DumpDatabase(const DumpFilesCallback& callback) {
319 remote_service_->DumpDatabase(
320 base::Bind(&SyncFileSystemService::DidDumpDatabase,
321 AsWeakPtr(), callback));
324 void SyncFileSystemService::GetFileSyncStatus(
325 const FileSystemURL& url, const SyncFileStatusCallback& callback) {
326 DCHECK(local_service_);
327 DCHECK(GetRemoteService(url.origin()));
329 // It's possible to get an invalid FileEntry.
330 if (!url.is_valid()) {
331 base::ThreadTaskRunnerHandle::Get()->PostTask(
334 SYNC_FILE_ERROR_INVALID_URL,
335 SYNC_FILE_STATUS_UNKNOWN));
339 local_service_->HasPendingLocalChanges(
341 base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus,
342 AsWeakPtr(), callback));
345 void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) {
346 observers_.AddObserver(observer);
349 void SyncFileSystemService::RemoveSyncEventObserver(
350 SyncEventObserver* observer) {
351 observers_.RemoveObserver(observer);
354 LocalChangeProcessor* SyncFileSystemService::GetLocalChangeProcessor(
355 const GURL& origin) {
356 return GetRemoteService(origin)->GetLocalChangeProcessor();
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());
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());
380 SyncServiceState SyncFileSystemService::GetSyncServiceState() {
381 // For now we always query the state from the main RemoteFileSyncService.
382 return RemoteStateToSyncServiceState(remote_service_->GetCurrentState());
385 SyncFileSystemService* SyncFileSystemService::GetSyncService() {
389 SyncFileSystemService::SyncFileSystemService(Profile* profile)
391 sync_enabled_(true) {
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);
402 local_service_ = local_service.Pass();
403 remote_service_ = remote_service.Pass();
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()));
410 local_service_->AddChangeObserver(local_syncer.get());
411 local_service_->SetLocalChangeProcessorCallback(
412 base::Bind(&GetLocalChangeProcessorAdapter, AsWeakPtr()));
414 remote_service_->AddServiceObserver(remote_syncer.get());
415 remote_service_->AddFileStatusObserver(this);
416 remote_service_->SetRemoteChangeProcessor(local_service_.get());
418 local_sync_runners_.push_back(local_syncer.release());
419 remote_sync_runners_.push_back(remote_syncer.release());
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);
428 ExtensionRegistry::Get(profile_)->AddObserver(this);
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;
438 if (status != SYNC_STATUS_OK) {
439 callback.Run(status);
443 // Local side of initialization for the app is done.
444 // Continue on initializing the remote side.
445 GetRemoteService(app_origin)->RegisterOrigin(
447 base::Bind(&SyncFileSystemService::DidRegisterOrigin,
448 AsWeakPtr(), app_origin, callback));
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));
460 UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.RegisterOriginResult",
461 GetRemoteService(app_origin)->GetCurrentState(),
462 REMOTE_SERVICE_STATE_MAX);
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);
470 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
471 callback.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE);
478 callback.Run(status);
481 void SyncFileSystemService::DidInitializeFileSystemForDump(
483 const DumpFilesCallback& callback,
484 SyncStatusCode status) {
485 DCHECK(!origin.is_empty());
487 if (status != SYNC_STATUS_OK) {
488 callback.Run(base::ListValue());
492 GetRemoteService(origin)->DumpFiles(
495 &SyncFileSystemService::DidDumpFiles,
501 void SyncFileSystemService::DidDumpFiles(
503 const DumpFilesCallback& callback,
504 scoped_ptr<base::ListValue> dump_files) {
505 if (!dump_files || !dump_files->GetSize()) {
506 callback.Run(base::ListValue());
510 base::ListValue* files = dump_files.get();
511 base::Callback<void(base::DictionaryValue*,
513 SyncFileStatus)> completion_callback =
514 base::Bind(&DidGetFileSyncStatusForDump,
515 base::Owned(dump_files.release()),
516 base::Owned(new size_t(0)),
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)) {
526 completion_callback.Run(
527 NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN);
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));
537 void SyncFileSystemService::DidDumpDatabase(
538 const DumpFilesCallback& callback, scoped_ptr<base::ListValue> list) {
540 list = make_scoped_ptr(new base::ListValue);
542 if (!v2_remote_service_) {
547 v2_remote_service_->DumpDatabase(
548 base::Bind(&SyncFileSystemService::DidDumpV2Database,
549 AsWeakPtr(), callback, base::Passed(&list)));
552 void SyncFileSystemService::DidDumpV2Database(
553 const DumpFilesCallback& callback,
554 scoped_ptr<base::ListValue> v1list,
555 scoped_ptr<base::ListValue> v2list) {
557 v1list = make_scoped_ptr(new base::ListValue);
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());
568 callback.Run(*v1list);
571 void SyncFileSystemService::DidGetExtensionStatusMap(
572 const ExtensionStatusMapCallback& callback,
573 scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map) {
575 status_map = make_scoped_ptr(new RemoteFileSyncService::OriginStatusMap);
576 if (!v2_remote_service_) {
577 callback.Run(*status_map);
581 v2_remote_service_->GetOriginStatusMap(
582 base::Bind(&SyncFileSystemService::DidGetV2ExtensionStatusMap,
585 base::Passed(&status_map)));
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|.
594 status_map_v1 = make_scoped_ptr(new RemoteFileSyncService::OriginStatusMap);
596 status_map_v1->insert(status_map_v2->begin(), status_map_v2->end());
598 callback.Run(*status_map_v1);
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_);
608 void SyncFileSystemService::DidGetLocalChangeStatus(
609 const SyncFileStatusCallback& callback,
610 SyncStatusCode status,
611 bool has_pending_local_changes) {
614 has_pending_local_changes ?
615 SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED);
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());
626 SyncEventObserver, observers_,
627 OnSyncStateUpdated(GURL(),
628 RemoteStateToSyncServiceState(state),
631 RunForEachSyncRunners(&SyncProcessRunner::Schedule);
634 void SyncFileSystemService::OnExtensionInstalled(
635 content::BrowserContext* browser_context,
636 const Extension* extension,
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);
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)
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
661 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): "
666 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
668 GetRemoteService(app_origin)->DisableOrigin(
670 base::Bind(&DidHandleUnloadedEvent, app_origin));
671 local_service_->SetOriginEnabled(app_origin, false);
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;
688 GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
689 DVLOG(1) << "Handle extension notification for UNINSTALLED: "
691 GetRemoteService(app_origin)->UninstallOrigin(
693 base::Bind(&DidHandleUninstalledEvent, app_origin));
694 local_service_->SetOriginEnabled(app_origin, false);
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(
704 base::Bind(&DidHandleLoadEvent, app_origin));
705 local_service_->SetOriginEnabled(app_origin, true);
708 void SyncFileSystemService::OnStateChanged() {
709 ProfileSyncServiceBase* profile_sync_service =
710 ProfileSyncServiceFactory::GetForProfile(profile_);
711 if (profile_sync_service)
712 UpdateSyncEnabledStatus(profile_sync_service);
715 void SyncFileSystemService::OnFileStatusChanged(
716 const FileSystemURL& url,
717 SyncFileStatus sync_status,
718 SyncAction action_taken,
719 SyncDirection direction) {
721 SyncEventObserver, observers_,
722 OnFileSynced(url, sync_status, action_taken, direction));
725 void SyncFileSystemService::UpdateSyncEnabledStatus(
726 ProfileSyncServiceBase* profile_sync_service) {
727 if (!profile_sync_service->HasSyncSetupCompleted())
729 bool old_sync_enabled = sync_enabled_;
730 sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has(
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);
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)();
751 RemoteFileSyncService* SyncFileSystemService::GetRemoteService(
752 const GURL& origin) {
754 return remote_service_.get();
755 if (!IsV2EnabledForOrigin(origin))
756 return remote_service_.get();
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());
770 return v2_remote_service_.get();
773 } // namespace sync_file_system