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