Home | History | Annotate | Download | only in drive_backend
      1 // Copyright 2014 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_worker.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "chrome/browser/drive/drive_service_interface.h"
     11 #include "chrome/browser/extensions/extension_service.h"
     12 #include "chrome/browser/sync_file_system/drive_backend/callback_helper.h"
     13 #include "chrome/browser/sync_file_system/drive_backend/conflict_resolver.h"
     14 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
     15 #include "chrome/browser/sync_file_system/drive_backend/list_changes_task.h"
     16 #include "chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer.h"
     17 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
     18 #include "chrome/browser/sync_file_system/drive_backend/register_app_task.h"
     19 #include "chrome/browser/sync_file_system/drive_backend/remote_change_processor_on_worker.h"
     20 #include "chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.h"
     21 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
     22 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
     23 #include "chrome/browser/sync_file_system/drive_backend/sync_task.h"
     24 #include "chrome/browser/sync_file_system/drive_backend/uninstall_app_task.h"
     25 #include "chrome/browser/sync_file_system/logger.h"
     26 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     27 #include "storage/common/fileapi/file_system_util.h"
     28 
     29 namespace sync_file_system {
     30 
     31 class RemoteChangeProcessor;
     32 
     33 namespace drive_backend {
     34 
     35 namespace {
     36 
     37 void EmptyStatusCallback(SyncStatusCode status) {}
     38 
     39 void InvokeIdleCallback(const base::Closure& idle_callback,
     40                         const SyncStatusCallback& callback) {
     41   idle_callback.Run();
     42   callback.Run(SYNC_STATUS_OK);
     43 }
     44 
     45 }  // namespace
     46 
     47 SyncWorker::SyncWorker(
     48     const base::FilePath& base_dir,
     49     const base::WeakPtr<ExtensionServiceInterface>& extension_service,
     50     leveldb::Env* env_override)
     51     : base_dir_(base_dir),
     52       env_override_(env_override),
     53       service_state_(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE),
     54       should_check_conflict_(true),
     55       should_check_remote_change_(true),
     56       listing_remote_changes_(false),
     57       sync_enabled_(false),
     58       extension_service_(extension_service),
     59       weak_ptr_factory_(this) {
     60   sequence_checker_.DetachFromSequence();
     61   DCHECK(base_dir_.IsAbsolute());
     62 }
     63 
     64 SyncWorker::~SyncWorker() {
     65   observers_.Clear();
     66 }
     67 
     68 void SyncWorker::Initialize(scoped_ptr<SyncEngineContext> context) {
     69   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
     70   DCHECK(!task_manager_);
     71 
     72   context_ = context.Pass();
     73 
     74   task_manager_.reset(new SyncTaskManager(
     75       weak_ptr_factory_.GetWeakPtr(), 0 /* maximum_background_task */,
     76       context_->GetWorkerTaskRunner()));
     77   task_manager_->Initialize(SYNC_STATUS_OK);
     78 
     79   PostInitializeTask();
     80 }
     81 
     82 void SyncWorker::RegisterOrigin(
     83     const GURL& origin,
     84     const SyncStatusCallback& callback) {
     85   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
     86 
     87   if (!GetMetadataDatabase())
     88     PostInitializeTask();
     89 
     90   scoped_ptr<RegisterAppTask> task(
     91       new RegisterAppTask(context_.get(), origin.host()));
     92   if (task->CanFinishImmediately()) {
     93     callback.Run(SYNC_STATUS_OK);
     94     return;
     95   }
     96 
     97   task_manager_->ScheduleSyncTask(
     98       FROM_HERE,
     99       task.PassAs<SyncTask>(),
    100       SyncTaskManager::PRIORITY_HIGH,
    101       callback);
    102 }
    103 
    104 void SyncWorker::EnableOrigin(
    105     const GURL& origin,
    106     const SyncStatusCallback& callback) {
    107   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    108 
    109   task_manager_->ScheduleTask(
    110       FROM_HERE,
    111       base::Bind(&SyncWorker::DoEnableApp,
    112                  weak_ptr_factory_.GetWeakPtr(),
    113                  origin.host()),
    114       SyncTaskManager::PRIORITY_HIGH,
    115       callback);
    116 }
    117 
    118 void SyncWorker::DisableOrigin(
    119     const GURL& origin,
    120     const SyncStatusCallback& callback) {
    121   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    122 
    123   task_manager_->ScheduleTask(
    124       FROM_HERE,
    125       base::Bind(&SyncWorker::DoDisableApp,
    126                  weak_ptr_factory_.GetWeakPtr(),
    127                  origin.host()),
    128       SyncTaskManager::PRIORITY_HIGH,
    129       callback);
    130 }
    131 
    132 void SyncWorker::UninstallOrigin(
    133     const GURL& origin,
    134     RemoteFileSyncService::UninstallFlag flag,
    135     const SyncStatusCallback& callback) {
    136   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    137 
    138   task_manager_->ScheduleSyncTask(
    139       FROM_HERE,
    140       scoped_ptr<SyncTask>(
    141           new UninstallAppTask(context_.get(), origin.host(), flag)),
    142       SyncTaskManager::PRIORITY_HIGH,
    143       callback);
    144 }
    145 
    146 void SyncWorker::ProcessRemoteChange(const SyncFileCallback& callback) {
    147   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    148 
    149   RemoteToLocalSyncer* syncer = new RemoteToLocalSyncer(context_.get());
    150   task_manager_->ScheduleSyncTask(
    151       FROM_HERE,
    152       scoped_ptr<SyncTask>(syncer),
    153       SyncTaskManager::PRIORITY_MED,
    154       base::Bind(&SyncWorker::DidProcessRemoteChange,
    155                  weak_ptr_factory_.GetWeakPtr(),
    156                  syncer,
    157                  callback));
    158 }
    159 
    160 void SyncWorker::SetRemoteChangeProcessor(
    161     RemoteChangeProcessorOnWorker* remote_change_processor_on_worker) {
    162   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    163 
    164   context_->SetRemoteChangeProcessor(remote_change_processor_on_worker);
    165 }
    166 
    167 RemoteServiceState SyncWorker::GetCurrentState() const {
    168   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    169 
    170   if (!sync_enabled_)
    171     return REMOTE_SERVICE_DISABLED;
    172   return service_state_;
    173 }
    174 
    175 void SyncWorker::GetOriginStatusMap(
    176     const RemoteFileSyncService::StatusMapCallback& callback) {
    177   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    178 
    179   if (!GetMetadataDatabase())
    180     return;
    181 
    182   std::vector<std::string> app_ids;
    183   GetMetadataDatabase()->GetRegisteredAppIDs(&app_ids);
    184 
    185   scoped_ptr<RemoteFileSyncService::OriginStatusMap>
    186       status_map(new RemoteFileSyncService::OriginStatusMap);
    187   for (std::vector<std::string>::const_iterator itr = app_ids.begin();
    188        itr != app_ids.end(); ++itr) {
    189     const std::string& app_id = *itr;
    190     GURL origin = extensions::Extension::GetBaseURLFromExtensionId(app_id);
    191     (*status_map)[origin] =
    192         GetMetadataDatabase()->IsAppEnabled(app_id) ? "Enabled" : "Disabled";
    193   }
    194 
    195   callback.Run(status_map.Pass());
    196 }
    197 
    198 scoped_ptr<base::ListValue> SyncWorker::DumpFiles(const GURL& origin) {
    199   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    200 
    201   if (!GetMetadataDatabase())
    202     return scoped_ptr<base::ListValue>();
    203   return GetMetadataDatabase()->DumpFiles(origin.host());
    204 }
    205 
    206 scoped_ptr<base::ListValue> SyncWorker::DumpDatabase() {
    207   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    208 
    209   if (!GetMetadataDatabase())
    210     return scoped_ptr<base::ListValue>();
    211   return GetMetadataDatabase()->DumpDatabase();
    212 }
    213 
    214 void SyncWorker::SetSyncEnabled(bool enabled) {
    215   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    216 
    217   if (sync_enabled_ == enabled)
    218     return;
    219 
    220   RemoteServiceState old_state = GetCurrentState();
    221   sync_enabled_ = enabled;
    222   if (old_state == GetCurrentState())
    223     return;
    224 
    225   FOR_EACH_OBSERVER(
    226       Observer,
    227       observers_,
    228       UpdateServiceState(
    229           GetCurrentState(),
    230           enabled ? "Sync is enabled" : "Sync is disabled"));
    231 }
    232 
    233 void SyncWorker::PromoteDemotedChanges(const base::Closure& callback) {
    234   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    235 
    236   MetadataDatabase* metadata_db = GetMetadataDatabase();
    237   if (metadata_db && metadata_db->HasDemotedDirtyTracker()) {
    238     metadata_db->PromoteDemotedTrackers();
    239     FOR_EACH_OBSERVER(
    240         Observer,
    241         observers_,
    242         OnPendingFileListUpdated(metadata_db->CountDirtyTracker()));
    243   }
    244   callback.Run();
    245 }
    246 
    247 void SyncWorker::ApplyLocalChange(const FileChange& local_change,
    248                                   const base::FilePath& local_path,
    249                                   const SyncFileMetadata& local_metadata,
    250                                   const storage::FileSystemURL& url,
    251                                   const SyncStatusCallback& callback) {
    252   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    253 
    254   LocalToRemoteSyncer* syncer = new LocalToRemoteSyncer(
    255       context_.get(), local_metadata, local_change, local_path, url);
    256   task_manager_->ScheduleSyncTask(
    257       FROM_HERE,
    258       scoped_ptr<SyncTask>(syncer),
    259       SyncTaskManager::PRIORITY_MED,
    260       base::Bind(&SyncWorker::DidApplyLocalChange,
    261                  weak_ptr_factory_.GetWeakPtr(),
    262                  syncer,
    263                  callback));
    264 }
    265 
    266 void SyncWorker::MaybeScheduleNextTask() {
    267   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    268 
    269   if (GetCurrentState() == REMOTE_SERVICE_DISABLED)
    270     return;
    271 
    272   // TODO(tzik): Notify observer of OnRemoteChangeQueueUpdated.
    273   // TODO(tzik): Add an interface to get the number of dirty trackers to
    274   // MetadataDatabase.
    275 
    276   if (MaybeStartFetchChanges())
    277     return;
    278 
    279   if (!call_on_idle_callback_.is_null()) {
    280     base::Closure callback = call_on_idle_callback_;
    281     call_on_idle_callback_.Reset();
    282     callback.Run();
    283   }
    284 }
    285 
    286 void SyncWorker::NotifyLastOperationStatus(
    287     SyncStatusCode status,
    288     bool used_network) {
    289   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    290 
    291   UpdateServiceStateFromSyncStatusCode(status, used_network);
    292 
    293   if (GetMetadataDatabase()) {
    294     FOR_EACH_OBSERVER(
    295         Observer, observers_,
    296         OnPendingFileListUpdated(GetMetadataDatabase()->CountDirtyTracker()));
    297   }
    298 }
    299 
    300 void SyncWorker::RecordTaskLog(scoped_ptr<TaskLogger::TaskLog> task_log) {
    301   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    302 
    303   context_->GetUITaskRunner()->PostTask(
    304       FROM_HERE,
    305       base::Bind(&TaskLogger::RecordLog,
    306                  context_->GetTaskLogger(),
    307                  base::Passed(&task_log)));
    308 }
    309 
    310 void SyncWorker::ActivateService(RemoteServiceState service_state,
    311                                  const std::string& description) {
    312   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    313   UpdateServiceState(service_state, description);
    314   if (!GetMetadataDatabase()) {
    315     PostInitializeTask();
    316     return;
    317   }
    318 
    319   should_check_remote_change_ = true;
    320   MaybeScheduleNextTask();
    321 }
    322 
    323 void SyncWorker::DeactivateService(const std::string& description) {
    324   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    325   UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, description);
    326 }
    327 
    328 void SyncWorker::DetachFromSequence() {
    329   task_manager_->DetachFromSequence();
    330   context_->DetachFromSequence();
    331   sequence_checker_.DetachFromSequence();
    332 }
    333 
    334 void SyncWorker::AddObserver(Observer* observer) {
    335   observers_.AddObserver(observer);
    336 }
    337 
    338 void SyncWorker::DoDisableApp(const std::string& app_id,
    339                               const SyncStatusCallback& callback) {
    340   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    341 
    342   if (!GetMetadataDatabase()) {
    343     callback.Run(SYNC_STATUS_OK);
    344     return;
    345   }
    346 
    347   SyncStatusCode status = GetMetadataDatabase()->DisableApp(app_id);
    348   callback.Run(status);
    349 }
    350 
    351 void SyncWorker::DoEnableApp(const std::string& app_id,
    352                              const SyncStatusCallback& callback) {
    353   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    354 
    355   if (!GetMetadataDatabase()) {
    356     callback.Run(SYNC_STATUS_OK);
    357     return;
    358   }
    359 
    360   SyncStatusCode status = GetMetadataDatabase()->EnableApp(app_id);
    361   callback.Run(status);
    362 }
    363 
    364 void SyncWorker::PostInitializeTask() {
    365   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    366   DCHECK(!GetMetadataDatabase());
    367 
    368   // This initializer task may not run if MetadataDatabase in context_ is
    369   // already initialized when it runs.
    370   SyncEngineInitializer* initializer =
    371       new SyncEngineInitializer(context_.get(),
    372                                 base_dir_.Append(kDatabaseName),
    373                                 env_override_);
    374   task_manager_->ScheduleSyncTask(
    375       FROM_HERE,
    376       scoped_ptr<SyncTask>(initializer),
    377       SyncTaskManager::PRIORITY_HIGH,
    378       base::Bind(&SyncWorker::DidInitialize,
    379                  weak_ptr_factory_.GetWeakPtr(),
    380                  initializer));
    381 }
    382 
    383 void SyncWorker::DidInitialize(SyncEngineInitializer* initializer,
    384                                SyncStatusCode status) {
    385   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    386 
    387   if (status == SYNC_STATUS_ACCESS_FORBIDDEN) {
    388     UpdateServiceState(REMOTE_SERVICE_ACCESS_FORBIDDEN, "Access forbidden");
    389     return;
    390   }
    391   if (status != SYNC_STATUS_OK) {
    392     UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE,
    393                        "Could not initialize remote service");
    394     return;
    395   }
    396 
    397   scoped_ptr<MetadataDatabase> metadata_database =
    398       initializer->PassMetadataDatabase();
    399   if (metadata_database) {
    400     context_->SetMetadataDatabase(metadata_database.Pass());
    401     return;
    402   }
    403 
    404   UpdateServiceState(REMOTE_SERVICE_OK, std::string());
    405   UpdateRegisteredApps();
    406 }
    407 
    408 void SyncWorker::UpdateRegisteredApps() {
    409   MetadataDatabase* metadata_db = GetMetadataDatabase();
    410   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    411   DCHECK(metadata_db);
    412 
    413   scoped_ptr<std::vector<std::string> > app_ids(new std::vector<std::string>);
    414   metadata_db->GetRegisteredAppIDs(app_ids.get());
    415 
    416   AppStatusMap* app_status = new AppStatusMap;
    417   base::Closure callback =
    418       base::Bind(&SyncWorker::DidQueryAppStatus,
    419                  weak_ptr_factory_.GetWeakPtr(),
    420                  base::Owned(app_status));
    421 
    422   context_->GetUITaskRunner()->PostTask(
    423       FROM_HERE,
    424       base::Bind(&SyncWorker::QueryAppStatusOnUIThread,
    425                  extension_service_,
    426                  base::Owned(app_ids.release()),
    427                  app_status,
    428                  RelayCallbackToTaskRunner(
    429                      context_->GetWorkerTaskRunner(),
    430                      FROM_HERE, callback)));
    431 }
    432 
    433 void SyncWorker::QueryAppStatusOnUIThread(
    434     const base::WeakPtr<ExtensionServiceInterface>& extension_service_ptr,
    435     const std::vector<std::string>* app_ids,
    436     AppStatusMap* status,
    437     const base::Closure& callback) {
    438   ExtensionServiceInterface* extension_service = extension_service_ptr.get();
    439   if (!extension_service) {
    440     callback.Run();
    441     return;
    442   }
    443 
    444   for (std::vector<std::string>::const_iterator itr = app_ids->begin();
    445        itr != app_ids->end(); ++itr) {
    446     const std::string& app_id = *itr;
    447     if (!extension_service->GetInstalledExtension(app_id))
    448       (*status)[app_id] = APP_STATUS_UNINSTALLED;
    449     else if (!extension_service->IsExtensionEnabled(app_id))
    450       (*status)[app_id] = APP_STATUS_DISABLED;
    451     else
    452       (*status)[app_id] = APP_STATUS_ENABLED;
    453   }
    454 
    455   callback.Run();
    456 }
    457 
    458 void SyncWorker::DidQueryAppStatus(const AppStatusMap* app_status) {
    459   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    460 
    461   MetadataDatabase* metadata_db = GetMetadataDatabase();
    462   DCHECK(metadata_db);
    463 
    464   // Update the status of every origin using status from ExtensionService.
    465   for (AppStatusMap::const_iterator itr = app_status->begin();
    466        itr != app_status->end(); ++itr) {
    467     const std::string& app_id = itr->first;
    468     GURL origin = extensions::Extension::GetBaseURLFromExtensionId(app_id);
    469 
    470     if (itr->second == APP_STATUS_UNINSTALLED) {
    471       // Extension has been uninstalled.
    472       // (At this stage we can't know if it was unpacked extension or not,
    473       // so just purge the remote folder.)
    474       UninstallOrigin(origin,
    475                       RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE,
    476                       base::Bind(&EmptyStatusCallback));
    477       continue;
    478     }
    479 
    480     FileTracker tracker;
    481     if (!metadata_db->FindAppRootTracker(app_id, &tracker)) {
    482       // App will register itself on first run.
    483       continue;
    484     }
    485 
    486     DCHECK(itr->second == APP_STATUS_ENABLED ||
    487            itr->second == APP_STATUS_DISABLED);
    488     bool is_app_enabled = (itr->second == APP_STATUS_ENABLED);
    489     bool is_app_root_tracker_enabled =
    490         (tracker.tracker_kind() == TRACKER_KIND_APP_ROOT);
    491     if (is_app_enabled && !is_app_root_tracker_enabled)
    492       EnableOrigin(origin, base::Bind(&EmptyStatusCallback));
    493     else if (!is_app_enabled && is_app_root_tracker_enabled)
    494       DisableOrigin(origin, base::Bind(&EmptyStatusCallback));
    495   }
    496 }
    497 
    498 void SyncWorker::DidProcessRemoteChange(RemoteToLocalSyncer* syncer,
    499                                         const SyncFileCallback& callback,
    500                                         SyncStatusCode status) {
    501   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    502 
    503   if (syncer->is_sync_root_deletion()) {
    504     MetadataDatabase::ClearDatabase(context_->PassMetadataDatabase());
    505     PostInitializeTask();
    506     callback.Run(status, syncer->url());
    507     return;
    508   }
    509 
    510   if (status == SYNC_STATUS_OK) {
    511     if (syncer->sync_action() != SYNC_ACTION_NONE &&
    512         syncer->url().is_valid()) {
    513       FOR_EACH_OBSERVER(
    514           Observer, observers_,
    515           OnFileStatusChanged(
    516               syncer->url(),
    517               SYNC_FILE_STATUS_SYNCED,
    518               syncer->sync_action(),
    519               SYNC_DIRECTION_REMOTE_TO_LOCAL));
    520     }
    521 
    522     if (syncer->sync_action() == SYNC_ACTION_DELETED &&
    523         syncer->url().is_valid() &&
    524         storage::VirtualPath::IsRootPath(syncer->url().path())) {
    525       RegisterOrigin(syncer->url().origin(), base::Bind(&EmptyStatusCallback));
    526     }
    527     should_check_conflict_ = true;
    528   }
    529   callback.Run(status, syncer->url());
    530 }
    531 
    532 void SyncWorker::DidApplyLocalChange(LocalToRemoteSyncer* syncer,
    533                                      const SyncStatusCallback& callback,
    534                                      SyncStatusCode status) {
    535   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    536 
    537   if ((status == SYNC_STATUS_OK || status == SYNC_STATUS_RETRY) &&
    538       syncer->url().is_valid() &&
    539       syncer->sync_action() != SYNC_ACTION_NONE) {
    540     storage::FileSystemURL updated_url = syncer->url();
    541     if (!syncer->target_path().empty()) {
    542       updated_url = CreateSyncableFileSystemURL(syncer->url().origin(),
    543                                                 syncer->target_path());
    544     }
    545     FOR_EACH_OBSERVER(Observer, observers_,
    546                       OnFileStatusChanged(updated_url,
    547                                           SYNC_FILE_STATUS_SYNCED,
    548                                           syncer->sync_action(),
    549                                           SYNC_DIRECTION_LOCAL_TO_REMOTE));
    550   }
    551 
    552   if (status == SYNC_STATUS_UNKNOWN_ORIGIN && syncer->url().is_valid()) {
    553     RegisterOrigin(syncer->url().origin(),
    554                    base::Bind(&EmptyStatusCallback));
    555   }
    556 
    557   if (syncer->needs_remote_change_listing() &&
    558       !listing_remote_changes_) {
    559     task_manager_->ScheduleSyncTask(
    560         FROM_HERE,
    561         scoped_ptr<SyncTask>(new ListChangesTask(context_.get())),
    562         SyncTaskManager::PRIORITY_HIGH,
    563         base::Bind(&SyncWorker::DidFetchChanges,
    564                    weak_ptr_factory_.GetWeakPtr()));
    565     should_check_remote_change_ = false;
    566     listing_remote_changes_ = true;
    567     time_to_check_changes_ =
    568         base::TimeTicks::Now() +
    569         base::TimeDelta::FromSeconds(kListChangesRetryDelaySeconds);
    570   }
    571 
    572   if (status == SYNC_STATUS_OK)
    573     should_check_conflict_ = true;
    574 
    575   callback.Run(status);
    576 }
    577 
    578 bool SyncWorker::MaybeStartFetchChanges() {
    579   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    580 
    581   if (GetCurrentState() == REMOTE_SERVICE_DISABLED)
    582     return false;
    583 
    584   if (!GetMetadataDatabase())
    585     return false;
    586 
    587   if (listing_remote_changes_)
    588     return false;
    589 
    590   base::TimeTicks now = base::TimeTicks::Now();
    591   if (!should_check_remote_change_ && now < time_to_check_changes_) {
    592     if (!GetMetadataDatabase()->HasDirtyTracker() &&
    593         should_check_conflict_) {
    594       should_check_conflict_ = false;
    595       return task_manager_->ScheduleSyncTaskIfIdle(
    596           FROM_HERE,
    597           scoped_ptr<SyncTask>(new ConflictResolver(context_.get())),
    598           base::Bind(&SyncWorker::DidResolveConflict,
    599                      weak_ptr_factory_.GetWeakPtr()));
    600     }
    601     return false;
    602   }
    603 
    604   if (task_manager_->ScheduleSyncTaskIfIdle(
    605           FROM_HERE,
    606           scoped_ptr<SyncTask>(new ListChangesTask(context_.get())),
    607           base::Bind(&SyncWorker::DidFetchChanges,
    608                      weak_ptr_factory_.GetWeakPtr()))) {
    609     should_check_remote_change_ = false;
    610     listing_remote_changes_ = true;
    611     time_to_check_changes_ =
    612         now + base::TimeDelta::FromSeconds(kListChangesRetryDelaySeconds);
    613     return true;
    614   }
    615   return false;
    616 }
    617 
    618 void SyncWorker::DidResolveConflict(SyncStatusCode status) {
    619   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    620 
    621   if (status == SYNC_STATUS_OK)
    622     should_check_conflict_ = true;
    623 }
    624 
    625 void SyncWorker::DidFetchChanges(SyncStatusCode status) {
    626   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    627 
    628   if (status == SYNC_STATUS_OK)
    629     should_check_conflict_ = true;
    630   listing_remote_changes_ = false;
    631 }
    632 
    633 void SyncWorker::UpdateServiceStateFromSyncStatusCode(
    634     SyncStatusCode status,
    635     bool used_network) {
    636   switch (status) {
    637     case SYNC_STATUS_OK:
    638       if (used_network)
    639         UpdateServiceState(REMOTE_SERVICE_OK, std::string());
    640       break;
    641 
    642     // Authentication error.
    643     case SYNC_STATUS_AUTHENTICATION_FAILED:
    644       UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED,
    645                          "Authentication required");
    646       break;
    647 
    648     // OAuth token error.
    649     case SYNC_STATUS_ACCESS_FORBIDDEN:
    650       UpdateServiceState(REMOTE_SERVICE_ACCESS_FORBIDDEN,
    651                          "Access forbidden");
    652       break;
    653 
    654     // Errors which could make the service temporarily unavailable.
    655     case SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE:
    656     case SYNC_STATUS_NETWORK_ERROR:
    657     case SYNC_STATUS_ABORT:
    658     case SYNC_STATUS_FAILED:
    659       UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE,
    660                          "Network or temporary service error.");
    661       break;
    662 
    663     // Errors which would require manual user intervention to resolve.
    664     case SYNC_DATABASE_ERROR_CORRUPTION:
    665     case SYNC_DATABASE_ERROR_IO_ERROR:
    666     case SYNC_DATABASE_ERROR_FAILED:
    667       UpdateServiceState(REMOTE_SERVICE_DISABLED,
    668                          "Unrecoverable database error");
    669       break;
    670 
    671     default:
    672       // Other errors don't affect service state
    673       break;
    674   }
    675 }
    676 
    677 void SyncWorker::UpdateServiceState(RemoteServiceState state,
    678                                     const std::string& description) {
    679   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    680 
    681   RemoteServiceState old_state = GetCurrentState();
    682   service_state_ = state;
    683 
    684   if (old_state == GetCurrentState())
    685     return;
    686 
    687   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    688             "Service state changed: %d->%d: %s",
    689             old_state, GetCurrentState(), description.c_str());
    690 
    691   FOR_EACH_OBSERVER(
    692       Observer, observers_,
    693       UpdateServiceState(GetCurrentState(), description));
    694 }
    695 
    696 void SyncWorker::CallOnIdleForTesting(const base::Closure& callback) {
    697   if (task_manager_->ScheduleTaskIfIdle(
    698           FROM_HERE,
    699           base::Bind(&InvokeIdleCallback, callback),
    700           base::Bind(&EmptyStatusCallback)))
    701     return;
    702   call_on_idle_callback_ = base::Bind(
    703       &SyncWorker::CallOnIdleForTesting,
    704       weak_ptr_factory_.GetWeakPtr(),
    705       callback);
    706 }
    707 
    708 drive::DriveServiceInterface* SyncWorker::GetDriveService() {
    709   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    710   return context_->GetDriveService();
    711 }
    712 
    713 drive::DriveUploaderInterface* SyncWorker::GetDriveUploader() {
    714   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    715   return context_->GetDriveUploader();
    716 }
    717 
    718 MetadataDatabase* SyncWorker::GetMetadataDatabase() {
    719   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
    720   return context_->GetMetadataDatabase();
    721 }
    722 
    723 }  // namespace drive_backend
    724 }  // namespace sync_file_system
    725