1 // Copyright (c) 2012 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/sync_file_system_service.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/format_macros.h" 11 #include "base/logging.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/metrics/histogram.h" 14 #include "base/single_thread_task_runner.h" 15 #include "base/stl_util.h" 16 #include "base/thread_task_runner_handle.h" 17 #include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h" 18 #include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h" 19 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/sync/profile_sync_service.h" 21 #include "chrome/browser/sync/profile_sync_service_factory.h" 22 #include "chrome/browser/sync_file_system/local/local_file_sync_service.h" 23 #include "chrome/browser/sync_file_system/logger.h" 24 #include "chrome/browser/sync_file_system/sync_direction.h" 25 #include "chrome/browser/sync_file_system/sync_event_observer.h" 26 #include "chrome/browser/sync_file_system/sync_file_metadata.h" 27 #include "chrome/browser/sync_file_system/sync_process_runner.h" 28 #include "chrome/browser/sync_file_system/sync_status_code.h" 29 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" 30 #include "components/keyed_service/content/browser_context_dependency_manager.h" 31 #include "content/public/browser/browser_thread.h" 32 #include "content/public/browser/storage_partition.h" 33 #include "extensions/browser/extension_prefs.h" 34 #include "extensions/browser/extension_registry.h" 35 #include "extensions/common/extension.h" 36 #include "extensions/common/manifest_constants.h" 37 #include "storage/browser/fileapi/file_system_context.h" 38 #include "url/gurl.h" 39 40 using content::BrowserThread; 41 using extensions::Extension; 42 using extensions::ExtensionPrefs; 43 using extensions::ExtensionRegistry; 44 using storage::FileSystemURL; 45 using storage::FileSystemURLSet; 46 47 namespace sync_file_system { 48 49 namespace { 50 51 const char kLocalSyncName[] = "Local sync"; 52 const char kRemoteSyncName[] = "Remote sync"; 53 54 SyncServiceState RemoteStateToSyncServiceState( 55 RemoteServiceState state) { 56 switch (state) { 57 case REMOTE_SERVICE_OK: 58 return SYNC_SERVICE_RUNNING; 59 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE: 60 return SYNC_SERVICE_TEMPORARY_UNAVAILABLE; 61 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED: 62 return SYNC_SERVICE_AUTHENTICATION_REQUIRED; 63 case REMOTE_SERVICE_ACCESS_FORBIDDEN: 64 return SYNC_SERVICE_TEMPORARY_UNAVAILABLE; 65 case REMOTE_SERVICE_DISABLED: 66 return SYNC_SERVICE_DISABLED; 67 case REMOTE_SERVICE_STATE_MAX: 68 NOTREACHED(); 69 } 70 NOTREACHED() << "Unknown remote service state: " << state; 71 return SYNC_SERVICE_DISABLED; 72 } 73 74 void DidHandleUninstalledEvent(const GURL& origin, SyncStatusCode code) { 75 if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) { 76 util::Log(logging::LOG_WARNING, FROM_HERE, 77 "Failed to uninstall origin for uninstall event: %s", 78 origin.spec().c_str()); 79 } 80 } 81 82 void DidHandleUnloadedEvent(const GURL& origin, SyncStatusCode code) { 83 if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) { 84 util::Log(logging::LOG_WARNING, FROM_HERE, 85 "Failed to disable origin for unload event: %s", 86 origin.spec().c_str()); 87 } 88 } 89 90 void DidHandleLoadEvent( 91 const GURL& origin, 92 SyncStatusCode code) { 93 if (code != SYNC_STATUS_OK) { 94 util::Log(logging::LOG_WARNING, FROM_HERE, 95 "Failed to enable origin for load event: %s", 96 origin.spec().c_str()); 97 } 98 } 99 100 std::string SyncFileStatusToString(SyncFileStatus sync_file_status) { 101 return extensions::api::sync_file_system::ToString( 102 extensions::SyncFileStatusToExtensionEnum(sync_file_status)); 103 } 104 105 // Gets called repeatedly until every SyncFileStatus has been mapped. 106 void DidGetFileSyncStatusForDump( 107 base::ListValue* files, 108 size_t* num_results, 109 const SyncFileSystemService::DumpFilesCallback& callback, 110 base::DictionaryValue* file, 111 SyncStatusCode sync_status_code, 112 SyncFileStatus sync_file_status) { 113 DCHECK(files); 114 DCHECK(num_results); 115 116 if (file) 117 file->SetString("status", SyncFileStatusToString(sync_file_status)); 118 119 // Once all results have been received, run the callback to signal end. 120 DCHECK_LE(*num_results, files->GetSize()); 121 if (++*num_results < files->GetSize()) 122 return; 123 124 callback.Run(*files); 125 } 126 127 // We need this indirection because WeakPtr can only be bound to methods 128 // without a return value. 129 LocalChangeProcessor* GetLocalChangeProcessorAdapter( 130 base::WeakPtr<SyncFileSystemService> service, 131 const GURL& origin) { 132 if (!service) 133 return NULL; 134 return service->GetLocalChangeProcessor(origin); 135 } 136 137 } // namespace 138 139 //--------------------------------------------------------------------------- 140 // SyncProcessRunner's. 141 142 // SyncProcessRunner implementation for LocalSync. 143 class LocalSyncRunner : public SyncProcessRunner, 144 public LocalFileSyncService::Observer { 145 public: 146 LocalSyncRunner(const std::string& name, 147 SyncFileSystemService* sync_service) 148 : SyncProcessRunner(name, sync_service, 149 scoped_ptr<SyncProcessRunner::TimerHelper>(), 1), 150 factory_(this) {} 151 152 virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE { 153 GetSyncService()->local_service_->ProcessLocalChange( 154 base::Bind(&LocalSyncRunner::DidProcessLocalChange, 155 factory_.GetWeakPtr(), callback)); 156 } 157 158 // LocalFileSyncService::Observer overrides. 159 virtual void OnLocalChangeAvailable(int64 pending_changes) OVERRIDE { 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 161 162 OnChangesUpdated(pending_changes); 163 164 // Kick other sync runners just in case they're not running. 165 GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule); 166 } 167 168 private: 169 void DidProcessLocalChange( 170 const SyncStatusCallback& callback, 171 SyncStatusCode status, 172 const FileSystemURL& url) { 173 util::Log(logging::LOG_VERBOSE, FROM_HERE, 174 "ProcessLocalChange finished with status=%d (%s) for url=%s", 175 status, SyncStatusCodeToString(status), 176 url.DebugString().c_str()); 177 callback.Run(status); 178 } 179 180 base::WeakPtrFactory<LocalSyncRunner> factory_; 181 DISALLOW_COPY_AND_ASSIGN(LocalSyncRunner); 182 }; 183 184 // SyncProcessRunner implementation for RemoteSync. 185 class RemoteSyncRunner : public SyncProcessRunner, 186 public RemoteFileSyncService::Observer { 187 public: 188 RemoteSyncRunner(const std::string& name, 189 SyncFileSystemService* sync_service, 190 RemoteFileSyncService* remote_service) 191 : SyncProcessRunner(name, sync_service, 192 scoped_ptr<SyncProcessRunner::TimerHelper>(), 1), 193 remote_service_(remote_service), 194 last_state_(REMOTE_SERVICE_OK), 195 factory_(this) {} 196 197 virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE { 198 remote_service_->ProcessRemoteChange( 199 base::Bind(&RemoteSyncRunner::DidProcessRemoteChange, 200 factory_.GetWeakPtr(), callback)); 201 } 202 203 virtual SyncServiceState GetServiceState() OVERRIDE { 204 return RemoteStateToSyncServiceState(last_state_); 205 } 206 207 // RemoteFileSyncService::Observer overrides. 208 virtual void OnRemoteChangeQueueUpdated(int64 pending_changes) OVERRIDE { 209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 210 211 OnChangesUpdated(pending_changes); 212 213 // Kick other sync runners just in case they're not running. 214 GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule); 215 } 216 217 virtual void OnRemoteServiceStateUpdated( 218 RemoteServiceState state, 219 const std::string& description) OVERRIDE { 220 // Just forward to SyncFileSystemService. 221 GetSyncService()->OnRemoteServiceStateUpdated(state, description); 222 last_state_ = state; 223 } 224 225 private: 226 void DidProcessRemoteChange( 227 const SyncStatusCallback& callback, 228 SyncStatusCode status, 229 const FileSystemURL& url) { 230 util::Log(logging::LOG_VERBOSE, FROM_HERE, 231 "ProcessRemoteChange finished with status=%d (%s) for url=%s", 232 status, SyncStatusCodeToString(status), 233 url.DebugString().c_str()); 234 235 if (status == SYNC_STATUS_FILE_BUSY) { 236 GetSyncService()->local_service_->RegisterURLForWaitingSync( 237 url, base::Bind(&RemoteSyncRunner::Schedule, 238 factory_.GetWeakPtr())); 239 } 240 callback.Run(status); 241 } 242 243 RemoteFileSyncService* remote_service_; 244 RemoteServiceState last_state_; 245 base::WeakPtrFactory<RemoteSyncRunner> factory_; 246 DISALLOW_COPY_AND_ASSIGN(RemoteSyncRunner); 247 }; 248 249 //----------------------------------------------------------------------------- 250 // SyncFileSystemService 251 252 void SyncFileSystemService::Shutdown() { 253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 254 255 local_sync_runners_.clear(); 256 remote_sync_runners_.clear(); 257 258 local_service_->Shutdown(); 259 local_service_.reset(); 260 261 remote_service_.reset(); 262 263 ProfileSyncServiceBase* profile_sync_service = 264 ProfileSyncServiceFactory::GetForProfile(profile_); 265 if (profile_sync_service) 266 profile_sync_service->RemoveObserver(this); 267 268 ExtensionRegistry::Get(profile_)->RemoveObserver(this); 269 270 profile_ = NULL; 271 } 272 273 SyncFileSystemService::~SyncFileSystemService() { 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 275 DCHECK(!profile_); 276 } 277 278 void SyncFileSystemService::InitializeForApp( 279 storage::FileSystemContext* file_system_context, 280 const GURL& app_origin, 281 const SyncStatusCallback& callback) { 282 DCHECK(local_service_); 283 DCHECK(remote_service_); 284 DCHECK(app_origin == app_origin.GetOrigin()); 285 286 util::Log(logging::LOG_VERBOSE, FROM_HERE, 287 "Initializing for App: %s", app_origin.spec().c_str()); 288 289 local_service_->MaybeInitializeFileSystemContext( 290 app_origin, file_system_context, 291 base::Bind(&SyncFileSystemService::DidInitializeFileSystem, 292 AsWeakPtr(), app_origin, callback)); 293 } 294 295 void SyncFileSystemService::GetExtensionStatusMap( 296 const ExtensionStatusMapCallback& callback) { 297 remote_service_->GetOriginStatusMap( 298 base::Bind(&SyncFileSystemService::DidGetExtensionStatusMap, 299 AsWeakPtr(), callback)); 300 } 301 302 void SyncFileSystemService::DumpFiles(const GURL& origin, 303 const DumpFilesCallback& callback) { 304 DCHECK(!origin.is_empty()); 305 306 content::StoragePartition* storage_partition = 307 content::BrowserContext::GetStoragePartitionForSite(profile_, origin); 308 storage::FileSystemContext* file_system_context = 309 storage_partition->GetFileSystemContext(); 310 local_service_->MaybeInitializeFileSystemContext( 311 origin, file_system_context, 312 base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump, 313 AsWeakPtr(), origin, callback)); 314 } 315 316 void SyncFileSystemService::DumpDatabase(const DumpFilesCallback& callback) { 317 remote_service_->DumpDatabase( 318 base::Bind(&SyncFileSystemService::DidDumpDatabase, 319 AsWeakPtr(), callback)); 320 } 321 322 void SyncFileSystemService::GetFileSyncStatus( 323 const FileSystemURL& url, const SyncFileStatusCallback& callback) { 324 DCHECK(local_service_); 325 DCHECK(GetRemoteService(url.origin())); 326 327 // It's possible to get an invalid FileEntry. 328 if (!url.is_valid()) { 329 base::ThreadTaskRunnerHandle::Get()->PostTask( 330 FROM_HERE, 331 base::Bind(callback, 332 SYNC_FILE_ERROR_INVALID_URL, 333 SYNC_FILE_STATUS_UNKNOWN)); 334 return; 335 } 336 337 local_service_->HasPendingLocalChanges( 338 url, 339 base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus, 340 AsWeakPtr(), callback)); 341 } 342 343 void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) { 344 observers_.AddObserver(observer); 345 } 346 347 void SyncFileSystemService::RemoveSyncEventObserver( 348 SyncEventObserver* observer) { 349 observers_.RemoveObserver(observer); 350 } 351 352 LocalChangeProcessor* SyncFileSystemService::GetLocalChangeProcessor( 353 const GURL& origin) { 354 return GetRemoteService(origin)->GetLocalChangeProcessor(); 355 } 356 357 void SyncFileSystemService::OnSyncIdle() { 358 if (promoting_demoted_changes_) 359 return; 360 promoting_demoted_changes_ = true; 361 362 int* job_count = new int(1); 363 base::Closure promote_completion_callback = 364 base::Bind(&SyncFileSystemService::OnPromotionCompleted, 365 AsWeakPtr(), base::Owned(job_count)); 366 367 int64 remote_changes = 0; 368 for (size_t i = 0; i < remote_sync_runners_.size(); ++i) 369 remote_changes += remote_sync_runners_[i]->pending_changes(); 370 if (remote_changes == 0) { 371 ++*job_count; 372 local_service_->PromoteDemotedChanges(promote_completion_callback); 373 } 374 375 int64 local_changes = 0; 376 for (size_t i = 0; i < local_sync_runners_.size(); ++i) 377 local_changes += local_sync_runners_[i]->pending_changes(); 378 if (local_changes == 0) { 379 ++*job_count; 380 remote_service_->PromoteDemotedChanges(promote_completion_callback); 381 } 382 383 promote_completion_callback.Run(); 384 } 385 386 void SyncFileSystemService::OnPromotionCompleted(int* count) { 387 if (--*count != 0) 388 return; 389 promoting_demoted_changes_ = false; 390 CheckIfIdle(); 391 } 392 393 void SyncFileSystemService::CheckIfIdle() { 394 if (promoting_demoted_changes_) 395 return; 396 397 for (size_t i = 0; i < remote_sync_runners_.size(); ++i) { 398 SyncServiceState service_state = remote_sync_runners_[i]->GetServiceState(); 399 if (service_state != SYNC_SERVICE_RUNNING) 400 continue; 401 402 if (remote_sync_runners_[i]->pending_changes()) 403 return; 404 } 405 406 for (size_t i = 0; i < local_sync_runners_.size(); ++i) { 407 SyncServiceState service_state = local_sync_runners_[i]->GetServiceState(); 408 if (service_state != SYNC_SERVICE_RUNNING) 409 continue; 410 411 if (local_sync_runners_[i]->pending_changes()) 412 return; 413 } 414 415 if (idle_callback_.is_null()) 416 return; 417 418 base::Closure callback = idle_callback_; 419 idle_callback_.Reset(); 420 callback.Run(); 421 } 422 423 SyncServiceState SyncFileSystemService::GetSyncServiceState() { 424 // For now we always query the state from the main RemoteFileSyncService. 425 return RemoteStateToSyncServiceState(remote_service_->GetCurrentState()); 426 } 427 428 SyncFileSystemService* SyncFileSystemService::GetSyncService() { 429 return this; 430 } 431 432 void SyncFileSystemService::CallOnIdleForTesting( 433 const base::Closure& callback) { 434 DCHECK(idle_callback_.is_null()); 435 idle_callback_ = callback; 436 CheckIfIdle(); 437 } 438 439 SyncFileSystemService::SyncFileSystemService(Profile* profile) 440 : profile_(profile), 441 sync_enabled_(true), 442 promoting_demoted_changes_(false) { 443 } 444 445 void SyncFileSystemService::Initialize( 446 scoped_ptr<LocalFileSyncService> local_service, 447 scoped_ptr<RemoteFileSyncService> remote_service) { 448 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 449 DCHECK(local_service); 450 DCHECK(remote_service); 451 DCHECK(profile_); 452 453 local_service_ = local_service.Pass(); 454 remote_service_ = remote_service.Pass(); 455 456 scoped_ptr<LocalSyncRunner> local_syncer( 457 new LocalSyncRunner(kLocalSyncName, this)); 458 scoped_ptr<RemoteSyncRunner> remote_syncer( 459 new RemoteSyncRunner(kRemoteSyncName, this, remote_service_.get())); 460 461 local_service_->AddChangeObserver(local_syncer.get()); 462 local_service_->SetLocalChangeProcessorCallback( 463 base::Bind(&GetLocalChangeProcessorAdapter, AsWeakPtr())); 464 465 remote_service_->AddServiceObserver(remote_syncer.get()); 466 remote_service_->AddFileStatusObserver(this); 467 remote_service_->SetRemoteChangeProcessor(local_service_.get()); 468 469 local_sync_runners_.push_back(local_syncer.release()); 470 remote_sync_runners_.push_back(remote_syncer.release()); 471 472 ProfileSyncServiceBase* profile_sync_service = 473 ProfileSyncServiceFactory::GetForProfile(profile_); 474 if (profile_sync_service) { 475 UpdateSyncEnabledStatus(profile_sync_service); 476 profile_sync_service->AddObserver(this); 477 } 478 479 ExtensionRegistry::Get(profile_)->AddObserver(this); 480 } 481 482 void SyncFileSystemService::DidInitializeFileSystem( 483 const GURL& app_origin, 484 const SyncStatusCallback& callback, 485 SyncStatusCode status) { 486 DVLOG(1) << "DidInitializeFileSystem: " 487 << app_origin.spec() << " " << status; 488 489 if (status != SYNC_STATUS_OK) { 490 callback.Run(status); 491 return; 492 } 493 494 // Local side of initialization for the app is done. 495 // Continue on initializing the remote side. 496 GetRemoteService(app_origin)->RegisterOrigin( 497 app_origin, 498 base::Bind(&SyncFileSystemService::DidRegisterOrigin, 499 AsWeakPtr(), app_origin, callback)); 500 } 501 502 void SyncFileSystemService::DidRegisterOrigin( 503 const GURL& app_origin, 504 const SyncStatusCallback& callback, 505 SyncStatusCode status) { 506 util::Log(logging::LOG_VERBOSE, FROM_HERE, 507 "DidInitializeForApp (registered the origin): %s: %s", 508 app_origin.spec().c_str(), 509 SyncStatusCodeToString(status)); 510 511 UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.RegisterOriginResult", 512 GetRemoteService(app_origin)->GetCurrentState(), 513 REMOTE_SERVICE_STATE_MAX); 514 515 if (status == SYNC_STATUS_FAILED) { 516 // If we got generic error return the service status information. 517 switch (GetRemoteService(app_origin)->GetCurrentState()) { 518 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED: 519 callback.Run(SYNC_STATUS_AUTHENTICATION_FAILED); 520 return; 521 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE: 522 callback.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE); 523 return; 524 default: 525 break; 526 } 527 } 528 529 callback.Run(status); 530 } 531 532 void SyncFileSystemService::DidInitializeFileSystemForDump( 533 const GURL& origin, 534 const DumpFilesCallback& callback, 535 SyncStatusCode status) { 536 DCHECK(!origin.is_empty()); 537 538 if (status != SYNC_STATUS_OK) { 539 callback.Run(base::ListValue()); 540 return; 541 } 542 543 GetRemoteService(origin)->DumpFiles( 544 origin, 545 base::Bind( 546 &SyncFileSystemService::DidDumpFiles, 547 AsWeakPtr(), 548 origin, 549 callback)); 550 } 551 552 void SyncFileSystemService::DidDumpFiles( 553 const GURL& origin, 554 const DumpFilesCallback& callback, 555 scoped_ptr<base::ListValue> dump_files) { 556 if (!dump_files || !dump_files->GetSize()) { 557 callback.Run(base::ListValue()); 558 return; 559 } 560 561 base::ListValue* files = dump_files.get(); 562 base::Callback<void(base::DictionaryValue*, 563 SyncStatusCode, 564 SyncFileStatus)> completion_callback = 565 base::Bind(&DidGetFileSyncStatusForDump, 566 base::Owned(dump_files.release()), 567 base::Owned(new size_t(0)), 568 callback); 569 570 // After all metadata loaded, sync status can be added to each entry. 571 for (size_t i = 0; i < files->GetSize(); ++i) { 572 base::DictionaryValue* file = NULL; 573 std::string path_string; 574 if (!files->GetDictionary(i, &file) || 575 !file->GetString("path", &path_string)) { 576 NOTREACHED(); 577 completion_callback.Run( 578 NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN); 579 continue; 580 } 581 582 base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path_string); 583 FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path); 584 GetFileSyncStatus(url, base::Bind(completion_callback, file)); 585 } 586 } 587 588 void SyncFileSystemService::DidDumpDatabase(const DumpFilesCallback& callback, 589 scoped_ptr<base::ListValue> list) { 590 if (!list) 591 list = make_scoped_ptr(new base::ListValue); 592 callback.Run(*list); 593 } 594 595 void SyncFileSystemService::DidGetExtensionStatusMap( 596 const ExtensionStatusMapCallback& callback, 597 scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map) { 598 if (!status_map) 599 status_map = make_scoped_ptr(new RemoteFileSyncService::OriginStatusMap); 600 callback.Run(*status_map); 601 } 602 603 void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) { 604 sync_enabled_ = enabled; 605 remote_service_->SetSyncEnabled(sync_enabled_); 606 } 607 608 void SyncFileSystemService::DidGetLocalChangeStatus( 609 const SyncFileStatusCallback& callback, 610 SyncStatusCode status, 611 bool has_pending_local_changes) { 612 callback.Run( 613 status, 614 has_pending_local_changes ? 615 SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED); 616 } 617 618 void SyncFileSystemService::OnRemoteServiceStateUpdated( 619 RemoteServiceState state, 620 const std::string& description) { 621 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 622 util::Log(logging::LOG_VERBOSE, FROM_HERE, 623 "OnRemoteServiceStateChanged: %d %s", state, description.c_str()); 624 625 FOR_EACH_OBSERVER( 626 SyncEventObserver, observers_, 627 OnSyncStateUpdated(GURL(), 628 RemoteStateToSyncServiceState(state), 629 description)); 630 631 RunForEachSyncRunners(&SyncProcessRunner::Schedule); 632 } 633 634 void SyncFileSystemService::OnExtensionInstalled( 635 content::BrowserContext* browser_context, 636 const Extension* extension, 637 bool is_update) { 638 GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id()); 639 DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin; 640 // NOTE: When an app is uninstalled and re-installed in a sequence, 641 // |local_service_| may still keeps |app_origin| as disabled origin. 642 local_service_->SetOriginEnabled(app_origin, true); 643 } 644 645 void SyncFileSystemService::OnExtensionUnloaded( 646 content::BrowserContext* browser_context, 647 const Extension* extension, 648 extensions::UnloadedExtensionInfo::Reason reason) { 649 if (reason != extensions::UnloadedExtensionInfo::REASON_DISABLE) 650 return; 651 652 GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id()); 653 int disable_reasons = 654 ExtensionPrefs::Get(profile_)->GetDisableReasons(extension->id()); 655 if (disable_reasons & Extension::DISABLE_RELOAD) { 656 // Bypass disabling the origin since the app will be re-enabled soon. 657 // NOTE: If re-enabling the app fails, the app is disabled while it is 658 // handled as enabled origin in the SyncFS. This should be safe and will be 659 // recovered when the user re-enables the app manually or the sync service 660 // restarts. 661 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): " 662 << app_origin; 663 return; 664 } 665 666 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): " 667 << app_origin; 668 GetRemoteService(app_origin)->DisableOrigin( 669 app_origin, 670 base::Bind(&DidHandleUnloadedEvent, app_origin)); 671 local_service_->SetOriginEnabled(app_origin, false); 672 } 673 674 void SyncFileSystemService::OnExtensionUninstalled( 675 content::BrowserContext* browser_context, 676 const Extension* extension, 677 extensions::UninstallReason reason) { 678 RemoteFileSyncService::UninstallFlag flag = 679 RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE; 680 // If it's loaded from an unpacked package and with key: field, 681 // the uninstall will not be sync'ed and the user might be using the 682 // same app key in other installs, so avoid purging the remote folder. 683 if (extensions::Manifest::IsUnpackedLocation(extension->location()) && 684 extension->manifest()->HasKey(extensions::manifest_keys::kKey)) { 685 flag = RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE; 686 } 687 688 GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id()); 689 DVLOG(1) << "Handle extension notification for UNINSTALLED: " 690 << app_origin; 691 GetRemoteService(app_origin)->UninstallOrigin( 692 app_origin, flag, 693 base::Bind(&DidHandleUninstalledEvent, app_origin)); 694 local_service_->SetOriginEnabled(app_origin, false); 695 } 696 697 void SyncFileSystemService::OnExtensionLoaded( 698 content::BrowserContext* browser_context, 699 const Extension* extension) { 700 GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id()); 701 DVLOG(1) << "Handle extension notification for LOADED: " << app_origin; 702 GetRemoteService(app_origin)->EnableOrigin( 703 app_origin, 704 base::Bind(&DidHandleLoadEvent, app_origin)); 705 local_service_->SetOriginEnabled(app_origin, true); 706 } 707 708 void SyncFileSystemService::OnStateChanged() { 709 ProfileSyncServiceBase* profile_sync_service = 710 ProfileSyncServiceFactory::GetForProfile(profile_); 711 if (profile_sync_service) 712 UpdateSyncEnabledStatus(profile_sync_service); 713 } 714 715 void SyncFileSystemService::OnFileStatusChanged( 716 const FileSystemURL& url, 717 SyncFileStatus sync_status, 718 SyncAction action_taken, 719 SyncDirection direction) { 720 FOR_EACH_OBSERVER( 721 SyncEventObserver, observers_, 722 OnFileSynced(url, sync_status, action_taken, direction)); 723 } 724 725 void SyncFileSystemService::UpdateSyncEnabledStatus( 726 ProfileSyncServiceBase* profile_sync_service) { 727 if (!profile_sync_service->HasSyncSetupCompleted()) 728 return; 729 bool old_sync_enabled = sync_enabled_; 730 sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has( 731 syncer::APPS); 732 remote_service_->SetSyncEnabled(sync_enabled_); 733 if (!old_sync_enabled && sync_enabled_) 734 RunForEachSyncRunners(&SyncProcessRunner::Schedule); 735 } 736 737 void SyncFileSystemService::RunForEachSyncRunners( 738 void(SyncProcessRunner::*method)()) { 739 for (ScopedVector<SyncProcessRunner>::iterator iter = 740 local_sync_runners_.begin(); 741 iter != local_sync_runners_.end(); ++iter) 742 ((*iter)->*method)(); 743 for (ScopedVector<SyncProcessRunner>::iterator iter = 744 remote_sync_runners_.begin(); 745 iter != remote_sync_runners_.end(); ++iter) 746 ((*iter)->*method)(); 747 } 748 749 RemoteFileSyncService* SyncFileSystemService::GetRemoteService( 750 const GURL& origin) { 751 return remote_service_.get(); 752 } 753 754 } // namespace sync_file_system 755