blob: 31ba68c6219642a3d3d25ccd3585217c98ef1dde [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sync_file_system/sync_file_system_service.h"
#include <string>
#include "base/bind.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/thread_task_runner_handle.h"
#include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
#include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/sync_file_system/local/local_file_sync_service.h"
#include "chrome/browser/sync_file_system/logger.h"
#include "chrome/browser/sync_file_system/sync_direction.h"
#include "chrome/browser/sync_file_system/sync_event_observer.h"
#include "chrome/browser/sync_file_system/sync_file_metadata.h"
#include "chrome/browser/sync_file_system/sync_process_runner.h"
#include "chrome/browser/sync_file_system/sync_status_code.h"
#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_constants.h"
#include "url/gurl.h"
#include "webkit/browser/fileapi/file_system_context.h"
using content::BrowserThread;
using extensions::Extension;
using extensions::ExtensionPrefs;
using extensions::ExtensionRegistry;
using fileapi::FileSystemURL;
using fileapi::FileSystemURLSet;
namespace sync_file_system {
namespace {
const char kLocalSyncName[] = "Local sync";
const char kRemoteSyncName[] = "Remote sync";
const char kRemoteSyncNameV2[] = "Remote sync (v2)";
SyncServiceState RemoteStateToSyncServiceState(
RemoteServiceState state) {
switch (state) {
case REMOTE_SERVICE_OK:
return SYNC_SERVICE_RUNNING;
case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
return SYNC_SERVICE_TEMPORARY_UNAVAILABLE;
case REMOTE_SERVICE_AUTHENTICATION_REQUIRED:
return SYNC_SERVICE_AUTHENTICATION_REQUIRED;
case REMOTE_SERVICE_DISABLED:
return SYNC_SERVICE_DISABLED;
case REMOTE_SERVICE_STATE_MAX:
NOTREACHED();
}
NOTREACHED() << "Unknown remote service state: " << state;
return SYNC_SERVICE_DISABLED;
}
void DidHandleUninstalledEvent(const GURL& origin, SyncStatusCode code) {
if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) {
util::Log(logging::LOG_WARNING, FROM_HERE,
"Failed to uninstall origin for uninstall event: %s",
origin.spec().c_str());
}
}
void DidHandleUnloadedEvent(const GURL& origin, SyncStatusCode code) {
if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) {
util::Log(logging::LOG_WARNING, FROM_HERE,
"Failed to disable origin for unload event: %s",
origin.spec().c_str());
}
}
void DidHandleLoadEvent(
const GURL& origin,
SyncStatusCode code) {
if (code != SYNC_STATUS_OK) {
util::Log(logging::LOG_WARNING, FROM_HERE,
"Failed to enable origin for load event: %s",
origin.spec().c_str());
}
}
std::string SyncFileStatusToString(SyncFileStatus sync_file_status) {
return extensions::api::sync_file_system::ToString(
extensions::SyncFileStatusToExtensionEnum(sync_file_status));
}
// Gets called repeatedly until every SyncFileStatus has been mapped.
void DidGetFileSyncStatusForDump(
base::ListValue* files,
size_t* num_results,
const SyncFileSystemService::DumpFilesCallback& callback,
base::DictionaryValue* file,
SyncStatusCode sync_status_code,
SyncFileStatus sync_file_status) {
DCHECK(files);
DCHECK(num_results);
if (file)
file->SetString("status", SyncFileStatusToString(sync_file_status));
// Once all results have been received, run the callback to signal end.
DCHECK_LE(*num_results, files->GetSize());
if (++*num_results < files->GetSize())
return;
callback.Run(*files);
}
// We need this indirection because WeakPtr can only be bound to methods
// without a return value.
LocalChangeProcessor* GetLocalChangeProcessorAdapter(
base::WeakPtr<SyncFileSystemService> service,
const GURL& origin) {
if (!service)
return NULL;
return service->GetLocalChangeProcessor(origin);
}
} // namespace
//---------------------------------------------------------------------------
// SyncProcessRunner's.
// SyncProcessRunner implementation for LocalSync.
class LocalSyncRunner : public SyncProcessRunner,
public LocalFileSyncService::Observer {
public:
LocalSyncRunner(const std::string& name,
SyncFileSystemService* sync_service)
: SyncProcessRunner(name, sync_service,
scoped_ptr<SyncProcessRunner::TimerHelper>(), 1),
factory_(this) {}
virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE {
GetSyncService()->local_service_->ProcessLocalChange(
base::Bind(&LocalSyncRunner::DidProcessLocalChange,
factory_.GetWeakPtr(), callback));
}
// LocalFileSyncService::Observer overrides.
virtual void OnLocalChangeAvailable(int64 pending_changes) OVERRIDE {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
OnChangesUpdated(pending_changes);
// Kick other sync runners just in case they're not running.
GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule);
}
private:
void DidProcessLocalChange(
const SyncStatusCallback& callback,
SyncStatusCode status,
const FileSystemURL& url) {
util::Log(logging::LOG_VERBOSE, FROM_HERE,
"ProcessLocalChange finished with status=%d (%s) for url=%s",
status, SyncStatusCodeToString(status),
url.DebugString().c_str());
callback.Run(status);
}
base::WeakPtrFactory<LocalSyncRunner> factory_;
DISALLOW_COPY_AND_ASSIGN(LocalSyncRunner);
};
// SyncProcessRunner implementation for RemoteSync.
class RemoteSyncRunner : public SyncProcessRunner,
public RemoteFileSyncService::Observer {
public:
RemoteSyncRunner(const std::string& name,
SyncFileSystemService* sync_service,
RemoteFileSyncService* remote_service)
: SyncProcessRunner(name, sync_service,
scoped_ptr<SyncProcessRunner::TimerHelper>(), 1),
remote_service_(remote_service),
last_state_(REMOTE_SERVICE_OK),
factory_(this) {}
virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE {
remote_service_->ProcessRemoteChange(
base::Bind(&RemoteSyncRunner::DidProcessRemoteChange,
factory_.GetWeakPtr(), callback));
}
virtual SyncServiceState GetServiceState() OVERRIDE {
return RemoteStateToSyncServiceState(last_state_);
}
// RemoteFileSyncService::Observer overrides.
virtual void OnRemoteChangeQueueUpdated(int64 pending_changes) OVERRIDE {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
OnChangesUpdated(pending_changes);
// Kick other sync runners just in case they're not running.
GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule);
}
virtual void OnRemoteServiceStateUpdated(
RemoteServiceState state,
const std::string& description) OVERRIDE {
// Just forward to SyncFileSystemService.
GetSyncService()->OnRemoteServiceStateUpdated(state, description);
last_state_ = state;
}
private:
void DidProcessRemoteChange(
const SyncStatusCallback& callback,
SyncStatusCode status,
const FileSystemURL& url) {
util::Log(logging::LOG_VERBOSE, FROM_HERE,
"ProcessRemoteChange finished with status=%d (%s) for url=%s",
status, SyncStatusCodeToString(status),
url.DebugString().c_str());
if (status == SYNC_STATUS_FILE_BUSY) {
GetSyncService()->local_service_->RegisterURLForWaitingSync(
url, base::Bind(&RemoteSyncRunner::Schedule,
factory_.GetWeakPtr()));
}
callback.Run(status);
}
RemoteFileSyncService* remote_service_;
RemoteServiceState last_state_;
base::WeakPtrFactory<RemoteSyncRunner> factory_;
DISALLOW_COPY_AND_ASSIGN(RemoteSyncRunner);
};
//-----------------------------------------------------------------------------
// SyncFileSystemService
void SyncFileSystemService::Shutdown() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
local_sync_runners_.clear();
remote_sync_runners_.clear();
local_service_->Shutdown();
local_service_.reset();
remote_service_.reset();
v2_remote_service_.reset();
ProfileSyncServiceBase* profile_sync_service =
ProfileSyncServiceFactory::GetForProfile(profile_);
if (profile_sync_service)
profile_sync_service->RemoveObserver(this);
ExtensionRegistry::Get(profile_)->RemoveObserver(this);
profile_ = NULL;
}
SyncFileSystemService::~SyncFileSystemService() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!profile_);
}
void SyncFileSystemService::InitializeForApp(
fileapi::FileSystemContext* file_system_context,
const GURL& app_origin,
const SyncStatusCallback& callback) {
DCHECK(local_service_);
DCHECK(remote_service_);
DCHECK(app_origin == app_origin.GetOrigin());
util::Log(logging::LOG_VERBOSE, FROM_HERE,
"Initializing for App: %s", app_origin.spec().c_str());
local_service_->MaybeInitializeFileSystemContext(
app_origin, file_system_context,
base::Bind(&SyncFileSystemService::DidInitializeFileSystem,
AsWeakPtr(), app_origin, callback));
}
void SyncFileSystemService::GetExtensionStatusMap(
const ExtensionStatusMapCallback& callback) {
remote_service_->GetOriginStatusMap(
base::Bind(&SyncFileSystemService::DidGetExtensionStatusMap,
AsWeakPtr(), callback));
}
void SyncFileSystemService::DumpFiles(const GURL& origin,
const DumpFilesCallback& callback) {
DCHECK(!origin.is_empty());
content::StoragePartition* storage_partition =
content::BrowserContext::GetStoragePartitionForSite(profile_, origin);
fileapi::FileSystemContext* file_system_context =
storage_partition->GetFileSystemContext();
local_service_->MaybeInitializeFileSystemContext(
origin, file_system_context,
base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump,
AsWeakPtr(), origin, callback));
}
void SyncFileSystemService::DumpDatabase(const DumpFilesCallback& callback) {
remote_service_->DumpDatabase(
base::Bind(&SyncFileSystemService::DidDumpDatabase,
AsWeakPtr(), callback));
}
void SyncFileSystemService::GetFileSyncStatus(
const FileSystemURL& url, const SyncFileStatusCallback& callback) {
DCHECK(local_service_);
DCHECK(GetRemoteService(url.origin()));
// It's possible to get an invalid FileEntry.
if (!url.is_valid()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(callback,
SYNC_FILE_ERROR_INVALID_URL,
SYNC_FILE_STATUS_UNKNOWN));
return;
}
local_service_->HasPendingLocalChanges(
url,
base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus,
AsWeakPtr(), callback));
}
void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) {
observers_.AddObserver(observer);
}
void SyncFileSystemService::RemoveSyncEventObserver(
SyncEventObserver* observer) {
observers_.RemoveObserver(observer);
}
LocalChangeProcessor* SyncFileSystemService::GetLocalChangeProcessor(
const GURL& origin) {
return GetRemoteService(origin)->GetLocalChangeProcessor();
}
void SyncFileSystemService::OnSyncIdle() {
int64 remote_changes = 0;
for (ScopedVector<SyncProcessRunner>::iterator iter =
remote_sync_runners_.begin();
iter != remote_sync_runners_.end(); ++iter)
remote_changes += (*iter)->pending_changes();
if (remote_changes == 0)
local_service_->PromoteDemotedChanges();
int64 local_changes = 0;
for (ScopedVector<SyncProcessRunner>::iterator iter =
local_sync_runners_.begin();
iter != local_sync_runners_.end(); ++iter)
local_changes += (*iter)->pending_changes();
if (local_changes == 0 && v2_remote_service_)
v2_remote_service_->PromoteDemotedChanges();
}
SyncServiceState SyncFileSystemService::GetSyncServiceState() {
// For now we always query the state from the main RemoteFileSyncService.
return RemoteStateToSyncServiceState(remote_service_->GetCurrentState());
}
SyncFileSystemService* SyncFileSystemService::GetSyncService() {
return this;
}
SyncFileSystemService::SyncFileSystemService(Profile* profile)
: profile_(profile),
sync_enabled_(true) {
}
void SyncFileSystemService::Initialize(
scoped_ptr<LocalFileSyncService> local_service,
scoped_ptr<RemoteFileSyncService> remote_service) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(local_service);
DCHECK(remote_service);
DCHECK(profile_);
local_service_ = local_service.Pass();
remote_service_ = remote_service.Pass();
scoped_ptr<LocalSyncRunner> local_syncer(
new LocalSyncRunner(kLocalSyncName, this));
scoped_ptr<RemoteSyncRunner> remote_syncer(
new RemoteSyncRunner(kRemoteSyncName, this, remote_service_.get()));
local_service_->AddChangeObserver(local_syncer.get());
local_service_->SetLocalChangeProcessorCallback(
base::Bind(&GetLocalChangeProcessorAdapter, AsWeakPtr()));
remote_service_->AddServiceObserver(remote_syncer.get());
remote_service_->AddFileStatusObserver(this);
remote_service_->SetRemoteChangeProcessor(local_service_.get());
local_sync_runners_.push_back(local_syncer.release());
remote_sync_runners_.push_back(remote_syncer.release());
ProfileSyncServiceBase* profile_sync_service =
ProfileSyncServiceFactory::GetForProfile(profile_);
if (profile_sync_service) {
UpdateSyncEnabledStatus(profile_sync_service);
profile_sync_service->AddObserver(this);
}
ExtensionRegistry::Get(profile_)->AddObserver(this);
}
void SyncFileSystemService::DidInitializeFileSystem(
const GURL& app_origin,
const SyncStatusCallback& callback,
SyncStatusCode status) {
DVLOG(1) << "DidInitializeFileSystem: "
<< app_origin.spec() << " " << status;
if (status != SYNC_STATUS_OK) {
callback.Run(status);
return;
}
// Local side of initialization for the app is done.
// Continue on initializing the remote side.
GetRemoteService(app_origin)->RegisterOrigin(
app_origin,
base::Bind(&SyncFileSystemService::DidRegisterOrigin,
AsWeakPtr(), app_origin, callback));
}
void SyncFileSystemService::DidRegisterOrigin(
const GURL& app_origin,
const SyncStatusCallback& callback,
SyncStatusCode status) {
util::Log(logging::LOG_VERBOSE, FROM_HERE,
"DidInitializeForApp (registered the origin): %s: %s",
app_origin.spec().c_str(),
SyncStatusCodeToString(status));
UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.RegisterOriginResult",
GetRemoteService(app_origin)->GetCurrentState(),
REMOTE_SERVICE_STATE_MAX);
if (status == SYNC_STATUS_FAILED) {
// If we got generic error return the service status information.
switch (GetRemoteService(app_origin)->GetCurrentState()) {
case REMOTE_SERVICE_AUTHENTICATION_REQUIRED:
callback.Run(SYNC_STATUS_AUTHENTICATION_FAILED);
return;
case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
callback.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE);
return;
default:
break;
}
}
callback.Run(status);
}
void SyncFileSystemService::DidInitializeFileSystemForDump(
const GURL& origin,
const DumpFilesCallback& callback,
SyncStatusCode status) {
DCHECK(!origin.is_empty());
if (status != SYNC_STATUS_OK) {
callback.Run(base::ListValue());
return;
}
GetRemoteService(origin)->DumpFiles(
origin,
base::Bind(
&SyncFileSystemService::DidDumpFiles,
AsWeakPtr(),
origin,
callback));
}
void SyncFileSystemService::DidDumpFiles(
const GURL& origin,
const DumpFilesCallback& callback,
scoped_ptr<base::ListValue> dump_files) {
if (!dump_files || !dump_files->GetSize()) {
callback.Run(base::ListValue());
return;
}
base::ListValue* files = dump_files.get();
base::Callback<void(base::DictionaryValue*,
SyncStatusCode,
SyncFileStatus)> completion_callback =
base::Bind(&DidGetFileSyncStatusForDump,
base::Owned(dump_files.release()),
base::Owned(new size_t(0)),
callback);
// After all metadata loaded, sync status can be added to each entry.
for (size_t i = 0; i < files->GetSize(); ++i) {
base::DictionaryValue* file = NULL;
std::string path_string;
if (!files->GetDictionary(i, &file) ||
!file->GetString("path", &path_string)) {
NOTREACHED();
completion_callback.Run(
NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN);
continue;
}
base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path_string);
FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path);
GetFileSyncStatus(url, base::Bind(completion_callback, file));
}
}
void SyncFileSystemService::DidDumpDatabase(
const DumpFilesCallback& callback, scoped_ptr<base::ListValue> list) {
if (!list)
list = make_scoped_ptr(new base::ListValue);
if (!v2_remote_service_) {
callback.Run(*list);
return;
}
v2_remote_service_->DumpDatabase(
base::Bind(&SyncFileSystemService::DidDumpV2Database,
AsWeakPtr(), callback, base::Passed(&list)));
}
void SyncFileSystemService::DidDumpV2Database(
const DumpFilesCallback& callback,
scoped_ptr<base::ListValue> v1list,
scoped_ptr<base::ListValue> v2list) {
DCHECK(v1list);
if (v2list) {
for (base::ListValue::iterator itr = v2list->begin();
itr != v2list->end();) {
scoped_ptr<base::Value> item;
itr = v2list->Erase(itr, &item);
v1list->Append(item.release());
}
}
callback.Run(*v1list);
}
void SyncFileSystemService::DidGetExtensionStatusMap(
const ExtensionStatusMapCallback& callback,
scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map) {
if (!v2_remote_service_) {
callback.Run(*status_map);
return;
}
v2_remote_service_->GetOriginStatusMap(
base::Bind(&SyncFileSystemService::DidGetV2ExtensionStatusMap,
AsWeakPtr(),
callback,
base::Passed(&status_map)));
}
void SyncFileSystemService::DidGetV2ExtensionStatusMap(
const ExtensionStatusMapCallback& callback,
scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map_v1,
scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map_v2) {
// Merge |status_map_v2| into |status_map_v1|.
status_map_v1->insert(status_map_v2->begin(), status_map_v2->end());
callback.Run(*status_map_v1);
}
void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) {
sync_enabled_ = enabled;
remote_service_->SetSyncEnabled(sync_enabled_);
if (v2_remote_service_)
v2_remote_service_->SetSyncEnabled(sync_enabled_);
}
void SyncFileSystemService::DidGetLocalChangeStatus(
const SyncFileStatusCallback& callback,
SyncStatusCode status,
bool has_pending_local_changes) {
callback.Run(
status,
has_pending_local_changes ?
SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED);
}
void SyncFileSystemService::OnRemoteServiceStateUpdated(
RemoteServiceState state,
const std::string& description) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
util::Log(logging::LOG_VERBOSE, FROM_HERE,
"OnRemoteServiceStateChanged: %d %s", state, description.c_str());
FOR_EACH_OBSERVER(
SyncEventObserver, observers_,
OnSyncStateUpdated(GURL(),
RemoteStateToSyncServiceState(state),
description));
RunForEachSyncRunners(&SyncProcessRunner::Schedule);
}
void SyncFileSystemService::OnExtensionInstalled(
content::BrowserContext* browser_context,
const Extension* extension,
bool is_update) {
GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin;
// NOTE: When an app is uninstalled and re-installed in a sequence,
// |local_service_| may still keeps |app_origin| as disabled origin.
local_service_->SetOriginEnabled(app_origin, true);
}
void SyncFileSystemService::OnExtensionUnloaded(
content::BrowserContext* browser_context,
const Extension* extension,
extensions::UnloadedExtensionInfo::Reason reason) {
if (reason != extensions::UnloadedExtensionInfo::REASON_DISABLE)
return;
GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
int disable_reasons =
ExtensionPrefs::Get(profile_)->GetDisableReasons(extension->id());
if (disable_reasons & Extension::DISABLE_RELOAD) {
// Bypass disabling the origin since the app will be re-enabled soon.
// NOTE: If re-enabling the app fails, the app is disabled while it is
// handled as enabled origin in the SyncFS. This should be safe and will be
// recovered when the user re-enables the app manually or the sync service
// restarts.
DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): "
<< app_origin;
return;
}
DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
<< app_origin;
GetRemoteService(app_origin)->DisableOrigin(
app_origin,
base::Bind(&DidHandleUnloadedEvent, app_origin));
local_service_->SetOriginEnabled(app_origin, false);
}
void SyncFileSystemService::OnExtensionUninstalled(
content::BrowserContext* browser_context,
const Extension* extension) {
RemoteFileSyncService::UninstallFlag flag =
RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE;
// If it's loaded from an unpacked package and with key: field,
// the uninstall will not be sync'ed and the user might be using the
// same app key in other installs, so avoid purging the remote folder.
if (extensions::Manifest::IsUnpackedLocation(extension->location()) &&
extension->manifest()->HasKey(extensions::manifest_keys::kKey)) {
flag = RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE;
}
GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
DVLOG(1) << "Handle extension notification for UNINSTALLED: "
<< app_origin;
GetRemoteService(app_origin)->UninstallOrigin(
app_origin, flag,
base::Bind(&DidHandleUninstalledEvent, app_origin));
local_service_->SetOriginEnabled(app_origin, false);
}
void SyncFileSystemService::OnExtensionLoaded(
content::BrowserContext* browser_context,
const Extension* extension) {
GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
DVLOG(1) << "Handle extension notification for LOADED: " << app_origin;
GetRemoteService(app_origin)->EnableOrigin(
app_origin,
base::Bind(&DidHandleLoadEvent, app_origin));
local_service_->SetOriginEnabled(app_origin, true);
}
void SyncFileSystemService::OnStateChanged() {
ProfileSyncServiceBase* profile_sync_service =
ProfileSyncServiceFactory::GetForProfile(profile_);
if (profile_sync_service)
UpdateSyncEnabledStatus(profile_sync_service);
}
void SyncFileSystemService::OnFileStatusChanged(
const FileSystemURL& url,
SyncFileStatus sync_status,
SyncAction action_taken,
SyncDirection direction) {
FOR_EACH_OBSERVER(
SyncEventObserver, observers_,
OnFileSynced(url, sync_status, action_taken, direction));
}
void SyncFileSystemService::UpdateSyncEnabledStatus(
ProfileSyncServiceBase* profile_sync_service) {
if (!profile_sync_service->HasSyncSetupCompleted())
return;
bool old_sync_enabled = sync_enabled_;
sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has(
syncer::APPS);
remote_service_->SetSyncEnabled(sync_enabled_);
if (v2_remote_service_)
v2_remote_service_->SetSyncEnabled(sync_enabled_);
if (!old_sync_enabled && sync_enabled_)
RunForEachSyncRunners(&SyncProcessRunner::Schedule);
}
void SyncFileSystemService::RunForEachSyncRunners(
void(SyncProcessRunner::*method)()) {
for (ScopedVector<SyncProcessRunner>::iterator iter =
local_sync_runners_.begin();
iter != local_sync_runners_.end(); ++iter)
((*iter)->*method)();
for (ScopedVector<SyncProcessRunner>::iterator iter =
remote_sync_runners_.begin();
iter != remote_sync_runners_.end(); ++iter)
((*iter)->*method)();
}
RemoteFileSyncService* SyncFileSystemService::GetRemoteService(
const GURL& origin) {
if (IsV2Enabled())
return remote_service_.get();
if (!IsV2EnabledForOrigin(origin))
return remote_service_.get();
if (!v2_remote_service_) {
v2_remote_service_ = RemoteFileSyncService::CreateForBrowserContext(
RemoteFileSyncService::V2, profile_, &task_logger_);
scoped_ptr<RemoteSyncRunner> v2_remote_syncer(
new RemoteSyncRunner(kRemoteSyncNameV2, this,
v2_remote_service_.get()));
v2_remote_service_->AddServiceObserver(v2_remote_syncer.get());
v2_remote_service_->AddFileStatusObserver(this);
v2_remote_service_->SetRemoteChangeProcessor(local_service_.get());
v2_remote_service_->SetSyncEnabled(sync_enabled_);
remote_sync_runners_.push_back(v2_remote_syncer.release());
}
return v2_remote_service_.get();
}
} // namespace sync_file_system