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/stl_util.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
17 #include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.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/keyed_service/content/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/browser/extension_prefs.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 fileapi::FileSystemURL
;
44 using fileapi::FileSystemURLSet
;
46 namespace sync_file_system
{
50 const char kLocalSyncName
[] = "Local sync";
51 const char kRemoteSyncName
[] = "Remote sync";
52 const char kRemoteSyncNameV2
[] = "Remote sync (v2)";
54 SyncServiceState
RemoteStateToSyncServiceState(
55 RemoteServiceState state
) {
57 case REMOTE_SERVICE_OK
:
58 return SYNC_SERVICE_RUNNING
;
59 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE
:
60 return SYNC_SERVICE_TEMPORARY_UNAVAILABLE
;
61 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED
:
62 return SYNC_SERVICE_AUTHENTICATION_REQUIRED
;
63 case REMOTE_SERVICE_DISABLED
:
64 return SYNC_SERVICE_DISABLED
;
65 case REMOTE_SERVICE_STATE_MAX
:
68 NOTREACHED() << "Unknown remote service state: " << state
;
69 return SYNC_SERVICE_DISABLED
;
72 void DidHandleOriginForExtensionUnloadedEvent(
75 SyncStatusCode code
) {
76 DCHECK(chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED
== type
||
77 chrome::NOTIFICATION_EXTENSION_UNINSTALLED
== type
);
78 if (code
!= SYNC_STATUS_OK
&&
79 code
!= SYNC_STATUS_UNKNOWN_ORIGIN
) {
81 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED
:
82 util::Log(logging::LOG_WARNING
,
84 "Disabling origin for UNLOADED(DISABLE) failed: %s",
85 origin
.spec().c_str());
87 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED
:
88 util::Log(logging::LOG_WARNING
,
90 "Uninstall origin for UNINSTALLED failed: %s",
91 origin
.spec().c_str());
99 void DidHandleOriginForExtensionEnabledEvent(
102 SyncStatusCode code
) {
103 DCHECK(chrome::NOTIFICATION_EXTENSION_ENABLED
== type
);
104 if (code
!= SYNC_STATUS_OK
)
105 util::Log(logging::LOG_WARNING
,
107 "Enabling origin for ENABLED failed: %s",
108 origin
.spec().c_str());
111 std::string
SyncFileStatusToString(SyncFileStatus sync_file_status
) {
112 return extensions::api::sync_file_system::ToString(
113 extensions::SyncFileStatusToExtensionEnum(sync_file_status
));
116 // Gets called repeatedly until every SyncFileStatus has been mapped.
117 void DidGetFileSyncStatusForDump(
118 base::ListValue
* files
,
120 const SyncFileSystemService::DumpFilesCallback
& callback
,
121 base::DictionaryValue
* file
,
122 SyncStatusCode sync_status_code
,
123 SyncFileStatus sync_file_status
) {
128 file
->SetString("status", SyncFileStatusToString(sync_file_status
));
130 // Once all results have been received, run the callback to signal end.
131 DCHECK_LE(*num_results
, files
->GetSize());
132 if (++*num_results
< files
->GetSize())
138 // We need this indirection because WeakPtr can only be bound to methods
139 // without a return value.
140 LocalChangeProcessor
* GetLocalChangeProcessorAdapter(
141 base::WeakPtr
<SyncFileSystemService
> service
,
142 const GURL
& origin
) {
145 return service
->GetLocalChangeProcessor(origin
);
150 //---------------------------------------------------------------------------
151 // SyncProcessRunner's.
153 // SyncProcessRunner implementation for LocalSync.
154 class LocalSyncRunner
: public SyncProcessRunner
,
155 public LocalFileSyncService::Observer
{
157 LocalSyncRunner(const std::string
& name
,
158 SyncFileSystemService
* sync_service
)
159 : SyncProcessRunner(name
, sync_service
),
162 virtual void StartSync(const SyncStatusCallback
& callback
) OVERRIDE
{
163 sync_service()->local_service_
->ProcessLocalChange(
164 base::Bind(&LocalSyncRunner::DidProcessLocalChange
,
165 factory_
.GetWeakPtr(), callback
));
168 // LocalFileSyncService::Observer overrides.
169 virtual void OnLocalChangeAvailable(int64 pending_changes
) OVERRIDE
{
170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
172 OnChangesUpdated(pending_changes
);
174 // Kick other sync runners just in case they're not running.
175 sync_service()->RunForEachSyncRunners(
176 &SyncProcessRunner::ScheduleIfNotRunning
);
180 void DidProcessLocalChange(
181 const SyncStatusCallback
& callback
,
182 SyncStatusCode status
,
183 const FileSystemURL
& url
) {
184 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
185 "ProcessLocalChange finished with status=%d (%s) for url=%s",
186 status
, SyncStatusCodeToString(status
),
187 url
.DebugString().c_str());
188 callback
.Run(status
);
191 base::WeakPtrFactory
<LocalSyncRunner
> factory_
;
192 DISALLOW_COPY_AND_ASSIGN(LocalSyncRunner
);
195 // SyncProcessRunner implementation for RemoteSync.
196 class RemoteSyncRunner
: public SyncProcessRunner
,
197 public RemoteFileSyncService::Observer
{
199 RemoteSyncRunner(const std::string
& name
,
200 SyncFileSystemService
* sync_service
,
201 RemoteFileSyncService
* remote_service
)
202 : SyncProcessRunner(name
, sync_service
),
203 remote_service_(remote_service
),
204 last_state_(REMOTE_SERVICE_OK
),
207 virtual void StartSync(const SyncStatusCallback
& callback
) OVERRIDE
{
208 remote_service_
->ProcessRemoteChange(
209 base::Bind(&RemoteSyncRunner::DidProcessRemoteChange
,
210 factory_
.GetWeakPtr(), callback
));
213 virtual SyncServiceState
GetServiceState() OVERRIDE
{
214 return RemoteStateToSyncServiceState(last_state_
);
217 // RemoteFileSyncService::Observer overrides.
218 virtual void OnRemoteChangeQueueUpdated(int64 pending_changes
) OVERRIDE
{
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
221 OnChangesUpdated(pending_changes
);
223 // Kick other sync runners just in case they're not running.
224 sync_service()->RunForEachSyncRunners(
225 &SyncProcessRunner::ScheduleIfNotRunning
);
228 virtual void OnRemoteServiceStateUpdated(
229 RemoteServiceState state
,
230 const std::string
& description
) OVERRIDE
{
231 // Just forward to SyncFileSystemService.
232 sync_service()->OnRemoteServiceStateUpdated(state
, description
);
237 void DidProcessRemoteChange(
238 const SyncStatusCallback
& callback
,
239 SyncStatusCode status
,
240 const FileSystemURL
& url
) {
241 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
242 "ProcessRemoteChange finished with status=%d (%s) for url=%s",
243 status
, SyncStatusCodeToString(status
),
244 url
.DebugString().c_str());
246 if (status
== SYNC_STATUS_FILE_BUSY
) {
247 sync_service()->local_service_
->RegisterURLForWaitingSync(
248 url
, base::Bind(&RemoteSyncRunner::Schedule
,
249 factory_
.GetWeakPtr()));
251 callback
.Run(status
);
254 RemoteFileSyncService
* remote_service_
;
255 RemoteServiceState last_state_
;
256 base::WeakPtrFactory
<RemoteSyncRunner
> factory_
;
257 DISALLOW_COPY_AND_ASSIGN(RemoteSyncRunner
);
260 //-----------------------------------------------------------------------------
261 // SyncFileSystemService
263 void SyncFileSystemService::Shutdown() {
264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
266 local_service_
->Shutdown();
267 local_service_
.reset();
269 remote_service_
.reset();
270 v2_remote_service_
.reset();
272 ProfileSyncServiceBase
* profile_sync_service
=
273 ProfileSyncServiceFactory::GetForProfile(profile_
);
274 if (profile_sync_service
)
275 profile_sync_service
->RemoveObserver(this);
280 SyncFileSystemService::~SyncFileSystemService() {
281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
285 void SyncFileSystemService::InitializeForApp(
286 fileapi::FileSystemContext
* file_system_context
,
287 const GURL
& app_origin
,
288 const SyncStatusCallback
& callback
) {
289 DCHECK(local_service_
);
290 DCHECK(remote_service_
);
291 DCHECK(app_origin
== app_origin
.GetOrigin());
293 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
294 "Initializing for App: %s", app_origin
.spec().c_str());
296 local_service_
->MaybeInitializeFileSystemContext(
297 app_origin
, file_system_context
,
298 base::Bind(&SyncFileSystemService::DidInitializeFileSystem
,
299 AsWeakPtr(), app_origin
, callback
));
302 SyncServiceState
SyncFileSystemService::GetSyncServiceState() {
303 // For now we always query the state from the main RemoteFileSyncService.
304 return RemoteStateToSyncServiceState(remote_service_
->GetCurrentState());
307 void SyncFileSystemService::GetExtensionStatusMap(
308 std::map
<GURL
, std::string
>* status_map
) {
311 remote_service_
->GetOriginStatusMap(status_map
);
312 if (v2_remote_service_
)
313 v2_remote_service_
->GetOriginStatusMap(status_map
);
316 void SyncFileSystemService::DumpFiles(const GURL
& origin
,
317 const DumpFilesCallback
& callback
) {
318 DCHECK(!origin
.is_empty());
320 content::StoragePartition
* storage_partition
=
321 content::BrowserContext::GetStoragePartitionForSite(profile_
, origin
);
322 fileapi::FileSystemContext
* file_system_context
=
323 storage_partition
->GetFileSystemContext();
324 local_service_
->MaybeInitializeFileSystemContext(
325 origin
, file_system_context
,
326 base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump
,
327 AsWeakPtr(), origin
, callback
));
330 scoped_ptr
<base::ListValue
> SyncFileSystemService::DumpDatabase() {
331 scoped_ptr
<base::ListValue
> list
= remote_service_
->DumpDatabase();
333 list
.reset(new base::ListValue
);
334 if (v2_remote_service_
) {
335 scoped_ptr
<base::ListValue
> v2list
= v2_remote_service_
->DumpDatabase();
338 for (base::ListValue::iterator itr
= v2list
->begin();
339 itr
!= v2list
->end(); ) {
340 scoped_ptr
<base::Value
> item
;
341 itr
= v2list
->Erase(itr
, &item
);
342 list
->Append(item
.release());
348 void SyncFileSystemService::GetFileSyncStatus(
349 const FileSystemURL
& url
, const SyncFileStatusCallback
& callback
) {
350 DCHECK(local_service_
);
351 DCHECK(GetRemoteService(url
.origin()));
353 // It's possible to get an invalid FileEntry.
354 if (!url
.is_valid()) {
355 base::MessageLoopProxy::current()->PostTask(
358 SYNC_FILE_ERROR_INVALID_URL
,
359 SYNC_FILE_STATUS_UNKNOWN
));
363 if (GetRemoteService(url
.origin())->IsConflicting(url
)) {
364 base::MessageLoopProxy::current()->PostTask(
368 SYNC_FILE_STATUS_CONFLICTING
));
372 local_service_
->HasPendingLocalChanges(
374 base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus
,
375 AsWeakPtr(), callback
));
378 void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver
* observer
) {
379 observers_
.AddObserver(observer
);
382 void SyncFileSystemService::RemoveSyncEventObserver(
383 SyncEventObserver
* observer
) {
384 observers_
.RemoveObserver(observer
);
387 ConflictResolutionPolicy
SyncFileSystemService::GetConflictResolutionPolicy(
388 const GURL
& origin
) {
389 return GetRemoteService(origin
)->GetConflictResolutionPolicy(origin
);
392 SyncStatusCode
SyncFileSystemService::SetConflictResolutionPolicy(
394 ConflictResolutionPolicy policy
) {
395 UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.ConflictResolutionPolicy",
396 policy
, CONFLICT_RESOLUTION_POLICY_MAX
);
397 return GetRemoteService(origin
)->SetConflictResolutionPolicy(origin
, policy
);
400 LocalChangeProcessor
* SyncFileSystemService::GetLocalChangeProcessor(
401 const GURL
& origin
) {
402 return GetRemoteService(origin
)->GetLocalChangeProcessor();
405 SyncFileSystemService::SyncFileSystemService(Profile
* profile
)
407 sync_enabled_(true) {
410 void SyncFileSystemService::Initialize(
411 scoped_ptr
<LocalFileSyncService
> local_service
,
412 scoped_ptr
<RemoteFileSyncService
> remote_service
) {
413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
414 DCHECK(local_service
);
415 DCHECK(remote_service
);
418 local_service_
= local_service
.Pass();
419 remote_service_
= remote_service
.Pass();
421 scoped_ptr
<LocalSyncRunner
> local_syncer(
422 new LocalSyncRunner(kLocalSyncName
, this));
423 scoped_ptr
<RemoteSyncRunner
> remote_syncer(
424 new RemoteSyncRunner(kRemoteSyncName
, this, remote_service_
.get()));
426 local_service_
->AddChangeObserver(local_syncer
.get());
427 local_service_
->SetLocalChangeProcessorCallback(
428 base::Bind(&GetLocalChangeProcessorAdapter
, AsWeakPtr()));
430 remote_service_
->AddServiceObserver(remote_syncer
.get());
431 remote_service_
->AddFileStatusObserver(this);
432 remote_service_
->SetRemoteChangeProcessor(local_service_
.get());
434 local_sync_runners_
.push_back(local_syncer
.release());
435 remote_sync_runners_
.push_back(remote_syncer
.release());
437 ProfileSyncServiceBase
* profile_sync_service
=
438 ProfileSyncServiceFactory::GetForProfile(profile_
);
439 if (profile_sync_service
) {
440 UpdateSyncEnabledStatus(profile_sync_service
);
441 profile_sync_service
->AddObserver(this);
444 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED
,
445 content::Source
<Profile
>(profile_
));
446 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED
,
447 content::Source
<Profile
>(profile_
));
448 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED
,
449 content::Source
<Profile
>(profile_
));
450 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED
,
451 content::Source
<Profile
>(profile_
));
454 void SyncFileSystemService::DidInitializeFileSystem(
455 const GURL
& app_origin
,
456 const SyncStatusCallback
& callback
,
457 SyncStatusCode status
) {
458 DVLOG(1) << "DidInitializeFileSystem: "
459 << app_origin
.spec() << " " << status
;
461 if (status
!= SYNC_STATUS_OK
) {
462 callback
.Run(status
);
466 // Local side of initialization for the app is done.
467 // Continue on initializing the remote side.
468 GetRemoteService(app_origin
)->RegisterOrigin(
470 base::Bind(&SyncFileSystemService::DidRegisterOrigin
,
471 AsWeakPtr(), app_origin
, callback
));
474 void SyncFileSystemService::DidRegisterOrigin(
475 const GURL
& app_origin
,
476 const SyncStatusCallback
& callback
,
477 SyncStatusCode status
) {
478 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
479 "DidInitializeForApp (registered the origin): %s: %s",
480 app_origin
.spec().c_str(),
481 SyncStatusCodeToString(status
));
483 UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.RegisterOriginResult",
484 GetRemoteService(app_origin
)->GetCurrentState(),
485 REMOTE_SERVICE_STATE_MAX
);
487 if (status
== SYNC_STATUS_FAILED
) {
488 // If we got generic error return the service status information.
489 switch (GetRemoteService(app_origin
)->GetCurrentState()) {
490 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED
:
491 callback
.Run(SYNC_STATUS_AUTHENTICATION_FAILED
);
493 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE
:
494 callback
.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE
);
501 callback
.Run(status
);
504 void SyncFileSystemService::DidInitializeFileSystemForDump(
506 const DumpFilesCallback
& callback
,
507 SyncStatusCode status
) {
508 DCHECK(!origin
.is_empty());
510 if (status
!= SYNC_STATUS_OK
) {
511 base::ListValue empty_result
;
512 callback
.Run(&empty_result
);
516 base::ListValue
* files
=
517 GetRemoteService(origin
)->DumpFiles(origin
).release();
519 callback
.Run(new base::ListValue
);
523 if (!files
->GetSize()) {
528 base::Callback
<void(base::DictionaryValue
* file
,
529 SyncStatusCode sync_status
,
530 SyncFileStatus sync_file_status
)> completion_callback
=
531 base::Bind(&DidGetFileSyncStatusForDump
, base::Owned(files
),
532 base::Owned(new size_t(0)), callback
);
534 // After all metadata loaded, sync status can be added to each entry.
535 for (size_t i
= 0; i
< files
->GetSize(); ++i
) {
536 base::DictionaryValue
* file
= NULL
;
537 std::string path_string
;
538 if (!files
->GetDictionary(i
, &file
) ||
539 !file
->GetString("path", &path_string
)) {
541 completion_callback
.Run(
542 NULL
, SYNC_FILE_ERROR_FAILED
, SYNC_FILE_STATUS_UNKNOWN
);
546 base::FilePath file_path
= base::FilePath::FromUTF8Unsafe(path_string
);
547 FileSystemURL url
= CreateSyncableFileSystemURL(origin
, file_path
);
548 GetFileSyncStatus(url
, base::Bind(completion_callback
, file
));
552 void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled
) {
553 sync_enabled_
= enabled
;
554 remote_service_
->SetSyncEnabled(sync_enabled_
);
555 if (v2_remote_service_
)
556 v2_remote_service_
->SetSyncEnabled(sync_enabled_
);
559 void SyncFileSystemService::DidGetLocalChangeStatus(
560 const SyncFileStatusCallback
& callback
,
561 SyncStatusCode status
,
562 bool has_pending_local_changes
) {
565 has_pending_local_changes
?
566 SYNC_FILE_STATUS_HAS_PENDING_CHANGES
: SYNC_FILE_STATUS_SYNCED
);
569 void SyncFileSystemService::OnSyncIdle() {
570 int64 remote_changes
= 0;
571 for (ScopedVector
<SyncProcessRunner
>::iterator iter
=
572 remote_sync_runners_
.begin();
573 iter
!= remote_sync_runners_
.end(); ++iter
)
574 remote_changes
+= (*iter
)->pending_changes();
575 if (remote_changes
== 0)
576 local_service_
->PromoteDemotedChanges();
578 int64 local_changes
= 0;
579 for (ScopedVector
<SyncProcessRunner
>::iterator iter
=
580 local_sync_runners_
.begin();
581 iter
!= local_sync_runners_
.end(); ++iter
)
582 local_changes
+= (*iter
)->pending_changes();
583 if (local_changes
== 0 && v2_remote_service_
)
584 v2_remote_service_
->PromoteDemotedChanges();
587 void SyncFileSystemService::OnRemoteServiceStateUpdated(
588 RemoteServiceState state
,
589 const std::string
& description
) {
590 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
591 util::Log(logging::LOG_VERBOSE
, FROM_HERE
,
592 "OnRemoteServiceStateChanged: %d %s", state
, description
.c_str());
595 SyncEventObserver
, observers_
,
596 OnSyncStateUpdated(GURL(),
597 RemoteStateToSyncServiceState(state
),
600 RunForEachSyncRunners(&SyncProcessRunner::Schedule
);
603 void SyncFileSystemService::Observe(
605 const content::NotificationSource
& source
,
606 const content::NotificationDetails
& details
) {
607 // Event notification sequence.
609 // (User action) (Notification type)
610 // Install: INSTALLED.
611 // Update: INSTALLED.
612 // Uninstall: UNINSTALLED.
613 // Launch, Close: No notification.
615 // Disable: UNLOADED(DISABLE).
616 // Reload, Restart: UNLOADED(DISABLE) -> INSTALLED -> ENABLED.
619 case chrome::NOTIFICATION_EXTENSION_INSTALLED
:
620 HandleExtensionInstalled(details
);
622 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED
:
623 HandleExtensionUnloaded(type
, details
);
625 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED
:
626 HandleExtensionUninstalled(type
, details
);
628 case chrome::NOTIFICATION_EXTENSION_ENABLED
:
629 HandleExtensionEnabled(type
, details
);
632 NOTREACHED() << "Unknown notification.";
637 void SyncFileSystemService::HandleExtensionInstalled(
638 const content::NotificationDetails
& details
) {
639 const Extension
* extension
=
640 content::Details
<const extensions::InstalledExtensionInfo
>(details
)->
642 GURL app_origin
= Extension::GetBaseURLFromExtensionId(extension
->id());
643 DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin
;
644 // NOTE: When an app is uninstalled and re-installed in a sequence,
645 // |local_service_| may still keeps |app_origin| as disabled origin.
646 local_service_
->SetOriginEnabled(app_origin
, true);
649 void SyncFileSystemService::HandleExtensionUnloaded(
651 const content::NotificationDetails
& details
) {
652 content::Details
<const extensions::UnloadedExtensionInfo
> info(details
);
653 if (info
->reason
!= extensions::UnloadedExtensionInfo::REASON_DISABLE
)
656 std::string extension_id
= info
->extension
->id();
657 GURL app_origin
= Extension::GetBaseURLFromExtensionId(extension_id
);
659 int reasons
= ExtensionPrefs::Get(profile_
)->GetDisableReasons(extension_id
);
660 if (reasons
& Extension::DISABLE_RELOAD
) {
661 // Bypass disabling the origin since the app will be re-enabled soon.
662 // NOTE: If re-enabling the app fails, the app is disabled while it is
663 // handled as enabled origin in the SyncFS. This should be safe and will be
664 // recovered when the user re-enables the app manually or the sync service
666 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): "
671 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
673 GetRemoteService(app_origin
)->DisableOrigin(
675 base::Bind(&DidHandleOriginForExtensionUnloadedEvent
,
677 local_service_
->SetOriginEnabled(app_origin
, false);
680 void SyncFileSystemService::HandleExtensionUninstalled(
682 const content::NotificationDetails
& details
) {
683 const Extension
* extension
= content::Details
<const Extension
>(details
).ptr();
686 RemoteFileSyncService::UninstallFlag flag
=
687 RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE
;
688 // If it's loaded from an unpacked package and with key: field,
689 // the uninstall will not be sync'ed and the user might be using the
690 // same app key in other installs, so avoid purging the remote folder.
691 if (extensions::Manifest::IsUnpackedLocation(extension
->location()) &&
692 extension
->manifest()->HasKey(extensions::manifest_keys::kKey
)) {
693 flag
= RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE
;
696 GURL app_origin
= Extension::GetBaseURLFromExtensionId(extension
->id());
697 DVLOG(1) << "Handle extension notification for UNINSTALLED: "
699 GetRemoteService(app_origin
)->UninstallOrigin(
701 base::Bind(&DidHandleOriginForExtensionUnloadedEvent
,
703 local_service_
->SetOriginEnabled(app_origin
, false);
706 void SyncFileSystemService::HandleExtensionEnabled(
708 const content::NotificationDetails
& details
) {
709 std::string extension_id
= content::Details
<const Extension
>(details
)->id();
710 GURL app_origin
= Extension::GetBaseURLFromExtensionId(extension_id
);
711 DVLOG(1) << "Handle extension notification for ENABLED: " << app_origin
;
712 GetRemoteService(app_origin
)->EnableOrigin(
714 base::Bind(&DidHandleOriginForExtensionEnabledEvent
, type
, app_origin
));
715 local_service_
->SetOriginEnabled(app_origin
, true);
718 void SyncFileSystemService::OnStateChanged() {
719 ProfileSyncServiceBase
* profile_sync_service
=
720 ProfileSyncServiceFactory::GetForProfile(profile_
);
721 if (profile_sync_service
)
722 UpdateSyncEnabledStatus(profile_sync_service
);
725 void SyncFileSystemService::OnFileStatusChanged(
726 const FileSystemURL
& url
,
727 SyncFileStatus sync_status
,
728 SyncAction action_taken
,
729 SyncDirection direction
) {
731 SyncEventObserver
, observers_
,
732 OnFileSynced(url
, sync_status
, action_taken
, direction
));
735 void SyncFileSystemService::UpdateSyncEnabledStatus(
736 ProfileSyncServiceBase
* profile_sync_service
) {
737 if (!profile_sync_service
->HasSyncSetupCompleted())
739 bool old_sync_enabled
= sync_enabled_
;
740 sync_enabled_
= profile_sync_service
->GetActiveDataTypes().Has(
742 remote_service_
->SetSyncEnabled(sync_enabled_
);
743 if (v2_remote_service_
)
744 v2_remote_service_
->SetSyncEnabled(sync_enabled_
);
745 if (!old_sync_enabled
&& sync_enabled_
)
746 RunForEachSyncRunners(&SyncProcessRunner::Schedule
);
749 void SyncFileSystemService::RunForEachSyncRunners(
750 void(SyncProcessRunner::*method
)()) {
751 for (ScopedVector
<SyncProcessRunner
>::iterator iter
=
752 local_sync_runners_
.begin();
753 iter
!= local_sync_runners_
.end(); ++iter
)
754 ((*iter
)->*method
)();
755 for (ScopedVector
<SyncProcessRunner
>::iterator iter
=
756 remote_sync_runners_
.begin();
757 iter
!= remote_sync_runners_
.end(); ++iter
)
758 ((*iter
)->*method
)();
761 RemoteFileSyncService
* SyncFileSystemService::GetRemoteService(
762 const GURL
& origin
) {
764 return remote_service_
.get();
765 if (!IsV2EnabledForOrigin(origin
))
766 return remote_service_
.get();
768 if (!v2_remote_service_
) {
769 v2_remote_service_
= RemoteFileSyncService::CreateForBrowserContext(
770 RemoteFileSyncService::V2
, profile_
);
771 scoped_ptr
<RemoteSyncRunner
> v2_remote_syncer(
772 new RemoteSyncRunner(kRemoteSyncNameV2
, this,
773 v2_remote_service_
.get()));
774 v2_remote_service_
->AddServiceObserver(v2_remote_syncer
.get());
775 v2_remote_service_
->AddFileStatusObserver(this);
776 v2_remote_service_
->SetRemoteChangeProcessor(local_service_
.get());
777 v2_remote_service_
->SetSyncEnabled(sync_enabled_
);
778 v2_remote_service_
->SetDefaultConflictResolutionPolicy(
779 remote_service_
->GetDefaultConflictResolutionPolicy());
780 remote_sync_runners_
.push_back(v2_remote_syncer
.release());
782 return v2_remote_service_
.get();
785 } // namespace sync_file_system