sync_file_system_service.cc revision 868fa2fe829687343ffae624259930155e16dbd8
14a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// Copyright (c) 2012 The Chromium Authors. All rights reserved. 24a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// Use of this source code is governed by a BSD-style license that can be 34a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// found in the LICENSE file. 44a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project 54a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "chrome/browser/sync_file_system/sync_file_system_service.h" 64a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project 74a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include <string> 84a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project 94a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "base/bind.h" 104a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "base/logging.h" 114a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "base/memory/ref_counted.h" 124a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "base/stl_util.h" 134a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h" 144a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "chrome/browser/profiles/profile.h" 154a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "chrome/browser/sync/profile_sync_service.h" 164a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "chrome/browser/sync/profile_sync_service_factory.h" 174a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "chrome/browser/sync_file_system/drive_file_sync_service.h" 184a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "chrome/browser/sync_file_system/local_file_sync_service.h" 194a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "chrome/browser/sync_file_system/logger.h" 204a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "chrome/browser/sync_file_system/sync_event_observer.h" 214a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "chrome/common/chrome_notification_types.h" 224a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "chrome/common/extensions/extension.h" 234a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "components/browser_context_keyed_service/browser_context_dependency_manager.h" 244a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "content/public/browser/browser_thread.h" 254a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "content/public/browser/notification_details.h" 264a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "content/public/browser/notification_service.h" 274a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "googleurl/src/gurl.h" 284a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "webkit/browser/fileapi/file_system_context.h" 294a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "webkit/browser/fileapi/syncable/sync_direction.h" 304a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "webkit/browser/fileapi/syncable/sync_file_metadata.h" 314a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "webkit/browser/fileapi/syncable/sync_status_code.h" 324a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project 334a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectusing content::BrowserThread; 344a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectusing fileapi::FileSystemURL; 354a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectusing fileapi::FileSystemURLSet; 364a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project 374a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectnamespace sync_file_system { 384a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project 394a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectnamespace { 404a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project 414a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectconst int64 kRetryTimerIntervalInSeconds = 20 * 60; // 20 min. 424a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project 434a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source ProjectSyncServiceState RemoteStateToSyncServiceState( 444a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project RemoteServiceState state) { 454a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project switch (state) { 464a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project case REMOTE_SERVICE_OK: 474a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project return SYNC_SERVICE_RUNNING; 484a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE: 494a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project return SYNC_SERVICE_TEMPORARY_UNAVAILABLE; 504a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project case REMOTE_SERVICE_AUTHENTICATION_REQUIRED: 514a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project return SYNC_SERVICE_AUTHENTICATION_REQUIRED; 524a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project case REMOTE_SERVICE_DISABLED: 534a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project return SYNC_SERVICE_DISABLED; 544a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project } 554a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project NOTREACHED() << "Unknown remote service state: " << state; 564a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project return SYNC_SERVICE_DISABLED; 574a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project} 584a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project 594a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectvoid DidHandleOriginForExtensionUnloadedEvent( 604a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project int type, 614a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project extension_misc::UnloadedExtensionReason reason, 624a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project const GURL& origin, 634a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project SyncStatusCode code) { 644a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project DCHECK(chrome::NOTIFICATION_EXTENSION_UNLOADED == type); 654a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project DCHECK(extension_misc::UNLOAD_REASON_DISABLE == reason || 664a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project extension_misc::UNLOAD_REASON_UNINSTALL == reason); 674a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project if (code != SYNC_STATUS_OK && 684a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project code != SYNC_STATUS_UNKNOWN_ORIGIN) { 694a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project switch (reason) { 704a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project case extension_misc::UNLOAD_REASON_DISABLE: 714a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project util::Log(logging::LOG_WARNING, 724a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project FROM_HERE, 734a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project "Disabling origin for UNLOAD(DISABLE) failed: %s", 744a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project origin.spec().c_str()); 754a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project break; 764a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project case extension_misc::UNLOAD_REASON_UNINSTALL: 774a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project util::Log(logging::LOG_WARNING, 784a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project FROM_HERE, 794a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project "Uninstall origin for UNLOAD(UNINSTALL) failed: %s", 804a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project origin.spec().c_str()); 814a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project break; 824a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project default: 834a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project break; 844a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project } 854a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project } 864a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project} 87 88void DidHandleOriginForExtensionEnabledEvent( 89 int type, 90 const GURL& origin, 91 SyncStatusCode code) { 92 DCHECK(chrome::NOTIFICATION_EXTENSION_ENABLED == type); 93 if (code != SYNC_STATUS_OK) 94 util::Log(logging::LOG_WARNING, 95 FROM_HERE, 96 "Enabling origin for ENABLED failed: %s", 97 origin.spec().c_str()); 98} 99 100} // namespace 101 102void SyncFileSystemService::Shutdown() { 103 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 104 105 local_file_service_->Shutdown(); 106 local_file_service_.reset(); 107 108 remote_file_service_.reset(); 109 110 ProfileSyncServiceBase* profile_sync_service = 111 ProfileSyncServiceFactory::GetForProfile(profile_); 112 if (profile_sync_service) 113 profile_sync_service->RemoveObserver(this); 114 115 profile_ = NULL; 116} 117 118SyncFileSystemService::~SyncFileSystemService() { 119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 120 DCHECK(!profile_); 121} 122 123void SyncFileSystemService::InitializeForApp( 124 fileapi::FileSystemContext* file_system_context, 125 const GURL& app_origin, 126 const SyncStatusCallback& callback) { 127 DCHECK(local_file_service_); 128 DCHECK(remote_file_service_); 129 DCHECK(app_origin == app_origin.GetOrigin()); 130 131 DVLOG(1) << "InitializeForApp: " << app_origin.spec(); 132 133 local_file_service_->MaybeInitializeFileSystemContext( 134 app_origin, file_system_context, 135 base::Bind(&SyncFileSystemService::DidInitializeFileSystem, 136 AsWeakPtr(), app_origin, callback)); 137} 138 139SyncServiceState SyncFileSystemService::GetSyncServiceState() { 140 return RemoteStateToSyncServiceState(remote_file_service_->GetCurrentState()); 141} 142 143void SyncFileSystemService::GetExtensionStatusMap( 144 std::map<GURL, std::string>* status_map) { 145 DCHECK(status_map); 146 remote_file_service_->GetOriginStatusMap(status_map); 147} 148 149void SyncFileSystemService::GetFileSyncStatus( 150 const FileSystemURL& url, const SyncFileStatusCallback& callback) { 151 DCHECK(local_file_service_); 152 DCHECK(remote_file_service_); 153 154 // It's possible to get an invalid FileEntry. 155 if (!url.is_valid()) { 156 base::MessageLoopProxy::current()->PostTask( 157 FROM_HERE, 158 base::Bind(callback, 159 SYNC_FILE_ERROR_INVALID_URL, 160 SYNC_FILE_STATUS_UNKNOWN)); 161 return; 162 } 163 164 if (remote_file_service_->IsConflicting(url)) { 165 base::MessageLoopProxy::current()->PostTask( 166 FROM_HERE, 167 base::Bind(callback, 168 SYNC_STATUS_OK, 169 SYNC_FILE_STATUS_CONFLICTING)); 170 return; 171 } 172 173 local_file_service_->HasPendingLocalChanges( 174 url, 175 base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus, 176 AsWeakPtr(), callback)); 177} 178 179void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) { 180 observers_.AddObserver(observer); 181} 182 183void SyncFileSystemService::RemoveSyncEventObserver( 184 SyncEventObserver* observer) { 185 observers_.RemoveObserver(observer); 186} 187 188ConflictResolutionPolicy 189SyncFileSystemService::GetConflictResolutionPolicy() const { 190 return remote_file_service_->GetConflictResolutionPolicy(); 191} 192 193SyncStatusCode SyncFileSystemService::SetConflictResolutionPolicy( 194 ConflictResolutionPolicy policy) { 195 return remote_file_service_->SetConflictResolutionPolicy(policy); 196} 197 198SyncFileSystemService::SyncFileSystemService(Profile* profile) 199 : profile_(profile), 200 pending_local_changes_(0), 201 pending_remote_changes_(0), 202 local_sync_running_(false), 203 remote_sync_running_(false), 204 is_waiting_remote_sync_enabled_(false), 205 sync_enabled_(true) { 206} 207 208void SyncFileSystemService::Initialize( 209 scoped_ptr<LocalFileSyncService> local_file_service, 210 scoped_ptr<RemoteFileSyncService> remote_file_service) { 211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 212 DCHECK(local_file_service); 213 DCHECK(remote_file_service); 214 DCHECK(profile_); 215 216 local_file_service_ = local_file_service.Pass(); 217 remote_file_service_ = remote_file_service.Pass(); 218 219 local_file_service_->AddChangeObserver(this); 220 local_file_service_->SetLocalChangeProcessor( 221 remote_file_service_->GetLocalChangeProcessor()); 222 223 remote_file_service_->AddServiceObserver(this); 224 remote_file_service_->AddFileStatusObserver(this); 225 remote_file_service_->SetRemoteChangeProcessor(local_file_service_.get()); 226 227 ProfileSyncServiceBase* profile_sync_service = 228 ProfileSyncServiceFactory::GetForProfile(profile_); 229 if (profile_sync_service) { 230 UpdateSyncEnabledStatus(profile_sync_service); 231 profile_sync_service->AddObserver(this); 232 } 233 234 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 235 content::Source<Profile>(profile_)); 236 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 237 content::Source<Profile>(profile_)); 238 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED, 239 content::Source<Profile>(profile_)); 240} 241 242void SyncFileSystemService::DidInitializeFileSystem( 243 const GURL& app_origin, 244 const SyncStatusCallback& callback, 245 SyncStatusCode status) { 246 DVLOG(1) << "DidInitializeFileSystem: " 247 << app_origin.spec() << " " << status; 248 249 if (status != SYNC_STATUS_OK) { 250 callback.Run(status); 251 return; 252 } 253 254 // Local side of initialization for the app is done. 255 // Continue on initializing the remote side. 256 remote_file_service_->RegisterOriginForTrackingChanges( 257 app_origin, 258 base::Bind(&SyncFileSystemService::DidRegisterOrigin, 259 AsWeakPtr(), app_origin, callback)); 260} 261 262void SyncFileSystemService::DidRegisterOrigin( 263 const GURL& app_origin, 264 const SyncStatusCallback& callback, 265 SyncStatusCode status) { 266 DVLOG(1) << "DidRegisterOrigin: " << app_origin.spec() << " " << status; 267 268 callback.Run(status); 269} 270 271void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) { 272 sync_enabled_ = enabled; 273 remote_file_service_->SetSyncEnabled(sync_enabled_); 274} 275 276void SyncFileSystemService::MaybeStartSync() { 277 if (!profile_ || !sync_enabled_) 278 return; 279 280 if (pending_local_changes_ + pending_remote_changes_ == 0) 281 return; 282 283 DVLOG(2) << "MaybeStartSync() called (remote service state:" 284 << remote_file_service_->GetCurrentState() << ")"; 285 switch (remote_file_service_->GetCurrentState()) { 286 case REMOTE_SERVICE_OK: 287 break; 288 289 case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE: 290 if (sync_retry_timer_.IsRunning()) 291 return; 292 sync_retry_timer_.Start( 293 FROM_HERE, 294 base::TimeDelta::FromSeconds(kRetryTimerIntervalInSeconds), 295 this, &SyncFileSystemService::MaybeStartSync); 296 break; 297 298 case REMOTE_SERVICE_AUTHENTICATION_REQUIRED: 299 case REMOTE_SERVICE_DISABLED: 300 // No point to run sync. 301 return; 302 } 303 304 StartRemoteSync(); 305 StartLocalSync(); 306} 307 308void SyncFileSystemService::StartRemoteSync() { 309 // See if we cannot / should not start a new remote sync. 310 if (remote_sync_running_ || pending_remote_changes_ == 0) 311 return; 312 // If we have registered a URL for waiting until sync is enabled on a 313 // file (and the registerred URL seems to be still valid) it won't be 314 // worth trying to start another remote sync. 315 if (is_waiting_remote_sync_enabled_) 316 return; 317 DCHECK(sync_enabled_); 318 319 DVLOG(1) << "Calling ProcessRemoteChange"; 320 remote_sync_running_ = true; 321 remote_file_service_->ProcessRemoteChange( 322 base::Bind(&SyncFileSystemService::DidProcessRemoteChange, 323 AsWeakPtr())); 324} 325 326void SyncFileSystemService::StartLocalSync() { 327 // See if we cannot / should not start a new local sync. 328 if (local_sync_running_ || pending_local_changes_ == 0) 329 return; 330 DCHECK(sync_enabled_); 331 332 DVLOG(1) << "Calling ProcessLocalChange"; 333 local_sync_running_ = true; 334 local_file_service_->ProcessLocalChange( 335 base::Bind(&SyncFileSystemService::DidProcessLocalChange, 336 AsWeakPtr())); 337} 338 339void SyncFileSystemService::DidProcessRemoteChange( 340 SyncStatusCode status, 341 const FileSystemURL& url) { 342 DVLOG(1) << "DidProcessRemoteChange: " 343 << " status=" << status 344 << " (" << SyncStatusCodeToString(status) << ")" 345 << " url=" << url.DebugString(); 346 DCHECK(remote_sync_running_); 347 remote_sync_running_ = false; 348 349 if (status != SYNC_STATUS_NO_CHANGE_TO_SYNC && 350 remote_file_service_->GetCurrentState() != REMOTE_SERVICE_DISABLED) { 351 DCHECK(url.is_valid()); 352 local_file_service_->ClearSyncFlagForURL(url); 353 } 354 355 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC) { 356 // We seem to have no changes to work on for now. 357 // TODO(kinuko): Might be better setting a timer to call MaybeStartSync. 358 return; 359 } 360 if (status == SYNC_STATUS_FILE_BUSY) { 361 is_waiting_remote_sync_enabled_ = true; 362 local_file_service_->RegisterURLForWaitingSync( 363 url, base::Bind(&SyncFileSystemService::OnSyncEnabledForRemoteSync, 364 AsWeakPtr())); 365 return; 366 } 367 368 base::MessageLoopProxy::current()->PostTask( 369 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 370 AsWeakPtr())); 371} 372 373void SyncFileSystemService::DidProcessLocalChange( 374 SyncStatusCode status, const FileSystemURL& url) { 375 DVLOG(1) << "DidProcessLocalChange:" 376 << " status=" << status 377 << " (" << SyncStatusCodeToString(status) << ")" 378 << " url=" << url.DebugString(); 379 DCHECK(local_sync_running_); 380 local_sync_running_ = false; 381 382 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC) { 383 // We seem to have no changes to work on for now. 384 return; 385 } 386 387 DCHECK(url.is_valid()); 388 local_file_service_->ClearSyncFlagForURL(url); 389 390 base::MessageLoopProxy::current()->PostTask( 391 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 392 AsWeakPtr())); 393} 394 395void SyncFileSystemService::DidGetLocalChangeStatus( 396 const SyncFileStatusCallback& callback, 397 SyncStatusCode status, 398 bool has_pending_local_changes) { 399 callback.Run( 400 status, 401 has_pending_local_changes ? 402 SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED); 403} 404 405void SyncFileSystemService::OnSyncEnabledForRemoteSync() { 406 is_waiting_remote_sync_enabled_ = false; 407 MaybeStartSync(); 408} 409 410void SyncFileSystemService::OnLocalChangeAvailable(int64 pending_changes) { 411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 412 DCHECK_GE(pending_changes, 0); 413 DVLOG(1) << "OnLocalChangeAvailable: " << pending_changes; 414 pending_local_changes_ = pending_changes; 415 if (pending_changes == 0) 416 return; 417 418 base::MessageLoopProxy::current()->PostTask( 419 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 420 AsWeakPtr())); 421} 422 423void SyncFileSystemService::OnRemoteChangeQueueUpdated(int64 pending_changes) { 424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 425 DCHECK_GE(pending_changes, 0); 426 DVLOG(1) << "OnRemoteChangeQueueUpdated: " << pending_changes; 427 pending_remote_changes_ = pending_changes; 428 if (pending_changes == 0) 429 return; 430 431 // The smallest change available might have changed from the previous one. 432 // Reset the is_waiting_remote_sync_enabled_ flag so that we can retry. 433 is_waiting_remote_sync_enabled_ = false; 434 435 base::MessageLoopProxy::current()->PostTask( 436 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 437 AsWeakPtr())); 438} 439 440void SyncFileSystemService::OnRemoteServiceStateUpdated( 441 RemoteServiceState state, 442 const std::string& description) { 443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 444 DVLOG(1) << "OnRemoteServiceStateUpdated: " << state 445 << " " << description; 446 447 if (state == REMOTE_SERVICE_OK) { 448 base::MessageLoopProxy::current()->PostTask( 449 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 450 AsWeakPtr())); 451 } 452 453 FOR_EACH_OBSERVER( 454 SyncEventObserver, observers_, 455 OnSyncStateUpdated(GURL(), 456 RemoteStateToSyncServiceState(state), 457 description)); 458} 459 460void SyncFileSystemService::Observe( 461 int type, 462 const content::NotificationSource& source, 463 const content::NotificationDetails& details) { 464 // Event notification sequence. 465 // 466 // (User action) (Notification type) 467 // Install: INSTALLED. 468 // Update: INSTALLED. 469 // Uninstall: UNLOADED(UNINSTALL). 470 // Launch, Close: No notification. 471 // Enable: ENABLED. 472 // Disable: UNLOADED(DISABLE). 473 // Reload, Restart: UNLOADED(DISABLE) -> INSTALLED -> ENABLED. 474 // 475 switch (type) { 476 case chrome::NOTIFICATION_EXTENSION_INSTALLED: 477 HandleExtensionInstalled(details); 478 break; 479 case chrome::NOTIFICATION_EXTENSION_UNLOADED: 480 HandleExtensionUnloaded(type, details); 481 break; 482 case chrome::NOTIFICATION_EXTENSION_ENABLED: 483 HandleExtensionEnabled(type, details); 484 break; 485 default: 486 NOTREACHED() << "Unknown notification."; 487 break; 488 } 489} 490 491void SyncFileSystemService::HandleExtensionInstalled( 492 const content::NotificationDetails& details) { 493 const extensions::Extension* extension = 494 content::Details<const extensions::InstalledExtensionInfo>(details)-> 495 extension; 496 GURL app_origin = 497 extensions::Extension::GetBaseURLFromExtensionId(extension->id()); 498 DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin; 499 // NOTE: When an app is uninstalled and re-installed in a sequence, 500 // |local_file_service_| may still keeps |app_origin| as disabled origin. 501 local_file_service_->SetOriginEnabled(app_origin, true); 502} 503 504void SyncFileSystemService::HandleExtensionUnloaded( 505 int type, 506 const content::NotificationDetails& details) { 507 content::Details<const extensions::UnloadedExtensionInfo> info(details); 508 std::string extension_id = info->extension->id(); 509 GURL app_origin = 510 extensions::Extension::GetBaseURLFromExtensionId(extension_id); 511 512 switch (info->reason) { 513 case extension_misc::UNLOAD_REASON_DISABLE: 514 DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): " 515 << app_origin; 516 remote_file_service_->DisableOriginForTrackingChanges( 517 app_origin, 518 base::Bind(&DidHandleOriginForExtensionUnloadedEvent, 519 type, info->reason, app_origin)); 520 local_file_service_->SetOriginEnabled(app_origin, false); 521 break; 522 case extension_misc::UNLOAD_REASON_UNINSTALL: 523 DVLOG(1) << "Handle extension notification for UNLOAD(UNINSTALL): " 524 << app_origin; 525 remote_file_service_->UninstallOrigin( 526 app_origin, 527 base::Bind(&DidHandleOriginForExtensionUnloadedEvent, 528 type, info->reason, app_origin)); 529 local_file_service_->SetOriginEnabled(app_origin, false); 530 break; 531 default: 532 // Nothing to do. 533 break; 534 } 535} 536 537void SyncFileSystemService::HandleExtensionEnabled( 538 int type, 539 const content::NotificationDetails& details) { 540 std::string extension_id = 541 content::Details<const extensions::Extension>(details)->id(); 542 GURL app_origin = 543 extensions::Extension::GetBaseURLFromExtensionId(extension_id); 544 DVLOG(1) << "Handle extension notification for ENABLED: " << app_origin; 545 remote_file_service_->EnableOriginForTrackingChanges( 546 app_origin, 547 base::Bind(&DidHandleOriginForExtensionEnabledEvent, type, app_origin)); 548 local_file_service_->SetOriginEnabled(app_origin, true); 549} 550 551void SyncFileSystemService::OnStateChanged() { 552 ProfileSyncServiceBase* profile_sync_service = 553 ProfileSyncServiceFactory::GetForProfile(profile_); 554 if (profile_sync_service) 555 UpdateSyncEnabledStatus(profile_sync_service); 556} 557 558void SyncFileSystemService::OnFileStatusChanged( 559 const FileSystemURL& url, 560 SyncFileStatus sync_status, 561 SyncAction action_taken, 562 SyncDirection direction) { 563 FOR_EACH_OBSERVER( 564 SyncEventObserver, observers_, 565 OnFileSynced(url, sync_status, action_taken, direction)); 566} 567 568void SyncFileSystemService::UpdateSyncEnabledStatus( 569 ProfileSyncServiceBase* profile_sync_service) { 570 if (!profile_sync_service->HasSyncSetupCompleted()) 571 return; 572 sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has( 573 syncer::APPS); 574 remote_file_service_->SetSyncEnabled(sync_enabled_); 575 if (sync_enabled_) { 576 base::MessageLoopProxy::current()->PostTask( 577 FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync, 578 AsWeakPtr())); 579 } 580} 581 582} // namespace sync_file_system 583