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