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