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/extensions/extension_prefs.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/sync/profile_sync_service.h"
20 #include "chrome/browser/sync/profile_sync_service_factory.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_process_runner.h"
27 #include "chrome/browser/sync_file_system/sync_status_code.h"
28 #include "chrome/browser/sync_file_system/syncable_file_system_util.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"
34 #include "extensions/common/extension.h"
35 #include "extensions/common/manifest_constants.h"
37 #include "webkit/browser/fileapi/file_system_context.h"
39 using content::BrowserThread
;
40 using extensions::Extension
;
41 using extensions::ExtensionPrefs
;
42 using fileapi::FileSystemURL
;
43 using fileapi::FileSystemURLSet
;
45 namespace sync_file_system
{
49 const char kLocalSyncName
[] = "Local sync";
50 const char kRemoteSyncName
[] = "Remote sync";
51 const char kRemoteSyncNameV2
[] = "Remote sync (v2)";
53 SyncServiceState
RemoteStateToSyncServiceState(
54 RemoteServiceState state
) {
56 case REMOTE_SERVICE_OK
:
57 return SYNC_SERVICE_RUNNING
;
58 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE
:
59 return SYNC_SERVICE_TEMPORARY_UNAVAILABLE
;
60 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED
:
61 return SYNC_SERVICE_AUTHENTICATION_REQUIRED
;
62 case REMOTE_SERVICE_DISABLED
:
63 return SYNC_SERVICE_DISABLED
;
65 NOTREACHED() << "Unknown remote service state: " << state
;
66 return SYNC_SERVICE_DISABLED
;
69 void DidHandleOriginForExtensionUnloadedEvent(
72 SyncStatusCode code
) {
73 DCHECK(chrome::NOTIFICATION_EXTENSION_UNLOADED
== type
||
74 chrome::NOTIFICATION_EXTENSION_UNINSTALLED
== type
);
75 if (code
!= SYNC_STATUS_OK
&&
76 code
!= SYNC_STATUS_UNKNOWN_ORIGIN
) {
78 case chrome::NOTIFICATION_EXTENSION_UNLOADED
:
79 util::Log(logging::LOG_WARNING
,
81 "Disabling origin for UNLOADED(DISABLE) failed: %s",
82 origin
.spec().c_str());
84 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED
:
85 util::Log(logging::LOG_WARNING
,
87 "Uninstall origin for UNINSTALLED failed: %s",
88 origin
.spec().c_str());
96 void DidHandleOriginForExtensionEnabledEvent(
99 SyncStatusCode code
) {
100 DCHECK(chrome::NOTIFICATION_EXTENSION_ENABLED
== type
);
101 if (code
!= SYNC_STATUS_OK
)
102 util::Log(logging::LOG_WARNING
,
104 "Enabling origin for ENABLED failed: %s",
105 origin
.spec().c_str());
108 std::string
SyncFileStatusToString(SyncFileStatus sync_file_status
) {
109 return extensions::api::sync_file_system::ToString(
110 extensions::SyncFileStatusToExtensionEnum(sync_file_status
));
113 // Gets called repeatedly until every SyncFileStatus has been mapped.
114 void DidGetFileSyncStatusForDump(
115 base::ListValue
* files
,
117 const SyncFileSystemService::DumpFilesCallback
& callback
,
118 base::DictionaryValue
* file
,
119 SyncStatusCode sync_status_code
,
120 SyncFileStatus sync_file_status
) {
125 file
->SetString("status", SyncFileStatusToString(sync_file_status
));
127 // Once all results have been received, run the callback to signal end.
128 DCHECK_LE(*num_results
, files
->GetSize());
129 if (++*num_results
< files
->GetSize())
135 // We need this indirection because WeakPtr can only be bound to methods
136 // without a return value.
137 LocalChangeProcessor
* GetLocalChangeProcessorAdapter(
138 base::WeakPtr
<SyncFileSystemService
> service
,
139 const GURL
& origin
) {
142 return service
->GetLocalChangeProcessor(origin
);
147 //---------------------------------------------------------------------------
148 // SyncProcessRunner's.
150 // SyncProcessRunner implementation for LocalSync.
151 class LocalSyncRunner
: public SyncProcessRunner
,
152 public LocalFileSyncService::Observer
{
154 LocalSyncRunner(const std::string
& name
,
155 SyncFileSystemService
* sync_service
)
156 : SyncProcessRunner(name
, sync_service
),
159 virtual void StartSync(const SyncStatusCallback
& callback
) OVERRIDE
{
160 sync_service()->local_service_
->ProcessLocalChange(
161 base::Bind(&LocalSyncRunner::DidProcessLocalChange
,
162 factory_
.GetWeakPtr(), callback
));
165 // LocalFileSyncService::Observer overrides.
166 virtual void OnLocalChangeAvailable(int64 pending_changes
) OVERRIDE
{
167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
169 OnChangesUpdated(pending_changes
);
171 // Kick other sync runners just in case they're not running.
172 sync_service()->RunForEachSyncRunners(
173 &SyncProcessRunner::ScheduleIfNotRunning
);
177 void DidProcessLocalChange(
178 const SyncStatusCallback
& callback
,
179 SyncStatusCode status
,
180 const FileSystemURL
& url
) {
181 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
182 "ProcessLocalChange finished with status=%d (%s) for url=%s",
183 status
, SyncStatusCodeToString(status
),
184 url
.DebugString().c_str());
185 callback
.Run(status
);
188 base::WeakPtrFactory
<LocalSyncRunner
> factory_
;
189 DISALLOW_COPY_AND_ASSIGN(LocalSyncRunner
);
192 // SyncProcessRunner implementation for RemoteSync.
193 class RemoteSyncRunner
: public SyncProcessRunner
,
194 public RemoteFileSyncService::Observer
{
196 RemoteSyncRunner(const std::string
& name
,
197 SyncFileSystemService
* sync_service
,
198 RemoteFileSyncService
* remote_service
)
199 : SyncProcessRunner(name
, sync_service
),
200 remote_service_(remote_service
),
201 last_state_(REMOTE_SERVICE_OK
),
204 virtual void StartSync(const SyncStatusCallback
& callback
) OVERRIDE
{
205 remote_service_
->ProcessRemoteChange(
206 base::Bind(&RemoteSyncRunner::DidProcessRemoteChange
,
207 factory_
.GetWeakPtr(), callback
));
210 virtual SyncServiceState
GetServiceState() OVERRIDE
{
211 return RemoteStateToSyncServiceState(last_state_
);
214 // RemoteFileSyncService::Observer overrides.
215 virtual void OnRemoteChangeQueueUpdated(int64 pending_changes
) OVERRIDE
{
216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
218 OnChangesUpdated(pending_changes
);
220 // Kick other sync runners just in case they're not running.
221 sync_service()->RunForEachSyncRunners(
222 &SyncProcessRunner::ScheduleIfNotRunning
);
225 virtual void OnRemoteServiceStateUpdated(
226 RemoteServiceState state
,
227 const std::string
& description
) OVERRIDE
{
228 // Just forward to SyncFileSystemService.
229 sync_service()->OnRemoteServiceStateUpdated(state
, description
);
234 void DidProcessRemoteChange(
235 const SyncStatusCallback
& callback
,
236 SyncStatusCode status
,
237 const FileSystemURL
& url
) {
238 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
239 "ProcessRemoteChange finished with status=%d (%s) for url=%s",
240 status
, SyncStatusCodeToString(status
),
241 url
.DebugString().c_str());
243 if (status
== SYNC_STATUS_FILE_BUSY
) {
244 sync_service()->local_service_
->RegisterURLForWaitingSync(
245 url
, base::Bind(&RemoteSyncRunner::Schedule
,
246 factory_
.GetWeakPtr()));
248 callback
.Run(status
);
251 RemoteFileSyncService
* remote_service_
;
252 RemoteServiceState last_state_
;
253 base::WeakPtrFactory
<RemoteSyncRunner
> factory_
;
254 DISALLOW_COPY_AND_ASSIGN(RemoteSyncRunner
);
257 //-----------------------------------------------------------------------------
258 // SyncFileSystemService
260 void SyncFileSystemService::Shutdown() {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
263 local_service_
->Shutdown();
264 local_service_
.reset();
266 remote_service_
.reset();
267 v2_remote_service_
.reset();
269 ProfileSyncServiceBase
* profile_sync_service
=
270 ProfileSyncServiceFactory::GetForProfile(profile_
);
271 if (profile_sync_service
)
272 profile_sync_service
->RemoveObserver(this);
277 SyncFileSystemService::~SyncFileSystemService() {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
282 void SyncFileSystemService::InitializeForApp(
283 fileapi::FileSystemContext
* file_system_context
,
284 const GURL
& app_origin
,
285 const SyncStatusCallback
& callback
) {
286 DCHECK(local_service_
);
287 DCHECK(remote_service_
);
288 DCHECK(app_origin
== app_origin
.GetOrigin());
290 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
291 "Initializing for App: %s", app_origin
.spec().c_str());
293 local_service_
->MaybeInitializeFileSystemContext(
294 app_origin
, file_system_context
,
295 base::Bind(&SyncFileSystemService::DidInitializeFileSystem
,
296 AsWeakPtr(), app_origin
, callback
));
299 SyncServiceState
SyncFileSystemService::GetSyncServiceState() {
300 // For now we always query the state from the main RemoteFileSyncService.
301 return RemoteStateToSyncServiceState(remote_service_
->GetCurrentState());
304 void SyncFileSystemService::GetExtensionStatusMap(
305 std::map
<GURL
, std::string
>* status_map
) {
308 remote_service_
->GetOriginStatusMap(status_map
);
309 if (v2_remote_service_
)
310 v2_remote_service_
->GetOriginStatusMap(status_map
);
313 void SyncFileSystemService::DumpFiles(const GURL
& origin
,
314 const DumpFilesCallback
& callback
) {
315 DCHECK(!origin
.is_empty());
317 content::StoragePartition
* storage_partition
=
318 content::BrowserContext::GetStoragePartitionForSite(profile_
, origin
);
319 fileapi::FileSystemContext
* file_system_context
=
320 storage_partition
->GetFileSystemContext();
321 local_service_
->MaybeInitializeFileSystemContext(
322 origin
, file_system_context
,
323 base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump
,
324 AsWeakPtr(), origin
, callback
));
327 scoped_ptr
<base::ListValue
> SyncFileSystemService::DumpDatabase() {
328 scoped_ptr
<base::ListValue
> list
= remote_service_
->DumpDatabase();
330 list
.reset(new base::ListValue
);
331 if (v2_remote_service_
) {
332 scoped_ptr
<base::ListValue
> v2list
= v2_remote_service_
->DumpDatabase();
335 for (base::ListValue::iterator itr
= v2list
->begin();
336 itr
!= v2list
->end(); ) {
337 scoped_ptr
<base::Value
> item
;
338 itr
= v2list
->Erase(itr
, &item
);
339 list
->Append(item
.release());
345 void SyncFileSystemService::GetFileSyncStatus(
346 const FileSystemURL
& url
, const SyncFileStatusCallback
& callback
) {
347 DCHECK(local_service_
);
348 DCHECK(GetRemoteService(url
.origin()));
350 // It's possible to get an invalid FileEntry.
351 if (!url
.is_valid()) {
352 base::MessageLoopProxy::current()->PostTask(
355 SYNC_FILE_ERROR_INVALID_URL
,
356 SYNC_FILE_STATUS_UNKNOWN
));
360 if (GetRemoteService(url
.origin())->IsConflicting(url
)) {
361 base::MessageLoopProxy::current()->PostTask(
365 SYNC_FILE_STATUS_CONFLICTING
));
369 local_service_
->HasPendingLocalChanges(
371 base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus
,
372 AsWeakPtr(), callback
));
375 void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver
* observer
) {
376 observers_
.AddObserver(observer
);
379 void SyncFileSystemService::RemoveSyncEventObserver(
380 SyncEventObserver
* observer
) {
381 observers_
.RemoveObserver(observer
);
384 ConflictResolutionPolicy
385 SyncFileSystemService::GetConflictResolutionPolicy() const {
386 return remote_service_
->GetConflictResolutionPolicy();
389 SyncStatusCode
SyncFileSystemService::SetConflictResolutionPolicy(
390 ConflictResolutionPolicy policy
) {
391 return remote_service_
->SetConflictResolutionPolicy(policy
);
394 LocalChangeProcessor
* SyncFileSystemService::GetLocalChangeProcessor(
395 const GURL
& origin
) {
396 return GetRemoteService(origin
)->GetLocalChangeProcessor();
399 SyncFileSystemService::SyncFileSystemService(Profile
* profile
)
401 sync_enabled_(true) {
404 void SyncFileSystemService::Initialize(
405 scoped_ptr
<LocalFileSyncService
> local_service
,
406 scoped_ptr
<RemoteFileSyncService
> remote_service
) {
407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
408 DCHECK(local_service
);
409 DCHECK(remote_service
);
412 local_service_
= local_service
.Pass();
413 remote_service_
= remote_service
.Pass();
415 scoped_ptr
<LocalSyncRunner
> local_syncer(
416 new LocalSyncRunner(kLocalSyncName
, this));
417 scoped_ptr
<RemoteSyncRunner
> remote_syncer(
418 new RemoteSyncRunner(kRemoteSyncName
, this, remote_service_
.get()));
420 local_service_
->AddChangeObserver(local_syncer
.get());
421 local_service_
->SetLocalChangeProcessorCallback(
422 base::Bind(&GetLocalChangeProcessorAdapter
, AsWeakPtr()));
424 remote_service_
->AddServiceObserver(remote_syncer
.get());
425 remote_service_
->AddFileStatusObserver(this);
426 remote_service_
->SetRemoteChangeProcessor(local_service_
.get());
428 local_sync_runners_
.push_back(local_syncer
.release());
429 remote_sync_runners_
.push_back(remote_syncer
.release());
431 ProfileSyncServiceBase
* profile_sync_service
=
432 ProfileSyncServiceFactory::GetForProfile(profile_
);
433 if (profile_sync_service
) {
434 UpdateSyncEnabledStatus(profile_sync_service
);
435 profile_sync_service
->AddObserver(this);
438 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED
,
439 content::Source
<Profile
>(profile_
));
440 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED
,
441 content::Source
<Profile
>(profile_
));
442 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED
,
443 content::Source
<Profile
>(profile_
));
444 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED
,
445 content::Source
<Profile
>(profile_
));
448 void SyncFileSystemService::DidInitializeFileSystem(
449 const GURL
& app_origin
,
450 const SyncStatusCallback
& callback
,
451 SyncStatusCode status
) {
452 DVLOG(1) << "DidInitializeFileSystem: "
453 << app_origin
.spec() << " " << status
;
455 if (status
!= SYNC_STATUS_OK
) {
456 callback
.Run(status
);
460 // Local side of initialization for the app is done.
461 // Continue on initializing the remote side.
462 GetRemoteService(app_origin
)->RegisterOrigin(
464 base::Bind(&SyncFileSystemService::DidRegisterOrigin
,
465 AsWeakPtr(), app_origin
, callback
));
468 void SyncFileSystemService::DidRegisterOrigin(
469 const GURL
& app_origin
,
470 const SyncStatusCallback
& callback
,
471 SyncStatusCode status
) {
472 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
473 "DidInitializeForApp (registered the origin): %s: %s",
474 app_origin
.spec().c_str(),
475 SyncStatusCodeToString(status
));
477 if (status
== SYNC_STATUS_FAILED
) {
478 // If we got generic error return the service status information.
479 switch (GetRemoteService(app_origin
)->GetCurrentState()) {
480 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED
:
481 callback
.Run(SYNC_STATUS_AUTHENTICATION_FAILED
);
483 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE
:
484 callback
.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE
);
491 callback
.Run(status
);
494 void SyncFileSystemService::DidInitializeFileSystemForDump(
496 const DumpFilesCallback
& callback
,
497 SyncStatusCode status
) {
498 DCHECK(!origin
.is_empty());
500 if (status
!= SYNC_STATUS_OK
) {
501 base::ListValue empty_result
;
502 callback
.Run(&empty_result
);
506 base::ListValue
* files
=
507 GetRemoteService(origin
)->DumpFiles(origin
).release();
509 callback
.Run(new base::ListValue
);
513 if (!files
->GetSize()) {
518 base::Callback
<void(base::DictionaryValue
* file
,
519 SyncStatusCode sync_status
,
520 SyncFileStatus sync_file_status
)> completion_callback
=
521 base::Bind(&DidGetFileSyncStatusForDump
, base::Owned(files
),
522 base::Owned(new size_t(0)), callback
);
524 // After all metadata loaded, sync status can be added to each entry.
525 for (size_t i
= 0; i
< files
->GetSize(); ++i
) {
526 base::DictionaryValue
* file
= NULL
;
527 std::string path_string
;
528 if (!files
->GetDictionary(i
, &file
) ||
529 !file
->GetString("path", &path_string
)) {
531 completion_callback
.Run(
532 NULL
, SYNC_FILE_ERROR_FAILED
, SYNC_FILE_STATUS_UNKNOWN
);
536 base::FilePath file_path
= base::FilePath::FromUTF8Unsafe(path_string
);
537 FileSystemURL url
= CreateSyncableFileSystemURL(origin
, file_path
);
538 GetFileSyncStatus(url
, base::Bind(completion_callback
, file
));
542 void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled
) {
543 sync_enabled_
= enabled
;
544 remote_service_
->SetSyncEnabled(sync_enabled_
);
545 if (v2_remote_service_
)
546 v2_remote_service_
->SetSyncEnabled(sync_enabled_
);
549 void SyncFileSystemService::DidGetLocalChangeStatus(
550 const SyncFileStatusCallback
& callback
,
551 SyncStatusCode status
,
552 bool has_pending_local_changes
) {
555 has_pending_local_changes
?
556 SYNC_FILE_STATUS_HAS_PENDING_CHANGES
: SYNC_FILE_STATUS_SYNCED
);
559 void SyncFileSystemService::OnSyncIdle() {
560 int64 remote_changes
= 0;
561 for (ScopedVector
<SyncProcessRunner
>::iterator iter
=
562 remote_sync_runners_
.begin();
563 iter
!= remote_sync_runners_
.end(); ++iter
)
564 remote_changes
+= (*iter
)->pending_changes();
565 if (remote_changes
== 0)
566 local_service_
->PromoteDemotedChanges();
568 int64 local_changes
= 0;
569 for (ScopedVector
<SyncProcessRunner
>::iterator iter
=
570 local_sync_runners_
.begin();
571 iter
!= local_sync_runners_
.end(); ++iter
)
572 local_changes
+= (*iter
)->pending_changes();
573 if (local_changes
== 0 && v2_remote_service_
)
574 v2_remote_service_
->PromoteDemotedChanges();
577 void SyncFileSystemService::OnRemoteServiceStateUpdated(
578 RemoteServiceState state
,
579 const std::string
& description
) {
580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
581 util::Log(logging::LOG_INFO
, FROM_HERE
,
582 "OnRemoteServiceStateChanged: %d %s", state
, description
.c_str());
585 SyncEventObserver
, observers_
,
586 OnSyncStateUpdated(GURL(),
587 RemoteStateToSyncServiceState(state
),
590 RunForEachSyncRunners(&SyncProcessRunner::Schedule
);
593 void SyncFileSystemService::Observe(
595 const content::NotificationSource
& source
,
596 const content::NotificationDetails
& details
) {
597 // Event notification sequence.
599 // (User action) (Notification type)
600 // Install: INSTALLED.
601 // Update: INSTALLED.
602 // Uninstall: UNINSTALLED.
603 // Launch, Close: No notification.
605 // Disable: UNLOADED(DISABLE).
606 // Reload, Restart: UNLOADED(DISABLE) -> INSTALLED -> ENABLED.
609 case chrome::NOTIFICATION_EXTENSION_INSTALLED
:
610 HandleExtensionInstalled(details
);
612 case chrome::NOTIFICATION_EXTENSION_UNLOADED
:
613 HandleExtensionUnloaded(type
, details
);
615 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED
:
616 HandleExtensionUninstalled(type
, details
);
618 case chrome::NOTIFICATION_EXTENSION_ENABLED
:
619 HandleExtensionEnabled(type
, details
);
622 NOTREACHED() << "Unknown notification.";
627 void SyncFileSystemService::HandleExtensionInstalled(
628 const content::NotificationDetails
& details
) {
629 const Extension
* extension
=
630 content::Details
<const extensions::InstalledExtensionInfo
>(details
)->
632 GURL app_origin
= Extension::GetBaseURLFromExtensionId(extension
->id());
633 DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin
;
634 // NOTE: When an app is uninstalled and re-installed in a sequence,
635 // |local_service_| may still keeps |app_origin| as disabled origin.
636 local_service_
->SetOriginEnabled(app_origin
, true);
639 void SyncFileSystemService::HandleExtensionUnloaded(
641 const content::NotificationDetails
& details
) {
642 content::Details
<const extensions::UnloadedExtensionInfo
> info(details
);
643 if (info
->reason
!= extensions::UnloadedExtensionInfo::REASON_DISABLE
)
646 std::string extension_id
= info
->extension
->id();
647 GURL app_origin
= Extension::GetBaseURLFromExtensionId(extension_id
);
649 int reasons
= ExtensionPrefs::Get(profile_
)->GetDisableReasons(extension_id
);
650 if (reasons
& Extension::DISABLE_RELOAD
) {
651 // Bypass disabling the origin since the app will be re-enabled soon.
652 // NOTE: If re-enabling the app fails, the app is disabled while it is
653 // handled as enabled origin in the SyncFS. This should be safe and will be
654 // recovered when the user re-enables the app manually or the sync service
656 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): "
661 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
663 GetRemoteService(app_origin
)->DisableOrigin(
665 base::Bind(&DidHandleOriginForExtensionUnloadedEvent
,
667 local_service_
->SetOriginEnabled(app_origin
, false);
670 void SyncFileSystemService::HandleExtensionUninstalled(
672 const content::NotificationDetails
& details
) {
673 const Extension
* extension
= content::Details
<const Extension
>(details
).ptr();
676 RemoteFileSyncService::UninstallFlag flag
=
677 RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE
;
678 // If it's loaded from an unpacked package and with key: field,
679 // the uninstall will not be sync'ed and the user might be using the
680 // same app key in other installs, so avoid purging the remote folder.
681 if (extensions::Manifest::IsUnpackedLocation(extension
->location()) &&
682 extension
->manifest()->HasKey(extensions::manifest_keys::kKey
)) {
683 flag
= RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE
;
686 GURL app_origin
= Extension::GetBaseURLFromExtensionId(extension
->id());
687 DVLOG(1) << "Handle extension notification for UNINSTALLED: "
689 GetRemoteService(app_origin
)->UninstallOrigin(
691 base::Bind(&DidHandleOriginForExtensionUnloadedEvent
,
693 local_service_
->SetOriginEnabled(app_origin
, false);
696 void SyncFileSystemService::HandleExtensionEnabled(
698 const content::NotificationDetails
& details
) {
699 std::string extension_id
= content::Details
<const Extension
>(details
)->id();
700 GURL app_origin
= Extension::GetBaseURLFromExtensionId(extension_id
);
701 DVLOG(1) << "Handle extension notification for ENABLED: " << app_origin
;
702 GetRemoteService(app_origin
)->EnableOrigin(
704 base::Bind(&DidHandleOriginForExtensionEnabledEvent
, type
, 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_
);
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 remote_sync_runners_
.push_back(v2_remote_syncer
.release());
769 return v2_remote_service_
.get();
772 } // namespace sync_file_system