sync_engine.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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 42namespace sync_file_system { 43namespace drive_backend { 44 45namespace { 46 47void EmptyStatusCallback(SyncStatusCode status) {} 48 49} // namespace 50 51scoped_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 107void 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 115SyncEngine::~SyncEngine() { 116 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); 117 drive_service_->RemoveObserver(this); 118 if (notification_manager_) 119 notification_manager_->RemoveObserver(this); 120} 121 122void 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 140void SyncEngine::AddServiceObserver(SyncServiceObserver* observer) { 141 service_observers_.AddObserver(observer); 142} 143 144void SyncEngine::AddFileStatusObserver(FileStatusObserver* observer) { 145 file_status_observers_.AddObserver(observer); 146} 147 148void 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 160void 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 171void 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 182void 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 192void 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 202void SyncEngine::SetRemoteChangeProcessor( 203 RemoteChangeProcessor* processor) { 204 remote_change_processor_ = processor; 205} 206 207LocalChangeProcessor* SyncEngine::GetLocalChangeProcessor() { 208 return this; 209} 210 211bool SyncEngine::IsConflicting(const fileapi::FileSystemURL& url) { 212 // TODO(tzik): Implement this before we support manual conflict resolution. 213 return false; 214} 215 216RemoteServiceState SyncEngine::GetCurrentState() const { 217 return service_state_; 218} 219 220void 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 238scoped_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 244scoped_ptr<base::ListValue> SyncEngine::DumpDatabase() { 245 if (!metadata_database_) 246 return scoped_ptr<base::ListValue>(); 247 return metadata_database_->DumpDatabase(); 248} 249 250void 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 265SyncStatusCode SyncEngine::SetConflictResolutionPolicy( 266 ConflictResolutionPolicy policy) { 267 conflict_resolution_policy_ = policy; 268 return SYNC_STATUS_OK; 269} 270 271ConflictResolutionPolicy 272SyncEngine::GetConflictResolutionPolicy() const { 273 return conflict_resolution_policy_; 274} 275 276void 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 283void 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 291void 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 311void 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 322void 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 335void 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 343void SyncEngine::OnPushNotificationEnabled(bool enabled) {} 344 345void 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 360void SyncEngine::OnRefreshTokenInvalid() { 361 UpdateServiceState( 362 REMOTE_SERVICE_AUTHENTICATION_REQUIRED, 363 "Found invalid refresh token."); 364} 365 366void 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 381drive::DriveServiceInterface* SyncEngine::GetDriveService() { 382 return drive_service_.get(); 383} 384 385drive::DriveUploaderInterface* SyncEngine::GetDriveUploader() { 386 return drive_uploader_.get(); 387} 388 389MetadataDatabase* SyncEngine::GetMetadataDatabase() { 390 return metadata_database_.get(); 391} 392 393RemoteChangeProcessor* SyncEngine::GetRemoteChangeProcessor() { 394 return remote_change_processor_; 395} 396 397base::SequencedTaskRunner* SyncEngine::GetBlockingTaskRunner() { 398 return task_runner_.get(); 399} 400 401SyncEngine::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 426void SyncEngine::DoDisableApp(const std::string& app_id, 427 const SyncStatusCallback& callback) { 428 metadata_database_->DisableApp(app_id, callback); 429} 430 431void SyncEngine::DoEnableApp(const std::string& app_id, 432 const SyncStatusCallback& callback) { 433 metadata_database_->EnableApp(app_id, callback); 434} 435 436void 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 453void 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 475void 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 DCHECK_EQ(SYNC_ACTION_NONE, syncer->sync_action()); 487 488 if (syncer->url().is_valid() && syncer->sync_action() != SYNC_ACTION_NONE) { 489 FOR_EACH_OBSERVER(FileStatusObserver, 490 file_status_observers_, 491 OnFileStatusChanged(syncer->url(), 492 SYNC_FILE_STATUS_SYNCED, 493 syncer->sync_action(), 494 SYNC_DIRECTION_REMOTE_TO_LOCAL)); 495 } 496 497 if (status == SYNC_STATUS_OK) { 498 if (syncer->sync_action() == SYNC_ACTION_DELETED && 499 syncer->url().is_valid() && 500 fileapi::VirtualPath::IsRootPath(syncer->url().path())) { 501 RegisterOrigin(syncer->url().origin(), base::Bind(&EmptyStatusCallback)); 502 } 503 should_check_conflict_ = true; 504 } 505 callback.Run(status, syncer->url()); 506} 507 508void SyncEngine::DidApplyLocalChange(LocalToRemoteSyncer* syncer, 509 const SyncStatusCallback& callback, 510 SyncStatusCode status) { 511 util::Log(logging::LOG_VERBOSE, FROM_HERE, 512 "[Local->Remote] ApplyLocalChange finished --> %s", 513 SyncStatusCodeToString(status)); 514 515 if ((status == SYNC_STATUS_OK || status == SYNC_STATUS_RETRY) && 516 syncer->url().is_valid() && 517 syncer->sync_action() != SYNC_ACTION_NONE) { 518 fileapi::FileSystemURL updated_url = syncer->url(); 519 if (!syncer->target_path().empty()) { 520 updated_url = CreateSyncableFileSystemURL(syncer->url().origin(), 521 syncer->target_path()); 522 } 523 FOR_EACH_OBSERVER(FileStatusObserver, 524 file_status_observers_, 525 OnFileStatusChanged(updated_url, 526 SYNC_FILE_STATUS_SYNCED, 527 syncer->sync_action(), 528 SYNC_DIRECTION_LOCAL_TO_REMOTE)); 529 } 530 531 if (status == SYNC_STATUS_UNKNOWN_ORIGIN && syncer->url().is_valid()) { 532 RegisterOrigin(syncer->url().origin(), 533 base::Bind(&EmptyStatusCallback)); 534 } 535 536 if (status != SYNC_STATUS_OK && 537 status != SYNC_STATUS_NO_CHANGE_TO_SYNC) { 538 callback.Run(status); 539 return; 540 } 541 542 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC) 543 metadata_database_->PromoteLowerPriorityTrackersToNormal(); 544 545 if (status == SYNC_STATUS_OK) 546 should_check_conflict_ = true; 547 548 callback.Run(status); 549} 550 551void SyncEngine::MaybeStartFetchChanges() { 552 if (GetCurrentState() == REMOTE_SERVICE_DISABLED) 553 return; 554 555 if (!metadata_database_) 556 return; 557 558 base::TimeTicks now = base::TimeTicks::Now(); 559 if (!should_check_remote_change_ && now < time_to_check_changes_) { 560 if (!metadata_database_->HasDirtyTracker() && should_check_conflict_) { 561 task_manager_->ScheduleSyncTaskIfIdle( 562 scoped_ptr<SyncTask>(new ConflictResolver(this)), 563 base::Bind(&SyncEngine::DidResolveConflict, 564 weak_ptr_factory_.GetWeakPtr())); 565 } 566 return; 567 } 568 569 if (task_manager_->ScheduleSyncTaskIfIdle( 570 scoped_ptr<SyncTask>(new ListChangesTask(this)), 571 base::Bind(&SyncEngine::DidFetchChanges, 572 weak_ptr_factory_.GetWeakPtr()))) { 573 should_check_remote_change_ = false; 574 time_to_check_changes_ = 575 now + base::TimeDelta::FromSeconds(kListChangesRetryDelaySeconds); 576 } 577} 578 579void SyncEngine::DidResolveConflict(SyncStatusCode status) { 580 if (status == SYNC_STATUS_NO_CONFLICT) 581 should_check_conflict_ = false; 582} 583 584void SyncEngine::DidFetchChanges(SyncStatusCode status) { 585 if (status == SYNC_STATUS_OK) 586 should_check_conflict_ = true; 587} 588 589void SyncEngine::UpdateServiceStateFromSyncStatusCode( 590 SyncStatusCode status, 591 bool used_network) { 592 switch (status) { 593 case SYNC_STATUS_OK: 594 if (used_network) 595 UpdateServiceState(REMOTE_SERVICE_OK, std::string()); 596 break; 597 598 // Authentication error. 599 case SYNC_STATUS_AUTHENTICATION_FAILED: 600 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED, 601 "Authentication required"); 602 break; 603 604 // OAuth token error. 605 case SYNC_STATUS_ACCESS_FORBIDDEN: 606 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED, 607 "Access forbidden"); 608 break; 609 610 // Errors which could make the service temporarily unavailable. 611 case SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE: 612 case SYNC_STATUS_NETWORK_ERROR: 613 case SYNC_STATUS_ABORT: 614 case SYNC_STATUS_FAILED: 615 if (drive_service_->HasRefreshToken()) { 616 UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, 617 "Network or temporary service error."); 618 } else { 619 UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED, 620 "Authentication required"); 621 } 622 break; 623 624 // Errors which would require manual user intervention to resolve. 625 case SYNC_DATABASE_ERROR_CORRUPTION: 626 case SYNC_DATABASE_ERROR_IO_ERROR: 627 case SYNC_DATABASE_ERROR_FAILED: 628 UpdateServiceState(REMOTE_SERVICE_DISABLED, 629 "Unrecoverable database error"); 630 break; 631 632 default: 633 // Other errors don't affect service state 634 break; 635 } 636} 637 638void SyncEngine::UpdateServiceState(RemoteServiceState state, 639 const std::string& description) { 640 RemoteServiceState old_state = GetCurrentState(); 641 service_state_ = state; 642 643 if (old_state == GetCurrentState()) 644 return; 645 646 util::Log(logging::LOG_INFO, FROM_HERE, 647 "Service state changed: %d->%d: %s", 648 old_state, GetCurrentState(), description.c_str()); 649 FOR_EACH_OBSERVER( 650 Observer, service_observers_, 651 OnRemoteServiceStateUpdated(GetCurrentState(), description)); 652} 653 654void SyncEngine::UpdateRegisteredApps() { 655 if (!extension_service_) 656 return; 657 658 DCHECK(metadata_database_); 659 std::vector<std::string> app_ids; 660 metadata_database_->GetRegisteredAppIDs(&app_ids); 661 662 // Update the status of every origin using status from ExtensionService. 663 for (std::vector<std::string>::const_iterator itr = app_ids.begin(); 664 itr != app_ids.end(); ++itr) { 665 const std::string& app_id = *itr; 666 GURL origin = 667 extensions::Extension::GetBaseURLFromExtensionId(app_id); 668 if (!extension_service_->GetInstalledExtension(app_id)) { 669 // Extension has been uninstalled. 670 // (At this stage we can't know if it was unpacked extension or not, 671 // so just purge the remote folder.) 672 UninstallOrigin(origin, 673 RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE, 674 base::Bind(&EmptyStatusCallback)); 675 continue; 676 } 677 FileTracker tracker; 678 if (!metadata_database_->FindAppRootTracker(app_id, &tracker)) { 679 // App will register itself on first run. 680 continue; 681 } 682 bool is_app_enabled = extension_service_->IsExtensionEnabled(app_id); 683 bool is_app_root_tracker_enabled = 684 tracker.tracker_kind() == TRACKER_KIND_APP_ROOT; 685 if (is_app_enabled && !is_app_root_tracker_enabled) 686 EnableOrigin(origin, base::Bind(&EmptyStatusCallback)); 687 else if (!is_app_enabled && is_app_root_tracker_enabled) 688 DisableOrigin(origin, base::Bind(&EmptyStatusCallback)); 689 } 690} 691 692} // namespace drive_backend 693} // namespace sync_file_system 694