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/drive_backend/drive_file_sync_service.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_status_code.h" 27 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" 28 #include "chrome/common/extensions/extension.h" 29 #include "components/browser_context_keyed_service/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 "url/gurl.h" 35 #include "webkit/browser/fileapi/file_system_context.h" 36 37 using content::BrowserThread; 38 using fileapi::FileSystemURL; 39 using fileapi::FileSystemURLSet; 40 41 namespace sync_file_system { 42 43 namespace { 44 45 const int64 kRetryTimerIntervalInSeconds = 20 * 60; // 20 min. 46 47 SyncServiceState RemoteStateToSyncServiceState( 48 RemoteServiceState state) { 49 switch (state) { 50 case REMOTE_SERVICE_OK: 51 return SYNC_SERVICE_RUNNING; 52 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE: 53 return SYNC_SERVICE_TEMPORARY_UNAVAILABLE; 54 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED: 55 return SYNC_SERVICE_AUTHENTICATION_REQUIRED; 56 case REMOTE_SERVICE_DISABLED: 57 return SYNC_SERVICE_DISABLED; 58 } 59 NOTREACHED() << "Unknown remote service state: " << state; 60 return SYNC_SERVICE_DISABLED; 61 } 62 63 void DidHandleOriginForExtensionUnloadedEvent( 64 int type, 65 const GURL& origin, 66 SyncStatusCode code) { 67 DCHECK(chrome::NOTIFICATION_EXTENSION_UNLOADED == type || 68 chrome::NOTIFICATION_EXTENSION_UNINSTALLED == type); 69 if (code != SYNC_STATUS_OK && 70 code != SYNC_STATUS_UNKNOWN_ORIGIN) { 71 switch (type) { 72 case chrome::NOTIFICATION_EXTENSION_UNLOADED: 73 util::Log(logging::LOG_WARNING, 74 FROM_HERE, 75 "Disabling origin for UNLOADED(DISABLE) failed: %s", 76 origin.spec().c_str()); 77 break; 78 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: 79 util::Log(logging::LOG_WARNING, 80 FROM_HERE, 81 "Uninstall origin for UNINSTALLED failed: %s", 82 origin.spec().c_str()); 83 break; 84 default: 85 break; 86 } 87 } 88 } 89 90 void DidHandleOriginForExtensionEnabledEvent( 91 int type, 92 const GURL& origin, 93 SyncStatusCode code) { 94 DCHECK(chrome::NOTIFICATION_EXTENSION_ENABLED == type); 95 if (code != SYNC_STATUS_OK) 96 util::Log(logging::LOG_WARNING, 97 FROM_HERE, 98 "Enabling origin for ENABLED failed: %s", 99 origin.spec().c_str()); 100 } 101 102 std::string SyncFileStatusToString(SyncFileStatus sync_file_status) { 103 return extensions::api::sync_file_system::ToString( 104 extensions::SyncFileStatusToExtensionEnum(sync_file_status)); 105 } 106 107 // Gets called repeatedly until every SyncFileStatus has been mapped. 108 void DidGetFileSyncStatusForDump( 109 base::ListValue* files, 110 size_t* num_results, 111 const SyncFileSystemService::DumpFilesCallback& callback, 112 base::DictionaryValue* file, 113 SyncStatusCode sync_status_code, 114 SyncFileStatus sync_file_status) { 115 DCHECK(files); 116 DCHECK(num_results); 117 118 if (file) 119 file->SetString("status", SyncFileStatusToString(sync_file_status)); 120 121 // Once all results have been received, run the callback to signal end. 122 DCHECK_LE(*num_results, files->GetSize()); 123 if (++*num_results < files->GetSize()) 124 return; 125 126 callback.Run(files); 127 } 128 129 } // namespace 130 131 void SyncFileSystemService::Shutdown() { 132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 133 134 local_file_service_->Shutdown(); 135 local_file_service_.reset(); 136 137 remote_file_service_.reset(); 138 139 ProfileSyncServiceBase* profile_sync_service = 140 ProfileSyncServiceFactory::GetForProfile(profile_); 141 if (profile_sync_service) 142 profile_sync_service->RemoveObserver(this); 143 144 profile_ = NULL; 145 } 146 147 SyncFileSystemService::~SyncFileSystemService() { 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 149 DCHECK(!profile_); 150 } 151 152 void SyncFileSystemService::InitializeForApp( 153 fileapi::FileSystemContext* file_system_context, 154 const GURL& app_origin, 155 const SyncStatusCallback& callback) { 156 DCHECK(local_file_service_); 157 DCHECK(remote_file_service_); 158 DCHECK(app_origin == app_origin.GetOrigin()); 159 160 util::Log(logging::LOG_VERBOSE, FROM_HERE, 161 "Initializing for App: %s", app_origin.spec().c_str()); 162 163 local_file_service_->MaybeInitializeFileSystemContext( 164 app_origin, file_system_context, 165 base::Bind(&SyncFileSystemService::DidInitializeFileSystem, 166 AsWeakPtr(), app_origin, callback)); 167 } 168 169 SyncServiceState SyncFileSystemService::GetSyncServiceState() { 170 return RemoteStateToSyncServiceState(remote_file_service_->GetCurrentState()); 171 } 172 173 void SyncFileSystemService::GetExtensionStatusMap( 174 std::map<GURL, std::string>* status_map) { 175 DCHECK(status_map); 176 remote_file_service_->GetOriginStatusMap(status_map); 177 } 178 179 void SyncFileSystemService::DumpFiles(const GURL& origin, 180 const DumpFilesCallback& callback) { 181 DCHECK(!origin.is_empty()); 182 183 content::StoragePartition* storage_partition = 184 content::BrowserContext::GetStoragePartitionForSite(profile_, origin); 185 fileapi::FileSystemContext* file_system_context = 186 storage_partition->GetFileSystemContext(); 187 local_file_service_->MaybeInitializeFileSystemContext( 188 origin, file_system_context, 189 base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump, 190 AsWeakPtr(), origin, callback)); 191 } 192 193 void SyncFileSystemService::GetFileSyncStatus( 194 const FileSystemURL& url, const SyncFileStatusCallback& callback) { 195 DCHECK(local_file_service_); 196 DCHECK(remote_file_service_); 197 198 // It's possible to get an invalid FileEntry. 199 if (!url.is_valid()) { 200 base::MessageLoopProxy::current()->PostTask( 201 FROM_HERE, 202 base::Bind(callback, 203 SYNC_FILE_ERROR_INVALID_URL, 204 SYNC_FILE_STATUS_UNKNOWN)); 205 return; 206 } 207 208 if (remote_file_service_->IsConflicting(url)) { 209 base::MessageLoopProxy::current()->PostTask( 210 FROM_HERE, 211 base::Bind(callback, 212 SYNC_STATUS_OK, 213 SYNC_FILE_STATUS_CONFLICTING)); 214 return; 215 } 216 217 local_file_service_->HasPendingLocalChanges( 218 url, 219 base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus, 220 AsWeakPtr(), callback)); 221 } 222 223 void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) { 224 observers_.AddObserver(observer); 225 } 226 227 void SyncFileSystemService::RemoveSyncEventObserver( 228 SyncEventObserver* observer) { 229 observers_.RemoveObserver(observer); 230 } 231 232 ConflictResolutionPolicy 233 SyncFileSystemService::GetConflictResolutionPolicy() const { 234 return remote_file_service_->GetConflictResolutionPolicy(); 235 } 236 237 SyncStatusCode SyncFileSystemService::SetConflictResolutionPolicy( 238 ConflictResolutionPolicy policy) { 239 return remote_file_service_->SetConflictResolutionPolicy(policy); 240 } 241 242 SyncFileSystemService::SyncFileSystemService(Profile* profile) 243 : profile_(profile), 244 pending_local_changes_(0), 245 pending_remote_changes_(0), 246 local_sync_running_(false), 247 remote_sync_running_(false), 248 is_waiting_remote_sync_enabled_(false), 249 sync_enabled_(true) { 250 } 251 252 void SyncFileSystemService::Initialize( 253 scoped_ptr<LocalFileSyncService> local_file_service, 254 scoped_ptr<RemoteFileSyncService> remote_file_service) { 255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 256 DCHECK(local_file_service); 257 DCHECK(remote_file_service); 258 DCHECK(profile_); 259 260 local_file_service_ = local_file_service.Pass(); 261 remote_file_service_ = remote_file_service.Pass(); 262 263 local_file_service_->AddChangeObserver(this); 264 local_file_service_->SetLocalChangeProcessor( 265 remote_file_service_->GetLocalChangeProcessor()); 266 267 remote_file_service_->AddServiceObserver(this); 268 remote_file_service_->AddFileStatusObserver(this); 269 remote_file_service_->SetRemoteChangeProcessor(local_file_service_.get()); 270 271 ProfileSyncServiceBase* profile_sync_service = 272 ProfileSyncServiceFactory::GetForProfile(profile_); 273 if (profile_sync_service) { 274 UpdateSyncEnabledStatus(profile_sync_service); 275 profile_sync_service->AddObserver(this); 276 } 277 278 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 279 content::Source<Profile>(profile_)); 280 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 281 content::Source<Profile>(profile_)); 282 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 283 content::Source<Profile>(profile_)); 284 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED, 285 content::Source<Profile>(profile_)); 286 } 287 288 void SyncFileSystemService::DidInitializeFileSystem( 289 const GURL& app_origin, 290 const SyncStatusCallback& callback, 291 SyncStatusCode status) { 292 DVLOG(1) << "DidInitializeFileSystem: " 293 << app_origin.spec() << " " << status; 294 295 if (status != SYNC_STATUS_OK) { 296 callback.Run(status); 297 return; 298 } 299 300 // Local side of initialization for the app is done. 301 // Continue on initializing the remote side. 302 remote_file_service_->RegisterOriginForTrackingChanges( 303 app_origin, 304 base::Bind(&SyncFileSystemService::DidRegisterOrigin, 305 AsWeakPtr(), app_origin, callback)); 306 } 307 308 void SyncFileSystemService::DidRegisterOrigin( 309 const GURL& app_origin, 310 const SyncStatusCallback& callback, 311 SyncStatusCode status) { 312 DVLOG(1) << "DidRegisterOrigin: " << app_origin.spec() << " " << status; 313 314 callback.Run(status); 315 } 316 317 void SyncFileSystemService::DidInitializeFileSystemForDump( 318 const GURL& origin, 319 const DumpFilesCallback& callback, 320 SyncStatusCode status) { 321 DCHECK(!origin.is_empty()); 322 323 if (status != SYNC_STATUS_OK) { 324 base::ListValue empty_result; 325 callback.Run(&empty_result); 326 return; 327 } 328 329 base::ListValue* files = remote_file_service_->DumpFiles(origin).release(); 330 if (!files->GetSize()) { 331 callback.Run(files); 332 return; 333 } 334 335 base::Callback<void(base::DictionaryValue* file, 336 SyncStatusCode sync_status, 337 SyncFileStatus sync_file_status)> completion_callback = 338 base::Bind(&DidGetFileSyncStatusForDump, base::Owned(files), 339 base::Owned(new size_t(0)), callback); 340 341 // After all metadata loaded, sync status can be added to each entry. 342 for (size_t i = 0; i < files->GetSize(); ++i) { 343 base::DictionaryValue* file = NULL; 344 std::string path_string; 345 if (!files->GetDictionary(i, &file) || 346 !file->GetString("path", &path_string)) { 347 NOTREACHED(); 348 completion_callback.Run( 349 NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN); 350 continue; 351 } 352 353 base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path_string); 354 FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path); 355 GetFileSyncStatus(url, base::Bind(completion_callback, file)); 356 } 357 } 358 359 void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) { 360 sync_enabled_ = enabled; 361 remote_file_service_->SetSyncEnabled(sync_enabled_); 362 } 363 364 void SyncFileSystemService::MaybeStartSync() { 365 if (!profile_ || !sync_enabled_) 366 return; 367 368 if (pending_local_changes_ + pending_remote_changes_ == 0) 369 return; 370 371 DVLOG(2) << "MaybeStartSync() called (remote service state:" 372 << remote_file_service_->GetCurrentState() << ")"; 373 switch (remote_file_service_->GetCurrentState()) { 374 case REMOTE_SERVICE_OK: 375 break; 376 377 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE: 378 if (sync_retry_timer_.IsRunning()) 379 return; 380 sync_retry_timer_.Start( 381 FROM_HERE, 382 base::TimeDelta::FromSeconds(kRetryTimerIntervalInSeconds), 383 this, &SyncFileSystemService::MaybeStartSync); 384 break; 385 386 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED: 387 case REMOTE_SERVICE_DISABLED: 388 // No point to run sync. 389 return; 390 } 391 392 StartRemoteSync(); 393 StartLocalSync(); 394 } 395 396 void SyncFileSystemService::StartRemoteSync() { 397 // See if we cannot / should not start a new remote sync. 398 if (remote_sync_running_ || pending_remote_changes_ == 0) 399 return; 400 // If we have registered a URL for waiting until sync is enabled on a 401 // file (and the registerred URL seems to be still valid) it won't be 402 // worth trying to start another remote sync. 403 if (is_waiting_remote_sync_enabled_) 404 return; 405 DCHECK(sync_enabled_); 406 407 util::Log(logging::LOG_VERBOSE, FROM_HERE, 408 "Calling ProcessRemoteChange for RemoteSync"); 409 remote_sync_running_ = true; 410 remote_file_service_->ProcessRemoteChange( 411 base::Bind(&SyncFileSystemService::DidProcessRemoteChange, 412 AsWeakPtr())); 413 } 414 415 void SyncFileSystemService::StartLocalSync() { 416 // See if we cannot / should not start a new local sync. 417 if (local_sync_running_ || pending_local_changes_ == 0) 418 return; 419 DCHECK(sync_enabled_); 420 421 util::Log(logging::LOG_VERBOSE, FROM_HERE, 422 "Calling ProcessLocalChange for LocalSync"); 423 local_sync_running_ = true; 424 local_file_service_->ProcessLocalChange( 425 base::Bind(&SyncFileSystemService::DidProcessLocalChange, 426 AsWeakPtr())); 427 } 428 429 void SyncFileSystemService::DidProcessRemoteChange( 430 SyncStatusCode status, 431 const FileSystemURL& url) { 432 util::Log(logging::LOG_VERBOSE, FROM_HERE, 433 "ProcessRemoteChange finished with status=%d (%s) for url=%s", 434 status, SyncStatusCodeToString(status), url.DebugString().c_str()); 435 DCHECK(remote_sync_running_); 436 remote_sync_running_ = false; 437 438 if (status != SYNC_STATUS_NO_CHANGE_TO_SYNC && 439 remote_file_service_->GetCurrentState() != REMOTE_SERVICE_DISABLED) { 440 DCHECK(url.is_valid()); 441 local_file_service_->ClearSyncFlagForURL(url); 442 } 443 444 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC) { 445 // We seem to have no changes to work on for now. 446 // TODO(kinuko): Might be better setting a timer to call MaybeStartSync. 447 return; 448 } 449 if (status == SYNC_STATUS_FILE_BUSY) { 450 is_waiting_remote_sync_enabled_ = true; 451 local_file_service_->RegisterURLForWaitingSync( 452 url, base::Bind(&SyncFileSystemService::OnSyncEnabledForRemoteSync, 453 AsWeakPtr())); 454 return; 455 } 456 457 base::MessageLoopProxy::current()->PostTask( 458 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 459 AsWeakPtr())); 460 } 461 462 void SyncFileSystemService::DidProcessLocalChange( 463 SyncStatusCode status, const FileSystemURL& url) { 464 util::Log(logging::LOG_VERBOSE, FROM_HERE, 465 "ProcessLocalChange finished with status=%d (%s) for url=%s", 466 status, SyncStatusCodeToString(status), url.DebugString().c_str()); 467 DCHECK(local_sync_running_); 468 local_sync_running_ = false; 469 470 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC) { 471 // We seem to have no changes to work on for now. 472 return; 473 } 474 475 DCHECK(url.is_valid()); 476 local_file_service_->ClearSyncFlagForURL(url); 477 478 base::MessageLoopProxy::current()->PostTask( 479 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 480 AsWeakPtr())); 481 } 482 483 void SyncFileSystemService::DidGetLocalChangeStatus( 484 const SyncFileStatusCallback& callback, 485 SyncStatusCode status, 486 bool has_pending_local_changes) { 487 callback.Run( 488 status, 489 has_pending_local_changes ? 490 SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED); 491 } 492 493 void SyncFileSystemService::OnSyncEnabledForRemoteSync() { 494 is_waiting_remote_sync_enabled_ = false; 495 MaybeStartSync(); 496 } 497 498 void SyncFileSystemService::OnLocalChangeAvailable(int64 pending_changes) { 499 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 500 DCHECK_GE(pending_changes, 0); 501 if (pending_local_changes_ != pending_changes) { 502 util::Log(logging::LOG_VERBOSE, FROM_HERE, 503 "OnLocalChangeAvailable: %" PRId64, pending_changes); 504 } 505 pending_local_changes_ = pending_changes; 506 if (pending_changes == 0) 507 return; 508 509 base::MessageLoopProxy::current()->PostTask( 510 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 511 AsWeakPtr())); 512 } 513 514 void SyncFileSystemService::OnRemoteChangeQueueUpdated(int64 pending_changes) { 515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 516 DCHECK_GE(pending_changes, 0); 517 518 if (pending_remote_changes_ != pending_changes) { 519 util::Log(logging::LOG_VERBOSE, FROM_HERE, 520 "OnRemoteChangeAvailable: %" PRId64, pending_changes); 521 } 522 pending_remote_changes_ = pending_changes; 523 if (pending_changes == 0) 524 return; 525 526 // The smallest change available might have changed from the previous one. 527 // Reset the is_waiting_remote_sync_enabled_ flag so that we can retry. 528 is_waiting_remote_sync_enabled_ = false; 529 530 base::MessageLoopProxy::current()->PostTask( 531 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 532 AsWeakPtr())); 533 } 534 535 void SyncFileSystemService::OnRemoteServiceStateUpdated( 536 RemoteServiceState state, 537 const std::string& description) { 538 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 539 util::Log(logging::LOG_INFO, FROM_HERE, 540 "OnRemoteServiceStateChanged: %d %s", state, description.c_str()); 541 542 if (state == REMOTE_SERVICE_OK) { 543 base::MessageLoopProxy::current()->PostTask( 544 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 545 AsWeakPtr())); 546 } 547 548 FOR_EACH_OBSERVER( 549 SyncEventObserver, observers_, 550 OnSyncStateUpdated(GURL(), 551 RemoteStateToSyncServiceState(state), 552 description)); 553 } 554 555 void SyncFileSystemService::Observe( 556 int type, 557 const content::NotificationSource& source, 558 const content::NotificationDetails& details) { 559 // Event notification sequence. 560 // 561 // (User action) (Notification type) 562 // Install: INSTALLED. 563 // Update: INSTALLED. 564 // Uninstall: UNINSTALLED. 565 // Launch, Close: No notification. 566 // Enable: ENABLED. 567 // Disable: UNLOADED(DISABLE). 568 // Reload, Restart: UNLOADED(DISABLE) -> INSTALLED -> ENABLED. 569 // 570 switch (type) { 571 case chrome::NOTIFICATION_EXTENSION_INSTALLED: 572 HandleExtensionInstalled(details); 573 break; 574 case chrome::NOTIFICATION_EXTENSION_UNLOADED: 575 HandleExtensionUnloaded(type, details); 576 break; 577 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: 578 HandleExtensionUninstalled(type, details); 579 break; 580 case chrome::NOTIFICATION_EXTENSION_ENABLED: 581 HandleExtensionEnabled(type, details); 582 break; 583 default: 584 NOTREACHED() << "Unknown notification."; 585 break; 586 } 587 } 588 589 void SyncFileSystemService::HandleExtensionInstalled( 590 const content::NotificationDetails& details) { 591 const extensions::Extension* extension = 592 content::Details<const extensions::InstalledExtensionInfo>(details)-> 593 extension; 594 GURL app_origin = 595 extensions::Extension::GetBaseURLFromExtensionId(extension->id()); 596 DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin; 597 // NOTE: When an app is uninstalled and re-installed in a sequence, 598 // |local_file_service_| may still keeps |app_origin| as disabled origin. 599 local_file_service_->SetOriginEnabled(app_origin, true); 600 } 601 602 void SyncFileSystemService::HandleExtensionUnloaded( 603 int type, 604 const content::NotificationDetails& details) { 605 content::Details<const extensions::UnloadedExtensionInfo> info(details); 606 std::string extension_id = info->extension->id(); 607 GURL app_origin = 608 extensions::Extension::GetBaseURLFromExtensionId(extension_id); 609 if (info->reason != extension_misc::UNLOAD_REASON_DISABLE) 610 return; 611 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): " 612 << app_origin; 613 remote_file_service_->DisableOriginForTrackingChanges( 614 app_origin, 615 base::Bind(&DidHandleOriginForExtensionUnloadedEvent, 616 type, app_origin)); 617 local_file_service_->SetOriginEnabled(app_origin, false); 618 } 619 620 void SyncFileSystemService::HandleExtensionUninstalled( 621 int type, 622 const content::NotificationDetails& details) { 623 std::string extension_id = 624 content::Details<const extensions::Extension>(details)->id(); 625 GURL app_origin = 626 extensions::Extension::GetBaseURLFromExtensionId(extension_id); 627 DVLOG(1) << "Handle extension notification for UNINSTALLED: " 628 << app_origin; 629 remote_file_service_->UninstallOrigin( 630 app_origin, 631 base::Bind(&DidHandleOriginForExtensionUnloadedEvent, 632 type, app_origin)); 633 local_file_service_->SetOriginEnabled(app_origin, false); 634 } 635 636 void SyncFileSystemService::HandleExtensionEnabled( 637 int type, 638 const content::NotificationDetails& details) { 639 std::string extension_id = 640 content::Details<const extensions::Extension>(details)->id(); 641 GURL app_origin = 642 extensions::Extension::GetBaseURLFromExtensionId(extension_id); 643 DVLOG(1) << "Handle extension notification for ENABLED: " << app_origin; 644 remote_file_service_->EnableOriginForTrackingChanges( 645 app_origin, 646 base::Bind(&DidHandleOriginForExtensionEnabledEvent, type, app_origin)); 647 local_file_service_->SetOriginEnabled(app_origin, true); 648 } 649 650 void SyncFileSystemService::OnStateChanged() { 651 ProfileSyncServiceBase* profile_sync_service = 652 ProfileSyncServiceFactory::GetForProfile(profile_); 653 if (profile_sync_service) 654 UpdateSyncEnabledStatus(profile_sync_service); 655 } 656 657 void SyncFileSystemService::OnFileStatusChanged( 658 const FileSystemURL& url, 659 SyncFileStatus sync_status, 660 SyncAction action_taken, 661 SyncDirection direction) { 662 FOR_EACH_OBSERVER( 663 SyncEventObserver, observers_, 664 OnFileSynced(url, sync_status, action_taken, direction)); 665 } 666 667 void SyncFileSystemService::UpdateSyncEnabledStatus( 668 ProfileSyncServiceBase* profile_sync_service) { 669 if (!profile_sync_service->HasSyncSetupCompleted()) 670 return; 671 sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has( 672 syncer::APPS); 673 remote_file_service_->SetSyncEnabled(sync_enabled_); 674 if (sync_enabled_) { 675 base::MessageLoopProxy::current()->PostTask( 676 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 677 AsWeakPtr())); 678 } 679 } 680 681 } // namespace sync_file_system 682