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