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