sync_file_system_service.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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_v1/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 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 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 90void 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 102std::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. 108void 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 131void 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 147SyncFileSystemService::~SyncFileSystemService() { 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 149 DCHECK(!profile_); 150} 151 152void 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 169SyncServiceState SyncFileSystemService::GetSyncServiceState() { 170 return RemoteStateToSyncServiceState(remote_file_service_->GetCurrentState()); 171} 172 173void SyncFileSystemService::GetExtensionStatusMap( 174 std::map<GURL, std::string>* status_map) { 175 DCHECK(status_map); 176 remote_file_service_->GetOriginStatusMap(status_map); 177} 178 179void 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 193void 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 223void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) { 224 observers_.AddObserver(observer); 225} 226 227void SyncFileSystemService::RemoveSyncEventObserver( 228 SyncEventObserver* observer) { 229 observers_.RemoveObserver(observer); 230} 231 232ConflictResolutionPolicy 233SyncFileSystemService::GetConflictResolutionPolicy() const { 234 return remote_file_service_->GetConflictResolutionPolicy(); 235} 236 237SyncStatusCode SyncFileSystemService::SetConflictResolutionPolicy( 238 ConflictResolutionPolicy policy) { 239 return remote_file_service_->SetConflictResolutionPolicy(policy); 240} 241 242SyncFileSystemService::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 252void 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 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_->RegisterOrigin( 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 util::Log(logging::LOG_VERBOSE, FROM_HERE, 313 "DidInitializeForApp (registered the origin): %s: %s", 314 app_origin.spec().c_str(), 315 SyncStatusCodeToString(status)); 316 317 callback.Run(status); 318} 319 320void SyncFileSystemService::DidInitializeFileSystemForDump( 321 const GURL& origin, 322 const DumpFilesCallback& callback, 323 SyncStatusCode status) { 324 DCHECK(!origin.is_empty()); 325 326 if (status != SYNC_STATUS_OK) { 327 base::ListValue empty_result; 328 callback.Run(&empty_result); 329 return; 330 } 331 332 base::ListValue* files = remote_file_service_->DumpFiles(origin).release(); 333 if (!files->GetSize()) { 334 callback.Run(files); 335 return; 336 } 337 338 base::Callback<void(base::DictionaryValue* file, 339 SyncStatusCode sync_status, 340 SyncFileStatus sync_file_status)> completion_callback = 341 base::Bind(&DidGetFileSyncStatusForDump, base::Owned(files), 342 base::Owned(new size_t(0)), callback); 343 344 // After all metadata loaded, sync status can be added to each entry. 345 for (size_t i = 0; i < files->GetSize(); ++i) { 346 base::DictionaryValue* file = NULL; 347 std::string path_string; 348 if (!files->GetDictionary(i, &file) || 349 !file->GetString("path", &path_string)) { 350 NOTREACHED(); 351 completion_callback.Run( 352 NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN); 353 continue; 354 } 355 356 base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path_string); 357 FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path); 358 GetFileSyncStatus(url, base::Bind(completion_callback, file)); 359 } 360} 361 362void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) { 363 sync_enabled_ = enabled; 364 remote_file_service_->SetSyncEnabled(sync_enabled_); 365} 366 367void SyncFileSystemService::MaybeStartSync() { 368 if (!profile_ || !sync_enabled_) 369 return; 370 371 if (pending_local_changes_ + pending_remote_changes_ == 0) 372 return; 373 374 DVLOG(2) << "MaybeStartSync() called (remote service state:" 375 << remote_file_service_->GetCurrentState() << ")"; 376 switch (remote_file_service_->GetCurrentState()) { 377 case REMOTE_SERVICE_OK: 378 break; 379 380 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE: 381 if (sync_retry_timer_.IsRunning()) 382 return; 383 sync_retry_timer_.Start( 384 FROM_HERE, 385 base::TimeDelta::FromSeconds(kRetryTimerIntervalInSeconds), 386 this, &SyncFileSystemService::MaybeStartSync); 387 break; 388 389 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED: 390 case REMOTE_SERVICE_DISABLED: 391 // No point to run sync. 392 return; 393 } 394 395 StartRemoteSync(); 396 StartLocalSync(); 397} 398 399void SyncFileSystemService::StartRemoteSync() { 400 // See if we cannot / should not start a new remote sync. 401 if (remote_sync_running_ || pending_remote_changes_ == 0) 402 return; 403 // If we have registered a URL for waiting until sync is enabled on a 404 // file (and the registerred URL seems to be still valid) it won't be 405 // worth trying to start another remote sync. 406 if (is_waiting_remote_sync_enabled_) 407 return; 408 DCHECK(sync_enabled_); 409 410 util::Log(logging::LOG_VERBOSE, FROM_HERE, 411 "Calling ProcessRemoteChange for RemoteSync"); 412 remote_sync_running_ = true; 413 remote_file_service_->ProcessRemoteChange( 414 base::Bind(&SyncFileSystemService::DidProcessRemoteChange, 415 AsWeakPtr())); 416} 417 418void SyncFileSystemService::StartLocalSync() { 419 // See if we cannot / should not start a new local sync. 420 if (local_sync_running_ || pending_local_changes_ == 0) 421 return; 422 DCHECK(sync_enabled_); 423 424 util::Log(logging::LOG_VERBOSE, FROM_HERE, 425 "Calling ProcessLocalChange for LocalSync"); 426 local_sync_running_ = true; 427 local_file_service_->ProcessLocalChange( 428 base::Bind(&SyncFileSystemService::DidProcessLocalChange, 429 AsWeakPtr())); 430} 431 432void SyncFileSystemService::DidProcessRemoteChange( 433 SyncStatusCode status, 434 const FileSystemURL& url) { 435 util::Log(logging::LOG_VERBOSE, FROM_HERE, 436 "ProcessRemoteChange finished with status=%d (%s) for url=%s", 437 status, SyncStatusCodeToString(status), url.DebugString().c_str()); 438 DCHECK(remote_sync_running_); 439 remote_sync_running_ = false; 440 441 if (status != SYNC_STATUS_NO_CHANGE_TO_SYNC && 442 remote_file_service_->GetCurrentState() != REMOTE_SERVICE_DISABLED) { 443 DCHECK(url.is_valid()); 444 local_file_service_->ClearSyncFlagForURL(url); 445 } 446 447 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC) { 448 // We seem to have no changes to work on for now. 449 // TODO(kinuko): Might be better setting a timer to call MaybeStartSync. 450 return; 451 } 452 if (status == SYNC_STATUS_FILE_BUSY) { 453 is_waiting_remote_sync_enabled_ = true; 454 local_file_service_->RegisterURLForWaitingSync( 455 url, base::Bind(&SyncFileSystemService::OnSyncEnabledForRemoteSync, 456 AsWeakPtr())); 457 return; 458 } 459 460 base::MessageLoopProxy::current()->PostTask( 461 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 462 AsWeakPtr())); 463} 464 465void SyncFileSystemService::DidProcessLocalChange( 466 SyncStatusCode status, const FileSystemURL& url) { 467 util::Log(logging::LOG_VERBOSE, FROM_HERE, 468 "ProcessLocalChange finished with status=%d (%s) for url=%s", 469 status, SyncStatusCodeToString(status), url.DebugString().c_str()); 470 DCHECK(local_sync_running_); 471 local_sync_running_ = false; 472 473 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC) { 474 // We seem to have no changes to work on for now. 475 return; 476 } 477 478 DCHECK(url.is_valid()); 479 local_file_service_->ClearSyncFlagForURL(url); 480 481 base::MessageLoopProxy::current()->PostTask( 482 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 483 AsWeakPtr())); 484} 485 486void SyncFileSystemService::DidGetLocalChangeStatus( 487 const SyncFileStatusCallback& callback, 488 SyncStatusCode status, 489 bool has_pending_local_changes) { 490 callback.Run( 491 status, 492 has_pending_local_changes ? 493 SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED); 494} 495 496void SyncFileSystemService::OnSyncEnabledForRemoteSync() { 497 is_waiting_remote_sync_enabled_ = false; 498 MaybeStartSync(); 499} 500 501void SyncFileSystemService::OnLocalChangeAvailable(int64 pending_changes) { 502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 503 DCHECK_GE(pending_changes, 0); 504 if (pending_local_changes_ != pending_changes) { 505 util::Log(logging::LOG_VERBOSE, FROM_HERE, 506 "OnLocalChangeAvailable: %" PRId64, pending_changes); 507 } 508 pending_local_changes_ = pending_changes; 509 if (pending_changes == 0) 510 return; 511 512 base::MessageLoopProxy::current()->PostTask( 513 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 514 AsWeakPtr())); 515} 516 517void SyncFileSystemService::OnRemoteChangeQueueUpdated(int64 pending_changes) { 518 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 519 DCHECK_GE(pending_changes, 0); 520 521 if (pending_remote_changes_ != pending_changes) { 522 util::Log(logging::LOG_VERBOSE, FROM_HERE, 523 "OnRemoteChangeAvailable: %" PRId64, pending_changes); 524 } 525 pending_remote_changes_ = pending_changes; 526 if (pending_changes == 0) 527 return; 528 529 // The smallest change available might have changed from the previous one. 530 // Reset the is_waiting_remote_sync_enabled_ flag so that we can retry. 531 is_waiting_remote_sync_enabled_ = false; 532 533 base::MessageLoopProxy::current()->PostTask( 534 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 535 AsWeakPtr())); 536} 537 538void SyncFileSystemService::OnRemoteServiceStateUpdated( 539 RemoteServiceState state, 540 const std::string& description) { 541 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 542 util::Log(logging::LOG_INFO, FROM_HERE, 543 "OnRemoteServiceStateChanged: %d %s", state, description.c_str()); 544 545 if (state == REMOTE_SERVICE_OK) { 546 base::MessageLoopProxy::current()->PostTask( 547 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 548 AsWeakPtr())); 549 } 550 551 FOR_EACH_OBSERVER( 552 SyncEventObserver, observers_, 553 OnSyncStateUpdated(GURL(), 554 RemoteStateToSyncServiceState(state), 555 description)); 556} 557 558void SyncFileSystemService::Observe( 559 int type, 560 const content::NotificationSource& source, 561 const content::NotificationDetails& details) { 562 // Event notification sequence. 563 // 564 // (User action) (Notification type) 565 // Install: INSTALLED. 566 // Update: INSTALLED. 567 // Uninstall: UNINSTALLED. 568 // Launch, Close: No notification. 569 // Enable: ENABLED. 570 // Disable: UNLOADED(DISABLE). 571 // Reload, Restart: UNLOADED(DISABLE) -> INSTALLED -> ENABLED. 572 // 573 switch (type) { 574 case chrome::NOTIFICATION_EXTENSION_INSTALLED: 575 HandleExtensionInstalled(details); 576 break; 577 case chrome::NOTIFICATION_EXTENSION_UNLOADED: 578 HandleExtensionUnloaded(type, details); 579 break; 580 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: 581 HandleExtensionUninstalled(type, details); 582 break; 583 case chrome::NOTIFICATION_EXTENSION_ENABLED: 584 HandleExtensionEnabled(type, details); 585 break; 586 default: 587 NOTREACHED() << "Unknown notification."; 588 break; 589 } 590} 591 592void SyncFileSystemService::HandleExtensionInstalled( 593 const content::NotificationDetails& details) { 594 const extensions::Extension* extension = 595 content::Details<const extensions::InstalledExtensionInfo>(details)-> 596 extension; 597 GURL app_origin = 598 extensions::Extension::GetBaseURLFromExtensionId(extension->id()); 599 DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin; 600 // NOTE: When an app is uninstalled and re-installed in a sequence, 601 // |local_file_service_| may still keeps |app_origin| as disabled origin. 602 local_file_service_->SetOriginEnabled(app_origin, true); 603} 604 605void SyncFileSystemService::HandleExtensionUnloaded( 606 int type, 607 const content::NotificationDetails& details) { 608 content::Details<const extensions::UnloadedExtensionInfo> info(details); 609 std::string extension_id = info->extension->id(); 610 GURL app_origin = 611 extensions::Extension::GetBaseURLFromExtensionId(extension_id); 612 if (info->reason != extension_misc::UNLOAD_REASON_DISABLE) 613 return; 614 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): " 615 << app_origin; 616 remote_file_service_->DisableOrigin( 617 app_origin, 618 base::Bind(&DidHandleOriginForExtensionUnloadedEvent, 619 type, app_origin)); 620 local_file_service_->SetOriginEnabled(app_origin, false); 621} 622 623void SyncFileSystemService::HandleExtensionUninstalled( 624 int type, 625 const content::NotificationDetails& details) { 626 std::string extension_id = 627 content::Details<const extensions::Extension>(details)->id(); 628 GURL app_origin = 629 extensions::Extension::GetBaseURLFromExtensionId(extension_id); 630 DVLOG(1) << "Handle extension notification for UNINSTALLED: " 631 << app_origin; 632 remote_file_service_->UninstallOrigin( 633 app_origin, 634 base::Bind(&DidHandleOriginForExtensionUnloadedEvent, 635 type, app_origin)); 636 local_file_service_->SetOriginEnabled(app_origin, false); 637} 638 639void SyncFileSystemService::HandleExtensionEnabled( 640 int type, 641 const content::NotificationDetails& details) { 642 std::string extension_id = 643 content::Details<const extensions::Extension>(details)->id(); 644 GURL app_origin = 645 extensions::Extension::GetBaseURLFromExtensionId(extension_id); 646 DVLOG(1) << "Handle extension notification for ENABLED: " << app_origin; 647 remote_file_service_->EnableOrigin( 648 app_origin, 649 base::Bind(&DidHandleOriginForExtensionEnabledEvent, type, app_origin)); 650 local_file_service_->SetOriginEnabled(app_origin, true); 651} 652 653void SyncFileSystemService::OnStateChanged() { 654 ProfileSyncServiceBase* profile_sync_service = 655 ProfileSyncServiceFactory::GetForProfile(profile_); 656 if (profile_sync_service) 657 UpdateSyncEnabledStatus(profile_sync_service); 658} 659 660void SyncFileSystemService::OnFileStatusChanged( 661 const FileSystemURL& url, 662 SyncFileStatus sync_status, 663 SyncAction action_taken, 664 SyncDirection direction) { 665 FOR_EACH_OBSERVER( 666 SyncEventObserver, observers_, 667 OnFileSynced(url, sync_status, action_taken, direction)); 668} 669 670void SyncFileSystemService::UpdateSyncEnabledStatus( 671 ProfileSyncServiceBase* profile_sync_service) { 672 if (!profile_sync_service->HasSyncSetupCompleted()) 673 return; 674 sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has( 675 syncer::APPS); 676 remote_file_service_->SetSyncEnabled(sync_enabled_); 677 if (sync_enabled_) { 678 base::MessageLoopProxy::current()->PostTask( 679 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 680 AsWeakPtr())); 681 } 682} 683 684} // namespace sync_file_system 685