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