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