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