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