Home | History | Annotate | Download | only in drive_backend
      1 // Copyright 2013 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/drive_backend/sync_engine.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/threading/sequenced_worker_pool.h"
      9 #include "base/values.h"
     10 #include "chrome/browser/drive/drive_api_service.h"
     11 #include "chrome/browser/drive/drive_notification_manager.h"
     12 #include "chrome/browser/drive/drive_notification_manager_factory.h"
     13 #include "chrome/browser/drive/drive_service_interface.h"
     14 #include "chrome/browser/drive/drive_uploader.h"
     15 #include "chrome/browser/drive/drive_uploader.h"
     16 #include "chrome/browser/extensions/extension_service.h"
     17 #include "chrome/browser/extensions/extension_service.h"
     18 #include "chrome/browser/extensions/extension_system_factory.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/signin/profile_oauth2_token_service.h"
     21 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     22 #include "chrome/browser/sync_file_system/drive_backend/conflict_resolver.h"
     23 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
     24 #include "chrome/browser/sync_file_system/drive_backend/list_changes_task.h"
     25 #include "chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer.h"
     26 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
     27 #include "chrome/browser/sync_file_system/drive_backend/register_app_task.h"
     28 #include "chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.h"
     29 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
     30 #include "chrome/browser/sync_file_system/drive_backend/uninstall_app_task.h"
     31 #include "chrome/browser/sync_file_system/file_status_observer.h"
     32 #include "chrome/browser/sync_file_system/logger.h"
     33 #include "chrome/browser/sync_file_system/sync_task.h"
     34 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     35 #include "content/public/browser/browser_thread.h"
     36 #include "extensions/common/extension.h"
     37 #include "google_apis/drive/drive_api_url_generator.h"
     38 #include "google_apis/drive/gdata_wapi_url_generator.h"
     39 #include "webkit/common/blob/scoped_file.h"
     40 #include "webkit/common/fileapi/file_system_util.h"
     41 
     42 namespace sync_file_system {
     43 namespace drive_backend {
     44 
     45 namespace {
     46 
     47 void EmptyStatusCallback(SyncStatusCode status) {}
     48 
     49 }  // namespace
     50 
     51 scoped_ptr<SyncEngine> SyncEngine::CreateForBrowserContext(
     52     content::BrowserContext* context) {
     53   GURL base_drive_url(
     54       google_apis::DriveApiUrlGenerator::kBaseUrlForProduction);
     55   GURL base_download_url(
     56       google_apis::DriveApiUrlGenerator::kBaseDownloadUrlForProduction);
     57   GURL wapi_base_url(
     58       google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction);
     59 
     60   scoped_refptr<base::SequencedWorkerPool> worker_pool(
     61       content::BrowserThread::GetBlockingPool());
     62   scoped_refptr<base::SequencedTaskRunner> drive_task_runner(
     63       worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
     64           worker_pool->GetSequenceToken(),
     65           base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
     66 
     67   ProfileOAuth2TokenService* token_service =
     68       ProfileOAuth2TokenServiceFactory::GetForProfile(
     69           Profile::FromBrowserContext(context));
     70   scoped_ptr<drive::DriveServiceInterface> drive_service(
     71       new drive::DriveAPIService(
     72           token_service,
     73           context->GetRequestContext(),
     74           drive_task_runner.get(),
     75           base_drive_url, base_download_url, wapi_base_url,
     76           std::string() /* custom_user_agent */));
     77   drive_service->Initialize(token_service->GetPrimaryAccountId());
     78 
     79   scoped_ptr<drive::DriveUploaderInterface> drive_uploader(
     80       new drive::DriveUploader(drive_service.get(), drive_task_runner.get()));
     81 
     82   drive::DriveNotificationManager* notification_manager =
     83       drive::DriveNotificationManagerFactory::GetForBrowserContext(context);
     84   ExtensionService* extension_service =
     85       extensions::ExtensionSystem::GetForBrowserContext(
     86           context)->extension_service();
     87 
     88   scoped_refptr<base::SequencedTaskRunner> task_runner(
     89       worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
     90           worker_pool->GetSequenceToken(),
     91           base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
     92 
     93   scoped_ptr<drive_backend::SyncEngine> sync_engine(
     94       new SyncEngine(
     95           GetSyncFileSystemDir(context->GetPath()),
     96           task_runner.get(),
     97           drive_service.Pass(),
     98           drive_uploader.Pass(),
     99           notification_manager,
    100           extension_service,
    101           token_service));
    102   sync_engine->Initialize();
    103 
    104   return sync_engine.Pass();
    105 }
    106 
    107 void SyncEngine::AppendDependsOnFactories(
    108     std::set<BrowserContextKeyedServiceFactory*>* factories) {
    109   DCHECK(factories);
    110   factories->insert(drive::DriveNotificationManagerFactory::GetInstance());
    111   factories->insert(ProfileOAuth2TokenServiceFactory::GetInstance());
    112   factories->insert(extensions::ExtensionSystemFactory::GetInstance());
    113 }
    114 
    115 SyncEngine::~SyncEngine() {
    116   net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
    117   drive_service_->RemoveObserver(this);
    118   if (notification_manager_)
    119     notification_manager_->RemoveObserver(this);
    120 }
    121 
    122 void SyncEngine::Initialize() {
    123   DCHECK(!task_manager_);
    124   task_manager_.reset(new SyncTaskManager(weak_ptr_factory_.GetWeakPtr()));
    125   task_manager_->Initialize(SYNC_STATUS_OK);
    126 
    127   PostInitializeTask();
    128 
    129   if (notification_manager_)
    130     notification_manager_->AddObserver(this);
    131   drive_service_->AddObserver(this);
    132   net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
    133 
    134   net::NetworkChangeNotifier::ConnectionType type =
    135       net::NetworkChangeNotifier::GetConnectionType();
    136   network_available_ =
    137       type != net::NetworkChangeNotifier::CONNECTION_NONE;
    138 }
    139 
    140 void SyncEngine::AddServiceObserver(SyncServiceObserver* observer) {
    141   service_observers_.AddObserver(observer);
    142 }
    143 
    144 void SyncEngine::AddFileStatusObserver(FileStatusObserver* observer) {
    145   file_status_observers_.AddObserver(observer);
    146 }
    147 
    148 void SyncEngine::RegisterOrigin(
    149     const GURL& origin,
    150     const SyncStatusCallback& callback) {
    151   if (!metadata_database_ && drive_service_->HasRefreshToken())
    152     PostInitializeTask();
    153 
    154   task_manager_->ScheduleSyncTaskAtPriority(
    155       scoped_ptr<SyncTask>(new RegisterAppTask(this, origin.host())),
    156       SyncTaskManager::PRIORITY_HIGH,
    157       callback);
    158 }
    159 
    160 void SyncEngine::EnableOrigin(
    161     const GURL& origin,
    162     const SyncStatusCallback& callback) {
    163   task_manager_->ScheduleTaskAtPriority(
    164       base::Bind(&SyncEngine::DoEnableApp,
    165                  weak_ptr_factory_.GetWeakPtr(),
    166                  origin.host()),
    167       SyncTaskManager::PRIORITY_HIGH,
    168       callback);
    169 }
    170 
    171 void SyncEngine::DisableOrigin(
    172     const GURL& origin,
    173     const SyncStatusCallback& callback) {
    174   task_manager_->ScheduleTaskAtPriority(
    175       base::Bind(&SyncEngine::DoDisableApp,
    176                  weak_ptr_factory_.GetWeakPtr(),
    177                  origin.host()),
    178       SyncTaskManager::PRIORITY_HIGH,
    179       callback);
    180 }
    181 
    182 void SyncEngine::UninstallOrigin(
    183     const GURL& origin,
    184     UninstallFlag flag,
    185     const SyncStatusCallback& callback) {
    186   task_manager_->ScheduleSyncTaskAtPriority(
    187       scoped_ptr<SyncTask>(new UninstallAppTask(this, origin.host(), flag)),
    188       SyncTaskManager::PRIORITY_HIGH,
    189       callback);
    190 }
    191 
    192 void SyncEngine::ProcessRemoteChange(
    193     const SyncFileCallback& callback) {
    194   RemoteToLocalSyncer* syncer = new RemoteToLocalSyncer(this);
    195   task_manager_->ScheduleSyncTask(
    196       scoped_ptr<SyncTask>(syncer),
    197       base::Bind(&SyncEngine::DidProcessRemoteChange,
    198                  weak_ptr_factory_.GetWeakPtr(),
    199                  syncer, callback));
    200 }
    201 
    202 void SyncEngine::SetRemoteChangeProcessor(
    203     RemoteChangeProcessor* processor) {
    204   remote_change_processor_ = processor;
    205 }
    206 
    207 LocalChangeProcessor* SyncEngine::GetLocalChangeProcessor() {
    208   return this;
    209 }
    210 
    211 bool SyncEngine::IsConflicting(const fileapi::FileSystemURL& url) {
    212   // TODO(tzik): Implement this before we support manual conflict resolution.
    213   return false;
    214 }
    215 
    216 RemoteServiceState SyncEngine::GetCurrentState() const {
    217   return service_state_;
    218 }
    219 
    220 void SyncEngine::GetOriginStatusMap(OriginStatusMap* status_map) {
    221   DCHECK(status_map);
    222   if (!extension_service_ || !metadata_database_)
    223     return;
    224 
    225   std::vector<std::string> app_ids;
    226   metadata_database_->GetRegisteredAppIDs(&app_ids);
    227 
    228   for (std::vector<std::string>::const_iterator itr = app_ids.begin();
    229        itr != app_ids.end(); ++itr) {
    230     const std::string& app_id = *itr;
    231     GURL origin =
    232         extensions::Extension::GetBaseURLFromExtensionId(app_id);
    233     (*status_map)[origin] =
    234         metadata_database_->IsAppEnabled(app_id) ? "Enabled" : "Disabled";
    235   }
    236 }
    237 
    238 scoped_ptr<base::ListValue> SyncEngine::DumpFiles(const GURL& origin) {
    239   if (!metadata_database_)
    240     return scoped_ptr<base::ListValue>();
    241   return metadata_database_->DumpFiles(origin.host());
    242 }
    243 
    244 scoped_ptr<base::ListValue> SyncEngine::DumpDatabase() {
    245   if (!metadata_database_)
    246     return scoped_ptr<base::ListValue>();
    247   return metadata_database_->DumpDatabase();
    248 }
    249 
    250 void SyncEngine::SetSyncEnabled(bool enabled) {
    251   if (sync_enabled_ == enabled)
    252     return;
    253 
    254   RemoteServiceState old_state = GetCurrentState();
    255   sync_enabled_ = enabled;
    256   if (old_state == GetCurrentState())
    257     return;
    258 
    259   const char* status_message = enabled ? "Sync is enabled" : "Sync is disabled";
    260   FOR_EACH_OBSERVER(
    261       Observer, service_observers_,
    262       OnRemoteServiceStateUpdated(GetCurrentState(), status_message));
    263 }
    264 
    265 SyncStatusCode SyncEngine::SetConflictResolutionPolicy(
    266     ConflictResolutionPolicy policy) {
    267   conflict_resolution_policy_ = policy;
    268   return SYNC_STATUS_OK;
    269 }
    270 
    271 ConflictResolutionPolicy
    272 SyncEngine::GetConflictResolutionPolicy() const {
    273   return conflict_resolution_policy_;
    274 }
    275 
    276 void SyncEngine::GetRemoteVersions(
    277     const fileapi::FileSystemURL& url,
    278     const RemoteVersionsCallback& callback) {
    279   // TODO(tzik): Implement this before we support manual conflict resolution.
    280   callback.Run(SYNC_STATUS_FAILED, std::vector<Version>());
    281 }
    282 
    283 void SyncEngine::DownloadRemoteVersion(
    284     const fileapi::FileSystemURL& url,
    285     const std::string& version_id,
    286     const DownloadVersionCallback& callback) {
    287   // TODO(tzik): Implement this before we support manual conflict resolution.
    288   callback.Run(SYNC_STATUS_FAILED, webkit_blob::ScopedFile());
    289 }
    290 
    291 void SyncEngine::ApplyLocalChange(
    292     const FileChange& local_change,
    293     const base::FilePath& local_path,
    294     const SyncFileMetadata& local_metadata,
    295     const fileapi::FileSystemURL& url,
    296     const SyncStatusCallback& callback) {
    297   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    298             "[Local->Remote] ApplyLocalChange: %s on %s",
    299             local_change.DebugString().c_str(),
    300             url.DebugString().c_str());
    301 
    302   LocalToRemoteSyncer* syncer = new LocalToRemoteSyncer(
    303       this, local_metadata, local_change, local_path, url);
    304   task_manager_->ScheduleSyncTask(
    305       scoped_ptr<SyncTask>(syncer),
    306       base::Bind(&SyncEngine::DidApplyLocalChange,
    307                  weak_ptr_factory_.GetWeakPtr(),
    308                  syncer, callback));
    309 }
    310 
    311 void SyncEngine::MaybeScheduleNextTask() {
    312   if (GetCurrentState() == REMOTE_SERVICE_DISABLED)
    313     return;
    314 
    315   // TODO(tzik): Notify observer of OnRemoteChangeQueueUpdated.
    316   // TODO(tzik): Add an interface to get the number of dirty trackers to
    317   // MetadataDatabase.
    318 
    319   MaybeStartFetchChanges();
    320 }
    321 
    322 void SyncEngine::NotifyLastOperationStatus(
    323     SyncStatusCode sync_status,
    324     bool used_network) {
    325   UpdateServiceStateFromSyncStatusCode(sync_status, used_network);
    326   if (metadata_database_) {
    327     FOR_EACH_OBSERVER(
    328         Observer,
    329         service_observers_,
    330         OnRemoteChangeQueueUpdated(
    331             metadata_database_->GetDirtyTrackerCount()));
    332   }
    333 }
    334 
    335 void SyncEngine::OnNotificationReceived() {
    336   if (service_state_ == REMOTE_SERVICE_TEMPORARY_UNAVAILABLE)
    337     UpdateServiceState(REMOTE_SERVICE_OK, "Got push notification for Drive.");
    338 
    339   should_check_remote_change_ = true;
    340   MaybeScheduleNextTask();
    341 }
    342 
    343 void SyncEngine::OnPushNotificationEnabled(bool enabled) {}
    344 
    345 void SyncEngine::OnReadyToSendRequests() {
    346   if (service_state_ == REMOTE_SERVICE_OK)
    347     return;
    348   UpdateServiceState(REMOTE_SERVICE_OK, "Authenticated");
    349 
    350   if (!metadata_database_ && auth_token_service_) {
    351     drive_service_->Initialize(auth_token_service_->GetPrimaryAccountId());
    352     PostInitializeTask();
    353     return;
    354   }
    355 
    356   should_check_remote_change_ = true;
    357   MaybeScheduleNextTask();
    358 }
    359 
    360 void SyncEngine::OnRefreshTokenInvalid() {
    361   UpdateServiceState(
    362       REMOTE_SERVICE_AUTHENTICATION_REQUIRED,
    363       "Found invalid refresh token.");
    364 }
    365 
    366 void SyncEngine::OnNetworkChanged(
    367     net::NetworkChangeNotifier::ConnectionType type) {
    368   bool new_network_availability =
    369       type != net::NetworkChangeNotifier::CONNECTION_NONE;
    370 
    371   if (network_available_ && !new_network_availability) {
    372     UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, "Disconnected");
    373   } else if (!network_available_ && new_network_availability) {
    374     UpdateServiceState(REMOTE_SERVICE_OK, "Connected");
    375     should_check_remote_change_ = true;
    376     MaybeStartFetchChanges();
    377   }
    378   network_available_ = new_network_availability;
    379 }
    380 
    381 drive::DriveServiceInterface* SyncEngine::GetDriveService() {
    382   return drive_service_.get();
    383 }
    384 
    385 drive::DriveUploaderInterface* SyncEngine::GetDriveUploader() {
    386   return drive_uploader_.get();
    387 }
    388 
    389 MetadataDatabase* SyncEngine::GetMetadataDatabase() {
    390   return metadata_database_.get();
    391 }
    392 
    393 RemoteChangeProcessor* SyncEngine::GetRemoteChangeProcessor() {
    394   return remote_change_processor_;
    395 }
    396 
    397 base::SequencedTaskRunner* SyncEngine::GetBlockingTaskRunner() {
    398   return task_runner_.get();
    399 }
    400 
    401 SyncEngine::SyncEngine(
    402     const base::FilePath& base_dir,
    403     base::SequencedTaskRunner* task_runner,
    404     scoped_ptr<drive::DriveServiceInterface> drive_service,
    405     scoped_ptr<drive::DriveUploaderInterface> drive_uploader,
    406     drive::DriveNotificationManager* notification_manager,
    407     ExtensionServiceInterface* extension_service,
    408     ProfileOAuth2TokenService* auth_token_service)
    409     : base_dir_(base_dir),
    410       task_runner_(task_runner),
    411       drive_service_(drive_service.Pass()),
    412       drive_uploader_(drive_uploader.Pass()),
    413       notification_manager_(notification_manager),
    414       extension_service_(extension_service),
    415       auth_token_service_(auth_token_service),
    416       remote_change_processor_(NULL),
    417       service_state_(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE),
    418       should_check_conflict_(true),
    419       should_check_remote_change_(true),
    420       sync_enabled_(false),
    421       conflict_resolution_policy_(CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN),
    422       network_available_(false),
    423       weak_ptr_factory_(this) {
    424 }
    425 
    426 void SyncEngine::DoDisableApp(const std::string& app_id,
    427                               const SyncStatusCallback& callback) {
    428   metadata_database_->DisableApp(app_id, callback);
    429 }
    430 
    431 void SyncEngine::DoEnableApp(const std::string& app_id,
    432                              const SyncStatusCallback& callback) {
    433   metadata_database_->EnableApp(app_id, callback);
    434 }
    435 
    436 void SyncEngine::PostInitializeTask() {
    437   DCHECK(!metadata_database_);
    438 
    439   // This initializer task may not run if metadata_database_ is already
    440   // initialized when it runs.
    441   SyncEngineInitializer* initializer =
    442       new SyncEngineInitializer(this,
    443                                 task_runner_.get(),
    444                                 drive_service_.get(),
    445                                 base_dir_.Append(kDatabaseName));
    446   task_manager_->ScheduleSyncTaskAtPriority(
    447       scoped_ptr<SyncTask>(initializer),
    448       SyncTaskManager::PRIORITY_HIGH,
    449       base::Bind(&SyncEngine::DidInitialize, weak_ptr_factory_.GetWeakPtr(),
    450                  initializer));
    451 }
    452 
    453 void SyncEngine::DidInitialize(SyncEngineInitializer* initializer,
    454                                SyncStatusCode status) {
    455   if (status != SYNC_STATUS_OK) {
    456     if (drive_service_->HasRefreshToken()) {
    457       UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE,
    458                          "Could not initialize remote service");
    459     } else {
    460       UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED,
    461                          "Authentication required.");
    462     }
    463     return;
    464   }
    465 
    466   scoped_ptr<MetadataDatabase> metadata_database =
    467       initializer->PassMetadataDatabase();
    468   if (metadata_database)
    469     metadata_database_ = metadata_database.Pass();
    470 
    471   DCHECK(metadata_database_);
    472   UpdateRegisteredApps();
    473 }
    474 
    475 void SyncEngine::DidProcessRemoteChange(RemoteToLocalSyncer* syncer,
    476                                         const SyncFileCallback& callback,
    477                                         SyncStatusCode status) {
    478   if (syncer->is_sync_root_deletion()) {
    479     MetadataDatabase::ClearDatabase(metadata_database_.Pass());
    480     PostInitializeTask();
    481     callback.Run(status, syncer->url());
    482     return;
    483   }
    484 
    485   if (status == SYNC_STATUS_OK) {
    486     if (syncer->sync_action() != SYNC_ACTION_NONE &&
    487         syncer->url().is_valid()) {
    488       FOR_EACH_OBSERVER(FileStatusObserver,
    489                         file_status_observers_,
    490                         OnFileStatusChanged(syncer->url(),
    491                                             SYNC_FILE_STATUS_SYNCED,
    492                                             syncer->sync_action(),
    493                                             SYNC_DIRECTION_REMOTE_TO_LOCAL));
    494     }
    495 
    496     if (syncer->sync_action() == SYNC_ACTION_DELETED &&
    497         syncer->url().is_valid() &&
    498         fileapi::VirtualPath::IsRootPath(syncer->url().path())) {
    499       RegisterOrigin(syncer->url().origin(), base::Bind(&EmptyStatusCallback));
    500     }
    501     should_check_conflict_ = true;
    502   }
    503   callback.Run(status, syncer->url());
    504 }
    505 
    506 void SyncEngine::DidApplyLocalChange(LocalToRemoteSyncer* syncer,
    507                                      const SyncStatusCallback& callback,
    508                                      SyncStatusCode status) {
    509   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    510             "[Local->Remote] ApplyLocalChange finished --> %s",
    511             SyncStatusCodeToString(status));
    512 
    513   if ((status == SYNC_STATUS_OK || status == SYNC_STATUS_RETRY) &&
    514       syncer->url().is_valid() &&
    515       syncer->sync_action() != SYNC_ACTION_NONE) {
    516     fileapi::FileSystemURL updated_url = syncer->url();
    517     if (!syncer->target_path().empty()) {
    518       updated_url = CreateSyncableFileSystemURL(syncer->url().origin(),
    519                                                 syncer->target_path());
    520     }
    521     FOR_EACH_OBSERVER(FileStatusObserver,
    522                       file_status_observers_,
    523                       OnFileStatusChanged(updated_url,
    524                                           SYNC_FILE_STATUS_SYNCED,
    525                                           syncer->sync_action(),
    526                                           SYNC_DIRECTION_LOCAL_TO_REMOTE));
    527   }
    528 
    529   if (status == SYNC_STATUS_UNKNOWN_ORIGIN && syncer->url().is_valid()) {
    530     RegisterOrigin(syncer->url().origin(),
    531                    base::Bind(&EmptyStatusCallback));
    532   }
    533 
    534   if (status != SYNC_STATUS_OK &&
    535       status != SYNC_STATUS_NO_CHANGE_TO_SYNC) {
    536     callback.Run(status);
    537     return;
    538   }
    539 
    540   if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC)
    541     metadata_database_->PromoteLowerPriorityTrackersToNormal();
    542 
    543   if (status == SYNC_STATUS_OK)
    544     should_check_conflict_ = true;
    545 
    546   callback.Run(status);
    547 }
    548 
    549 void SyncEngine::MaybeStartFetchChanges() {
    550   if (GetCurrentState() == REMOTE_SERVICE_DISABLED)
    551     return;
    552 
    553   if (!metadata_database_)
    554     return;
    555 
    556   base::TimeTicks now = base::TimeTicks::Now();
    557   if (!should_check_remote_change_ && now < time_to_check_changes_) {
    558     if (!metadata_database_->HasDirtyTracker() && should_check_conflict_) {
    559       task_manager_->ScheduleSyncTaskIfIdle(
    560           scoped_ptr<SyncTask>(new ConflictResolver(this)),
    561           base::Bind(&SyncEngine::DidResolveConflict,
    562                      weak_ptr_factory_.GetWeakPtr()));
    563     }
    564     return;
    565   }
    566 
    567   if (task_manager_->ScheduleSyncTaskIfIdle(
    568           scoped_ptr<SyncTask>(new ListChangesTask(this)),
    569           base::Bind(&SyncEngine::DidFetchChanges,
    570                      weak_ptr_factory_.GetWeakPtr()))) {
    571     should_check_remote_change_ = false;
    572     time_to_check_changes_ =
    573         now + base::TimeDelta::FromSeconds(kListChangesRetryDelaySeconds);
    574   }
    575 }
    576 
    577 void SyncEngine::DidResolveConflict(SyncStatusCode status) {
    578   if (status == SYNC_STATUS_NO_CONFLICT)
    579     should_check_conflict_ = false;
    580 }
    581 
    582 void SyncEngine::DidFetchChanges(SyncStatusCode status) {
    583   if (status == SYNC_STATUS_OK)
    584     should_check_conflict_ = true;
    585 }
    586 
    587 void SyncEngine::UpdateServiceStateFromSyncStatusCode(
    588       SyncStatusCode status,
    589       bool used_network) {
    590   switch (status) {
    591     case SYNC_STATUS_OK:
    592       if (used_network)
    593         UpdateServiceState(REMOTE_SERVICE_OK, std::string());
    594       break;
    595 
    596     // Authentication error.
    597     case SYNC_STATUS_AUTHENTICATION_FAILED:
    598       UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED,
    599                          "Authentication required");
    600       break;
    601 
    602     // OAuth token error.
    603     case SYNC_STATUS_ACCESS_FORBIDDEN:
    604       UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED,
    605                          "Access forbidden");
    606       break;
    607 
    608     // Errors which could make the service temporarily unavailable.
    609     case SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE:
    610     case SYNC_STATUS_NETWORK_ERROR:
    611     case SYNC_STATUS_ABORT:
    612     case SYNC_STATUS_FAILED:
    613       if (drive_service_->HasRefreshToken()) {
    614         UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE,
    615                            "Network or temporary service error.");
    616       } else {
    617         UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED,
    618                            "Authentication required");
    619       }
    620       break;
    621 
    622     // Errors which would require manual user intervention to resolve.
    623     case SYNC_DATABASE_ERROR_CORRUPTION:
    624     case SYNC_DATABASE_ERROR_IO_ERROR:
    625     case SYNC_DATABASE_ERROR_FAILED:
    626       UpdateServiceState(REMOTE_SERVICE_DISABLED,
    627                          "Unrecoverable database error");
    628       break;
    629 
    630     default:
    631       // Other errors don't affect service state
    632       break;
    633   }
    634 }
    635 
    636 void SyncEngine::UpdateServiceState(RemoteServiceState state,
    637                                     const std::string& description) {
    638   RemoteServiceState old_state = GetCurrentState();
    639   service_state_ = state;
    640 
    641   if (old_state == GetCurrentState())
    642     return;
    643 
    644   util::Log(logging::LOG_INFO, FROM_HERE,
    645             "Service state changed: %d->%d: %s",
    646             old_state, GetCurrentState(), description.c_str());
    647   FOR_EACH_OBSERVER(
    648       Observer, service_observers_,
    649       OnRemoteServiceStateUpdated(GetCurrentState(), description));
    650 }
    651 
    652 void SyncEngine::UpdateRegisteredApps() {
    653   if (!extension_service_)
    654     return;
    655 
    656   DCHECK(metadata_database_);
    657   std::vector<std::string> app_ids;
    658   metadata_database_->GetRegisteredAppIDs(&app_ids);
    659 
    660   // Update the status of every origin using status from ExtensionService.
    661   for (std::vector<std::string>::const_iterator itr = app_ids.begin();
    662        itr != app_ids.end(); ++itr) {
    663     const std::string& app_id = *itr;
    664     GURL origin =
    665         extensions::Extension::GetBaseURLFromExtensionId(app_id);
    666     if (!extension_service_->GetInstalledExtension(app_id)) {
    667       // Extension has been uninstalled.
    668       // (At this stage we can't know if it was unpacked extension or not,
    669       // so just purge the remote folder.)
    670       UninstallOrigin(origin,
    671                       RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE,
    672                       base::Bind(&EmptyStatusCallback));
    673       continue;
    674     }
    675     FileTracker tracker;
    676     if (!metadata_database_->FindAppRootTracker(app_id, &tracker)) {
    677       // App will register itself on first run.
    678       continue;
    679     }
    680     bool is_app_enabled = extension_service_->IsExtensionEnabled(app_id);
    681     bool is_app_root_tracker_enabled =
    682         tracker.tracker_kind() == TRACKER_KIND_APP_ROOT;
    683     if (is_app_enabled && !is_app_root_tracker_enabled)
    684       EnableOrigin(origin, base::Bind(&EmptyStatusCallback));
    685     else if (!is_app_enabled && is_app_root_tracker_enabled)
    686       DisableOrigin(origin, base::Bind(&EmptyStatusCallback));
    687   }
    688 }
    689 
    690 }  // namespace drive_backend
    691 }  // namespace sync_file_system
    692