sync_worker.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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      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
85void 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
107void 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
121void 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
135void 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
149void 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
164void 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
171RemoteServiceState SyncWorker::GetCurrentState() const {
172  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
173
174  if (!sync_enabled_)
175    return REMOTE_SERVICE_DISABLED;
176  return service_state_;
177}
178
179void 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
202scoped_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
210scoped_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
218void 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
237void 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
250void 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
270void 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
283void 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
297void 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
307void 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
317void 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
335void 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
345void 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
362drive::DriveServiceInterface* SyncWorker::GetDriveService() {
363  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
364  return context_->GetDriveService();
365}
366
367drive::DriveUploaderInterface* SyncWorker::GetDriveUploader() {
368  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
369  return context_->GetDriveUploader();
370}
371
372MetadataDatabase* SyncWorker::GetMetadataDatabase() {
373  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
374  return context_->GetMetadataDatabase();
375}
376
377SyncTaskManager* SyncWorker::GetSyncTaskManager() {
378  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
379  return task_manager_.get();
380}
381
382void SyncWorker::DetachFromSequence() {
383  context_->DetachFromSequence();
384  sequence_checker_.DetachFromSequence();
385}
386
387void SyncWorker::AddObserver(Observer* observer) {
388  observers_.AddObserver(observer);
389}
390
391void SyncWorker::SetHasRefreshToken(bool has_refresh_token) {
392  has_refresh_token_ = has_refresh_token;
393}
394
395void 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
406void 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
417void 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
436void 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
459void 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
484void 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
509void 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
549void 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
583void 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
629void 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
667void SyncWorker::DidResolveConflict(SyncStatusCode status) {
668  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
669
670  if (status == SYNC_STATUS_OK)
671    should_check_conflict_ = true;
672}
673
674void 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
682void 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
731void 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