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