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