sync_worker.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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
29namespace sync_file_system {
30
31class RemoteChangeProcessor;
32
33namespace drive_backend {
34
35namespace {
36
37void EmptyStatusCallback(SyncStatusCode status) {}
38
39void 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
47SyncWorker::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
64SyncWorker::~SyncWorker() {
65  observers_.Clear();
66}
67
68void 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
82void 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
104void 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
118void 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
132void 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
146void 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
160void 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
167RemoteServiceState SyncWorker::GetCurrentState() const {
168  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
169
170  if (!sync_enabled_)
171    return REMOTE_SERVICE_DISABLED;
172  return service_state_;
173}
174
175void 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
198scoped_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
206scoped_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
214void 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
233void 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
247void 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
266void 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
286void 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
300void 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
310void 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
323void SyncWorker::DeactivateService(const std::string& description) {
324  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
325  UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, description);
326}
327
328void SyncWorker::DetachFromSequence() {
329  task_manager_->DetachFromSequence();
330  context_->DetachFromSequence();
331  sequence_checker_.DetachFromSequence();
332}
333
334void SyncWorker::AddObserver(Observer* observer) {
335  observers_.AddObserver(observer);
336}
337
338void 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
351void 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
364void 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
383void 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
408void 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
433void 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
458void 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
498void 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
532void 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
578bool 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
618void SyncWorker::DidResolveConflict(SyncStatusCode status) {
619  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
620
621  if (status == SYNC_STATUS_OK)
622    should_check_conflict_ = true;
623}
624
625void 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
633void 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
677void 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
696void 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
708drive::DriveServiceInterface* SyncWorker::GetDriveService() {
709  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
710  return context_->GetDriveService();
711}
712
713drive::DriveUploaderInterface* SyncWorker::GetDriveUploader() {
714  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
715  return context_->GetDriveUploader();
716}
717
718MetadataDatabase* SyncWorker::GetMetadataDatabase() {
719  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
720  return context_->GetMetadataDatabase();
721}
722
723}  // namespace drive_backend
724}  // namespace sync_file_system
725