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/stl_util.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
16 #include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/sync/profile_sync_service.h"
19 #include "chrome/browser/sync/profile_sync_service_factory.h"
20 #include "chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.h"
21 #include "chrome/browser/sync_file_system/local/local_file_sync_service.h"
22 #include "chrome/browser/sync_file_system/logger.h"
23 #include "chrome/browser/sync_file_system/sync_direction.h"
24 #include "chrome/browser/sync_file_system/sync_event_observer.h"
25 #include "chrome/browser/sync_file_system/sync_file_metadata.h"
26 #include "chrome/browser/sync_file_system/sync_status_code.h"
27 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
28 #include "chrome/common/extensions/extension.h"
29 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/browser/notification_details.h"
32 #include "content/public/browser/notification_service.h"
33 #include "content/public/browser/storage_partition.h"
35 #include "webkit/browser/fileapi/file_system_context.h"
37 using content::BrowserThread
;
38 using fileapi::FileSystemURL
;
39 using fileapi::FileSystemURLSet
;
41 namespace sync_file_system
{
45 const int64 kRetryTimerIntervalInSeconds
= 20 * 60; // 20 min.
47 SyncServiceState
RemoteStateToSyncServiceState(
48 RemoteServiceState state
) {
50 case REMOTE_SERVICE_OK
:
51 return SYNC_SERVICE_RUNNING
;
52 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE
:
53 return SYNC_SERVICE_TEMPORARY_UNAVAILABLE
;
54 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED
:
55 return SYNC_SERVICE_AUTHENTICATION_REQUIRED
;
56 case REMOTE_SERVICE_DISABLED
:
57 return SYNC_SERVICE_DISABLED
;
59 NOTREACHED() << "Unknown remote service state: " << state
;
60 return SYNC_SERVICE_DISABLED
;
63 void DidHandleOriginForExtensionUnloadedEvent(
66 SyncStatusCode code
) {
67 DCHECK(chrome::NOTIFICATION_EXTENSION_UNLOADED
== type
||
68 chrome::NOTIFICATION_EXTENSION_UNINSTALLED
== type
);
69 if (code
!= SYNC_STATUS_OK
&&
70 code
!= SYNC_STATUS_UNKNOWN_ORIGIN
) {
72 case chrome::NOTIFICATION_EXTENSION_UNLOADED
:
73 util::Log(logging::LOG_WARNING
,
75 "Disabling origin for UNLOADED(DISABLE) failed: %s",
76 origin
.spec().c_str());
78 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED
:
79 util::Log(logging::LOG_WARNING
,
81 "Uninstall origin for UNINSTALLED failed: %s",
82 origin
.spec().c_str());
90 void DidHandleOriginForExtensionEnabledEvent(
93 SyncStatusCode code
) {
94 DCHECK(chrome::NOTIFICATION_EXTENSION_ENABLED
== type
);
95 if (code
!= SYNC_STATUS_OK
)
96 util::Log(logging::LOG_WARNING
,
98 "Enabling origin for ENABLED failed: %s",
99 origin
.spec().c_str());
102 std::string
SyncFileStatusToString(SyncFileStatus sync_file_status
) {
103 return extensions::api::sync_file_system::ToString(
104 extensions::SyncFileStatusToExtensionEnum(sync_file_status
));
107 // Gets called repeatedly until every SyncFileStatus has been mapped.
108 void DidGetFileSyncStatusForDump(
109 base::ListValue
* files
,
111 const SyncFileSystemService::DumpFilesCallback
& callback
,
112 base::DictionaryValue
* file
,
113 SyncStatusCode sync_status_code
,
114 SyncFileStatus sync_file_status
) {
119 file
->SetString("status", SyncFileStatusToString(sync_file_status
));
121 // Once all results have been received, run the callback to signal end.
122 DCHECK_LE(*num_results
, files
->GetSize());
123 if (++*num_results
< files
->GetSize())
131 void SyncFileSystemService::Shutdown() {
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
134 local_file_service_
->Shutdown();
135 local_file_service_
.reset();
137 remote_file_service_
.reset();
139 ProfileSyncServiceBase
* profile_sync_service
=
140 ProfileSyncServiceFactory::GetForProfile(profile_
);
141 if (profile_sync_service
)
142 profile_sync_service
->RemoveObserver(this);
147 SyncFileSystemService::~SyncFileSystemService() {
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
152 void SyncFileSystemService::InitializeForApp(
153 fileapi::FileSystemContext
* file_system_context
,
154 const GURL
& app_origin
,
155 const SyncStatusCallback
& callback
) {
156 DCHECK(local_file_service_
);
157 DCHECK(remote_file_service_
);
158 DCHECK(app_origin
== app_origin
.GetOrigin());
160 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
161 "Initializing for App: %s", app_origin
.spec().c_str());
163 local_file_service_
->MaybeInitializeFileSystemContext(
164 app_origin
, file_system_context
,
165 base::Bind(&SyncFileSystemService::DidInitializeFileSystem
,
166 AsWeakPtr(), app_origin
, callback
));
169 SyncServiceState
SyncFileSystemService::GetSyncServiceState() {
170 return RemoteStateToSyncServiceState(remote_file_service_
->GetCurrentState());
173 void SyncFileSystemService::GetExtensionStatusMap(
174 std::map
<GURL
, std::string
>* status_map
) {
176 remote_file_service_
->GetOriginStatusMap(status_map
);
179 void SyncFileSystemService::DumpFiles(const GURL
& origin
,
180 const DumpFilesCallback
& callback
) {
181 DCHECK(!origin
.is_empty());
183 content::StoragePartition
* storage_partition
=
184 content::BrowserContext::GetStoragePartitionForSite(profile_
, origin
);
185 fileapi::FileSystemContext
* file_system_context
=
186 storage_partition
->GetFileSystemContext();
187 local_file_service_
->MaybeInitializeFileSystemContext(
188 origin
, file_system_context
,
189 base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump
,
190 AsWeakPtr(), origin
, callback
));
193 void SyncFileSystemService::GetFileSyncStatus(
194 const FileSystemURL
& url
, const SyncFileStatusCallback
& callback
) {
195 DCHECK(local_file_service_
);
196 DCHECK(remote_file_service_
);
198 // It's possible to get an invalid FileEntry.
199 if (!url
.is_valid()) {
200 base::MessageLoopProxy::current()->PostTask(
203 SYNC_FILE_ERROR_INVALID_URL
,
204 SYNC_FILE_STATUS_UNKNOWN
));
208 if (remote_file_service_
->IsConflicting(url
)) {
209 base::MessageLoopProxy::current()->PostTask(
213 SYNC_FILE_STATUS_CONFLICTING
));
217 local_file_service_
->HasPendingLocalChanges(
219 base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus
,
220 AsWeakPtr(), callback
));
223 void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver
* observer
) {
224 observers_
.AddObserver(observer
);
227 void SyncFileSystemService::RemoveSyncEventObserver(
228 SyncEventObserver
* observer
) {
229 observers_
.RemoveObserver(observer
);
232 ConflictResolutionPolicy
233 SyncFileSystemService::GetConflictResolutionPolicy() const {
234 return remote_file_service_
->GetConflictResolutionPolicy();
237 SyncStatusCode
SyncFileSystemService::SetConflictResolutionPolicy(
238 ConflictResolutionPolicy policy
) {
239 return remote_file_service_
->SetConflictResolutionPolicy(policy
);
242 SyncFileSystemService::SyncFileSystemService(Profile
* profile
)
244 pending_local_changes_(0),
245 pending_remote_changes_(0),
246 local_sync_running_(false),
247 remote_sync_running_(false),
248 is_waiting_remote_sync_enabled_(false),
249 sync_enabled_(true) {
252 void SyncFileSystemService::Initialize(
253 scoped_ptr
<LocalFileSyncService
> local_file_service
,
254 scoped_ptr
<RemoteFileSyncService
> remote_file_service
) {
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
256 DCHECK(local_file_service
);
257 DCHECK(remote_file_service
);
260 local_file_service_
= local_file_service
.Pass();
261 remote_file_service_
= remote_file_service
.Pass();
263 local_file_service_
->AddChangeObserver(this);
264 local_file_service_
->SetLocalChangeProcessor(
265 remote_file_service_
->GetLocalChangeProcessor());
267 remote_file_service_
->AddServiceObserver(this);
268 remote_file_service_
->AddFileStatusObserver(this);
269 remote_file_service_
->SetRemoteChangeProcessor(local_file_service_
.get());
271 ProfileSyncServiceBase
* profile_sync_service
=
272 ProfileSyncServiceFactory::GetForProfile(profile_
);
273 if (profile_sync_service
) {
274 UpdateSyncEnabledStatus(profile_sync_service
);
275 profile_sync_service
->AddObserver(this);
278 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED
,
279 content::Source
<Profile
>(profile_
));
280 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED
,
281 content::Source
<Profile
>(profile_
));
282 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED
,
283 content::Source
<Profile
>(profile_
));
284 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED
,
285 content::Source
<Profile
>(profile_
));
288 void SyncFileSystemService::DidInitializeFileSystem(
289 const GURL
& app_origin
,
290 const SyncStatusCallback
& callback
,
291 SyncStatusCode status
) {
292 DVLOG(1) << "DidInitializeFileSystem: "
293 << app_origin
.spec() << " " << status
;
295 if (status
!= SYNC_STATUS_OK
) {
296 callback
.Run(status
);
300 // Local side of initialization for the app is done.
301 // Continue on initializing the remote side.
302 remote_file_service_
->RegisterOriginForTrackingChanges(
304 base::Bind(&SyncFileSystemService::DidRegisterOrigin
,
305 AsWeakPtr(), app_origin
, callback
));
308 void SyncFileSystemService::DidRegisterOrigin(
309 const GURL
& app_origin
,
310 const SyncStatusCallback
& callback
,
311 SyncStatusCode status
) {
312 DVLOG(1) << "DidRegisterOrigin: " << app_origin
.spec() << " " << status
;
314 callback
.Run(status
);
317 void SyncFileSystemService::DidInitializeFileSystemForDump(
319 const DumpFilesCallback
& callback
,
320 SyncStatusCode status
) {
321 DCHECK(!origin
.is_empty());
323 if (status
!= SYNC_STATUS_OK
) {
324 base::ListValue empty_result
;
325 callback
.Run(&empty_result
);
329 base::ListValue
* files
= remote_file_service_
->DumpFiles(origin
).release();
330 if (!files
->GetSize()) {
335 base::Callback
<void(base::DictionaryValue
* file
,
336 SyncStatusCode sync_status
,
337 SyncFileStatus sync_file_status
)> completion_callback
=
338 base::Bind(&DidGetFileSyncStatusForDump
, base::Owned(files
),
339 base::Owned(new size_t(0)), callback
);
341 // After all metadata loaded, sync status can be added to each entry.
342 for (size_t i
= 0; i
< files
->GetSize(); ++i
) {
343 base::DictionaryValue
* file
= NULL
;
344 std::string path_string
;
345 if (!files
->GetDictionary(i
, &file
) ||
346 !file
->GetString("path", &path_string
)) {
348 completion_callback
.Run(
349 NULL
, SYNC_FILE_ERROR_FAILED
, SYNC_FILE_STATUS_UNKNOWN
);
353 base::FilePath file_path
= base::FilePath::FromUTF8Unsafe(path_string
);
354 FileSystemURL url
= CreateSyncableFileSystemURL(origin
, file_path
);
355 GetFileSyncStatus(url
, base::Bind(completion_callback
, file
));
359 void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled
) {
360 sync_enabled_
= enabled
;
361 remote_file_service_
->SetSyncEnabled(sync_enabled_
);
364 void SyncFileSystemService::MaybeStartSync() {
365 if (!profile_
|| !sync_enabled_
)
368 if (pending_local_changes_
+ pending_remote_changes_
== 0)
371 DVLOG(2) << "MaybeStartSync() called (remote service state:"
372 << remote_file_service_
->GetCurrentState() << ")";
373 switch (remote_file_service_
->GetCurrentState()) {
374 case REMOTE_SERVICE_OK
:
377 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE
:
378 if (sync_retry_timer_
.IsRunning())
380 sync_retry_timer_
.Start(
382 base::TimeDelta::FromSeconds(kRetryTimerIntervalInSeconds
),
383 this, &SyncFileSystemService::MaybeStartSync
);
386 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED
:
387 case REMOTE_SERVICE_DISABLED
:
388 // No point to run sync.
396 void SyncFileSystemService::StartRemoteSync() {
397 // See if we cannot / should not start a new remote sync.
398 if (remote_sync_running_
|| pending_remote_changes_
== 0)
400 // If we have registered a URL for waiting until sync is enabled on a
401 // file (and the registerred URL seems to be still valid) it won't be
402 // worth trying to start another remote sync.
403 if (is_waiting_remote_sync_enabled_
)
405 DCHECK(sync_enabled_
);
407 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
408 "Calling ProcessRemoteChange for RemoteSync");
409 remote_sync_running_
= true;
410 remote_file_service_
->ProcessRemoteChange(
411 base::Bind(&SyncFileSystemService::DidProcessRemoteChange
,
415 void SyncFileSystemService::StartLocalSync() {
416 // See if we cannot / should not start a new local sync.
417 if (local_sync_running_
|| pending_local_changes_
== 0)
419 DCHECK(sync_enabled_
);
421 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
422 "Calling ProcessLocalChange for LocalSync");
423 local_sync_running_
= true;
424 local_file_service_
->ProcessLocalChange(
425 base::Bind(&SyncFileSystemService::DidProcessLocalChange
,
429 void SyncFileSystemService::DidProcessRemoteChange(
430 SyncStatusCode status
,
431 const FileSystemURL
& url
) {
432 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
433 "ProcessRemoteChange finished with status=%d (%s) for url=%s",
434 status
, SyncStatusCodeToString(status
), url
.DebugString().c_str());
435 DCHECK(remote_sync_running_
);
436 remote_sync_running_
= false;
438 if (status
!= SYNC_STATUS_NO_CHANGE_TO_SYNC
&&
439 remote_file_service_
->GetCurrentState() != REMOTE_SERVICE_DISABLED
) {
440 DCHECK(url
.is_valid());
441 local_file_service_
->ClearSyncFlagForURL(url
);
444 if (status
== SYNC_STATUS_NO_CHANGE_TO_SYNC
) {
445 // We seem to have no changes to work on for now.
446 // TODO(kinuko): Might be better setting a timer to call MaybeStartSync.
449 if (status
== SYNC_STATUS_FILE_BUSY
) {
450 is_waiting_remote_sync_enabled_
= true;
451 local_file_service_
->RegisterURLForWaitingSync(
452 url
, base::Bind(&SyncFileSystemService::OnSyncEnabledForRemoteSync
,
457 base::MessageLoopProxy::current()->PostTask(
458 FROM_HERE
, base::Bind(&SyncFileSystemService::MaybeStartSync
,
462 void SyncFileSystemService::DidProcessLocalChange(
463 SyncStatusCode status
, const FileSystemURL
& url
) {
464 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
465 "ProcessLocalChange finished with status=%d (%s) for url=%s",
466 status
, SyncStatusCodeToString(status
), url
.DebugString().c_str());
467 DCHECK(local_sync_running_
);
468 local_sync_running_
= false;
470 if (status
== SYNC_STATUS_NO_CHANGE_TO_SYNC
) {
471 // We seem to have no changes to work on for now.
475 DCHECK(url
.is_valid());
476 local_file_service_
->ClearSyncFlagForURL(url
);
478 base::MessageLoopProxy::current()->PostTask(
479 FROM_HERE
, base::Bind(&SyncFileSystemService::MaybeStartSync
,
483 void SyncFileSystemService::DidGetLocalChangeStatus(
484 const SyncFileStatusCallback
& callback
,
485 SyncStatusCode status
,
486 bool has_pending_local_changes
) {
489 has_pending_local_changes
?
490 SYNC_FILE_STATUS_HAS_PENDING_CHANGES
: SYNC_FILE_STATUS_SYNCED
);
493 void SyncFileSystemService::OnSyncEnabledForRemoteSync() {
494 is_waiting_remote_sync_enabled_
= false;
498 void SyncFileSystemService::OnLocalChangeAvailable(int64 pending_changes
) {
499 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
500 DCHECK_GE(pending_changes
, 0);
501 if (pending_local_changes_
!= pending_changes
) {
502 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
503 "OnLocalChangeAvailable: %" PRId64
, pending_changes
);
505 pending_local_changes_
= pending_changes
;
506 if (pending_changes
== 0)
509 base::MessageLoopProxy::current()->PostTask(
510 FROM_HERE
, base::Bind(&SyncFileSystemService::MaybeStartSync
,
514 void SyncFileSystemService::OnRemoteChangeQueueUpdated(int64 pending_changes
) {
515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
516 DCHECK_GE(pending_changes
, 0);
518 if (pending_remote_changes_
!= pending_changes
) {
519 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
520 "OnRemoteChangeAvailable: %" PRId64
, pending_changes
);
522 pending_remote_changes_
= pending_changes
;
523 if (pending_changes
== 0)
526 // The smallest change available might have changed from the previous one.
527 // Reset the is_waiting_remote_sync_enabled_ flag so that we can retry.
528 is_waiting_remote_sync_enabled_
= false;
530 base::MessageLoopProxy::current()->PostTask(
531 FROM_HERE
, base::Bind(&SyncFileSystemService::MaybeStartSync
,
535 void SyncFileSystemService::OnRemoteServiceStateUpdated(
536 RemoteServiceState state
,
537 const std::string
& description
) {
538 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
539 util::Log(logging::LOG_INFO
, FROM_HERE
,
540 "OnRemoteServiceStateChanged: %d %s", state
, description
.c_str());
542 if (state
== REMOTE_SERVICE_OK
) {
543 base::MessageLoopProxy::current()->PostTask(
544 FROM_HERE
, base::Bind(&SyncFileSystemService::MaybeStartSync
,
549 SyncEventObserver
, observers_
,
550 OnSyncStateUpdated(GURL(),
551 RemoteStateToSyncServiceState(state
),
555 void SyncFileSystemService::Observe(
557 const content::NotificationSource
& source
,
558 const content::NotificationDetails
& details
) {
559 // Event notification sequence.
561 // (User action) (Notification type)
562 // Install: INSTALLED.
563 // Update: INSTALLED.
564 // Uninstall: UNINSTALLED.
565 // Launch, Close: No notification.
567 // Disable: UNLOADED(DISABLE).
568 // Reload, Restart: UNLOADED(DISABLE) -> INSTALLED -> ENABLED.
571 case chrome::NOTIFICATION_EXTENSION_INSTALLED
:
572 HandleExtensionInstalled(details
);
574 case chrome::NOTIFICATION_EXTENSION_UNLOADED
:
575 HandleExtensionUnloaded(type
, details
);
577 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED
:
578 HandleExtensionUninstalled(type
, details
);
580 case chrome::NOTIFICATION_EXTENSION_ENABLED
:
581 HandleExtensionEnabled(type
, details
);
584 NOTREACHED() << "Unknown notification.";
589 void SyncFileSystemService::HandleExtensionInstalled(
590 const content::NotificationDetails
& details
) {
591 const extensions::Extension
* extension
=
592 content::Details
<const extensions::InstalledExtensionInfo
>(details
)->
595 extensions::Extension::GetBaseURLFromExtensionId(extension
->id());
596 DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin
;
597 // NOTE: When an app is uninstalled and re-installed in a sequence,
598 // |local_file_service_| may still keeps |app_origin| as disabled origin.
599 local_file_service_
->SetOriginEnabled(app_origin
, true);
602 void SyncFileSystemService::HandleExtensionUnloaded(
604 const content::NotificationDetails
& details
) {
605 content::Details
<const extensions::UnloadedExtensionInfo
> info(details
);
606 std::string extension_id
= info
->extension
->id();
608 extensions::Extension::GetBaseURLFromExtensionId(extension_id
);
609 if (info
->reason
!= extension_misc::UNLOAD_REASON_DISABLE
)
611 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
613 remote_file_service_
->DisableOriginForTrackingChanges(
615 base::Bind(&DidHandleOriginForExtensionUnloadedEvent
,
617 local_file_service_
->SetOriginEnabled(app_origin
, false);
620 void SyncFileSystemService::HandleExtensionUninstalled(
622 const content::NotificationDetails
& details
) {
623 std::string extension_id
=
624 content::Details
<const extensions::Extension
>(details
)->id();
626 extensions::Extension::GetBaseURLFromExtensionId(extension_id
);
627 DVLOG(1) << "Handle extension notification for UNINSTALLED: "
629 remote_file_service_
->UninstallOrigin(
631 base::Bind(&DidHandleOriginForExtensionUnloadedEvent
,
633 local_file_service_
->SetOriginEnabled(app_origin
, false);
636 void SyncFileSystemService::HandleExtensionEnabled(
638 const content::NotificationDetails
& details
) {
639 std::string extension_id
=
640 content::Details
<const extensions::Extension
>(details
)->id();
642 extensions::Extension::GetBaseURLFromExtensionId(extension_id
);
643 DVLOG(1) << "Handle extension notification for ENABLED: " << app_origin
;
644 remote_file_service_
->EnableOriginForTrackingChanges(
646 base::Bind(&DidHandleOriginForExtensionEnabledEvent
, type
, app_origin
));
647 local_file_service_
->SetOriginEnabled(app_origin
, true);
650 void SyncFileSystemService::OnStateChanged() {
651 ProfileSyncServiceBase
* profile_sync_service
=
652 ProfileSyncServiceFactory::GetForProfile(profile_
);
653 if (profile_sync_service
)
654 UpdateSyncEnabledStatus(profile_sync_service
);
657 void SyncFileSystemService::OnFileStatusChanged(
658 const FileSystemURL
& url
,
659 SyncFileStatus sync_status
,
660 SyncAction action_taken
,
661 SyncDirection direction
) {
663 SyncEventObserver
, observers_
,
664 OnFileSynced(url
, sync_status
, action_taken
, direction
));
667 void SyncFileSystemService::UpdateSyncEnabledStatus(
668 ProfileSyncServiceBase
* profile_sync_service
) {
669 if (!profile_sync_service
->HasSyncSetupCompleted())
671 sync_enabled_
= profile_sync_service
->GetActiveDataTypes().Has(
673 remote_file_service_
->SetSyncEnabled(sync_enabled_
);
675 base::MessageLoopProxy::current()->PostTask(
676 FROM_HERE
, base::Bind(&SyncFileSystemService::MaybeStartSync
,
681 } // namespace sync_file_system