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