sync_file_system_service.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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/metrics/histogram.h" 14#include "base/stl_util.h" 15#include "chrome/browser/chrome_notification_types.h" 16#include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h" 17#include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.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/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_process_runner.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 "components/keyed_service/content/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 "extensions/browser/extension_prefs.h" 35#include "extensions/common/extension.h" 36#include "extensions/common/manifest_constants.h" 37#include "url/gurl.h" 38#include "webkit/browser/fileapi/file_system_context.h" 39 40using content::BrowserThread; 41using extensions::Extension; 42using extensions::ExtensionPrefs; 43using fileapi::FileSystemURL; 44using fileapi::FileSystemURLSet; 45 46namespace sync_file_system { 47 48namespace { 49 50const char kLocalSyncName[] = "Local sync"; 51const char kRemoteSyncName[] = "Remote sync"; 52const char kRemoteSyncNameV2[] = "Remote sync (v2)"; 53 54SyncServiceState RemoteStateToSyncServiceState( 55 RemoteServiceState state) { 56 switch (state) { 57 case REMOTE_SERVICE_OK: 58 return SYNC_SERVICE_RUNNING; 59 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE: 60 return SYNC_SERVICE_TEMPORARY_UNAVAILABLE; 61 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED: 62 return SYNC_SERVICE_AUTHENTICATION_REQUIRED; 63 case REMOTE_SERVICE_DISABLED: 64 return SYNC_SERVICE_DISABLED; 65 case REMOTE_SERVICE_STATE_MAX: 66 NOTREACHED(); 67 } 68 NOTREACHED() << "Unknown remote service state: " << state; 69 return SYNC_SERVICE_DISABLED; 70} 71 72void DidHandleOriginForExtensionUnloadedEvent( 73 int type, 74 const GURL& origin, 75 SyncStatusCode code) { 76 DCHECK(chrome::NOTIFICATION_EXTENSION_UNLOADED == type || 77 chrome::NOTIFICATION_EXTENSION_UNINSTALLED == type); 78 if (code != SYNC_STATUS_OK && 79 code != SYNC_STATUS_UNKNOWN_ORIGIN) { 80 switch (type) { 81 case chrome::NOTIFICATION_EXTENSION_UNLOADED: 82 util::Log(logging::LOG_WARNING, 83 FROM_HERE, 84 "Disabling origin for UNLOADED(DISABLE) failed: %s", 85 origin.spec().c_str()); 86 break; 87 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: 88 util::Log(logging::LOG_WARNING, 89 FROM_HERE, 90 "Uninstall origin for UNINSTALLED failed: %s", 91 origin.spec().c_str()); 92 break; 93 default: 94 break; 95 } 96 } 97} 98 99void DidHandleOriginForExtensionEnabledEvent( 100 int type, 101 const GURL& origin, 102 SyncStatusCode code) { 103 DCHECK(chrome::NOTIFICATION_EXTENSION_ENABLED == type); 104 if (code != SYNC_STATUS_OK) 105 util::Log(logging::LOG_WARNING, 106 FROM_HERE, 107 "Enabling origin for ENABLED failed: %s", 108 origin.spec().c_str()); 109} 110 111std::string SyncFileStatusToString(SyncFileStatus sync_file_status) { 112 return extensions::api::sync_file_system::ToString( 113 extensions::SyncFileStatusToExtensionEnum(sync_file_status)); 114} 115 116// Gets called repeatedly until every SyncFileStatus has been mapped. 117void DidGetFileSyncStatusForDump( 118 base::ListValue* files, 119 size_t* num_results, 120 const SyncFileSystemService::DumpFilesCallback& callback, 121 base::DictionaryValue* file, 122 SyncStatusCode sync_status_code, 123 SyncFileStatus sync_file_status) { 124 DCHECK(files); 125 DCHECK(num_results); 126 127 if (file) 128 file->SetString("status", SyncFileStatusToString(sync_file_status)); 129 130 // Once all results have been received, run the callback to signal end. 131 DCHECK_LE(*num_results, files->GetSize()); 132 if (++*num_results < files->GetSize()) 133 return; 134 135 callback.Run(files); 136} 137 138// We need this indirection because WeakPtr can only be bound to methods 139// without a return value. 140LocalChangeProcessor* GetLocalChangeProcessorAdapter( 141 base::WeakPtr<SyncFileSystemService> service, 142 const GURL& origin) { 143 if (!service) 144 return NULL; 145 return service->GetLocalChangeProcessor(origin); 146} 147 148} // namespace 149 150//--------------------------------------------------------------------------- 151// SyncProcessRunner's. 152 153// SyncProcessRunner implementation for LocalSync. 154class LocalSyncRunner : public SyncProcessRunner, 155 public LocalFileSyncService::Observer { 156 public: 157 LocalSyncRunner(const std::string& name, 158 SyncFileSystemService* sync_service) 159 : SyncProcessRunner(name, sync_service), 160 factory_(this) {} 161 162 virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE { 163 sync_service()->local_service_->ProcessLocalChange( 164 base::Bind(&LocalSyncRunner::DidProcessLocalChange, 165 factory_.GetWeakPtr(), callback)); 166 } 167 168 // LocalFileSyncService::Observer overrides. 169 virtual void OnLocalChangeAvailable(int64 pending_changes) OVERRIDE { 170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 171 172 OnChangesUpdated(pending_changes); 173 174 // Kick other sync runners just in case they're not running. 175 sync_service()->RunForEachSyncRunners( 176 &SyncProcessRunner::ScheduleIfNotRunning); 177 } 178 179 private: 180 void DidProcessLocalChange( 181 const SyncStatusCallback& callback, 182 SyncStatusCode status, 183 const FileSystemURL& url) { 184 util::Log(logging::LOG_VERBOSE, FROM_HERE, 185 "ProcessLocalChange finished with status=%d (%s) for url=%s", 186 status, SyncStatusCodeToString(status), 187 url.DebugString().c_str()); 188 callback.Run(status); 189 } 190 191 base::WeakPtrFactory<LocalSyncRunner> factory_; 192 DISALLOW_COPY_AND_ASSIGN(LocalSyncRunner); 193}; 194 195// SyncProcessRunner implementation for RemoteSync. 196class RemoteSyncRunner : public SyncProcessRunner, 197 public RemoteFileSyncService::Observer { 198 public: 199 RemoteSyncRunner(const std::string& name, 200 SyncFileSystemService* sync_service, 201 RemoteFileSyncService* remote_service) 202 : SyncProcessRunner(name, sync_service), 203 remote_service_(remote_service), 204 last_state_(REMOTE_SERVICE_OK), 205 factory_(this) {} 206 207 virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE { 208 remote_service_->ProcessRemoteChange( 209 base::Bind(&RemoteSyncRunner::DidProcessRemoteChange, 210 factory_.GetWeakPtr(), callback)); 211 } 212 213 virtual SyncServiceState GetServiceState() OVERRIDE { 214 return RemoteStateToSyncServiceState(last_state_); 215 } 216 217 // RemoteFileSyncService::Observer overrides. 218 virtual void OnRemoteChangeQueueUpdated(int64 pending_changes) OVERRIDE { 219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 220 221 OnChangesUpdated(pending_changes); 222 223 // Kick other sync runners just in case they're not running. 224 sync_service()->RunForEachSyncRunners( 225 &SyncProcessRunner::ScheduleIfNotRunning); 226 } 227 228 virtual void OnRemoteServiceStateUpdated( 229 RemoteServiceState state, 230 const std::string& description) OVERRIDE { 231 // Just forward to SyncFileSystemService. 232 sync_service()->OnRemoteServiceStateUpdated(state, description); 233 last_state_ = state; 234 } 235 236 private: 237 void DidProcessRemoteChange( 238 const SyncStatusCallback& callback, 239 SyncStatusCode status, 240 const FileSystemURL& url) { 241 util::Log(logging::LOG_VERBOSE, FROM_HERE, 242 "ProcessRemoteChange finished with status=%d (%s) for url=%s", 243 status, SyncStatusCodeToString(status), 244 url.DebugString().c_str()); 245 246 if (status == SYNC_STATUS_FILE_BUSY) { 247 sync_service()->local_service_->RegisterURLForWaitingSync( 248 url, base::Bind(&RemoteSyncRunner::Schedule, 249 factory_.GetWeakPtr())); 250 } 251 callback.Run(status); 252 } 253 254 RemoteFileSyncService* remote_service_; 255 RemoteServiceState last_state_; 256 base::WeakPtrFactory<RemoteSyncRunner> factory_; 257 DISALLOW_COPY_AND_ASSIGN(RemoteSyncRunner); 258}; 259 260//----------------------------------------------------------------------------- 261// SyncFileSystemService 262 263void SyncFileSystemService::Shutdown() { 264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 265 266 local_service_->Shutdown(); 267 local_service_.reset(); 268 269 remote_service_.reset(); 270 v2_remote_service_.reset(); 271 272 ProfileSyncServiceBase* profile_sync_service = 273 ProfileSyncServiceFactory::GetForProfile(profile_); 274 if (profile_sync_service) 275 profile_sync_service->RemoveObserver(this); 276 277 profile_ = NULL; 278} 279 280SyncFileSystemService::~SyncFileSystemService() { 281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 282 DCHECK(!profile_); 283} 284 285void SyncFileSystemService::InitializeForApp( 286 fileapi::FileSystemContext* file_system_context, 287 const GURL& app_origin, 288 const SyncStatusCallback& callback) { 289 DCHECK(local_service_); 290 DCHECK(remote_service_); 291 DCHECK(app_origin == app_origin.GetOrigin()); 292 293 util::Log(logging::LOG_VERBOSE, FROM_HERE, 294 "Initializing for App: %s", app_origin.spec().c_str()); 295 296 local_service_->MaybeInitializeFileSystemContext( 297 app_origin, file_system_context, 298 base::Bind(&SyncFileSystemService::DidInitializeFileSystem, 299 AsWeakPtr(), app_origin, callback)); 300} 301 302SyncServiceState SyncFileSystemService::GetSyncServiceState() { 303 // For now we always query the state from the main RemoteFileSyncService. 304 return RemoteStateToSyncServiceState(remote_service_->GetCurrentState()); 305} 306 307void SyncFileSystemService::GetExtensionStatusMap( 308 std::map<GURL, std::string>* status_map) { 309 DCHECK(status_map); 310 status_map->clear(); 311 remote_service_->GetOriginStatusMap(status_map); 312 if (v2_remote_service_) 313 v2_remote_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_service_->MaybeInitializeFileSystemContext( 325 origin, file_system_context, 326 base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump, 327 AsWeakPtr(), origin, callback)); 328} 329 330scoped_ptr<base::ListValue> SyncFileSystemService::DumpDatabase() { 331 scoped_ptr<base::ListValue> list = remote_service_->DumpDatabase(); 332 if (!list) 333 list.reset(new base::ListValue); 334 if (v2_remote_service_) { 335 scoped_ptr<base::ListValue> v2list = v2_remote_service_->DumpDatabase(); 336 if (!v2list) 337 return list.Pass(); 338 for (base::ListValue::iterator itr = v2list->begin(); 339 itr != v2list->end(); ) { 340 scoped_ptr<base::Value> item; 341 itr = v2list->Erase(itr, &item); 342 list->Append(item.release()); 343 } 344 } 345 return list.Pass(); 346} 347 348void SyncFileSystemService::GetFileSyncStatus( 349 const FileSystemURL& url, const SyncFileStatusCallback& callback) { 350 DCHECK(local_service_); 351 DCHECK(GetRemoteService(url.origin())); 352 353 // It's possible to get an invalid FileEntry. 354 if (!url.is_valid()) { 355 base::MessageLoopProxy::current()->PostTask( 356 FROM_HERE, 357 base::Bind(callback, 358 SYNC_FILE_ERROR_INVALID_URL, 359 SYNC_FILE_STATUS_UNKNOWN)); 360 return; 361 } 362 363 if (GetRemoteService(url.origin())->IsConflicting(url)) { 364 base::MessageLoopProxy::current()->PostTask( 365 FROM_HERE, 366 base::Bind(callback, 367 SYNC_STATUS_OK, 368 SYNC_FILE_STATUS_CONFLICTING)); 369 return; 370 } 371 372 local_service_->HasPendingLocalChanges( 373 url, 374 base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus, 375 AsWeakPtr(), callback)); 376} 377 378void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) { 379 observers_.AddObserver(observer); 380} 381 382void SyncFileSystemService::RemoveSyncEventObserver( 383 SyncEventObserver* observer) { 384 observers_.RemoveObserver(observer); 385} 386 387ConflictResolutionPolicy SyncFileSystemService::GetConflictResolutionPolicy( 388 const GURL& origin) { 389 return GetRemoteService(origin)->GetConflictResolutionPolicy(origin); 390} 391 392SyncStatusCode SyncFileSystemService::SetConflictResolutionPolicy( 393 const GURL& origin, 394 ConflictResolutionPolicy policy) { 395 UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.ConflictResolutionPolicy", 396 policy, CONFLICT_RESOLUTION_POLICY_MAX); 397 return GetRemoteService(origin)->SetConflictResolutionPolicy(origin, policy); 398} 399 400LocalChangeProcessor* SyncFileSystemService::GetLocalChangeProcessor( 401 const GURL& origin) { 402 return GetRemoteService(origin)->GetLocalChangeProcessor(); 403} 404 405SyncFileSystemService::SyncFileSystemService(Profile* profile) 406 : profile_(profile), 407 sync_enabled_(true) { 408} 409 410void SyncFileSystemService::Initialize( 411 scoped_ptr<LocalFileSyncService> local_service, 412 scoped_ptr<RemoteFileSyncService> remote_service) { 413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 414 DCHECK(local_service); 415 DCHECK(remote_service); 416 DCHECK(profile_); 417 418 local_service_ = local_service.Pass(); 419 remote_service_ = remote_service.Pass(); 420 421 scoped_ptr<LocalSyncRunner> local_syncer( 422 new LocalSyncRunner(kLocalSyncName, this)); 423 scoped_ptr<RemoteSyncRunner> remote_syncer( 424 new RemoteSyncRunner(kRemoteSyncName, this, remote_service_.get())); 425 426 local_service_->AddChangeObserver(local_syncer.get()); 427 local_service_->SetLocalChangeProcessorCallback( 428 base::Bind(&GetLocalChangeProcessorAdapter, AsWeakPtr())); 429 430 remote_service_->AddServiceObserver(remote_syncer.get()); 431 remote_service_->AddFileStatusObserver(this); 432 remote_service_->SetRemoteChangeProcessor(local_service_.get()); 433 434 local_sync_runners_.push_back(local_syncer.release()); 435 remote_sync_runners_.push_back(remote_syncer.release()); 436 437 ProfileSyncServiceBase* profile_sync_service = 438 ProfileSyncServiceFactory::GetForProfile(profile_); 439 if (profile_sync_service) { 440 UpdateSyncEnabledStatus(profile_sync_service); 441 profile_sync_service->AddObserver(this); 442 } 443 444 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 445 content::Source<Profile>(profile_)); 446 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 447 content::Source<Profile>(profile_)); 448 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 449 content::Source<Profile>(profile_)); 450 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED, 451 content::Source<Profile>(profile_)); 452} 453 454void SyncFileSystemService::DidInitializeFileSystem( 455 const GURL& app_origin, 456 const SyncStatusCallback& callback, 457 SyncStatusCode status) { 458 DVLOG(1) << "DidInitializeFileSystem: " 459 << app_origin.spec() << " " << status; 460 461 if (status != SYNC_STATUS_OK) { 462 callback.Run(status); 463 return; 464 } 465 466 // Local side of initialization for the app is done. 467 // Continue on initializing the remote side. 468 GetRemoteService(app_origin)->RegisterOrigin( 469 app_origin, 470 base::Bind(&SyncFileSystemService::DidRegisterOrigin, 471 AsWeakPtr(), app_origin, callback)); 472} 473 474void SyncFileSystemService::DidRegisterOrigin( 475 const GURL& app_origin, 476 const SyncStatusCallback& callback, 477 SyncStatusCode status) { 478 util::Log(logging::LOG_VERBOSE, FROM_HERE, 479 "DidInitializeForApp (registered the origin): %s: %s", 480 app_origin.spec().c_str(), 481 SyncStatusCodeToString(status)); 482 483 UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.RegisterOriginResult", 484 GetRemoteService(app_origin)->GetCurrentState(), 485 REMOTE_SERVICE_STATE_MAX); 486 487 if (status == SYNC_STATUS_FAILED) { 488 // If we got generic error return the service status information. 489 switch (GetRemoteService(app_origin)->GetCurrentState()) { 490 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED: 491 callback.Run(SYNC_STATUS_AUTHENTICATION_FAILED); 492 return; 493 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE: 494 callback.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE); 495 return; 496 default: 497 break; 498 } 499 } 500 501 callback.Run(status); 502} 503 504void SyncFileSystemService::DidInitializeFileSystemForDump( 505 const GURL& origin, 506 const DumpFilesCallback& callback, 507 SyncStatusCode status) { 508 DCHECK(!origin.is_empty()); 509 510 if (status != SYNC_STATUS_OK) { 511 base::ListValue empty_result; 512 callback.Run(&empty_result); 513 return; 514 } 515 516 base::ListValue* files = 517 GetRemoteService(origin)->DumpFiles(origin).release(); 518 if (!files) { 519 callback.Run(new base::ListValue); 520 return; 521 } 522 523 if (!files->GetSize()) { 524 callback.Run(files); 525 return; 526 } 527 528 base::Callback<void(base::DictionaryValue* file, 529 SyncStatusCode sync_status, 530 SyncFileStatus sync_file_status)> completion_callback = 531 base::Bind(&DidGetFileSyncStatusForDump, base::Owned(files), 532 base::Owned(new size_t(0)), callback); 533 534 // After all metadata loaded, sync status can be added to each entry. 535 for (size_t i = 0; i < files->GetSize(); ++i) { 536 base::DictionaryValue* file = NULL; 537 std::string path_string; 538 if (!files->GetDictionary(i, &file) || 539 !file->GetString("path", &path_string)) { 540 NOTREACHED(); 541 completion_callback.Run( 542 NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN); 543 continue; 544 } 545 546 base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path_string); 547 FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path); 548 GetFileSyncStatus(url, base::Bind(completion_callback, file)); 549 } 550} 551 552void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) { 553 sync_enabled_ = enabled; 554 remote_service_->SetSyncEnabled(sync_enabled_); 555 if (v2_remote_service_) 556 v2_remote_service_->SetSyncEnabled(sync_enabled_); 557} 558 559void SyncFileSystemService::DidGetLocalChangeStatus( 560 const SyncFileStatusCallback& callback, 561 SyncStatusCode status, 562 bool has_pending_local_changes) { 563 callback.Run( 564 status, 565 has_pending_local_changes ? 566 SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED); 567} 568 569void SyncFileSystemService::OnSyncIdle() { 570 int64 remote_changes = 0; 571 for (ScopedVector<SyncProcessRunner>::iterator iter = 572 remote_sync_runners_.begin(); 573 iter != remote_sync_runners_.end(); ++iter) 574 remote_changes += (*iter)->pending_changes(); 575 if (remote_changes == 0) 576 local_service_->PromoteDemotedChanges(); 577 578 int64 local_changes = 0; 579 for (ScopedVector<SyncProcessRunner>::iterator iter = 580 local_sync_runners_.begin(); 581 iter != local_sync_runners_.end(); ++iter) 582 local_changes += (*iter)->pending_changes(); 583 if (local_changes == 0 && v2_remote_service_) 584 v2_remote_service_->PromoteDemotedChanges(); 585} 586 587void SyncFileSystemService::OnRemoteServiceStateUpdated( 588 RemoteServiceState state, 589 const std::string& description) { 590 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 591 util::Log(logging::LOG_VERBOSE, FROM_HERE, 592 "OnRemoteServiceStateChanged: %d %s", state, description.c_str()); 593 594 FOR_EACH_OBSERVER( 595 SyncEventObserver, observers_, 596 OnSyncStateUpdated(GURL(), 597 RemoteStateToSyncServiceState(state), 598 description)); 599 600 RunForEachSyncRunners(&SyncProcessRunner::Schedule); 601} 602 603void SyncFileSystemService::Observe( 604 int type, 605 const content::NotificationSource& source, 606 const content::NotificationDetails& details) { 607 // Event notification sequence. 608 // 609 // (User action) (Notification type) 610 // Install: INSTALLED. 611 // Update: INSTALLED. 612 // Uninstall: UNINSTALLED. 613 // Launch, Close: No notification. 614 // Enable: ENABLED. 615 // Disable: UNLOADED(DISABLE). 616 // Reload, Restart: UNLOADED(DISABLE) -> INSTALLED -> ENABLED. 617 // 618 switch (type) { 619 case chrome::NOTIFICATION_EXTENSION_INSTALLED: 620 HandleExtensionInstalled(details); 621 break; 622 case chrome::NOTIFICATION_EXTENSION_UNLOADED: 623 HandleExtensionUnloaded(type, details); 624 break; 625 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: 626 HandleExtensionUninstalled(type, details); 627 break; 628 case chrome::NOTIFICATION_EXTENSION_ENABLED: 629 HandleExtensionEnabled(type, details); 630 break; 631 default: 632 NOTREACHED() << "Unknown notification."; 633 break; 634 } 635} 636 637void SyncFileSystemService::HandleExtensionInstalled( 638 const content::NotificationDetails& details) { 639 const Extension* extension = 640 content::Details<const extensions::InstalledExtensionInfo>(details)-> 641 extension; 642 GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id()); 643 DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin; 644 // NOTE: When an app is uninstalled and re-installed in a sequence, 645 // |local_service_| may still keeps |app_origin| as disabled origin. 646 local_service_->SetOriginEnabled(app_origin, true); 647} 648 649void SyncFileSystemService::HandleExtensionUnloaded( 650 int type, 651 const content::NotificationDetails& details) { 652 content::Details<const extensions::UnloadedExtensionInfo> info(details); 653 if (info->reason != extensions::UnloadedExtensionInfo::REASON_DISABLE) 654 return; 655 656 std::string extension_id = info->extension->id(); 657 GURL app_origin = Extension::GetBaseURLFromExtensionId(extension_id); 658 659 int reasons = ExtensionPrefs::Get(profile_)->GetDisableReasons(extension_id); 660 if (reasons & Extension::DISABLE_RELOAD) { 661 // Bypass disabling the origin since the app will be re-enabled soon. 662 // NOTE: If re-enabling the app fails, the app is disabled while it is 663 // handled as enabled origin in the SyncFS. This should be safe and will be 664 // recovered when the user re-enables the app manually or the sync service 665 // restarts. 666 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): " 667 << app_origin; 668 return; 669 } 670 671 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): " 672 << app_origin; 673 GetRemoteService(app_origin)->DisableOrigin( 674 app_origin, 675 base::Bind(&DidHandleOriginForExtensionUnloadedEvent, 676 type, app_origin)); 677 local_service_->SetOriginEnabled(app_origin, false); 678} 679 680void SyncFileSystemService::HandleExtensionUninstalled( 681 int type, 682 const content::NotificationDetails& details) { 683 const Extension* extension = content::Details<const Extension>(details).ptr(); 684 DCHECK(extension); 685 686 RemoteFileSyncService::UninstallFlag flag = 687 RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE; 688 // If it's loaded from an unpacked package and with key: field, 689 // the uninstall will not be sync'ed and the user might be using the 690 // same app key in other installs, so avoid purging the remote folder. 691 if (extensions::Manifest::IsUnpackedLocation(extension->location()) && 692 extension->manifest()->HasKey(extensions::manifest_keys::kKey)) { 693 flag = RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE; 694 } 695 696 GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id()); 697 DVLOG(1) << "Handle extension notification for UNINSTALLED: " 698 << app_origin; 699 GetRemoteService(app_origin)->UninstallOrigin( 700 app_origin, flag, 701 base::Bind(&DidHandleOriginForExtensionUnloadedEvent, 702 type, app_origin)); 703 local_service_->SetOriginEnabled(app_origin, false); 704} 705 706void SyncFileSystemService::HandleExtensionEnabled( 707 int type, 708 const content::NotificationDetails& details) { 709 std::string extension_id = content::Details<const Extension>(details)->id(); 710 GURL app_origin = Extension::GetBaseURLFromExtensionId(extension_id); 711 DVLOG(1) << "Handle extension notification for ENABLED: " << app_origin; 712 GetRemoteService(app_origin)->EnableOrigin( 713 app_origin, 714 base::Bind(&DidHandleOriginForExtensionEnabledEvent, type, app_origin)); 715 local_service_->SetOriginEnabled(app_origin, true); 716} 717 718void SyncFileSystemService::OnStateChanged() { 719 ProfileSyncServiceBase* profile_sync_service = 720 ProfileSyncServiceFactory::GetForProfile(profile_); 721 if (profile_sync_service) 722 UpdateSyncEnabledStatus(profile_sync_service); 723} 724 725void SyncFileSystemService::OnFileStatusChanged( 726 const FileSystemURL& url, 727 SyncFileStatus sync_status, 728 SyncAction action_taken, 729 SyncDirection direction) { 730 FOR_EACH_OBSERVER( 731 SyncEventObserver, observers_, 732 OnFileSynced(url, sync_status, action_taken, direction)); 733} 734 735void SyncFileSystemService::UpdateSyncEnabledStatus( 736 ProfileSyncServiceBase* profile_sync_service) { 737 if (!profile_sync_service->HasSyncSetupCompleted()) 738 return; 739 bool old_sync_enabled = sync_enabled_; 740 sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has( 741 syncer::APPS); 742 remote_service_->SetSyncEnabled(sync_enabled_); 743 if (v2_remote_service_) 744 v2_remote_service_->SetSyncEnabled(sync_enabled_); 745 if (!old_sync_enabled && sync_enabled_) 746 RunForEachSyncRunners(&SyncProcessRunner::Schedule); 747} 748 749void SyncFileSystemService::RunForEachSyncRunners( 750 void(SyncProcessRunner::*method)()) { 751 for (ScopedVector<SyncProcessRunner>::iterator iter = 752 local_sync_runners_.begin(); 753 iter != local_sync_runners_.end(); ++iter) 754 ((*iter)->*method)(); 755 for (ScopedVector<SyncProcessRunner>::iterator iter = 756 remote_sync_runners_.begin(); 757 iter != remote_sync_runners_.end(); ++iter) 758 ((*iter)->*method)(); 759} 760 761RemoteFileSyncService* SyncFileSystemService::GetRemoteService( 762 const GURL& origin) { 763 if (IsV2Enabled()) 764 return remote_service_.get(); 765 if (!IsV2EnabledForOrigin(origin)) 766 return remote_service_.get(); 767 768 if (!v2_remote_service_) { 769 v2_remote_service_ = RemoteFileSyncService::CreateForBrowserContext( 770 RemoteFileSyncService::V2, profile_); 771 scoped_ptr<RemoteSyncRunner> v2_remote_syncer( 772 new RemoteSyncRunner(kRemoteSyncNameV2, this, 773 v2_remote_service_.get())); 774 v2_remote_service_->AddServiceObserver(v2_remote_syncer.get()); 775 v2_remote_service_->AddFileStatusObserver(this); 776 v2_remote_service_->SetRemoteChangeProcessor(local_service_.get()); 777 v2_remote_service_->SetSyncEnabled(sync_enabled_); 778 v2_remote_service_->SetDefaultConflictResolutionPolicy( 779 remote_service_->GetDefaultConflictResolutionPolicy()); 780 remote_sync_runners_.push_back(v2_remote_syncer.release()); 781 } 782 return v2_remote_service_.get(); 783} 784 785} // namespace sync_file_system 786