sync_file_system_service.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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 "url/gurl.h" 38#include "webkit/browser/fileapi/file_system_context.h" 39 40using content::BrowserThread; 41using extensions::Extension; 42using extensions::ExtensionPrefs; 43using extensions::ExtensionRegistry; 44using fileapi::FileSystemURL; 45using fileapi::FileSystemURLSet; 46 47namespace sync_file_system { 48 49namespace { 50 51const char kLocalSyncName[] = "Local sync"; 52const char kRemoteSyncName[] = "Remote sync"; 53const char kRemoteSyncNameV2[] = "Remote sync (v2)"; 54 55SyncServiceState RemoteStateToSyncServiceState( 56 RemoteServiceState state) { 57 switch (state) { 58 case REMOTE_SERVICE_OK: 59 return SYNC_SERVICE_RUNNING; 60 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE: 61 return SYNC_SERVICE_TEMPORARY_UNAVAILABLE; 62 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED: 63 return SYNC_SERVICE_AUTHENTICATION_REQUIRED; 64 case REMOTE_SERVICE_ACCESS_FORBIDDEN: 65 return SYNC_SERVICE_TEMPORARY_UNAVAILABLE; 66 case REMOTE_SERVICE_DISABLED: 67 return SYNC_SERVICE_DISABLED; 68 case REMOTE_SERVICE_STATE_MAX: 69 NOTREACHED(); 70 } 71 NOTREACHED() << "Unknown remote service state: " << state; 72 return SYNC_SERVICE_DISABLED; 73} 74 75void DidHandleUninstalledEvent(const GURL& origin, SyncStatusCode code) { 76 if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) { 77 util::Log(logging::LOG_WARNING, FROM_HERE, 78 "Failed to uninstall origin for uninstall event: %s", 79 origin.spec().c_str()); 80 } 81} 82 83void DidHandleUnloadedEvent(const GURL& origin, SyncStatusCode code) { 84 if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) { 85 util::Log(logging::LOG_WARNING, FROM_HERE, 86 "Failed to disable origin for unload event: %s", 87 origin.spec().c_str()); 88 } 89} 90 91void DidHandleLoadEvent( 92 const GURL& origin, 93 SyncStatusCode code) { 94 if (code != SYNC_STATUS_OK) { 95 util::Log(logging::LOG_WARNING, FROM_HERE, 96 "Failed to enable origin for load event: %s", 97 origin.spec().c_str()); 98 } 99} 100 101std::string SyncFileStatusToString(SyncFileStatus sync_file_status) { 102 return extensions::api::sync_file_system::ToString( 103 extensions::SyncFileStatusToExtensionEnum(sync_file_status)); 104} 105 106// Gets called repeatedly until every SyncFileStatus has been mapped. 107void DidGetFileSyncStatusForDump( 108 base::ListValue* files, 109 size_t* num_results, 110 const SyncFileSystemService::DumpFilesCallback& callback, 111 base::DictionaryValue* file, 112 SyncStatusCode sync_status_code, 113 SyncFileStatus sync_file_status) { 114 DCHECK(files); 115 DCHECK(num_results); 116 117 if (file) 118 file->SetString("status", SyncFileStatusToString(sync_file_status)); 119 120 // Once all results have been received, run the callback to signal end. 121 DCHECK_LE(*num_results, files->GetSize()); 122 if (++*num_results < files->GetSize()) 123 return; 124 125 callback.Run(*files); 126} 127 128// We need this indirection because WeakPtr can only be bound to methods 129// without a return value. 130LocalChangeProcessor* GetLocalChangeProcessorAdapter( 131 base::WeakPtr<SyncFileSystemService> service, 132 const GURL& origin) { 133 if (!service) 134 return NULL; 135 return service->GetLocalChangeProcessor(origin); 136} 137 138} // namespace 139 140//--------------------------------------------------------------------------- 141// SyncProcessRunner's. 142 143// SyncProcessRunner implementation for LocalSync. 144class LocalSyncRunner : public SyncProcessRunner, 145 public LocalFileSyncService::Observer { 146 public: 147 LocalSyncRunner(const std::string& name, 148 SyncFileSystemService* sync_service) 149 : SyncProcessRunner(name, sync_service, 150 scoped_ptr<SyncProcessRunner::TimerHelper>(), 1), 151 factory_(this) {} 152 153 virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE { 154 GetSyncService()->local_service_->ProcessLocalChange( 155 base::Bind(&LocalSyncRunner::DidProcessLocalChange, 156 factory_.GetWeakPtr(), callback)); 157 } 158 159 // LocalFileSyncService::Observer overrides. 160 virtual void OnLocalChangeAvailable(int64 pending_changes) OVERRIDE { 161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 162 163 OnChangesUpdated(pending_changes); 164 165 // Kick other sync runners just in case they're not running. 166 GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule); 167 } 168 169 private: 170 void DidProcessLocalChange( 171 const SyncStatusCallback& callback, 172 SyncStatusCode status, 173 const FileSystemURL& url) { 174 util::Log(logging::LOG_VERBOSE, FROM_HERE, 175 "ProcessLocalChange finished with status=%d (%s) for url=%s", 176 status, SyncStatusCodeToString(status), 177 url.DebugString().c_str()); 178 callback.Run(status); 179 } 180 181 base::WeakPtrFactory<LocalSyncRunner> factory_; 182 DISALLOW_COPY_AND_ASSIGN(LocalSyncRunner); 183}; 184 185// SyncProcessRunner implementation for RemoteSync. 186class RemoteSyncRunner : public SyncProcessRunner, 187 public RemoteFileSyncService::Observer { 188 public: 189 RemoteSyncRunner(const std::string& name, 190 SyncFileSystemService* sync_service, 191 RemoteFileSyncService* remote_service) 192 : SyncProcessRunner(name, sync_service, 193 scoped_ptr<SyncProcessRunner::TimerHelper>(), 1), 194 remote_service_(remote_service), 195 last_state_(REMOTE_SERVICE_OK), 196 factory_(this) {} 197 198 virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE { 199 remote_service_->ProcessRemoteChange( 200 base::Bind(&RemoteSyncRunner::DidProcessRemoteChange, 201 factory_.GetWeakPtr(), callback)); 202 } 203 204 virtual SyncServiceState GetServiceState() OVERRIDE { 205 return RemoteStateToSyncServiceState(last_state_); 206 } 207 208 // RemoteFileSyncService::Observer overrides. 209 virtual void OnRemoteChangeQueueUpdated(int64 pending_changes) OVERRIDE { 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 211 212 OnChangesUpdated(pending_changes); 213 214 // Kick other sync runners just in case they're not running. 215 GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule); 216 } 217 218 virtual void OnRemoteServiceStateUpdated( 219 RemoteServiceState state, 220 const std::string& description) OVERRIDE { 221 // Just forward to SyncFileSystemService. 222 GetSyncService()->OnRemoteServiceStateUpdated(state, description); 223 last_state_ = state; 224 } 225 226 private: 227 void DidProcessRemoteChange( 228 const SyncStatusCallback& callback, 229 SyncStatusCode status, 230 const FileSystemURL& url) { 231 util::Log(logging::LOG_VERBOSE, FROM_HERE, 232 "ProcessRemoteChange finished with status=%d (%s) for url=%s", 233 status, SyncStatusCodeToString(status), 234 url.DebugString().c_str()); 235 236 if (status == SYNC_STATUS_FILE_BUSY) { 237 GetSyncService()->local_service_->RegisterURLForWaitingSync( 238 url, base::Bind(&RemoteSyncRunner::Schedule, 239 factory_.GetWeakPtr())); 240 } 241 callback.Run(status); 242 } 243 244 RemoteFileSyncService* remote_service_; 245 RemoteServiceState last_state_; 246 base::WeakPtrFactory<RemoteSyncRunner> factory_; 247 DISALLOW_COPY_AND_ASSIGN(RemoteSyncRunner); 248}; 249 250//----------------------------------------------------------------------------- 251// SyncFileSystemService 252 253void SyncFileSystemService::Shutdown() { 254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 255 256 local_sync_runners_.clear(); 257 remote_sync_runners_.clear(); 258 259 local_service_->Shutdown(); 260 local_service_.reset(); 261 262 remote_service_.reset(); 263 v2_remote_service_.reset(); 264 265 ProfileSyncServiceBase* profile_sync_service = 266 ProfileSyncServiceFactory::GetForProfile(profile_); 267 if (profile_sync_service) 268 profile_sync_service->RemoveObserver(this); 269 270 ExtensionRegistry::Get(profile_)->RemoveObserver(this); 271 272 profile_ = NULL; 273} 274 275SyncFileSystemService::~SyncFileSystemService() { 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 277 DCHECK(!profile_); 278} 279 280void SyncFileSystemService::InitializeForApp( 281 fileapi::FileSystemContext* file_system_context, 282 const GURL& app_origin, 283 const SyncStatusCallback& callback) { 284 DCHECK(local_service_); 285 DCHECK(remote_service_); 286 DCHECK(app_origin == app_origin.GetOrigin()); 287 288 util::Log(logging::LOG_VERBOSE, FROM_HERE, 289 "Initializing for App: %s", app_origin.spec().c_str()); 290 291 local_service_->MaybeInitializeFileSystemContext( 292 app_origin, file_system_context, 293 base::Bind(&SyncFileSystemService::DidInitializeFileSystem, 294 AsWeakPtr(), app_origin, callback)); 295} 296 297void SyncFileSystemService::GetExtensionStatusMap( 298 const ExtensionStatusMapCallback& callback) { 299 remote_service_->GetOriginStatusMap( 300 base::Bind(&SyncFileSystemService::DidGetExtensionStatusMap, 301 AsWeakPtr(), callback)); 302} 303 304void SyncFileSystemService::DumpFiles(const GURL& origin, 305 const DumpFilesCallback& callback) { 306 DCHECK(!origin.is_empty()); 307 308 content::StoragePartition* storage_partition = 309 content::BrowserContext::GetStoragePartitionForSite(profile_, origin); 310 fileapi::FileSystemContext* file_system_context = 311 storage_partition->GetFileSystemContext(); 312 local_service_->MaybeInitializeFileSystemContext( 313 origin, file_system_context, 314 base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump, 315 AsWeakPtr(), origin, callback)); 316} 317 318void SyncFileSystemService::DumpDatabase(const DumpFilesCallback& callback) { 319 remote_service_->DumpDatabase( 320 base::Bind(&SyncFileSystemService::DidDumpDatabase, 321 AsWeakPtr(), callback)); 322} 323 324void SyncFileSystemService::GetFileSyncStatus( 325 const FileSystemURL& url, const SyncFileStatusCallback& callback) { 326 DCHECK(local_service_); 327 DCHECK(GetRemoteService(url.origin())); 328 329 // It's possible to get an invalid FileEntry. 330 if (!url.is_valid()) { 331 base::ThreadTaskRunnerHandle::Get()->PostTask( 332 FROM_HERE, 333 base::Bind(callback, 334 SYNC_FILE_ERROR_INVALID_URL, 335 SYNC_FILE_STATUS_UNKNOWN)); 336 return; 337 } 338 339 local_service_->HasPendingLocalChanges( 340 url, 341 base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus, 342 AsWeakPtr(), callback)); 343} 344 345void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) { 346 observers_.AddObserver(observer); 347} 348 349void SyncFileSystemService::RemoveSyncEventObserver( 350 SyncEventObserver* observer) { 351 observers_.RemoveObserver(observer); 352} 353 354LocalChangeProcessor* SyncFileSystemService::GetLocalChangeProcessor( 355 const GURL& origin) { 356 return GetRemoteService(origin)->GetLocalChangeProcessor(); 357} 358 359void SyncFileSystemService::OnSyncIdle() { 360 int64 remote_changes = 0; 361 for (ScopedVector<SyncProcessRunner>::iterator iter = 362 remote_sync_runners_.begin(); 363 iter != remote_sync_runners_.end(); ++iter) 364 remote_changes += (*iter)->pending_changes(); 365 if (remote_changes == 0) 366 local_service_->PromoteDemotedChanges(NoopClosure()); 367 368 int64 local_changes = 0; 369 for (ScopedVector<SyncProcessRunner>::iterator iter = 370 local_sync_runners_.begin(); 371 iter != local_sync_runners_.end(); ++iter) 372 local_changes += (*iter)->pending_changes(); 373 if (local_changes == 0) { 374 remote_service_->PromoteDemotedChanges(NoopClosure()); 375 if (v2_remote_service_) 376 v2_remote_service_->PromoteDemotedChanges(NoopClosure()); 377 } 378} 379 380SyncServiceState SyncFileSystemService::GetSyncServiceState() { 381 // For now we always query the state from the main RemoteFileSyncService. 382 return RemoteStateToSyncServiceState(remote_service_->GetCurrentState()); 383} 384 385SyncFileSystemService* SyncFileSystemService::GetSyncService() { 386 return this; 387} 388 389SyncFileSystemService::SyncFileSystemService(Profile* profile) 390 : profile_(profile), 391 sync_enabled_(true) { 392} 393 394void SyncFileSystemService::Initialize( 395 scoped_ptr<LocalFileSyncService> local_service, 396 scoped_ptr<RemoteFileSyncService> remote_service) { 397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 398 DCHECK(local_service); 399 DCHECK(remote_service); 400 DCHECK(profile_); 401 402 local_service_ = local_service.Pass(); 403 remote_service_ = remote_service.Pass(); 404 405 scoped_ptr<LocalSyncRunner> local_syncer( 406 new LocalSyncRunner(kLocalSyncName, this)); 407 scoped_ptr<RemoteSyncRunner> remote_syncer( 408 new RemoteSyncRunner(kRemoteSyncName, this, remote_service_.get())); 409 410 local_service_->AddChangeObserver(local_syncer.get()); 411 local_service_->SetLocalChangeProcessorCallback( 412 base::Bind(&GetLocalChangeProcessorAdapter, AsWeakPtr())); 413 414 remote_service_->AddServiceObserver(remote_syncer.get()); 415 remote_service_->AddFileStatusObserver(this); 416 remote_service_->SetRemoteChangeProcessor(local_service_.get()); 417 418 local_sync_runners_.push_back(local_syncer.release()); 419 remote_sync_runners_.push_back(remote_syncer.release()); 420 421 ProfileSyncServiceBase* profile_sync_service = 422 ProfileSyncServiceFactory::GetForProfile(profile_); 423 if (profile_sync_service) { 424 UpdateSyncEnabledStatus(profile_sync_service); 425 profile_sync_service->AddObserver(this); 426 } 427 428 ExtensionRegistry::Get(profile_)->AddObserver(this); 429} 430 431void SyncFileSystemService::DidInitializeFileSystem( 432 const GURL& app_origin, 433 const SyncStatusCallback& callback, 434 SyncStatusCode status) { 435 DVLOG(1) << "DidInitializeFileSystem: " 436 << app_origin.spec() << " " << status; 437 438 if (status != SYNC_STATUS_OK) { 439 callback.Run(status); 440 return; 441 } 442 443 // Local side of initialization for the app is done. 444 // Continue on initializing the remote side. 445 GetRemoteService(app_origin)->RegisterOrigin( 446 app_origin, 447 base::Bind(&SyncFileSystemService::DidRegisterOrigin, 448 AsWeakPtr(), app_origin, callback)); 449} 450 451void SyncFileSystemService::DidRegisterOrigin( 452 const GURL& app_origin, 453 const SyncStatusCallback& callback, 454 SyncStatusCode status) { 455 util::Log(logging::LOG_VERBOSE, FROM_HERE, 456 "DidInitializeForApp (registered the origin): %s: %s", 457 app_origin.spec().c_str(), 458 SyncStatusCodeToString(status)); 459 460 UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.RegisterOriginResult", 461 GetRemoteService(app_origin)->GetCurrentState(), 462 REMOTE_SERVICE_STATE_MAX); 463 464 if (status == SYNC_STATUS_FAILED) { 465 // If we got generic error return the service status information. 466 switch (GetRemoteService(app_origin)->GetCurrentState()) { 467 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED: 468 callback.Run(SYNC_STATUS_AUTHENTICATION_FAILED); 469 return; 470 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE: 471 callback.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE); 472 return; 473 default: 474 break; 475 } 476 } 477 478 callback.Run(status); 479} 480 481void SyncFileSystemService::DidInitializeFileSystemForDump( 482 const GURL& origin, 483 const DumpFilesCallback& callback, 484 SyncStatusCode status) { 485 DCHECK(!origin.is_empty()); 486 487 if (status != SYNC_STATUS_OK) { 488 callback.Run(base::ListValue()); 489 return; 490 } 491 492 GetRemoteService(origin)->DumpFiles( 493 origin, 494 base::Bind( 495 &SyncFileSystemService::DidDumpFiles, 496 AsWeakPtr(), 497 origin, 498 callback)); 499} 500 501void SyncFileSystemService::DidDumpFiles( 502 const GURL& origin, 503 const DumpFilesCallback& callback, 504 scoped_ptr<base::ListValue> dump_files) { 505 if (!dump_files || !dump_files->GetSize()) { 506 callback.Run(base::ListValue()); 507 return; 508 } 509 510 base::ListValue* files = dump_files.get(); 511 base::Callback<void(base::DictionaryValue*, 512 SyncStatusCode, 513 SyncFileStatus)> completion_callback = 514 base::Bind(&DidGetFileSyncStatusForDump, 515 base::Owned(dump_files.release()), 516 base::Owned(new size_t(0)), 517 callback); 518 519 // After all metadata loaded, sync status can be added to each entry. 520 for (size_t i = 0; i < files->GetSize(); ++i) { 521 base::DictionaryValue* file = NULL; 522 std::string path_string; 523 if (!files->GetDictionary(i, &file) || 524 !file->GetString("path", &path_string)) { 525 NOTREACHED(); 526 completion_callback.Run( 527 NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN); 528 continue; 529 } 530 531 base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path_string); 532 FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path); 533 GetFileSyncStatus(url, base::Bind(completion_callback, file)); 534 } 535} 536 537void SyncFileSystemService::DidDumpDatabase( 538 const DumpFilesCallback& callback, scoped_ptr<base::ListValue> list) { 539 if (!list) 540 list = make_scoped_ptr(new base::ListValue); 541 542 if (!v2_remote_service_) { 543 callback.Run(*list); 544 return; 545 } 546 547 v2_remote_service_->DumpDatabase( 548 base::Bind(&SyncFileSystemService::DidDumpV2Database, 549 AsWeakPtr(), callback, base::Passed(&list))); 550} 551 552void SyncFileSystemService::DidDumpV2Database( 553 const DumpFilesCallback& callback, 554 scoped_ptr<base::ListValue> v1list, 555 scoped_ptr<base::ListValue> v2list) { 556 if (!v1list) 557 v1list = make_scoped_ptr(new base::ListValue); 558 559 if (v2list) { 560 for (base::ListValue::iterator itr = v2list->begin(); 561 itr != v2list->end();) { 562 scoped_ptr<base::Value> item; 563 itr = v2list->Erase(itr, &item); 564 v1list->Append(item.release()); 565 } 566 } 567 568 callback.Run(*v1list); 569} 570 571void SyncFileSystemService::DidGetExtensionStatusMap( 572 const ExtensionStatusMapCallback& callback, 573 scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map) { 574 if (!status_map) 575 status_map = make_scoped_ptr(new RemoteFileSyncService::OriginStatusMap); 576 if (!v2_remote_service_) { 577 callback.Run(*status_map); 578 return; 579 } 580 581 v2_remote_service_->GetOriginStatusMap( 582 base::Bind(&SyncFileSystemService::DidGetV2ExtensionStatusMap, 583 AsWeakPtr(), 584 callback, 585 base::Passed(&status_map))); 586} 587 588void SyncFileSystemService::DidGetV2ExtensionStatusMap( 589 const ExtensionStatusMapCallback& callback, 590 scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map_v1, 591 scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map_v2) { 592 // Merge |status_map_v2| into |status_map_v1|. 593 if (!status_map_v1) 594 status_map_v1 = make_scoped_ptr(new RemoteFileSyncService::OriginStatusMap); 595 if (status_map_v2) 596 status_map_v1->insert(status_map_v2->begin(), status_map_v2->end()); 597 598 callback.Run(*status_map_v1); 599} 600 601void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) { 602 sync_enabled_ = enabled; 603 remote_service_->SetSyncEnabled(sync_enabled_); 604 if (v2_remote_service_) 605 v2_remote_service_->SetSyncEnabled(sync_enabled_); 606} 607 608void 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 618void 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 634void 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 645void 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 674void 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 697void 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 708void SyncFileSystemService::OnStateChanged() { 709 ProfileSyncServiceBase* profile_sync_service = 710 ProfileSyncServiceFactory::GetForProfile(profile_); 711 if (profile_sync_service) 712 UpdateSyncEnabledStatus(profile_sync_service); 713} 714 715void 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 725void 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 (v2_remote_service_) 734 v2_remote_service_->SetSyncEnabled(sync_enabled_); 735 if (!old_sync_enabled && sync_enabled_) 736 RunForEachSyncRunners(&SyncProcessRunner::Schedule); 737} 738 739void SyncFileSystemService::RunForEachSyncRunners( 740 void(SyncProcessRunner::*method)()) { 741 for (ScopedVector<SyncProcessRunner>::iterator iter = 742 local_sync_runners_.begin(); 743 iter != local_sync_runners_.end(); ++iter) 744 ((*iter)->*method)(); 745 for (ScopedVector<SyncProcessRunner>::iterator iter = 746 remote_sync_runners_.begin(); 747 iter != remote_sync_runners_.end(); ++iter) 748 ((*iter)->*method)(); 749} 750 751RemoteFileSyncService* SyncFileSystemService::GetRemoteService( 752 const GURL& origin) { 753 if (IsV2Enabled()) 754 return remote_service_.get(); 755 if (!IsV2EnabledForOrigin(origin)) 756 return remote_service_.get(); 757 758 if (!v2_remote_service_) { 759 v2_remote_service_ = RemoteFileSyncService::CreateForBrowserContext( 760 RemoteFileSyncService::V2, profile_, &task_logger_); 761 scoped_ptr<RemoteSyncRunner> v2_remote_syncer( 762 new RemoteSyncRunner(kRemoteSyncNameV2, this, 763 v2_remote_service_.get())); 764 v2_remote_service_->AddServiceObserver(v2_remote_syncer.get()); 765 v2_remote_service_->AddFileStatusObserver(this); 766 v2_remote_service_->SetRemoteChangeProcessor(local_service_.get()); 767 v2_remote_service_->SetSyncEnabled(sync_enabled_); 768 remote_sync_runners_.push_back(v2_remote_syncer.release()); 769 } 770 return v2_remote_service_.get(); 771} 772 773} // namespace sync_file_system 774