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