Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / sync_file_system_service.cc
blobae210731283fe7072f36308d45fd27d2fb72dce0
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"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/format_macros.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/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"
36 #include "url/gurl.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 {
47 namespace {
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) {
55 switch (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(
70 int type,
71 const GURL& origin,
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) {
77 switch (type) {
78 case chrome::NOTIFICATION_EXTENSION_UNLOADED:
79 util::Log(logging::LOG_WARNING,
80 FROM_HERE,
81 "Disabling origin for UNLOADED(DISABLE) failed: %s",
82 origin.spec().c_str());
83 break;
84 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
85 util::Log(logging::LOG_WARNING,
86 FROM_HERE,
87 "Uninstall origin for UNINSTALLED failed: %s",
88 origin.spec().c_str());
89 break;
90 default:
91 break;
96 void DidHandleOriginForExtensionEnabledEvent(
97 int type,
98 const GURL& origin,
99 SyncStatusCode code) {
100 DCHECK(chrome::NOTIFICATION_EXTENSION_ENABLED == type);
101 if (code != SYNC_STATUS_OK)
102 util::Log(logging::LOG_WARNING,
103 FROM_HERE,
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,
116 size_t* num_results,
117 const SyncFileSystemService::DumpFilesCallback& callback,
118 base::DictionaryValue* file,
119 SyncStatusCode sync_status_code,
120 SyncFileStatus sync_file_status) {
121 DCHECK(files);
122 DCHECK(num_results);
124 if (file)
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())
130 return;
132 callback.Run(files);
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) {
140 if (!service)
141 return NULL;
142 return service->GetLocalChangeProcessor(origin);
145 } // namespace
147 //---------------------------------------------------------------------------
148 // SyncProcessRunner's.
150 // SyncProcessRunner implementation for LocalSync.
151 class LocalSyncRunner : public SyncProcessRunner,
152 public LocalFileSyncService::Observer {
153 public:
154 LocalSyncRunner(const std::string& name,
155 SyncFileSystemService* sync_service)
156 : SyncProcessRunner(name, sync_service),
157 factory_(this) {}
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);
176 private:
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 {
195 public:
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),
202 factory_(this) {}
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);
230 last_state_ = state;
233 private:
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);
274 profile_ = NULL;
277 SyncFileSystemService::~SyncFileSystemService() {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
279 DCHECK(!profile_);
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) {
306 DCHECK(status_map);
307 status_map->clear();
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();
329 if (!list)
330 list.reset(new base::ListValue);
331 if (v2_remote_service_) {
332 scoped_ptr<base::ListValue> v2list = v2_remote_service_->DumpDatabase();
333 if (!v2list)
334 return list.Pass();
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());
342 return list.Pass();
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(
353 FROM_HERE,
354 base::Bind(callback,
355 SYNC_FILE_ERROR_INVALID_URL,
356 SYNC_FILE_STATUS_UNKNOWN));
357 return;
360 if (GetRemoteService(url.origin())->IsConflicting(url)) {
361 base::MessageLoopProxy::current()->PostTask(
362 FROM_HERE,
363 base::Bind(callback,
364 SYNC_STATUS_OK,
365 SYNC_FILE_STATUS_CONFLICTING));
366 return;
369 local_service_->HasPendingLocalChanges(
370 url,
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)
400 : 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);
410 DCHECK(profile_);
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);
457 return;
460 // Local side of initialization for the app is done.
461 // Continue on initializing the remote side.
462 GetRemoteService(app_origin)->RegisterOrigin(
463 app_origin,
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);
482 return;
483 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
484 callback.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE);
485 return;
486 default:
487 break;
491 callback.Run(status);
494 void SyncFileSystemService::DidInitializeFileSystemForDump(
495 const GURL& origin,
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);
503 return;
506 base::ListValue* files =
507 GetRemoteService(origin)->DumpFiles(origin).release();
508 if (!files) {
509 callback.Run(new base::ListValue);
510 return;
513 if (!files->GetSize()) {
514 callback.Run(files);
515 return;
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)) {
530 NOTREACHED();
531 completion_callback.Run(
532 NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN);
533 continue;
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) {
553 callback.Run(
554 status,
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());
584 FOR_EACH_OBSERVER(
585 SyncEventObserver, observers_,
586 OnSyncStateUpdated(GURL(),
587 RemoteStateToSyncServiceState(state),
588 description));
590 RunForEachSyncRunners(&SyncProcessRunner::Schedule);
593 void SyncFileSystemService::Observe(
594 int type,
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.
604 // Enable: ENABLED.
605 // Disable: UNLOADED(DISABLE).
606 // Reload, Restart: UNLOADED(DISABLE) -> INSTALLED -> ENABLED.
608 switch (type) {
609 case chrome::NOTIFICATION_EXTENSION_INSTALLED:
610 HandleExtensionInstalled(details);
611 break;
612 case chrome::NOTIFICATION_EXTENSION_UNLOADED:
613 HandleExtensionUnloaded(type, details);
614 break;
615 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
616 HandleExtensionUninstalled(type, details);
617 break;
618 case chrome::NOTIFICATION_EXTENSION_ENABLED:
619 HandleExtensionEnabled(type, details);
620 break;
621 default:
622 NOTREACHED() << "Unknown notification.";
623 break;
627 void SyncFileSystemService::HandleExtensionInstalled(
628 const content::NotificationDetails& details) {
629 const Extension* extension =
630 content::Details<const extensions::InstalledExtensionInfo>(details)->
631 extension;
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(
640 int type,
641 const content::NotificationDetails& details) {
642 content::Details<const extensions::UnloadedExtensionInfo> info(details);
643 if (info->reason != extensions::UnloadedExtensionInfo::REASON_DISABLE)
644 return;
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
655 // restarts.
656 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): "
657 << app_origin;
658 return;
661 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
662 << app_origin;
663 GetRemoteService(app_origin)->DisableOrigin(
664 app_origin,
665 base::Bind(&DidHandleOriginForExtensionUnloadedEvent,
666 type, app_origin));
667 local_service_->SetOriginEnabled(app_origin, false);
670 void SyncFileSystemService::HandleExtensionUninstalled(
671 int type,
672 const content::NotificationDetails& details) {
673 const Extension* extension = content::Details<const Extension>(details).ptr();
674 DCHECK(extension);
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: "
688 << app_origin;
689 GetRemoteService(app_origin)->UninstallOrigin(
690 app_origin, flag,
691 base::Bind(&DidHandleOriginForExtensionUnloadedEvent,
692 type, app_origin));
693 local_service_->SetOriginEnabled(app_origin, false);
696 void SyncFileSystemService::HandleExtensionEnabled(
697 int type,
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(
703 app_origin,
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) {
720 FOR_EACH_OBSERVER(
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())
728 return;
729 bool old_sync_enabled = sync_enabled_;
730 sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has(
731 syncer::APPS);
732 remote_service_->SetSyncEnabled(sync_enabled_);
733 if (v2_remote_service_)
734 v2_remote_service_->SetSyncEnabled(sync_enabled_);
735 if (!old_sync_enabled && sync_enabled_)
736 RunForEachSyncRunners(&SyncProcessRunner::Schedule);
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) {
753 if (IsV2Enabled())
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