Home | History | Annotate | Download | only in sync_file_system
      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.
      4 
      5 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
      6 
      7 #include <string>
      8 
      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/single_thread_task_runner.h"
     15 #include "base/stl_util.h"
     16 #include "base/thread_task_runner_handle.h"
     17 #include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
     18 #include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/sync/profile_sync_service.h"
     21 #include "chrome/browser/sync/profile_sync_service_factory.h"
     22 #include "chrome/browser/sync_file_system/local/local_file_sync_service.h"
     23 #include "chrome/browser/sync_file_system/logger.h"
     24 #include "chrome/browser/sync_file_system/sync_direction.h"
     25 #include "chrome/browser/sync_file_system/sync_event_observer.h"
     26 #include "chrome/browser/sync_file_system/sync_file_metadata.h"
     27 #include "chrome/browser/sync_file_system/sync_process_runner.h"
     28 #include "chrome/browser/sync_file_system/sync_status_code.h"
     29 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     30 #include "components/keyed_service/content/browser_context_dependency_manager.h"
     31 #include "content/public/browser/browser_thread.h"
     32 #include "content/public/browser/storage_partition.h"
     33 #include "extensions/browser/extension_prefs.h"
     34 #include "extensions/browser/extension_registry.h"
     35 #include "extensions/common/extension.h"
     36 #include "extensions/common/manifest_constants.h"
     37 #include "storage/browser/fileapi/file_system_context.h"
     38 #include "url/gurl.h"
     39 
     40 using content::BrowserThread;
     41 using extensions::Extension;
     42 using extensions::ExtensionPrefs;
     43 using extensions::ExtensionRegistry;
     44 using storage::FileSystemURL;
     45 using storage::FileSystemURLSet;
     46 
     47 namespace sync_file_system {
     48 
     49 namespace {
     50 
     51 const char kLocalSyncName[] = "Local sync";
     52 const char kRemoteSyncName[] = "Remote sync";
     53 
     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_ACCESS_FORBIDDEN:
     64       return SYNC_SERVICE_TEMPORARY_UNAVAILABLE;
     65     case REMOTE_SERVICE_DISABLED:
     66       return SYNC_SERVICE_DISABLED;
     67     case REMOTE_SERVICE_STATE_MAX:
     68       NOTREACHED();
     69   }
     70   NOTREACHED() << "Unknown remote service state: " << state;
     71   return SYNC_SERVICE_DISABLED;
     72 }
     73 
     74 void DidHandleUninstalledEvent(const GURL& origin, SyncStatusCode code) {
     75   if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) {
     76     util::Log(logging::LOG_WARNING, FROM_HERE,
     77               "Failed to uninstall origin for uninstall event: %s",
     78               origin.spec().c_str());
     79   }
     80 }
     81 
     82 void DidHandleUnloadedEvent(const GURL& origin, SyncStatusCode code) {
     83   if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) {
     84     util::Log(logging::LOG_WARNING, FROM_HERE,
     85               "Failed to disable origin for unload event: %s",
     86               origin.spec().c_str());
     87   }
     88 }
     89 
     90 void DidHandleLoadEvent(
     91     const GURL& origin,
     92     SyncStatusCode code) {
     93   if (code != SYNC_STATUS_OK) {
     94     util::Log(logging::LOG_WARNING, FROM_HERE,
     95               "Failed to enable origin for load event: %s",
     96               origin.spec().c_str());
     97   }
     98 }
     99 
    100 std::string SyncFileStatusToString(SyncFileStatus sync_file_status) {
    101   return extensions::api::sync_file_system::ToString(
    102       extensions::SyncFileStatusToExtensionEnum(sync_file_status));
    103 }
    104 
    105 // Gets called repeatedly until every SyncFileStatus has been mapped.
    106 void DidGetFileSyncStatusForDump(
    107     base::ListValue* files,
    108     size_t* num_results,
    109     const SyncFileSystemService::DumpFilesCallback& callback,
    110     base::DictionaryValue* file,
    111     SyncStatusCode sync_status_code,
    112     SyncFileStatus sync_file_status) {
    113   DCHECK(files);
    114   DCHECK(num_results);
    115 
    116   if (file)
    117     file->SetString("status", SyncFileStatusToString(sync_file_status));
    118 
    119   // Once all results have been received, run the callback to signal end.
    120   DCHECK_LE(*num_results, files->GetSize());
    121   if (++*num_results < files->GetSize())
    122     return;
    123 
    124   callback.Run(*files);
    125 }
    126 
    127 // We need this indirection because WeakPtr can only be bound to methods
    128 // without a return value.
    129 LocalChangeProcessor* GetLocalChangeProcessorAdapter(
    130     base::WeakPtr<SyncFileSystemService> service,
    131     const GURL& origin) {
    132   if (!service)
    133     return NULL;
    134   return service->GetLocalChangeProcessor(origin);
    135 }
    136 
    137 }  // namespace
    138 
    139 //---------------------------------------------------------------------------
    140 // SyncProcessRunner's.
    141 
    142 // SyncProcessRunner implementation for LocalSync.
    143 class LocalSyncRunner : public SyncProcessRunner,
    144                         public LocalFileSyncService::Observer {
    145  public:
    146   LocalSyncRunner(const std::string& name,
    147                   SyncFileSystemService* sync_service)
    148       : SyncProcessRunner(name, sync_service,
    149                           scoped_ptr<SyncProcessRunner::TimerHelper>(), 1),
    150         factory_(this) {}
    151 
    152   virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE {
    153     GetSyncService()->local_service_->ProcessLocalChange(
    154         base::Bind(&LocalSyncRunner::DidProcessLocalChange,
    155                    factory_.GetWeakPtr(), callback));
    156   }
    157 
    158   // LocalFileSyncService::Observer overrides.
    159   virtual void OnLocalChangeAvailable(int64 pending_changes) OVERRIDE {
    160     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    161 
    162     OnChangesUpdated(pending_changes);
    163 
    164     // Kick other sync runners just in case they're not running.
    165     GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule);
    166   }
    167 
    168  private:
    169   void DidProcessLocalChange(
    170       const SyncStatusCallback& callback,
    171       SyncStatusCode status,
    172       const FileSystemURL& url) {
    173     util::Log(logging::LOG_VERBOSE, FROM_HERE,
    174               "ProcessLocalChange finished with status=%d (%s) for url=%s",
    175               status, SyncStatusCodeToString(status),
    176               url.DebugString().c_str());
    177     callback.Run(status);
    178   }
    179 
    180   base::WeakPtrFactory<LocalSyncRunner> factory_;
    181   DISALLOW_COPY_AND_ASSIGN(LocalSyncRunner);
    182 };
    183 
    184 // SyncProcessRunner implementation for RemoteSync.
    185 class RemoteSyncRunner : public SyncProcessRunner,
    186                          public RemoteFileSyncService::Observer {
    187  public:
    188   RemoteSyncRunner(const std::string& name,
    189                    SyncFileSystemService* sync_service,
    190                    RemoteFileSyncService* remote_service)
    191       : SyncProcessRunner(name, sync_service,
    192                           scoped_ptr<SyncProcessRunner::TimerHelper>(), 1),
    193         remote_service_(remote_service),
    194         last_state_(REMOTE_SERVICE_OK),
    195         factory_(this) {}
    196 
    197   virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE {
    198     remote_service_->ProcessRemoteChange(
    199         base::Bind(&RemoteSyncRunner::DidProcessRemoteChange,
    200                    factory_.GetWeakPtr(), callback));
    201   }
    202 
    203   virtual SyncServiceState GetServiceState() OVERRIDE {
    204     return RemoteStateToSyncServiceState(last_state_);
    205   }
    206 
    207   // RemoteFileSyncService::Observer overrides.
    208   virtual void OnRemoteChangeQueueUpdated(int64 pending_changes) OVERRIDE {
    209     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    210 
    211     OnChangesUpdated(pending_changes);
    212 
    213     // Kick other sync runners just in case they're not running.
    214     GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule);
    215   }
    216 
    217   virtual void OnRemoteServiceStateUpdated(
    218       RemoteServiceState state,
    219       const std::string& description) OVERRIDE {
    220     // Just forward to SyncFileSystemService.
    221     GetSyncService()->OnRemoteServiceStateUpdated(state, description);
    222     last_state_ = state;
    223   }
    224 
    225  private:
    226   void DidProcessRemoteChange(
    227       const SyncStatusCallback& callback,
    228       SyncStatusCode status,
    229       const FileSystemURL& url) {
    230     util::Log(logging::LOG_VERBOSE, FROM_HERE,
    231               "ProcessRemoteChange finished with status=%d (%s) for url=%s",
    232               status, SyncStatusCodeToString(status),
    233               url.DebugString().c_str());
    234 
    235     if (status == SYNC_STATUS_FILE_BUSY) {
    236       GetSyncService()->local_service_->RegisterURLForWaitingSync(
    237           url, base::Bind(&RemoteSyncRunner::Schedule,
    238                           factory_.GetWeakPtr()));
    239     }
    240     callback.Run(status);
    241   }
    242 
    243   RemoteFileSyncService* remote_service_;
    244   RemoteServiceState last_state_;
    245   base::WeakPtrFactory<RemoteSyncRunner> factory_;
    246   DISALLOW_COPY_AND_ASSIGN(RemoteSyncRunner);
    247 };
    248 
    249 //-----------------------------------------------------------------------------
    250 // SyncFileSystemService
    251 
    252 void SyncFileSystemService::Shutdown() {
    253   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    254 
    255   local_sync_runners_.clear();
    256   remote_sync_runners_.clear();
    257 
    258   local_service_->Shutdown();
    259   local_service_.reset();
    260 
    261   remote_service_.reset();
    262 
    263   ProfileSyncServiceBase* profile_sync_service =
    264       ProfileSyncServiceFactory::GetForProfile(profile_);
    265   if (profile_sync_service)
    266     profile_sync_service->RemoveObserver(this);
    267 
    268   ExtensionRegistry::Get(profile_)->RemoveObserver(this);
    269 
    270   profile_ = NULL;
    271 }
    272 
    273 SyncFileSystemService::~SyncFileSystemService() {
    274   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    275   DCHECK(!profile_);
    276 }
    277 
    278 void SyncFileSystemService::InitializeForApp(
    279     storage::FileSystemContext* file_system_context,
    280     const GURL& app_origin,
    281     const SyncStatusCallback& callback) {
    282   DCHECK(local_service_);
    283   DCHECK(remote_service_);
    284   DCHECK(app_origin == app_origin.GetOrigin());
    285 
    286   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    287             "Initializing for App: %s", app_origin.spec().c_str());
    288 
    289   local_service_->MaybeInitializeFileSystemContext(
    290       app_origin, file_system_context,
    291       base::Bind(&SyncFileSystemService::DidInitializeFileSystem,
    292                  AsWeakPtr(), app_origin, callback));
    293 }
    294 
    295 void SyncFileSystemService::GetExtensionStatusMap(
    296     const ExtensionStatusMapCallback& callback) {
    297   remote_service_->GetOriginStatusMap(
    298       base::Bind(&SyncFileSystemService::DidGetExtensionStatusMap,
    299                  AsWeakPtr(), callback));
    300 }
    301 
    302 void SyncFileSystemService::DumpFiles(const GURL& origin,
    303                                       const DumpFilesCallback& callback) {
    304   DCHECK(!origin.is_empty());
    305 
    306   content::StoragePartition* storage_partition =
    307       content::BrowserContext::GetStoragePartitionForSite(profile_, origin);
    308   storage::FileSystemContext* file_system_context =
    309       storage_partition->GetFileSystemContext();
    310   local_service_->MaybeInitializeFileSystemContext(
    311       origin, file_system_context,
    312       base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump,
    313                  AsWeakPtr(), origin, callback));
    314 }
    315 
    316 void SyncFileSystemService::DumpDatabase(const DumpFilesCallback& callback) {
    317   remote_service_->DumpDatabase(
    318       base::Bind(&SyncFileSystemService::DidDumpDatabase,
    319                  AsWeakPtr(), callback));
    320 }
    321 
    322 void SyncFileSystemService::GetFileSyncStatus(
    323     const FileSystemURL& url, const SyncFileStatusCallback& callback) {
    324   DCHECK(local_service_);
    325   DCHECK(GetRemoteService(url.origin()));
    326 
    327   // It's possible to get an invalid FileEntry.
    328   if (!url.is_valid()) {
    329     base::ThreadTaskRunnerHandle::Get()->PostTask(
    330         FROM_HERE,
    331         base::Bind(callback,
    332                    SYNC_FILE_ERROR_INVALID_URL,
    333                    SYNC_FILE_STATUS_UNKNOWN));
    334     return;
    335   }
    336 
    337   local_service_->HasPendingLocalChanges(
    338       url,
    339       base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus,
    340                  AsWeakPtr(), callback));
    341 }
    342 
    343 void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) {
    344   observers_.AddObserver(observer);
    345 }
    346 
    347 void SyncFileSystemService::RemoveSyncEventObserver(
    348     SyncEventObserver* observer) {
    349   observers_.RemoveObserver(observer);
    350 }
    351 
    352 LocalChangeProcessor* SyncFileSystemService::GetLocalChangeProcessor(
    353     const GURL& origin) {
    354   return GetRemoteService(origin)->GetLocalChangeProcessor();
    355 }
    356 
    357 void SyncFileSystemService::OnSyncIdle() {
    358   if (promoting_demoted_changes_)
    359     return;
    360   promoting_demoted_changes_ = true;
    361 
    362   int* job_count = new int(1);
    363   base::Closure promote_completion_callback =
    364       base::Bind(&SyncFileSystemService::OnPromotionCompleted,
    365                  AsWeakPtr(), base::Owned(job_count));
    366 
    367   int64 remote_changes = 0;
    368   for (size_t i = 0; i < remote_sync_runners_.size(); ++i)
    369     remote_changes += remote_sync_runners_[i]->pending_changes();
    370   if (remote_changes == 0) {
    371     ++*job_count;
    372     local_service_->PromoteDemotedChanges(promote_completion_callback);
    373   }
    374 
    375   int64 local_changes = 0;
    376   for (size_t i = 0; i < local_sync_runners_.size(); ++i)
    377     local_changes += local_sync_runners_[i]->pending_changes();
    378   if (local_changes == 0) {
    379     ++*job_count;
    380     remote_service_->PromoteDemotedChanges(promote_completion_callback);
    381   }
    382 
    383   promote_completion_callback.Run();
    384 }
    385 
    386 void SyncFileSystemService::OnPromotionCompleted(int* count) {
    387   if (--*count != 0)
    388     return;
    389   promoting_demoted_changes_ = false;
    390   CheckIfIdle();
    391 }
    392 
    393 void SyncFileSystemService::CheckIfIdle() {
    394   if (promoting_demoted_changes_)
    395     return;
    396 
    397   for (size_t i = 0; i < remote_sync_runners_.size(); ++i) {
    398     SyncServiceState service_state = remote_sync_runners_[i]->GetServiceState();
    399     if (service_state != SYNC_SERVICE_RUNNING)
    400       continue;
    401 
    402     if (remote_sync_runners_[i]->pending_changes())
    403       return;
    404   }
    405 
    406   for (size_t i = 0; i < local_sync_runners_.size(); ++i) {
    407     SyncServiceState service_state = local_sync_runners_[i]->GetServiceState();
    408     if (service_state != SYNC_SERVICE_RUNNING)
    409       continue;
    410 
    411     if (local_sync_runners_[i]->pending_changes())
    412       return;
    413   }
    414 
    415   if (idle_callback_.is_null())
    416     return;
    417 
    418   base::Closure callback = idle_callback_;
    419   idle_callback_.Reset();
    420   callback.Run();
    421 }
    422 
    423 SyncServiceState SyncFileSystemService::GetSyncServiceState() {
    424   // For now we always query the state from the main RemoteFileSyncService.
    425   return RemoteStateToSyncServiceState(remote_service_->GetCurrentState());
    426 }
    427 
    428 SyncFileSystemService* SyncFileSystemService::GetSyncService() {
    429   return this;
    430 }
    431 
    432 void SyncFileSystemService::CallOnIdleForTesting(
    433     const base::Closure& callback) {
    434   DCHECK(idle_callback_.is_null());
    435   idle_callback_ = callback;
    436   CheckIfIdle();
    437 }
    438 
    439 SyncFileSystemService::SyncFileSystemService(Profile* profile)
    440     : profile_(profile),
    441       sync_enabled_(true),
    442       promoting_demoted_changes_(false) {
    443 }
    444 
    445 void SyncFileSystemService::Initialize(
    446     scoped_ptr<LocalFileSyncService> local_service,
    447     scoped_ptr<RemoteFileSyncService> remote_service) {
    448   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    449   DCHECK(local_service);
    450   DCHECK(remote_service);
    451   DCHECK(profile_);
    452 
    453   local_service_ = local_service.Pass();
    454   remote_service_ = remote_service.Pass();
    455 
    456   scoped_ptr<LocalSyncRunner> local_syncer(
    457       new LocalSyncRunner(kLocalSyncName, this));
    458   scoped_ptr<RemoteSyncRunner> remote_syncer(
    459       new RemoteSyncRunner(kRemoteSyncName, this, remote_service_.get()));
    460 
    461   local_service_->AddChangeObserver(local_syncer.get());
    462   local_service_->SetLocalChangeProcessorCallback(
    463       base::Bind(&GetLocalChangeProcessorAdapter, AsWeakPtr()));
    464 
    465   remote_service_->AddServiceObserver(remote_syncer.get());
    466   remote_service_->AddFileStatusObserver(this);
    467   remote_service_->SetRemoteChangeProcessor(local_service_.get());
    468 
    469   local_sync_runners_.push_back(local_syncer.release());
    470   remote_sync_runners_.push_back(remote_syncer.release());
    471 
    472   ProfileSyncServiceBase* profile_sync_service =
    473       ProfileSyncServiceFactory::GetForProfile(profile_);
    474   if (profile_sync_service) {
    475     UpdateSyncEnabledStatus(profile_sync_service);
    476     profile_sync_service->AddObserver(this);
    477   }
    478 
    479   ExtensionRegistry::Get(profile_)->AddObserver(this);
    480 }
    481 
    482 void SyncFileSystemService::DidInitializeFileSystem(
    483     const GURL& app_origin,
    484     const SyncStatusCallback& callback,
    485     SyncStatusCode status) {
    486   DVLOG(1) << "DidInitializeFileSystem: "
    487            << app_origin.spec() << " " << status;
    488 
    489   if (status != SYNC_STATUS_OK) {
    490     callback.Run(status);
    491     return;
    492   }
    493 
    494   // Local side of initialization for the app is done.
    495   // Continue on initializing the remote side.
    496   GetRemoteService(app_origin)->RegisterOrigin(
    497       app_origin,
    498       base::Bind(&SyncFileSystemService::DidRegisterOrigin,
    499                  AsWeakPtr(), app_origin, callback));
    500 }
    501 
    502 void SyncFileSystemService::DidRegisterOrigin(
    503     const GURL& app_origin,
    504     const SyncStatusCallback& callback,
    505     SyncStatusCode status) {
    506   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    507             "DidInitializeForApp (registered the origin): %s: %s",
    508             app_origin.spec().c_str(),
    509             SyncStatusCodeToString(status));
    510 
    511   UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.RegisterOriginResult",
    512                             GetRemoteService(app_origin)->GetCurrentState(),
    513                             REMOTE_SERVICE_STATE_MAX);
    514 
    515   if (status == SYNC_STATUS_FAILED) {
    516     // If we got generic error return the service status information.
    517     switch (GetRemoteService(app_origin)->GetCurrentState()) {
    518       case REMOTE_SERVICE_AUTHENTICATION_REQUIRED:
    519         callback.Run(SYNC_STATUS_AUTHENTICATION_FAILED);
    520         return;
    521       case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
    522         callback.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE);
    523         return;
    524       default:
    525         break;
    526     }
    527   }
    528 
    529   callback.Run(status);
    530 }
    531 
    532 void SyncFileSystemService::DidInitializeFileSystemForDump(
    533     const GURL& origin,
    534     const DumpFilesCallback& callback,
    535     SyncStatusCode status) {
    536   DCHECK(!origin.is_empty());
    537 
    538   if (status != SYNC_STATUS_OK) {
    539     callback.Run(base::ListValue());
    540     return;
    541   }
    542 
    543   GetRemoteService(origin)->DumpFiles(
    544       origin,
    545       base::Bind(
    546           &SyncFileSystemService::DidDumpFiles,
    547           AsWeakPtr(),
    548           origin,
    549           callback));
    550 }
    551 
    552 void SyncFileSystemService::DidDumpFiles(
    553     const GURL& origin,
    554     const DumpFilesCallback& callback,
    555     scoped_ptr<base::ListValue> dump_files) {
    556   if (!dump_files || !dump_files->GetSize()) {
    557     callback.Run(base::ListValue());
    558     return;
    559   }
    560 
    561   base::ListValue* files = dump_files.get();
    562   base::Callback<void(base::DictionaryValue*,
    563                       SyncStatusCode,
    564                       SyncFileStatus)> completion_callback =
    565       base::Bind(&DidGetFileSyncStatusForDump,
    566                  base::Owned(dump_files.release()),
    567                  base::Owned(new size_t(0)),
    568                  callback);
    569 
    570   // After all metadata loaded, sync status can be added to each entry.
    571   for (size_t i = 0; i < files->GetSize(); ++i) {
    572     base::DictionaryValue* file = NULL;
    573     std::string path_string;
    574     if (!files->GetDictionary(i, &file) ||
    575         !file->GetString("path", &path_string)) {
    576       NOTREACHED();
    577       completion_callback.Run(
    578           NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN);
    579       continue;
    580     }
    581 
    582     base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path_string);
    583     FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path);
    584     GetFileSyncStatus(url, base::Bind(completion_callback, file));
    585   }
    586 }
    587 
    588 void SyncFileSystemService::DidDumpDatabase(const DumpFilesCallback& callback,
    589                                             scoped_ptr<base::ListValue> list) {
    590   if (!list)
    591     list = make_scoped_ptr(new base::ListValue);
    592   callback.Run(*list);
    593 }
    594 
    595 void SyncFileSystemService::DidGetExtensionStatusMap(
    596     const ExtensionStatusMapCallback& callback,
    597     scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map) {
    598   if (!status_map)
    599     status_map = make_scoped_ptr(new RemoteFileSyncService::OriginStatusMap);
    600   callback.Run(*status_map);
    601 }
    602 
    603 void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) {
    604   sync_enabled_ = enabled;
    605   remote_service_->SetSyncEnabled(sync_enabled_);
    606 }
    607 
    608 void SyncFileSystemService::DidGetLocalChangeStatus(
    609     const SyncFileStatusCallback& callback,
    610     SyncStatusCode status,
    611     bool has_pending_local_changes) {
    612   callback.Run(
    613       status,
    614       has_pending_local_changes ?
    615           SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED);
    616 }
    617 
    618 void SyncFileSystemService::OnRemoteServiceStateUpdated(
    619     RemoteServiceState state,
    620     const std::string& description) {
    621   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    622   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    623             "OnRemoteServiceStateChanged: %d %s", state, description.c_str());
    624 
    625   FOR_EACH_OBSERVER(
    626       SyncEventObserver, observers_,
    627       OnSyncStateUpdated(GURL(),
    628                          RemoteStateToSyncServiceState(state),
    629                          description));
    630 
    631   RunForEachSyncRunners(&SyncProcessRunner::Schedule);
    632 }
    633 
    634 void SyncFileSystemService::OnExtensionInstalled(
    635     content::BrowserContext* browser_context,
    636     const Extension* extension,
    637     bool is_update) {
    638   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
    639   DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin;
    640   // NOTE: When an app is uninstalled and re-installed in a sequence,
    641   // |local_service_| may still keeps |app_origin| as disabled origin.
    642   local_service_->SetOriginEnabled(app_origin, true);
    643 }
    644 
    645 void SyncFileSystemService::OnExtensionUnloaded(
    646     content::BrowserContext* browser_context,
    647     const Extension* extension,
    648     extensions::UnloadedExtensionInfo::Reason reason) {
    649   if (reason != extensions::UnloadedExtensionInfo::REASON_DISABLE)
    650     return;
    651 
    652   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
    653   int disable_reasons =
    654       ExtensionPrefs::Get(profile_)->GetDisableReasons(extension->id());
    655   if (disable_reasons & Extension::DISABLE_RELOAD) {
    656     // Bypass disabling the origin since the app will be re-enabled soon.
    657     // NOTE: If re-enabling the app fails, the app is disabled while it is
    658     // handled as enabled origin in the SyncFS. This should be safe and will be
    659     // recovered when the user re-enables the app manually or the sync service
    660     // restarts.
    661     DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): "
    662              << app_origin;
    663     return;
    664   }
    665 
    666   DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
    667            << app_origin;
    668   GetRemoteService(app_origin)->DisableOrigin(
    669       app_origin,
    670       base::Bind(&DidHandleUnloadedEvent, app_origin));
    671   local_service_->SetOriginEnabled(app_origin, false);
    672 }
    673 
    674 void SyncFileSystemService::OnExtensionUninstalled(
    675     content::BrowserContext* browser_context,
    676     const Extension* extension,
    677     extensions::UninstallReason reason) {
    678   RemoteFileSyncService::UninstallFlag flag =
    679       RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE;
    680   // If it's loaded from an unpacked package and with key: field,
    681   // the uninstall will not be sync'ed and the user might be using the
    682   // same app key in other installs, so avoid purging the remote folder.
    683   if (extensions::Manifest::IsUnpackedLocation(extension->location()) &&
    684       extension->manifest()->HasKey(extensions::manifest_keys::kKey)) {
    685     flag = RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE;
    686   }
    687 
    688   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
    689   DVLOG(1) << "Handle extension notification for UNINSTALLED: "
    690            << app_origin;
    691   GetRemoteService(app_origin)->UninstallOrigin(
    692       app_origin, flag,
    693       base::Bind(&DidHandleUninstalledEvent, app_origin));
    694   local_service_->SetOriginEnabled(app_origin, false);
    695 }
    696 
    697 void SyncFileSystemService::OnExtensionLoaded(
    698     content::BrowserContext* browser_context,
    699     const Extension* extension) {
    700   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
    701   DVLOG(1) << "Handle extension notification for LOADED: " << app_origin;
    702   GetRemoteService(app_origin)->EnableOrigin(
    703       app_origin,
    704       base::Bind(&DidHandleLoadEvent, app_origin));
    705   local_service_->SetOriginEnabled(app_origin, true);
    706 }
    707 
    708 void SyncFileSystemService::OnStateChanged() {
    709   ProfileSyncServiceBase* profile_sync_service =
    710       ProfileSyncServiceFactory::GetForProfile(profile_);
    711   if (profile_sync_service)
    712     UpdateSyncEnabledStatus(profile_sync_service);
    713 }
    714 
    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));
    723 }
    724 
    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 (!old_sync_enabled && sync_enabled_)
    734     RunForEachSyncRunners(&SyncProcessRunner::Schedule);
    735 }
    736 
    737 void SyncFileSystemService::RunForEachSyncRunners(
    738     void(SyncProcessRunner::*method)()) {
    739   for (ScopedVector<SyncProcessRunner>::iterator iter =
    740            local_sync_runners_.begin();
    741        iter != local_sync_runners_.end(); ++iter)
    742     ((*iter)->*method)();
    743   for (ScopedVector<SyncProcessRunner>::iterator iter =
    744            remote_sync_runners_.begin();
    745        iter != remote_sync_runners_.end(); ++iter)
    746     ((*iter)->*method)();
    747 }
    748 
    749 RemoteFileSyncService* SyncFileSystemService::GetRemoteService(
    750     const GURL& origin) {
    751   return remote_service_.get();
    752 }
    753 
    754 }  // namespace sync_file_system
    755