sync_file_system_service.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 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_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/common/extensions/extension.h" 26#include "components/browser_context_keyed_service/browser_context_dependency_manager.h" 27#include "content/public/browser/browser_thread.h" 28#include "content/public/browser/notification_details.h" 29#include "content/public/browser/notification_service.h" 30#include "content/public/browser/storage_partition.h" 31#include "url/gurl.h" 32#include "webkit/browser/fileapi/file_system_context.h" 33#include "webkit/browser/fileapi/syncable/sync_file_metadata.h" 34#include "webkit/browser/fileapi/syncable/sync_status_code.h" 35#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h" 36 37using content::BrowserThread; 38using fileapi::FileSystemURL; 39using fileapi::FileSystemURLSet; 40 41namespace sync_file_system { 42 43namespace { 44 45const int64 kRetryTimerIntervalInSeconds = 20 * 60; // 20 min. 46 47SyncServiceState 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 63void DidHandleOriginForExtensionUnloadedEvent( 64 int type, 65 extension_misc::UnloadedExtensionReason reason, 66 const GURL& origin, 67 SyncStatusCode code) { 68 DCHECK(chrome::NOTIFICATION_EXTENSION_UNLOADED == type); 69 DCHECK(extension_misc::UNLOAD_REASON_DISABLE == reason || 70 extension_misc::UNLOAD_REASON_UNINSTALL == reason); 71 if (code != SYNC_STATUS_OK && 72 code != SYNC_STATUS_UNKNOWN_ORIGIN) { 73 switch (reason) { 74 case extension_misc::UNLOAD_REASON_DISABLE: 75 util::Log(logging::LOG_WARNING, 76 FROM_HERE, 77 "Disabling origin for UNLOAD(DISABLE) failed: %s", 78 origin.spec().c_str()); 79 break; 80 case extension_misc::UNLOAD_REASON_UNINSTALL: 81 util::Log(logging::LOG_WARNING, 82 FROM_HERE, 83 "Uninstall origin for UNLOAD(UNINSTALL) failed: %s", 84 origin.spec().c_str()); 85 break; 86 default: 87 break; 88 } 89 } 90} 91 92void DidHandleOriginForExtensionEnabledEvent( 93 int type, 94 const GURL& origin, 95 SyncStatusCode code) { 96 DCHECK(chrome::NOTIFICATION_EXTENSION_ENABLED == type); 97 if (code != SYNC_STATUS_OK) 98 util::Log(logging::LOG_WARNING, 99 FROM_HERE, 100 "Enabling origin for ENABLED failed: %s", 101 origin.spec().c_str()); 102} 103 104std::string SyncFileStatusToString(SyncFileStatus sync_file_status) { 105 return extensions::api::sync_file_system::ToString( 106 extensions::SyncFileStatusToExtensionEnum(sync_file_status)); 107} 108 109// Gets called repeatedly until every SyncFileStatus has been mapped. 110void DidGetFileSyncStatusForDump( 111 base::ListValue* files, 112 size_t* num_results, 113 const SyncFileSystemService::DumpFilesCallback& callback, 114 base::DictionaryValue* file, 115 SyncStatusCode sync_status_code, 116 SyncFileStatus sync_file_status) { 117 DCHECK(files); 118 DCHECK(num_results); 119 120 if (file) 121 file->SetString("status", SyncFileStatusToString(sync_file_status)); 122 123 // Once all results have been received, run the callback to signal end. 124 DCHECK_LE(*num_results, files->GetSize()); 125 if (++*num_results < files->GetSize()) 126 return; 127 128 callback.Run(files); 129} 130 131} // namespace 132 133void SyncFileSystemService::Shutdown() { 134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 135 136 local_file_service_->Shutdown(); 137 local_file_service_.reset(); 138 139 remote_file_service_.reset(); 140 141 ProfileSyncServiceBase* profile_sync_service = 142 ProfileSyncServiceFactory::GetForProfile(profile_); 143 if (profile_sync_service) 144 profile_sync_service->RemoveObserver(this); 145 146 profile_ = NULL; 147} 148 149SyncFileSystemService::~SyncFileSystemService() { 150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 151 DCHECK(!profile_); 152} 153 154void SyncFileSystemService::InitializeForApp( 155 fileapi::FileSystemContext* file_system_context, 156 const GURL& app_origin, 157 const SyncStatusCallback& callback) { 158 DCHECK(local_file_service_); 159 DCHECK(remote_file_service_); 160 DCHECK(app_origin == app_origin.GetOrigin()); 161 162 util::Log(logging::LOG_VERBOSE, FROM_HERE, 163 "Initializing for App: %s", app_origin.spec().c_str()); 164 165 local_file_service_->MaybeInitializeFileSystemContext( 166 app_origin, file_system_context, 167 base::Bind(&SyncFileSystemService::DidInitializeFileSystem, 168 AsWeakPtr(), app_origin, callback)); 169} 170 171SyncServiceState SyncFileSystemService::GetSyncServiceState() { 172 return RemoteStateToSyncServiceState(remote_file_service_->GetCurrentState()); 173} 174 175void SyncFileSystemService::GetExtensionStatusMap( 176 std::map<GURL, std::string>* status_map) { 177 DCHECK(status_map); 178 remote_file_service_->GetOriginStatusMap(status_map); 179} 180 181void SyncFileSystemService::DumpFiles(const GURL& origin, 182 const DumpFilesCallback& callback) { 183 DCHECK(!origin.is_empty()); 184 185 content::StoragePartition* storage_partition = 186 content::BrowserContext::GetStoragePartitionForSite(profile_, origin); 187 fileapi::FileSystemContext* file_system_context = 188 storage_partition->GetFileSystemContext(); 189 local_file_service_->MaybeInitializeFileSystemContext( 190 origin, file_system_context, 191 base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump, 192 AsWeakPtr(), origin, callback)); 193} 194 195void SyncFileSystemService::GetFileSyncStatus( 196 const FileSystemURL& url, const SyncFileStatusCallback& callback) { 197 DCHECK(local_file_service_); 198 DCHECK(remote_file_service_); 199 200 // It's possible to get an invalid FileEntry. 201 if (!url.is_valid()) { 202 base::MessageLoopProxy::current()->PostTask( 203 FROM_HERE, 204 base::Bind(callback, 205 SYNC_FILE_ERROR_INVALID_URL, 206 SYNC_FILE_STATUS_UNKNOWN)); 207 return; 208 } 209 210 if (remote_file_service_->IsConflicting(url)) { 211 base::MessageLoopProxy::current()->PostTask( 212 FROM_HERE, 213 base::Bind(callback, 214 SYNC_STATUS_OK, 215 SYNC_FILE_STATUS_CONFLICTING)); 216 return; 217 } 218 219 local_file_service_->HasPendingLocalChanges( 220 url, 221 base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus, 222 AsWeakPtr(), callback)); 223} 224 225void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) { 226 observers_.AddObserver(observer); 227} 228 229void SyncFileSystemService::RemoveSyncEventObserver( 230 SyncEventObserver* observer) { 231 observers_.RemoveObserver(observer); 232} 233 234ConflictResolutionPolicy 235SyncFileSystemService::GetConflictResolutionPolicy() const { 236 return remote_file_service_->GetConflictResolutionPolicy(); 237} 238 239SyncStatusCode SyncFileSystemService::SetConflictResolutionPolicy( 240 ConflictResolutionPolicy policy) { 241 return remote_file_service_->SetConflictResolutionPolicy(policy); 242} 243 244SyncFileSystemService::SyncFileSystemService(Profile* profile) 245 : profile_(profile), 246 pending_local_changes_(0), 247 pending_remote_changes_(0), 248 local_sync_running_(false), 249 remote_sync_running_(false), 250 is_waiting_remote_sync_enabled_(false), 251 sync_enabled_(true) { 252} 253 254void SyncFileSystemService::Initialize( 255 scoped_ptr<LocalFileSyncService> local_file_service, 256 scoped_ptr<RemoteFileSyncService> remote_file_service) { 257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 258 DCHECK(local_file_service); 259 DCHECK(remote_file_service); 260 DCHECK(profile_); 261 262 local_file_service_ = local_file_service.Pass(); 263 remote_file_service_ = remote_file_service.Pass(); 264 265 local_file_service_->AddChangeObserver(this); 266 local_file_service_->SetLocalChangeProcessor( 267 remote_file_service_->GetLocalChangeProcessor()); 268 269 remote_file_service_->AddServiceObserver(this); 270 remote_file_service_->AddFileStatusObserver(this); 271 remote_file_service_->SetRemoteChangeProcessor(local_file_service_.get()); 272 273 ProfileSyncServiceBase* profile_sync_service = 274 ProfileSyncServiceFactory::GetForProfile(profile_); 275 if (profile_sync_service) { 276 UpdateSyncEnabledStatus(profile_sync_service); 277 profile_sync_service->AddObserver(this); 278 } 279 280 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 281 content::Source<Profile>(profile_)); 282 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 283 content::Source<Profile>(profile_)); 284 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED, 285 content::Source<Profile>(profile_)); 286} 287 288void 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 308void 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 317void 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 359void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) { 360 sync_enabled_ = enabled; 361 remote_file_service_->SetSyncEnabled(sync_enabled_); 362} 363 364void 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 396void 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 415void 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 429void 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 462void 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 483void 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 493void SyncFileSystemService::OnSyncEnabledForRemoteSync() { 494 is_waiting_remote_sync_enabled_ = false; 495 MaybeStartSync(); 496} 497 498void 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 514void 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 535void 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 555void 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: UNLOADED(UNINSTALL). 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_ENABLED: 578 HandleExtensionEnabled(type, details); 579 break; 580 default: 581 NOTREACHED() << "Unknown notification."; 582 break; 583 } 584} 585 586void SyncFileSystemService::HandleExtensionInstalled( 587 const content::NotificationDetails& details) { 588 const extensions::Extension* extension = 589 content::Details<const extensions::InstalledExtensionInfo>(details)-> 590 extension; 591 GURL app_origin = 592 extensions::Extension::GetBaseURLFromExtensionId(extension->id()); 593 DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin; 594 // NOTE: When an app is uninstalled and re-installed in a sequence, 595 // |local_file_service_| may still keeps |app_origin| as disabled origin. 596 local_file_service_->SetOriginEnabled(app_origin, true); 597} 598 599void SyncFileSystemService::HandleExtensionUnloaded( 600 int type, 601 const content::NotificationDetails& details) { 602 content::Details<const extensions::UnloadedExtensionInfo> info(details); 603 std::string extension_id = info->extension->id(); 604 GURL app_origin = 605 extensions::Extension::GetBaseURLFromExtensionId(extension_id); 606 607 switch (info->reason) { 608 case extension_misc::UNLOAD_REASON_DISABLE: 609 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): " 610 << app_origin; 611 remote_file_service_->DisableOriginForTrackingChanges( 612 app_origin, 613 base::Bind(&DidHandleOriginForExtensionUnloadedEvent, 614 type, info->reason, app_origin)); 615 local_file_service_->SetOriginEnabled(app_origin, false); 616 break; 617 case extension_misc::UNLOAD_REASON_UNINSTALL: 618 DVLOG(1) << "Handle extension notification for UNLOAD(UNINSTALL): " 619 << app_origin; 620 remote_file_service_->UninstallOrigin( 621 app_origin, 622 base::Bind(&DidHandleOriginForExtensionUnloadedEvent, 623 type, info->reason, app_origin)); 624 local_file_service_->SetOriginEnabled(app_origin, false); 625 break; 626 default: 627 // Nothing to do. 628 break; 629 } 630} 631 632void SyncFileSystemService::HandleExtensionEnabled( 633 int type, 634 const content::NotificationDetails& details) { 635 std::string extension_id = 636 content::Details<const extensions::Extension>(details)->id(); 637 GURL app_origin = 638 extensions::Extension::GetBaseURLFromExtensionId(extension_id); 639 DVLOG(1) << "Handle extension notification for ENABLED: " << app_origin; 640 remote_file_service_->EnableOriginForTrackingChanges( 641 app_origin, 642 base::Bind(&DidHandleOriginForExtensionEnabledEvent, type, app_origin)); 643 local_file_service_->SetOriginEnabled(app_origin, true); 644} 645 646void SyncFileSystemService::OnStateChanged() { 647 ProfileSyncServiceBase* profile_sync_service = 648 ProfileSyncServiceFactory::GetForProfile(profile_); 649 if (profile_sync_service) 650 UpdateSyncEnabledStatus(profile_sync_service); 651} 652 653void SyncFileSystemService::OnFileStatusChanged( 654 const FileSystemURL& url, 655 SyncFileStatus sync_status, 656 SyncAction action_taken, 657 SyncDirection direction) { 658 FOR_EACH_OBSERVER( 659 SyncEventObserver, observers_, 660 OnFileSynced(url, sync_status, action_taken, direction)); 661} 662 663void SyncFileSystemService::UpdateSyncEnabledStatus( 664 ProfileSyncServiceBase* profile_sync_service) { 665 if (!profile_sync_service->HasSyncSetupCompleted()) 666 return; 667 sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has( 668 syncer::APPS); 669 remote_file_service_->SetSyncEnabled(sync_enabled_); 670 if (sync_enabled_) { 671 base::MessageLoopProxy::current()->PostTask( 672 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 673 AsWeakPtr())); 674 } 675} 676 677} // namespace sync_file_system 678