Fix infinite recursion on hiding panel when created during fullscreen mode.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / sync_file_system_service.cc
blob9f19c7e7a415bf882bbf793ae13024a68d977825
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/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"
37 #include "url/gurl.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 {
48 namespace {
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) {
56 switch (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:
66 NOTREACHED();
68 NOTREACHED() << "Unknown remote service state: " << state;
69 return SYNC_SERVICE_DISABLED;
72 void DidHandleOriginForExtensionUnloadedEvent(
73 int type,
74 const GURL& origin,
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) {
80 switch (type) {
81 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED:
82 util::Log(logging::LOG_WARNING,
83 FROM_HERE,
84 "Disabling origin for UNLOADED(DISABLE) failed: %s",
85 origin.spec().c_str());
86 break;
87 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
88 util::Log(logging::LOG_WARNING,
89 FROM_HERE,
90 "Uninstall origin for UNINSTALLED failed: %s",
91 origin.spec().c_str());
92 break;
93 default:
94 break;
99 void DidHandleOriginForExtensionEnabledEvent(
100 int type,
101 const GURL& origin,
102 SyncStatusCode code) {
103 DCHECK(chrome::NOTIFICATION_EXTENSION_ENABLED == type);
104 if (code != SYNC_STATUS_OK)
105 util::Log(logging::LOG_WARNING,
106 FROM_HERE,
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,
119 size_t* num_results,
120 const SyncFileSystemService::DumpFilesCallback& callback,
121 base::DictionaryValue* file,
122 SyncStatusCode sync_status_code,
123 SyncFileStatus sync_file_status) {
124 DCHECK(files);
125 DCHECK(num_results);
127 if (file)
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())
133 return;
135 callback.Run(files);
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) {
143 if (!service)
144 return NULL;
145 return service->GetLocalChangeProcessor(origin);
148 } // namespace
150 //---------------------------------------------------------------------------
151 // SyncProcessRunner's.
153 // SyncProcessRunner implementation for LocalSync.
154 class LocalSyncRunner : public SyncProcessRunner,
155 public LocalFileSyncService::Observer {
156 public:
157 LocalSyncRunner(const std::string& name,
158 SyncFileSystemService* sync_service)
159 : SyncProcessRunner(name, sync_service),
160 factory_(this) {}
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);
179 private:
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 {
198 public:
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),
205 factory_(this) {}
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);
233 last_state_ = state;
236 private:
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);
277 profile_ = NULL;
280 SyncFileSystemService::~SyncFileSystemService() {
281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
282 DCHECK(!profile_);
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) {
309 DCHECK(status_map);
310 status_map->clear();
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();
332 if (!list)
333 list.reset(new base::ListValue);
334 if (v2_remote_service_) {
335 scoped_ptr<base::ListValue> v2list = v2_remote_service_->DumpDatabase();
336 if (!v2list)
337 return list.Pass();
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());
345 return list.Pass();
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(
356 FROM_HERE,
357 base::Bind(callback,
358 SYNC_FILE_ERROR_INVALID_URL,
359 SYNC_FILE_STATUS_UNKNOWN));
360 return;
363 if (GetRemoteService(url.origin())->IsConflicting(url)) {
364 base::MessageLoopProxy::current()->PostTask(
365 FROM_HERE,
366 base::Bind(callback,
367 SYNC_STATUS_OK,
368 SYNC_FILE_STATUS_CONFLICTING));
369 return;
372 local_service_->HasPendingLocalChanges(
373 url,
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(
393 const GURL& origin,
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)
406 : 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);
416 DCHECK(profile_);
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);
463 return;
466 // Local side of initialization for the app is done.
467 // Continue on initializing the remote side.
468 GetRemoteService(app_origin)->RegisterOrigin(
469 app_origin,
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);
492 return;
493 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
494 callback.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE);
495 return;
496 default:
497 break;
501 callback.Run(status);
504 void SyncFileSystemService::DidInitializeFileSystemForDump(
505 const GURL& origin,
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);
513 return;
516 base::ListValue* files =
517 GetRemoteService(origin)->DumpFiles(origin).release();
518 if (!files) {
519 callback.Run(new base::ListValue);
520 return;
523 if (!files->GetSize()) {
524 callback.Run(files);
525 return;
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)) {
540 NOTREACHED();
541 completion_callback.Run(
542 NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN);
543 continue;
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) {
563 callback.Run(
564 status,
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());
594 FOR_EACH_OBSERVER(
595 SyncEventObserver, observers_,
596 OnSyncStateUpdated(GURL(),
597 RemoteStateToSyncServiceState(state),
598 description));
600 RunForEachSyncRunners(&SyncProcessRunner::Schedule);
603 void SyncFileSystemService::Observe(
604 int type,
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.
614 // Enable: ENABLED.
615 // Disable: UNLOADED(DISABLE).
616 // Reload, Restart: UNLOADED(DISABLE) -> INSTALLED -> ENABLED.
618 switch (type) {
619 case chrome::NOTIFICATION_EXTENSION_INSTALLED:
620 HandleExtensionInstalled(details);
621 break;
622 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED:
623 HandleExtensionUnloaded(type, details);
624 break;
625 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
626 HandleExtensionUninstalled(type, details);
627 break;
628 case chrome::NOTIFICATION_EXTENSION_ENABLED:
629 HandleExtensionEnabled(type, details);
630 break;
631 default:
632 NOTREACHED() << "Unknown notification.";
633 break;
637 void SyncFileSystemService::HandleExtensionInstalled(
638 const content::NotificationDetails& details) {
639 const Extension* extension =
640 content::Details<const extensions::InstalledExtensionInfo>(details)->
641 extension;
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(
650 int type,
651 const content::NotificationDetails& details) {
652 content::Details<const extensions::UnloadedExtensionInfo> info(details);
653 if (info->reason != extensions::UnloadedExtensionInfo::REASON_DISABLE)
654 return;
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
665 // restarts.
666 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): "
667 << app_origin;
668 return;
671 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
672 << app_origin;
673 GetRemoteService(app_origin)->DisableOrigin(
674 app_origin,
675 base::Bind(&DidHandleOriginForExtensionUnloadedEvent,
676 type, app_origin));
677 local_service_->SetOriginEnabled(app_origin, false);
680 void SyncFileSystemService::HandleExtensionUninstalled(
681 int type,
682 const content::NotificationDetails& details) {
683 const Extension* extension = content::Details<const Extension>(details).ptr();
684 DCHECK(extension);
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: "
698 << app_origin;
699 GetRemoteService(app_origin)->UninstallOrigin(
700 app_origin, flag,
701 base::Bind(&DidHandleOriginForExtensionUnloadedEvent,
702 type, app_origin));
703 local_service_->SetOriginEnabled(app_origin, false);
706 void SyncFileSystemService::HandleExtensionEnabled(
707 int type,
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(
713 app_origin,
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) {
730 FOR_EACH_OBSERVER(
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())
738 return;
739 bool old_sync_enabled = sync_enabled_;
740 sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has(
741 syncer::APPS);
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) {
763 if (IsV2Enabled())
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