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